@miragon/wardley-dsl 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/index.cjs +30 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +30 -30
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -464,7 +464,7 @@ function unknownStatementMessage(line) {
|
|
|
464
464
|
const core = linkCore(line);
|
|
465
465
|
if (/->|\+('[^']*')?(<>|>|<)/.test(core)) return "Link needs a name on both sides";
|
|
466
466
|
const flowValue = /\+'[^']*'/.exec(core);
|
|
467
|
-
if (flowValue) return `Flow ${flowValue[0]} has no direction
|
|
467
|
+
if (flowValue) return `Flow ${flowValue[0]} has no direction: add ">", "<" or "<>"`;
|
|
468
468
|
return `Unknown statement "${line.split(/\s/)[0]}"`;
|
|
469
469
|
}
|
|
470
470
|
function buildEdges(links, idOfName, unresolved, labelOf, built) {
|
|
@@ -594,7 +594,7 @@ var MapReader = class {
|
|
|
594
594
|
}
|
|
595
595
|
/** For a line that looks like a known construct but cannot be parsed. */
|
|
596
596
|
failed(line) {
|
|
597
|
-
this.keep(line, "Line not understood
|
|
597
|
+
this.keep(line, "Line not understood: kept as written");
|
|
598
598
|
}
|
|
599
599
|
// A reference binds to the name as written first, so `X 2` stays bound to an explicit "X 2" even
|
|
600
600
|
// when a duplicate "X" was renamed to "X 2"; the serializer then writes that reference by the
|
|
@@ -609,7 +609,7 @@ var MapReader = class {
|
|
|
609
609
|
setConfig(keyword, update) {
|
|
610
610
|
const earlier = this.lineThatSetConfig.get(keyword);
|
|
611
611
|
if (earlier !== void 0) {
|
|
612
|
-
this.diag(`Repeated "${keyword}"
|
|
612
|
+
this.diag(`Repeated "${keyword}": replaces the one on line ${earlier}`);
|
|
613
613
|
}
|
|
614
614
|
this.lineThatSetConfig.set(keyword, this.lineNo);
|
|
615
615
|
const configLines2 = this.configLinesByKeyword.get(keyword) ?? [];
|
|
@@ -647,7 +647,7 @@ var MapReader = class {
|
|
|
647
647
|
return true;
|
|
648
648
|
}
|
|
649
649
|
this.keywordLinks.push(link);
|
|
650
|
-
if (leftDeclared) this.diag(`Link: "${link.right}" not found
|
|
650
|
+
if (leftDeclared) this.diag(`Link: "${link.right}" not found; read as a "${kw}" statement`);
|
|
651
651
|
return false;
|
|
652
652
|
}
|
|
653
653
|
/** Clamps a normalized value to [0,1] — with a diagnostic instead of a later validation crash. */
|
|
@@ -663,7 +663,7 @@ var MapReader = class {
|
|
|
663
663
|
}
|
|
664
664
|
/** A suffix written in front of the coordinates is part of the name or text (OWM). */
|
|
665
665
|
reportMisplacedSuffix(groups, where, fix) {
|
|
666
|
-
if (groups.length) this.diag(`"${groups.join(" ")}" ${where}
|
|
666
|
+
if (groups.length) this.diag(`"${groups.join(" ")}" ${where}: ${fix}`);
|
|
667
667
|
}
|
|
668
668
|
/**
|
|
669
669
|
* A text as the serializer writes it. Its comment markers are protected only by flow values
|
|
@@ -674,7 +674,7 @@ var MapReader = class {
|
|
|
674
674
|
const written = escapeCommentMarkers(text);
|
|
675
675
|
if (written !== text) {
|
|
676
676
|
this.diag(
|
|
677
|
-
`"${text}" read as "${written}"
|
|
677
|
+
`"${text}" read as "${written}", because "//" or "/*" there would start a comment once saved`,
|
|
678
678
|
line,
|
|
679
679
|
source
|
|
680
680
|
);
|
|
@@ -687,7 +687,7 @@ var MapReader = class {
|
|
|
687
687
|
const name = this.namesInUse.claim(base);
|
|
688
688
|
if (name !== base) {
|
|
689
689
|
this.diag(
|
|
690
|
-
`Duplicate name "${sourceName}"
|
|
690
|
+
`Duplicate name "${sourceName}": renamed to "${name}"; links bind to the first "${sourceName}"`,
|
|
691
691
|
atLine,
|
|
692
692
|
atText
|
|
693
693
|
);
|
|
@@ -701,20 +701,20 @@ var MapReader = class {
|
|
|
701
701
|
this.blockPipeline = this.lastPipeline;
|
|
702
702
|
this.recordBlockLine(this.blockPipeline, "open");
|
|
703
703
|
this.blockOpening = { line: this.lineNo, text: this.currentLine };
|
|
704
|
-
} else this.diag('Ignored "{"
|
|
704
|
+
} else this.diag('Ignored "{": a block must directly follow a pipeline line');
|
|
705
705
|
this.lastPipeline = null;
|
|
706
706
|
}
|
|
707
707
|
closeBlock() {
|
|
708
708
|
if (this.blockPipeline) {
|
|
709
709
|
this.recordBlockLine(this.blockPipeline, "close");
|
|
710
710
|
this.blockPipeline = null;
|
|
711
|
-
} else this.diag('Ignored "}"
|
|
711
|
+
} else this.diag('Ignored "}": no pipeline block is open');
|
|
712
712
|
this.lastPipeline = null;
|
|
713
713
|
}
|
|
714
714
|
endUnclosedBlock() {
|
|
715
715
|
if (!this.blockPipeline) return;
|
|
716
716
|
this.diag(
|
|
717
|
-
`Pipeline block of "${this.blockPipeline.name}" is never closed
|
|
717
|
+
`Pipeline block of "${this.blockPipeline.name}" is never closed: add "}"`,
|
|
718
718
|
this.blockOpening.line,
|
|
719
719
|
this.blockOpening.text
|
|
720
720
|
);
|
|
@@ -754,7 +754,7 @@ var MapReader = class {
|
|
|
754
754
|
if (blockCommentStart) {
|
|
755
755
|
const { line, text: startText } = blockCommentStart;
|
|
756
756
|
this.diag(
|
|
757
|
-
'Block comment "/*" is never closed
|
|
757
|
+
'Block comment "/*" is never closed: the rest of the file is a comment',
|
|
758
758
|
line,
|
|
759
759
|
startText
|
|
760
760
|
);
|
|
@@ -855,7 +855,7 @@ var MapReader = class {
|
|
|
855
855
|
}
|
|
856
856
|
if (splitAtCoords(after)?.name) {
|
|
857
857
|
this.diag(
|
|
858
|
-
`Component with [visibility, maturity] inside the block of pipeline "${blockPipeline.name}" is not a child
|
|
858
|
+
`Component with [visibility, maturity] inside the block of pipeline "${blockPipeline.name}" is not a child: use [maturity]`
|
|
859
859
|
);
|
|
860
860
|
}
|
|
861
861
|
return false;
|
|
@@ -923,7 +923,7 @@ var MapReader = class {
|
|
|
923
923
|
let body = after;
|
|
924
924
|
let opensBlock = false;
|
|
925
925
|
while (body.endsWith("{")) {
|
|
926
|
-
if (opensBlock) this.diag('Ignored "{"
|
|
926
|
+
if (opensBlock) this.diag('Ignored "{": a block must directly follow a pipeline line');
|
|
927
927
|
opensBlock = true;
|
|
928
928
|
body = body.slice(0, -1).trim();
|
|
929
929
|
}
|
|
@@ -990,7 +990,7 @@ var MapReader = class {
|
|
|
990
990
|
if (problem) this.diag(problem);
|
|
991
991
|
if (!Number.isInteger(coords.a) || !Number.isInteger(coords.b)) {
|
|
992
992
|
this.diag(
|
|
993
|
-
`Map size ${coords.a}\xD7${coords.b} is not in whole pixels
|
|
993
|
+
`Map size ${coords.a}\xD7${coords.b} is not in whole pixels: OWM only reads whole-pixel sizes`
|
|
994
994
|
);
|
|
995
995
|
}
|
|
996
996
|
}
|
|
@@ -1019,7 +1019,7 @@ var MapReader = class {
|
|
|
1019
1019
|
});
|
|
1020
1020
|
if (written.length !== 1 && !(written.length === 3 && written.every(Boolean))) {
|
|
1021
1021
|
const read = [label, ...ends ?? []].join("->");
|
|
1022
|
-
this.diag(`y-axis takes "Label" or "Label->Bottom->Top"
|
|
1022
|
+
this.diag(`y-axis takes "Label" or "Label->Bottom->Top": read as "${read}"`);
|
|
1023
1023
|
}
|
|
1024
1024
|
}
|
|
1025
1025
|
readAnnotationsBox(line, after) {
|
|
@@ -1027,7 +1027,7 @@ var MapReader = class {
|
|
|
1027
1027
|
if (!split) {
|
|
1028
1028
|
return this.keep(
|
|
1029
1029
|
line,
|
|
1030
|
-
"Annotations box has no position
|
|
1030
|
+
"Annotations box has no position: not used; add [visibility, maturity]"
|
|
1031
1031
|
);
|
|
1032
1032
|
}
|
|
1033
1033
|
this.reportTextBefore(split.name);
|
|
@@ -1042,7 +1042,7 @@ var MapReader = class {
|
|
|
1042
1042
|
if (!Number.isSafeInteger(number)) return this.failed(line);
|
|
1043
1043
|
const found = parsePositions(after.replace(/^\s*\d+\s*/, ""));
|
|
1044
1044
|
if (!found) {
|
|
1045
|
-
return this.keep(line, "Annotation has no position
|
|
1045
|
+
return this.keep(line, "Annotation has no position: not drawn; add [visibility, maturity]");
|
|
1046
1046
|
}
|
|
1047
1047
|
if (!found.tuples.length) return this.failed(line);
|
|
1048
1048
|
for (const unreadable of found.unreadable) this.diag(unreadableNumberMessage(unreadable));
|
|
@@ -1109,7 +1109,7 @@ var MapReader = class {
|
|
|
1109
1109
|
*/
|
|
1110
1110
|
readMethod(line, after, kw) {
|
|
1111
1111
|
if (this.pushComponent(after, kw)) return;
|
|
1112
|
-
if (!after) return this.keep(line, `${kw}: needs a component name
|
|
1112
|
+
if (!after) return this.keep(line, `${kw}: needs a component name; not used`);
|
|
1113
1113
|
this.pendingMethod.push({
|
|
1114
1114
|
name: after,
|
|
1115
1115
|
method: kw,
|
|
@@ -1281,7 +1281,7 @@ var MapReader = class {
|
|
|
1281
1281
|
this.keepLine(p.raw, p.lineNo, p.text);
|
|
1282
1282
|
if (!component) {
|
|
1283
1283
|
this.diag(
|
|
1284
|
-
`Pipeline "${p.name}" has no range
|
|
1284
|
+
`Pipeline "${p.name}" has no range: not drawn; add [start, end] or child components`,
|
|
1285
1285
|
p.lineNo,
|
|
1286
1286
|
p.text
|
|
1287
1287
|
);
|
|
@@ -1294,7 +1294,7 @@ var MapReader = class {
|
|
|
1294
1294
|
const widened = range.start !== writtenRange.start || range.end !== writtenRange.end;
|
|
1295
1295
|
if (widened && !writtenRange.fromChildren) {
|
|
1296
1296
|
this.diag(
|
|
1297
|
-
`Pipeline "${p.name}" range is empty or reversed
|
|
1297
|
+
`Pipeline "${p.name}" range is empty or reversed: changed to [${range.start}, ${range.end}]`,
|
|
1298
1298
|
p.lineNo,
|
|
1299
1299
|
p.text
|
|
1300
1300
|
);
|
|
@@ -1343,7 +1343,7 @@ var MapReader = class {
|
|
|
1343
1343
|
const component = this.elements[index];
|
|
1344
1344
|
const earlier = evolveLineOf.get(component.id);
|
|
1345
1345
|
if (earlier !== void 0) {
|
|
1346
|
-
const message = `Repeated evolve for "${ev.name}"
|
|
1346
|
+
const message = `Repeated evolve for "${ev.name}": replaces the one on line ${earlier}`;
|
|
1347
1347
|
this.diag(message, ev.lineNo, ev.text);
|
|
1348
1348
|
}
|
|
1349
1349
|
evolveLineOf.set(component.id, ev.lineNo);
|
|
@@ -1371,7 +1371,7 @@ var MapReader = class {
|
|
|
1371
1371
|
const el = this.elements[index];
|
|
1372
1372
|
const replaced = el.decorators?.method;
|
|
1373
1373
|
if (replaced && replaced !== pm.method) {
|
|
1374
|
-
const message = `${pm.method}:
|
|
1374
|
+
const message = `${pm.method}: replaces the method "${replaced}" of "${pm.name}"`;
|
|
1375
1375
|
this.diag(message, pm.lineNo, pm.text);
|
|
1376
1376
|
}
|
|
1377
1377
|
this.elements[index] = { ...el, decorators: { ...el.decorators, method: pm.method } };
|
|
@@ -1382,7 +1382,7 @@ var MapReader = class {
|
|
|
1382
1382
|
}
|
|
1383
1383
|
};
|
|
1384
1384
|
function renamedMessage(sourceName, name) {
|
|
1385
|
-
return `Name "${sourceName}" renamed to "${name}"
|
|
1385
|
+
return `Name "${sourceName}" renamed to "${name}", because a name cannot hold link operators ("->", "+>", "+<", "+'"), comment markers or a leading "{"`;
|
|
1386
1386
|
}
|
|
1387
1387
|
function withoutTrailingCarriageReturns(line) {
|
|
1388
1388
|
let end = line.length;
|
|
@@ -1396,7 +1396,7 @@ function withoutClosersOfKeptComments(entries, report) {
|
|
|
1396
1396
|
if (!entry.isComment && nextParse.insideBlockComment && text.includes("*/")) {
|
|
1397
1397
|
text = text.replaceAll("*/", " ");
|
|
1398
1398
|
report(
|
|
1399
|
-
'Ignored "*/"
|
|
1399
|
+
'Ignored "*/": this line is kept after an unclosed "/*" and would end that comment',
|
|
1400
1400
|
entry.lineNo,
|
|
1401
1401
|
entry.source
|
|
1402
1402
|
);
|
|
@@ -1415,7 +1415,7 @@ function replacedConfigLines(unusedLines, config, report) {
|
|
|
1415
1415
|
const replaced = configIsSet[unused.keyword];
|
|
1416
1416
|
if (replaced) replacedIndexes.add(unused.index);
|
|
1417
1417
|
const outcome = replaced ? `removed; another "${unused.keyword}" line sets it` : "not used";
|
|
1418
|
-
report(`${unused.reason}
|
|
1418
|
+
report(`${unused.reason}: ${outcome}`, unused.line, unused.text);
|
|
1419
1419
|
}
|
|
1420
1420
|
return replacedIndexes;
|
|
1421
1421
|
}
|
|
@@ -1427,7 +1427,7 @@ function resolveUrlReferences(elements, refs, definitions, report, resolved) {
|
|
|
1427
1427
|
if (earlier) {
|
|
1428
1428
|
replaced.add(earlier);
|
|
1429
1429
|
report(
|
|
1430
|
-
`Repeated url definition "${definition.name}"
|
|
1430
|
+
`Repeated url definition "${definition.name}": replaces the one on line ${earlier.lineNo}, which is kept unused`,
|
|
1431
1431
|
definition.lineNo,
|
|
1432
1432
|
definition.text
|
|
1433
1433
|
);
|
|
@@ -1440,7 +1440,7 @@ function resolveUrlReferences(elements, refs, definitions, report, resolved) {
|
|
|
1440
1440
|
if (definition) used.add(definition);
|
|
1441
1441
|
const address = definition?.address ?? (/^[a-z][\w+.-]*:\/\//i.test(ref) ? ref : void 0);
|
|
1442
1442
|
if (!address) {
|
|
1443
|
-
report(`url(${ref}) has no matching "url ${ref} [address]" line
|
|
1443
|
+
report(`url(${ref}) has no matching "url ${ref} [address]" line: ignored`, line, text);
|
|
1444
1444
|
continue;
|
|
1445
1445
|
}
|
|
1446
1446
|
const el = elements[index];
|
|
@@ -1575,7 +1575,7 @@ function splitPipelineLine(body) {
|
|
|
1575
1575
|
return { name: rest, range: null, suffixText: groups.join(" "), misplaced: [] };
|
|
1576
1576
|
}
|
|
1577
1577
|
function unreadableNumberMessage(text) {
|
|
1578
|
-
return `Unreadable number in "${text}"
|
|
1578
|
+
return `Unreadable number in "${text}": ignored`;
|
|
1579
1579
|
}
|
|
1580
1580
|
function pipelineRange(p) {
|
|
1581
1581
|
if (p.start !== void 0 && p.end !== void 0) {
|
|
@@ -1667,7 +1667,7 @@ function splitMisplacedEvolveSuffix(name) {
|
|
|
1667
1667
|
return rest ? { name: rest, suffix: m[0] } : null;
|
|
1668
1668
|
}
|
|
1669
1669
|
function misplacedEvolveSuffixHint({ name, suffix }) {
|
|
1670
|
-
return suffix.startsWith("(") ?
|
|
1670
|
+
return suffix.startsWith("(") ? `; for component "${name}", write "${suffix}" after the target` : `; for component "${name}", write "${suffix}" on its component line`;
|
|
1671
1671
|
}
|
|
1672
1672
|
var NUMBER_TOKEN_RE = /(^|\s)([-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[-+]?\d+)?)(?=\s|\(|$)/gi;
|
|
1673
1673
|
function parseEvolve(after, report) {
|
|
@@ -1706,7 +1706,7 @@ function sizeOutsideLimits(width, height) {
|
|
|
1706
1706
|
const minimum = `${PLOT_MIN.width}\xD7${PLOT_MIN.height}`;
|
|
1707
1707
|
const maximum = `${PLOT_MAX.width}\xD7${PLOT_MAX.height}`;
|
|
1708
1708
|
const limit = below && above ? `outside ${minimum} to ${maximum}` : below ? `below the minimum ${minimum}` : `above the maximum ${maximum}`;
|
|
1709
|
-
return `Map size ${width}\xD7${height} is ${limit}
|
|
1709
|
+
return `Map size ${width}\xD7${height} is ${limit}: drawn at ${drawnWidth}\xD7${drawnHeight}`;
|
|
1710
1710
|
}
|
|
1711
1711
|
|
|
1712
1712
|
// src/serializer.ts
|