Migrating
Changes from 0.2
mutateFile,checkFileandloadDocmoved to@miragon/bpmn-cli/node;Doc.load(file)isreadDoc(file)there.mutateDocnever writes;out,dryRun,backupandmustNotExistare options of the file helpers (mutateDocToFile,mutateFile).layoutXmlisbpmn layouton a string; the former wrapper around bpmn-auto-layout is internal (layoutModel(model, { engine: 'auto' })).package.jsonhasexports: only.,./nodeand./package.jsonresolve (no deep imports intodist/).- A write keeps the file's text outside what it changed, and a result equal to the file is not written (
MutationResult.unchanged,written: false; What a write changes). - New ids follow the file's id style (Ids); since 0.3 they also speak (see below).
checkFile/checkDocreturn the validation profile that ran (CheckResult.profile), andMutationOptions/CheckOptionstakeprofile,contentRepo,validatorsandfile; in a design-iq content repository the CLI and the file helpers run the design profile by default (--profile noneswitches it off). The validation profile is gone again after 0.6 (see Changes from 0.6).readXmland the other file helpers read a file in the encoding its XML declaration names (0.2 read UTF-8 only); a write is UTF-8 and declares it.- A full redraw gives an element it draws that has no id (a hand-written message flow, pool, process or collaboration) an id first; 0.2 wrote
bpmnElement="undefined".
Changes from 0.3
- A mutation's result reports warnings as a delta:
warningsis{ added, resolved, preexistingCount }(0.3: the op warnings as an array), andvalidationhas nowarnings(0.3: every warning of the result, repeated on every write); the text lists the added warnings (three or more of one code as one line), the resolved findings and one line counting the file's own (the platform profile's findings included).MutationResult.validation.warnings(mutateDoc) is unchanged;MutationResult.deltahas the comparison. --jsonprints compact JSON on one line;--prettyindents it.showprints each node's lane (lane=<id>) instead of member lists in thelanes:section, and message flows asmessageFlow <id> ["name"]: <source> "name" -> <target> "name".- New ids speak (Ids): names, a kind and a place for unnamed elements (
Gateway_AfterCheckInvoice), the ends for flows (Flow_CheckInvoiceToBookInvoice); 0.3 gave flows and unnamed elements a hash (Flow_0k3x9qa). A flow whose id names its ends is renamed when an edit changes them (0.3: every existing id stayed); the result says so on the changed line and inrenamed(old id -> new id). A taken id gets_2andW_ID_SUFFIXEDfor every generated id, also flows and the event definitions of a Camunda 8 file. A generated id has at most 64 characters;new --name(or a speaking--id) names the definitions too (Definitions_OrderHandling; 0.3:Definitions_1). - An
applybatch refers to an element it creates by an alias ("as": "$check",flowAs,joinAs,refAsfor the message / error / signal / escalation an op creates or finds;MutationResult.aliases/result.aliases: alias -> final id) or by an explicitid; new errorsE_UNKNOWN_ALIAS,E_DUPLICATE_ALIAS. --summary(mutationSummary/renderSummary) is new; the summary and the JSON of a mutation carryaliasesandrenamed, the summary one line per format op (format).remove --with-branch/--bridge-all(E_AMBIGUOUS_BRANCH,E_AMBIGUOUS_BRIDGE); a node added into a flow between two lanes takes the lane of its row (W_LANE_INHERITED).- Format commands:
compact, pool order (order <collaborationId> <participantId...>, ops JSONpools), the selectors--path/--via,--kind,--branchof place, align, color and tidy (E_NO_MATCH,E_NOT_PARTICIPANT), negativespace --by;show --layoutprints columns (c0 Event_Start, c1 ..., JSONcolumns,gaps); four soft metric kinds (backwardFlow,segmentOverlap,labelOutsideFrame,messageLabelFar);layout.reshaped/format[].reshaped. - Camunda 8:
validateand every write run the Camunda 8 profile (34W_C8_*codes; 0.3 said "no Camunda 8 engine rules yet");new --target camunda8writes the platform version; new user tasks of a Camunda 8 file getzeebe:userTask, new event definitions an id;set <id> zeebe:<attr>for an attribute of a zeebe element isE_WRONG_HOST, exceptzeebe:correlationKey, which (likeext add <id> zeebe:subscription) goes to the message a catch event or receive task waits for; the profile parses FEEL;showprintsjob=,form=,assignee=... and a message's correlation key. The core grew by about 200 KB minified / 57 KB gzip (Browser bundles; the FEEL check and the schema-text rules about 23 KB / 7 KB of it).
Changes from 0.4
bpmn renderandrenderSvg(core) /renderPng(@miragon/bpmn-cli/node) are new: the diagram as SVG or PNG without a browser, with the image size, the image-token estimate and the other planes (render); new errorE_RENDER. The package depends on@resvg/resvg-wasm(MPL-2.0, loaded on the first PNG) and ships the Arimo font (OFL-1.1,assets/fonts). For agents: crops (--aroundwith exactly the nodes ofshow --around,--path,--scope, ids), halos (--highlight), the layout problems numbered in the image (--problems;locateProblemsin the library),--tiles, and--render <file>on every mutating command (the result with created / changed / moved elements and the added problems).- The Claude Code plugin's skill looks at what it drew: after a change to the drawing it renders into
.bpmn-render/of the working directory, reads the PNG and fixes the numbered problems with the format commands (Claude Code plugin); a new eval case,tidy-after-edit, measures it. - The Camunda 7 and Camunda 8 profile rules load on demand (Browser bundles):
applyToXmlalone is 618.2 KB minified / 195.8 KB gzip in a host's bundle (0.4: 750.7 / 232.9), the whole entry 814.7 / 255.1 KB without the renderer, 860.7 / 271.3 KB with it (0.4: 945.9 / 291.7). The CLI's output is unchanged. Their chunks import nothing, so a host's entry module can still await a call at top level. - Unchanged:
applyToXml,newXml,layoutXml,validateXml,mutateDoc,checkDocand the file helpers (they load the rules themselves). - Migration: a caller of the synchronous
runProfile(doc)orvalidateDoc(doc, { platform })that does not go through one of them callsawait loadProfiles()once (orawait loadProfile('c7')/loadProfile('c8')for one platform) before; without it they throwE_PROFILE_NOT_LOADEDon a Camunda 7 / 8 document (plain BPMN andplatform: 'none'need no rules). In a test suite one setup line does it (vitestsetupFiles, or a top-levelawait loadProfiles()). - New:
loadProfile(platform)andloadProfiles(platforms?); a host prefetches the chunk when it opens a Camunda 7 / 8 file. A chunk that cannot be loaded rejects the call withE_PROFILE_LOAD(categoryio, exit 4) before a result exists; a later call imports it again, but a browser may keep the failed fetch until the page reloads. tools/iso/check.mjsenforces size budgets (tools/iso/budget.json) and prints the on-demand chunks (--table: the table above).
Changes from 0.5
- A batch that edits a hand-made drawing places its new nodes like the same ops sent as single commands (issue #18): a task and a decision spliced into a flow stay in the row also when the decision gets a new "no" branch or comes from
split, a boundary path waits for the normal flow, and each placed node's flows are routed before the next node is placed. On the plugin eval's model the agent's batches give the same shapes as single commands and score 0 (before: 9 to 19). A new flow that would enter a merge backwards moves the merge after its sources (Layout modes). place <boundaryEventId> --side top|bottom(op keyside) moves a boundary event to the other border of its host, with its exception path (Formatting without XML).- An annotation's association to a flow docks on the nearest point of the flow it reaches in a straight line without cutting a shape, else it is routed around the shapes; when the flow is rerouted, it follows.
E_NO_ROOMfromplace/aligncarries the checked space-tool run that makes the room with the fewest layout problems (details.ops; asdetails.commandwhen the refused op saw the file's own drawing).benchhas two batch edits, E8 and E9, and--comparereports the runs adding crossings / backward flows per edit, with a budget for E8 / E9 (tools/bench/soft-budget.json).- A new branch or boundary path in a hand-made drawing crosses far fewer lines (issue #18, stage B): its row is chosen with the line its nodes take on it; when every row below crosses a line, the row right under the anchor is opened (bypass and loop-back lines move down with the shapes), or the branch goes above its anchor, a boundary path above its host with the event on the top border. A crossing left is repaired once more (the flow routed again, the branch at its next row) when that lowers the score. On a private corpus of real models (single commands) a boundary path adds a crossing in 2 % of the runs (before 23 %), a new branch at a split in 5 % (before 20 %), a decision spliced into a branch in 7 % (before 38 %) (Layout modes). A row in an expanded sub-process keeps clear of the boundary events on its border (no new task on a transaction's cancel event). After the verification: the path of a boundary event on its host's top border (
place --side top, thenadd ... --after <event>) runs above the host and no longer tears the hand-drawn row apart; a boundary event drawn by hand keeps its border; the top border is not taken where a line runs through the spot; the repair never trades a crossing with a new flow for one between two drawn lines; a line along a new end event is routed again; a reroute that would still cross is not measured (faster writes on large models).
Changes from 0.6
The design profile, bpmn-cli's copy of design-iq's save gate, is gone (issue #35). bpmn-cli no longer looks for a
bpmiq.ymlabove a file, and a write in a design-iq content repository is no longer checked against design-iq's rules.The CLI option
--profileis gone from every mutating command and fromvalidate. It is now an unknown option (E_USAGE, exit 1): drop it from scripts.The library options
profileandcontentRepoare gone: fromapplyToXml,newXml,layoutXmlandvalidateXml(EditOptions,LayoutXmlOptions,ValidateXmlOptions), fromMutationOptionsandCheckOptions(mutateDoc,layoutDoc,checkDoc) and from the file helpers (mutateFile,mutateDocToFile,layoutFile,layoutDocToFile,checkFile). TypeScript reports them; at runtime they are ignored, so a host that passedprofile: 'none'only drops it.filestays: it is the validators'ctx.file.Removed exports of
@miragon/bpmn-cli:designFindings,designValidator,undeclaredPrefixes,DESIGN_VALIDATOR,resolveProfile,profileValidators,modelsFolderOf,PROFILE_CHOICES,CONTENT_CONFIG_FILEand the typesDesignOptions,UndeclaredPrefix,ContentRepo,ProfileChoice,ProfileInfo.Removed exports of
@miragon/bpmn-cli/node:findContentRepo,contentModelIds,contentRepoOf,resolveFileProfileand the typeContentRepoOnDisk.The result of
bpmn validate --json,validateXml(ValidationReport) andcheckFile/checkDoc(CheckResult) has noprofilefield.bpmn kinds --jsonhas noprofileskey, andbpmn kinds --section profilesis gone.The codes
E_DESIGN_*andW_DESIGN_*are gone from the error catalogue (ERROR_CATALOGUE,bpmn kinds --section errors), and so are thebpmn guide designtopic and the DESIGN-IQ section ofbpmn guide.Unchanged: the validator hook (
validators,W_PREEXISTING_ERROR,E_VALIDATOR_FAILED,covers), the platform profiles (--platform, Camunda 7 / 8), stickies (bpmiq:stickyfollows its node) and the decision links in every spelling.Migration: in a design-iq content repository, run design-iq's own validator after edits:
npx @miragon/design-iq-validator --root .Migration: a library host that wants a check inside the write passes its own validator through
validators(Validators). An error a change adds refuses the write (E_VALIDATION); one the file already had is aW_PREEXISTING_ERRORwarning. design-iq's live host already passes its own check this way.A generated id is no longer cut at 61 characters: the cap of 64 includes a collision suffix (issue #31). 0.6 could cut a flow's end inside a word (
Flow_ConsignationSynchronisierenToConsignationsProtokollieren); now an id within 64 characters is not cut again, and a longer one loses whole words. A name still gives at most 40 characters of words, as in 0.6, but a cut no longer ends on a filler word such asundoran(Activity_LieferantenbestellungVersenden, 0.6:Activity_LieferantenbestellungVersendenUnd), nor does a cut flow end. A flow's ends keep the most words that fit (0.6 shared the room by characters), an end never shrinks to a number or to a bare Join, two numbers never run into one (0.6:Flow_2ToVertragsunterlagenarchivierung,Flow_32024To...), and the id never ends on a number a cut left that reads like a collision suffix. A flow named by its ends' ids (Flow_<sourceId>_<targetId>) keeps each id's prefix when it is cut, where the prefixes leave room for the words after them. A scoped flow (Flow_KotO_ValidateToReserve) cuts its two end words instead of losing the target (0.6:Flow_KotO_WarenwirtschaftssystemabgleichTo), and a number is no end word (0.6:Flow_KotO_ReserveTo4). A file prefix too long to leave an id room gives way to the bpmn-cli prefix where the id would not fit with it (0.6 went past 64 characters), and so does a flow prefix or scope that leaves the ends fewer than 16 characters where they do not fit beside it at whole words (0.6 kept it and cut them). A taken id whose glued suffix (stemTo and scopedTo flows) follows a digit getsNobefore the number (flow_checkOrderToSendPdf10No2; 0.6:...Pdf102); 0.6's glued ids still follow their ends. Where a file's data object references and data objects share one prefix (bare ids too), the backingbpmn:DataObject/bpmn:DataStoreof a long name keeps itsObject/Storeword after the cut body (processDataArtefactItem_lieferung_vollstaendig_object; 0.6:..._eingegangen_2withW_ID_SUFFIXED). A flow the length cap cut still counts for the file's flow form, also one 0.6 cut (in 0.6, enough of them switched a file ofFlow_<sourceId>_<targetId>flows toFlow_<Source>To<Target>, and its flows stopped following their ends). The same edit can therefore give a long id that differs from the one 0.6 gave. Flows 0.6 named are still renamed after their ends, also as 0.6 cut them and in a file that now reads as another form (they then get that form's id).Flow ids can be kept (issue #32):
--keep-flow-idson every mutating command andapply,BPMN_KEEP_FLOW_IDS=1as the default of a shell or an agent session,keepFlowIdsinEditOptions/MutationOptions. A flow the file had then keeps its id when an edit gives it other ends, and the change names each one whose id no longer names its ends (W_FLOW_ID_STALE, with thebpmn setthat renames it; after a splicingadd --flow-id, to that id; Limitations). A library caller that setsDoc.followFlowEnds = falsegets these warnings now too, and a--strictrun exits 5 on them. Only the flows the document had keep their ids: a flow the samerunOp,runOpsormutateDoccall created follows its ends,renameslists it andcreatedhas its final id (0.6: every id stayed). Name such a flow with an alias where an op creates it (flowAson an add that appends or prepends and on split nodes,outAson an add that splices, prepends or hasto, for the flow out of the new node,ason connect) instead of guessing its id. With ids kept,moveputs the moved node's out-flow back at its new place (changed, keeping its id, documentation and extensions; its name and condition stay with the bridge, and its change says which; a node that is not bridged, or whose bridge a later node of the same move removed, drops them withW_LABEL_DROPPED/W_CONDITION_DROPPEDunless the flow is put back between its old ends) instead of removing it and creating a new one (0.6), so a flow between nodes moved together stays theirs.A batch or an op learns the file's id style before its first op runs (
Doc.idStyle). Before, it was learned when the first new id was needed, so the ops before that could change it: a first op that removed flows (also a singlemove, which detaches its node first), renamed ids (set <flow> id=), named elements or retyped them could make it learn another style from what was left: new elements were named in it, and a flow whose id named its old ends was not renamed (with ids kept: not reported asW_FLOW_ID_STALE). Such batches and commands now name and rename in the style of the file as read.A flow end is also recognised by its name where its id speaks, and in a batch by the id and name it had before a
set id=/set name=earlier in the batch. 0.6 named an end only as it was called at that moment: afterset Activity_Check id=Activity_Verify(in the same batch, or in a command before while the end keeps its name "Check"), orset name=on an end whose id says nothing, a splice next to it keptFlow_CheckToOkwithout a word. Such flows are now renamed after their new ends (Flow_VerifyToLog; with ids kept:W_FLOW_ID_STALE), so a file whose flow ids name their ends by the ends' names (Flow_CheckToOkbetweenActivity_Verify"Check" andEvent_Ok) sees more renames. An end without a name renamed in a command before is still missed: nothing records its old id across commands.A file's flow form stays put. The flows bpmn-cli names by their ends in a file of
flow12/f3ids (fPackToWeigh, in snake_casefpack_to_weigh) count for that prefix: 0.6 counted them against it, and after a few edits such a file read asFlow_, named new flowsFlow_ArchiveToShipand no longer renamed its ownfBillTo...flows. A tie between two flow prefixes goes to the one more flows use (f3counts forf), then to the alphabetically first (0.6: the one declared first, so a move that declared a flow elsewhere could flip it); a tie between two forms under one prefix (two hashes and twoFlow_Task_A_Task_Bflows) to the one that names the ends, so new flows there take that form instead ofFlow_<Source>To<Target>. A tie between scopes stays as in 0.6. 0.6's scoped flows cut to an empty target word (Flow_KotO_WarenwirtschaftssystemabgleichTo) count for the scopedTo form, so enough of them no longer switch a 0.6 file toFlow_<Source>To<Target>. A flow named after its ends under any flow prefix or form the file's flows use (aSequenceFlow_and aFlow_prefix from two modeler versions,F_next toG_, a second scope) is renamed after its new ends (with ids kept:W_FLOW_ID_STALE); 0.6 recognised only the winning one, so a followed hint could stop naming its ends on the next read. Such files see more renames, and in a few the learned flow prefix changes (show --conventions).A sequence flow without id (valid BPMN, written by hand) no longer makes
add,splitorapplyfail withE_INTERNAL(exit 70) when they splice into it, nor a bridge into it: it gets an id from its new ends (or the--flow-idof theaddthat splices into it) and is listed as changed with(id added: it had none). A removed one isremoved sequenceFlow (no id)(0.6:undefined);--summaryleaves it out ofremoved:.The change report names a flow that took the id a renamed flow freed by its own id:
add --id Activity_Check --after Event_CheckintoFlow_CheckToDonelistscreated sequenceFlow Flow_CheckToDone - Activity_Check -> Event_Doneand the spliced flow as changed (Flow_CheckToCheck,renamed: Flow_CheckToDone -> Flow_CheckToCheck); 0.6 listed both underFlow_CheckToCheck, and--summarydropped the changed one. The written file is the same.Node 22.12 or later (
engines.node; commander 15 and vitest 5 need it, 0.6 declared Node 20).bpmn validateand every write run the project's bpmnlint configuration: the nearest.bpmnlintrcabove the file, up to the repository root, whoever owns it (outside a git repository: the file's directory only; bpmnlint).validateexits 2 on its errors; a write lists the findings the change added (warning [bpmnlint error] ...) and never refuses because of them.--no-lint-configleaves bpmnlint out of the output; without a.bpmnlintrcnothing of bpmnlint is loaded and bpmnlint adds nothing.bpmnlint11.15.0 and@miragon/bpmnlint-plugin-rules0.12.1 are dependencies (exact versions);bpmn-moddleresolves to 10.3.Library:
NamedValidator.blocks: falsemakes a validator advisory (ValidatorReport.blocks); the file helpers run the.bpmnlintrctoo, with only the rules bpmn-cli ships unlesslintProjectCode: true(project plugins then run only in a git repository of the host's user);checkFiletakesFileCheckOptions(lintConfig,lintFrom,lintBlocks,lintProjectCode);warningLines(warnings, advisory)andrenderSummary(summary, { advisory })group an advisory validator's findings by code and message (advisoryValidators(report)gives the names; the CLI passes them);--summary'spreexistingCountcounts an advisory validator's old findings too.Two validators of the same name are compared in order (0.6 compared every run with the first one's baseline), and a lint warning that a resolved validator finding says again (
covers) is listed once inresolved, as that finding (0.6 listed both:W_DEAD_ENDnext to the validator's finding about the same element).A write that fails (
-onaming a directory, a directory without write permission) isE_IO(exit 4) and leaves no temp file; 0.6 reportedE_INTERNAL(exit 70) and left.<name>.<pid>.tmpbehind.writeAtomicthrows thatCliError.Output piped into a reader that closes early (
| head) ends without anEPIPEtrace and keeps the command's exit code (0.6 printed a Node stack trace and exited 1 when the command succeeded), and a model piped in from a slow writer (curl ... | bpmn validate -) is read whole (0.6 could fail withE_IOEAGAIN).Where the
.bpmnlintrcthat runs has@miragon/rules/element-id-namingon (recommended-for-automationturns it on,recommended-for-modelinghas it off), the ids a write generates follow its prefixes and case instead of the file's style:serviceTask_checkInvoicenext toActivity_CheckOrder,flow_checkInvoiceToBookInvoicealso for a flow renamed after its new ends (bpmnlint). The process and definitions ids ofnewchange only where the rule namesbpmn:Process/bpmn:Definitionsexactly (process_orderHandling,process_mainwithout a name); no id the file has changes. Under camelCase or PascalCase a taken id gets a glued2(serviceTask_checkInvoice2; after a digitNo2:serviceTask_step1No2) and a split's join is<gatewayId>Join. A result names such ids (conventions:;MutationResult.conventions).--no-lint-configgives the ids of before.Library:
MutationOptions,EditOptionsandNewDocOptionstakeconventions(IdConventions, plain data;idConventionsFromLintbuilds them from a rule setting with the plugin's naming helpers). The file helpers pass the conventions of the.bpmnlintrcthey run, unless the host passesconventionsor a validator named bpmnlint of its own.bpmnlintValidatortakesnotes(W_CONFIG_IGNORED), andLoadedBpmnlinthaswhere.Library: with
platform: 'none'(MutationOptions.platform), asetop withcalledDecisionon a business rule task whose link has an engine spelling updates it in that spelling (camunda:decisionRef,operaton:decisionRef; azeebe:calledDecisiongets thedecisionIdand keeps itsresultVariable; issue #42). 0.6 replaced it with an unprefixedcalledDecisionand dropped theresultVariable. A task without a link takes the engine spelling of the file's other links when they all have the same one, else the unprefixedcalledDecisionas before. The change'sdetailnames the spelling written (calledDecision=risk (camunda:decisionRef); 0.6:calledDecision=risk (calledDecision); removed camunda:decisionRef). The CLI is unchanged: it detects the engine from such a link, sobpmn set <file> <id> calledDecision=<decision>writes the Camunda 7 / 8 spelling as in 0.6, and in a file without engine content the unprefixedcalledDecision(Set keys).In an
applybatch (and a typed batch ofmutateDoc/runOps) an alias follows its element through a retype to another type, also to the new id the declared id conventions give it (serviceTask_checkInvoice->userTask_checkInvoice), so a batch can create, retype and then configure an element. 0.6 failed a later op that used the alias withE_NOT_FOUND(exit 2) and left the alias out ofaliases(thealiases:line and--json), which now lists it with the new id.Library: a typed
splitop (mutateDoc,runOps,mutateFile) whose branch has nonodesarray isE_USAGE, worded likeparseOps(split branches[0]: missing required key "nodes" (...)); 0.6 made it a direct gateway -> join flow. Writenodes: []for a direct flow, as the CLI already asked.branchesornodesthat are not arrays of objects, and a node without a stringkind, areE_USAGEtoo (0.6: aTypeError, a node withoutkindwith the split gateway already added). The split checks this before it changes anything.movechecks the chain before anything changes: when the node a chain of several ids starts after (the--afteranchor, the source of the--flow) is one of its later nodes, inside one or a boundary event of one, or a--beforeanchor lies inside one, the move fails withE_INVALID_PLACEMENT(exit 2). 0.6 wrote a rewired model with exit 0 (move A Join Done --after Join: unreachable nodes, a flow listed as created and removed). A single node after its own boundary event isE_INVALID_PLACEMENTtoo (0.6:E_NOT_FOUND).A move that leaves its nodes where they are (
move B --after Awith A -> B) changes nothing and adds a note (Activity_B is already after Activity_A), in both flow-id modes. 0.6 detached and placed the node again: by default new or suffixed flow ids (W_ID_SUFFIXED), the out-flow's label on the in-flow, and a gateway or merge in the chain lost its other flows; some such moves were refused (E_HAS_SUCCESSOR,E_HAS_PREDECESSOR,E_NO_FLOW,E_INVALID_BRIDGE) and are notes now. In a batch its flow keys go to the flow into the first node, and"flowId"renames that flow (0.6 made a new flow with that id where the node was appended, and dropped the id where it was spliced). The incremental layout places only the nodes a move relocated (0.6: every node a move named, so a move in place could rearrange a hand-made drawing). Library:ChangeSet.relocatedlists them.A full redraw (
bpmn layout,--relayout/--layout full, an engine-owned drawing redrawn inautomode, theW_LAYOUT_INCREMENTAL_FAILEDfallback,--engine auto) draws group boxes again around the elements they held, with their DI id and colour; 0.6 dropped every group's shape. A group with nothing drawn inside keeps its box, or its size below the drawing when the redraw put shapes on it, and the layout block has a note (LayoutStatus.notesandLayoutResult.notescan now come from a full redraw). The built-in engine keeps the parts of a group that no flow connects together, so files with groups can get another order of such parts; without groups the order is unchanged.The layout metrics (
bpmn metrics,layoutProblems,layout.metricsof every write,render --problems) no longer treat a group as a leaf shape: a group never overlaps, lies on a line or has a label on it (its own label still counts). Scores of drawings with a group are lower than in 0.6 for the same file: gallery.bpmn 182 -> 64.A group of the collaboration no longer gives
W_LAYOUT_DI_NOT_CREATED. An association between a text annotation and a group still has no line after a full redraw; its warning now readsNo DI created for <id> (an end is a group: its box is drawn after the layout).DI ids stay within 64 characters, a collision suffix included, also in a new drawing (a new file, a file without DI, or DI whose ids show no form) and its full redraws: where
BPMNShape_<id>,BPMNEdge_<id>,BPMNPlane_<id>orBPMNDiagram_<id>would pass 61 characters (room for a_99), the id in it is cut at whole words, and a cut id that is taken gets_2; 0.6 wrote them uncut there. Element ids up to 49 characters give the same DI ids as before. DI ids a file already has are never cut. Element ids, the CLI's output and the library's results do not change.bpmn set <file> <id> id=<new>(and anapplybatch'sset) takes a DI id derived from the old id along (<id>_di,BPMNShape_<id>,BPMNEdge_<id>,Edge_<id>, also cut, also with a_2), as a flow renamed after its ends always did; 0.6 leftBPMNShape_<old>. So following aW_FLOW_ID_STALEhint gives the file the default rename gives. A DI edge id 0.6 cut to numbers (BPMNEdge_Flow_Pruefung10To2030) now follows its flow too. When the new DI id is taken, a renamed element (or a flow renamed after its ends) gets it with_2; 0.6 left the old one. The renamed element's DI element is written anew, as the renamed element itself already was: its attributes in bpmn-moddle's order, and a comment inside it is dropped (the result's note counts it). In a batch, a DI id of an element removed earlier in it is free for a laterset id=, as it is for a command of its own.Under
--no-layouta flow whose ends an op changed (a bridge, a splice, a move,set source=/target=) loses its BPMNEdge in both flow-id modes, and with it the line's colour, label position and DI id. 0.6 kept the line at the old ends, and with--keep-flow-idssaid nothing. A line that already reaches the new ends stays, and so does one into a node the same write added (it has no shape yet). The note counts and names those flows:removed 2 stale diagram element(s), among them the edge(s) of Flow_AToC (their ends changed; the next model edit without --no-layout draws them, or `bpmn route <file> <flowId>`)(0.6:removed 1 stale diagram element(s); run `bpmn layout` to redraw; without such flows the command now names<file>). The quality line lists them asmissinguntil a write that updates the layout draws them, plain.routedraws such a flow on its own (0.6:E_NO_SHAPEfor a flow without a line, which is also whatcolorandlabelgive on it until then). A second BPMNDiagram of the same process loses those edges on every write.A line whose end lies more than 10 px outside its end's shape (left there by another tool or an older
--no-layoutwrite) is routed again by every write that keeps the drawing and by the format commands that change the geometry (tidy,place,compact, ...), and listed inreroutedwith a note (Flow_X routed again: it did not reach Activity_C); not on a plane with vertical pools or lanes, where nothing is routed. A no-op on such a file is no longer byte-identical. The layout metrics have a new hard kind for such a line,detachedEdge(weight 10, ids[edge, the end(s) it misses], a new key incountsand inMETRIC_KEYS), so the score of a file that has one is higher than in 0.6 (a scenario with 9 such lines: 42 -> 132).A new pool's process takes the prefix two of the file's process ids share, in the case their bodies show, else the file's:
process_customerandprocess_shopgiveprocess_bankAccountalso next toParticipant_pools (0.6:Process_bankAccount, from the shape of the file's other prefixes); the pools' ids never count. Where no two process ids share a prefix, the process id is the one of 0.6, and files bpmn-cli made keepProcess_<Name>.