@spintax/core 0.5.3 → 0.6.0
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/CHANGELOG.md +42 -0
- package/dist/index.cjs +44 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -748,9 +748,14 @@ function checkVariableReferences(text, idx, known, out) {
|
|
|
748
748
|
for (const m of value.matchAll(/%(\w+)%/gu)) refs.push((m[1] ?? "").toLowerCase());
|
|
749
749
|
refsOf.set(name, refs);
|
|
750
750
|
}
|
|
751
|
-
const reachesCycle = namesThatReachACycle(defs, refsOf);
|
|
751
|
+
const { reaches: reachesCycle, via } = namesThatReachACycle(defs, refsOf);
|
|
752
752
|
for (const name of defs.keys()) {
|
|
753
|
-
|
|
753
|
+
if (!reachesCycle.has(name)) continue;
|
|
754
|
+
out.push(err(
|
|
755
|
+
"variable.circular-reference",
|
|
756
|
+
`Circular variable reference: ${cyclePath(name, via)}.`,
|
|
757
|
+
{ ...defPos.get(name) ?? somewhere, data: { name } }
|
|
758
|
+
));
|
|
754
759
|
}
|
|
755
760
|
const body = text.replace(/^[ \t]*#(?:set|def)[ \t]+%\w+%[ \t]*=[ \t]*.*?$/gmu, (m) => m.replace(/[^\n]/g, " "));
|
|
756
761
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -774,6 +779,12 @@ function namesThatReachACycle(defs, refsOf) {
|
|
|
774
779
|
const BLACK = 2;
|
|
775
780
|
const color = /* @__PURE__ */ new Map();
|
|
776
781
|
const reaches = /* @__PURE__ */ new Set();
|
|
782
|
+
const via = /* @__PURE__ */ new Map();
|
|
783
|
+
const mark = (name, witness) => {
|
|
784
|
+
if (reaches.has(name)) return;
|
|
785
|
+
reaches.add(name);
|
|
786
|
+
via.set(name, witness);
|
|
787
|
+
};
|
|
777
788
|
for (const root of defs.keys()) {
|
|
778
789
|
if (color.has(root)) continue;
|
|
779
790
|
const stack = [{ name: root, refs: refsOf.get(root) ?? [], i: 0 }];
|
|
@@ -785,9 +796,9 @@ function namesThatReachACycle(defs, refsOf) {
|
|
|
785
796
|
top.i += 1;
|
|
786
797
|
if (ref === top.name || !defs.has(ref)) continue;
|
|
787
798
|
const c = color.get(ref);
|
|
788
|
-
if (c === GREY)
|
|
799
|
+
if (c === GREY) mark(top.name, ref);
|
|
789
800
|
else if (c === BLACK) {
|
|
790
|
-
if (reaches.has(ref))
|
|
801
|
+
if (reaches.has(ref)) mark(top.name, ref);
|
|
791
802
|
} else {
|
|
792
803
|
stack.push({ name: ref, refs: refsOf.get(ref) ?? [], i: 0 });
|
|
793
804
|
color.set(ref, GREY);
|
|
@@ -795,42 +806,41 @@ function namesThatReachACycle(defs, refsOf) {
|
|
|
795
806
|
} else {
|
|
796
807
|
stack.pop();
|
|
797
808
|
color.set(top.name, BLACK);
|
|
798
|
-
if (stack.length > 0 && reaches.has(top.name))
|
|
809
|
+
if (stack.length > 0 && reaches.has(top.name)) mark(stack[stack.length - 1].name, top.name);
|
|
799
810
|
}
|
|
800
811
|
}
|
|
801
812
|
}
|
|
802
|
-
return reaches;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
const top = stack[stack.length - 1];
|
|
816
|
-
if (top.i >= top.refs.length) {
|
|
817
|
-
leave(top);
|
|
818
|
-
continue;
|
|
813
|
+
return { reaches, via };
|
|
814
|
+
}
|
|
815
|
+
var CYCLE_PATH_LIMIT = 8;
|
|
816
|
+
function cyclePath(name, via) {
|
|
817
|
+
const seen = /* @__PURE__ */ new Set([name]);
|
|
818
|
+
const shown = [name];
|
|
819
|
+
let current = name;
|
|
820
|
+
for (; ; ) {
|
|
821
|
+
const next = via.get(current);
|
|
822
|
+
if (next === void 0) break;
|
|
823
|
+
if (seen.has(next)) {
|
|
824
|
+
shown.push(next);
|
|
825
|
+
return shown.join(" \u2192 ");
|
|
819
826
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
path.push(ref);
|
|
827
|
+
if (shown.length >= CYCLE_PATH_LIMIT) {
|
|
828
|
+
let more = 0;
|
|
829
|
+
let walk2 = next;
|
|
830
|
+
while (!seen.has(walk2)) {
|
|
831
|
+
seen.add(walk2);
|
|
832
|
+
more += 1;
|
|
833
|
+
const step = via.get(walk2);
|
|
834
|
+
if (step === void 0) break;
|
|
835
|
+
walk2 = step;
|
|
836
|
+
}
|
|
837
|
+
return `${shown.join(" \u2192 ")} \u2192 \u2026 (${more} more)`;
|
|
832
838
|
}
|
|
839
|
+
seen.add(next);
|
|
840
|
+
shown.push(next);
|
|
841
|
+
current = next;
|
|
833
842
|
}
|
|
843
|
+
return shown.join(" \u2192 ");
|
|
834
844
|
}
|
|
835
845
|
function checkIncludeTargets(text, idx, known, out) {
|
|
836
846
|
const set = new Set(known);
|