@0disoft/mensor-compiler 0.1.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.
Files changed (90) hide show
  1. package/LICENSE +201 -0
  2. package/dist/src/check-project.d.ts +9 -0
  3. package/dist/src/check-project.d.ts.map +1 -0
  4. package/dist/src/check-project.js +334 -0
  5. package/dist/src/check-project.js.map +1 -0
  6. package/dist/src/compiler-timing.d.ts +25 -0
  7. package/dist/src/compiler-timing.d.ts.map +1 -0
  8. package/dist/src/compiler-timing.js +72 -0
  9. package/dist/src/compiler-timing.js.map +1 -0
  10. package/dist/src/feature-roots.d.ts +6 -0
  11. package/dist/src/feature-roots.d.ts.map +1 -0
  12. package/dist/src/feature-roots.js +8 -0
  13. package/dist/src/feature-roots.js.map +1 -0
  14. package/dist/src/filesystem.d.ts +4 -0
  15. package/dist/src/filesystem.d.ts.map +1 -0
  16. package/dist/src/filesystem.js +127 -0
  17. package/dist/src/filesystem.js.map +1 -0
  18. package/dist/src/form-facts.d.ts +37 -0
  19. package/dist/src/form-facts.d.ts.map +1 -0
  20. package/dist/src/form-facts.js +2 -0
  21. package/dist/src/form-facts.js.map +1 -0
  22. package/dist/src/form-index-semantics.d.ts +4 -0
  23. package/dist/src/form-index-semantics.d.ts.map +1 -0
  24. package/dist/src/form-index-semantics.js +149 -0
  25. package/dist/src/form-index-semantics.js.map +1 -0
  26. package/dist/src/form-index-types.d.ts +69 -0
  27. package/dist/src/form-index-types.d.ts.map +1 -0
  28. package/dist/src/form-index-types.js +11 -0
  29. package/dist/src/form-index-types.js.map +1 -0
  30. package/dist/src/form-index-validation.d.ts +3 -0
  31. package/dist/src/form-index-validation.d.ts.map +1 -0
  32. package/dist/src/form-index-validation.js +360 -0
  33. package/dist/src/form-index-validation.js.map +1 -0
  34. package/dist/src/form-index.d.ts +8 -0
  35. package/dist/src/form-index.d.ts.map +1 -0
  36. package/dist/src/form-index.js +94 -0
  37. package/dist/src/form-index.js.map +1 -0
  38. package/dist/src/form-rule.d.ts +9 -0
  39. package/dist/src/form-rule.d.ts.map +1 -0
  40. package/dist/src/form-rule.js +399 -0
  41. package/dist/src/form-rule.js.map +1 -0
  42. package/dist/src/handler-rule.d.ts +10 -0
  43. package/dist/src/handler-rule.d.ts.map +1 -0
  44. package/dist/src/handler-rule.js +75 -0
  45. package/dist/src/handler-rule.js.map +1 -0
  46. package/dist/src/html-forms.d.ts +12 -0
  47. package/dist/src/html-forms.d.ts.map +1 -0
  48. package/dist/src/html-forms.js +275 -0
  49. package/dist/src/html-forms.js.map +1 -0
  50. package/dist/src/index.d.ts +3 -0
  51. package/dist/src/index.d.ts.map +1 -0
  52. package/dist/src/index.js +2 -0
  53. package/dist/src/index.js.map +1 -0
  54. package/dist/src/locations.d.ts +12 -0
  55. package/dist/src/locations.d.ts.map +1 -0
  56. package/dist/src/locations.js +148 -0
  57. package/dist/src/locations.js.map +1 -0
  58. package/dist/src/module-boundary-rule.d.ts +12 -0
  59. package/dist/src/module-boundary-rule.d.ts.map +1 -0
  60. package/dist/src/module-boundary-rule.js +256 -0
  61. package/dist/src/module-boundary-rule.js.map +1 -0
  62. package/dist/src/ownership-rule.d.ts +13 -0
  63. package/dist/src/ownership-rule.d.ts.map +1 -0
  64. package/dist/src/ownership-rule.js +98 -0
  65. package/dist/src/ownership-rule.js.map +1 -0
  66. package/dist/src/paths.d.ts +11 -0
  67. package/dist/src/paths.d.ts.map +1 -0
  68. package/dist/src/paths.js +35 -0
  69. package/dist/src/paths.js.map +1 -0
  70. package/dist/src/route-index.d.ts +9 -0
  71. package/dist/src/route-index.d.ts.map +1 -0
  72. package/dist/src/route-index.js +31 -0
  73. package/dist/src/route-index.js.map +1 -0
  74. package/dist/src/route-rule.d.ts +11 -0
  75. package/dist/src/route-rule.d.ts.map +1 -0
  76. package/dist/src/route-rule.js +54 -0
  77. package/dist/src/route-rule.js.map +1 -0
  78. package/dist/src/source-fact-index.d.ts +8 -0
  79. package/dist/src/source-fact-index.d.ts.map +1 -0
  80. package/dist/src/source-fact-index.js +38 -0
  81. package/dist/src/source-fact-index.js.map +1 -0
  82. package/dist/src/types.d.ts +29 -0
  83. package/dist/src/types.d.ts.map +1 -0
  84. package/dist/src/types.js +2 -0
  85. package/dist/src/types.js.map +1 -0
  86. package/dist/src/typescript-source.d.ts +22 -0
  87. package/dist/src/typescript-source.d.ts.map +1 -0
  88. package/dist/src/typescript-source.js +352 -0
  89. package/dist/src/typescript-source.js.map +1 -0
  90. package/package.json +48 -0
@@ -0,0 +1,256 @@
1
+ import * as path from "node:path";
2
+ import { findFeatureOwner, sortFeatureRoots } from "./feature-roots.js";
3
+ import { projectBoundaryRange } from "./locations.js";
4
+ import { compareText, InputFailure } from "./paths.js";
5
+ const sourceExtensions = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
6
+ export async function checkImportBoundaries(options) {
7
+ if (options.boundaries.length === 0) {
8
+ return [];
9
+ }
10
+ validateBoundaries(options.boundaries, options.fileRoles);
11
+ const sourceFiles = options.discoveredFiles
12
+ .filter(isSourceFile)
13
+ .sort(compareText);
14
+ const discovered = new Set(sourceFiles);
15
+ const featureRoots = sortFeatureRoots(options.featureContractPaths.map((contract) => ({
16
+ root: path.posix.dirname(contract),
17
+ })));
18
+ const parsed = new Map();
19
+ for (const file of sourceFiles) {
20
+ const fact = await options.sourceFacts.get(file);
21
+ parsed.set(file, fact);
22
+ }
23
+ const modules = new Map();
24
+ for (const file of sourceFiles) {
25
+ const fact = parsed.get(file);
26
+ if (fact === undefined) {
27
+ continue;
28
+ }
29
+ const edges = fact.imports.flatMap((entry) => {
30
+ const target = resolveImport(file, entry.specifier, discovered);
31
+ if (target === undefined) {
32
+ return [];
33
+ }
34
+ return [{
35
+ edgeKind: entry.edgeKind,
36
+ specifier: entry.specifier,
37
+ range: entry.range,
38
+ target,
39
+ }];
40
+ });
41
+ modules.set(file, {
42
+ file,
43
+ role: classifyProjectRole(file, featureRoots, options.fileRoles),
44
+ fact,
45
+ edges: [...edges].sort(compareEdges),
46
+ });
47
+ }
48
+ const diagnostics = [];
49
+ options.boundaries.forEach((boundary, boundaryIndex) => {
50
+ const roots = [...modules.values()]
51
+ .filter((module) => boundary.from.includes(module.role))
52
+ .sort((left, right) => compareText(left.file, right.file));
53
+ for (const root of roots) {
54
+ if (boundary.mode === "direct") {
55
+ diagnostics.push(...checkDirectBoundary(root, boundary, boundaryIndex, modules, options));
56
+ }
57
+ else {
58
+ diagnostics.push(...checkTransitiveBoundary(root, boundary, boundaryIndex, modules, options));
59
+ }
60
+ }
61
+ });
62
+ return diagnostics;
63
+ }
64
+ function checkDirectBoundary(root, boundary, boundaryIndex, modules, options) {
65
+ const diagnostics = root.fact.unsupportedDynamicImports.map((range) => dynamicImportDiagnostic(root, range, boundary, boundaryIndex, options));
66
+ for (const edge of root.edges) {
67
+ const target = modules.get(edge.target);
68
+ if (target !== undefined && boundary.deny.includes(target.role)) {
69
+ diagnostics.push(boundaryViolationDiagnostic(root, edge, target, [root.file, target.file], boundary, boundaryIndex, options));
70
+ }
71
+ }
72
+ return diagnostics;
73
+ }
74
+ function checkTransitiveBoundary(root, boundary, boundaryIndex, modules, options) {
75
+ const diagnostics = [];
76
+ const queue = [
77
+ { module: root, chain: [root.file] },
78
+ ];
79
+ const visited = new Set();
80
+ for (let index = 0; index < queue.length; index += 1) {
81
+ const current = queue[index];
82
+ if (current === undefined || visited.has(current.module.file)) {
83
+ continue;
84
+ }
85
+ visited.add(current.module.file);
86
+ diagnostics.push(...current.module.fact.unsupportedDynamicImports.map((range) => dynamicImportDiagnostic(current.module, range, boundary, boundaryIndex, options)));
87
+ for (const edge of current.module.edges) {
88
+ const target = modules.get(edge.target);
89
+ if (target === undefined) {
90
+ continue;
91
+ }
92
+ const chain = [...current.chain, target.file];
93
+ if (boundary.deny.includes(target.role)) {
94
+ diagnostics.push(boundaryViolationDiagnostic(root, edge, target, chain, boundary, boundaryIndex, options));
95
+ }
96
+ else if (!visited.has(target.file)) {
97
+ queue.push({ module: target, chain });
98
+ }
99
+ }
100
+ }
101
+ return diagnostics;
102
+ }
103
+ function boundaryViolationDiagnostic(root, edge, target, importChain, boundary, boundaryIndex, options) {
104
+ return {
105
+ code: "module.boundary_violation",
106
+ severity: "error",
107
+ category: "environment-boundary",
108
+ message: `Boundary ${JSON.stringify(boundary.id)} forbids ${JSON.stringify(root.role)} code from reaching ${JSON.stringify(target.role)} module ${JSON.stringify(target.file)}.`,
109
+ file: importChain[importChain.length - 2] ?? root.file,
110
+ range: edge.range,
111
+ facts: {
112
+ boundaryId: boundary.id,
113
+ edgeKind: edge.edgeKind,
114
+ importChain,
115
+ importSpecifier: edge.specifier,
116
+ mode: boundary.mode,
117
+ sourceRole: root.role,
118
+ targetFile: target.file,
119
+ targetRole: target.role,
120
+ },
121
+ related: [
122
+ {
123
+ role: "forbidden-target",
124
+ message: `This module is classified as ${target.role}.`,
125
+ file: target.file,
126
+ range: zeroRange(),
127
+ },
128
+ {
129
+ role: "boundary-declaration",
130
+ message: "This project contract declares the violated boundary.",
131
+ file: options.projectContractPath,
132
+ range: projectBoundaryRange(options.projectText, boundaryIndex),
133
+ },
134
+ ],
135
+ repair: {
136
+ strategy: "remove-forbidden-module-edge",
137
+ hint: `Move shared contracts behind an allowed module and remove the dependency on ${target.file}.`,
138
+ mustPreserve: [
139
+ `boundary ${boundary.id}`,
140
+ `${target.role} classification of ${target.file}`,
141
+ ],
142
+ mustNot: [
143
+ "delete the boundary",
144
+ `reclassify ${target.file} to hide the violation`,
145
+ ],
146
+ },
147
+ };
148
+ }
149
+ function dynamicImportDiagnostic(source, range, boundary, boundaryIndex, options) {
150
+ return {
151
+ code: "module.dynamic_import_unsupported",
152
+ severity: "error",
153
+ category: "environment-boundary",
154
+ message: `Boundary ${JSON.stringify(boundary.id)} cannot analyze a non-literal dynamic import.`,
155
+ file: source.file,
156
+ range,
157
+ facts: {
158
+ boundaryId: boundary.id,
159
+ mode: boundary.mode,
160
+ sourceRole: source.role,
161
+ },
162
+ related: [
163
+ {
164
+ role: "boundary-declaration",
165
+ message: "This project contract requires deterministic import analysis.",
166
+ file: options.projectContractPath,
167
+ range: projectBoundaryRange(options.projectText, boundaryIndex),
168
+ },
169
+ ],
170
+ repair: {
171
+ strategy: "make-dynamic-import-literal",
172
+ hint: "Replace the computed dynamic import with explicit literal import targets.",
173
+ mustPreserve: [`boundary ${boundary.id}`, "module loading behavior"],
174
+ mustNot: ["disable the boundary", "hide the import behind runtime string construction"],
175
+ },
176
+ };
177
+ }
178
+ function validateBoundaries(boundaries, fileRoles) {
179
+ const roles = new Set(fileRoles.map((entry) => entry.role));
180
+ const ids = new Set();
181
+ for (const boundary of boundaries) {
182
+ if (ids.has(boundary.id)) {
183
+ throw new InputFailure("configuration", "boundaries.duplicate_id", `Boundary ${JSON.stringify(boundary.id)} is declared more than once.`);
184
+ }
185
+ ids.add(boundary.id);
186
+ for (const role of [...boundary.from, ...boundary.deny]) {
187
+ if (!roles.has(role)) {
188
+ throw new InputFailure("configuration", "boundaries.role_unknown", `Boundary ${JSON.stringify(boundary.id)} references unknown role ${JSON.stringify(role)}.`);
189
+ }
190
+ }
191
+ }
192
+ }
193
+ function classifyProjectRole(file, featureRoots, fileRoles) {
194
+ const feature = findFeatureOwner(file, featureRoots);
195
+ if (feature === undefined) {
196
+ return "unclassified";
197
+ }
198
+ const featureFile = file.slice(feature.root.length + 1);
199
+ return fileRoles.find((entry) => featureFile.startsWith(`${entry.withinFeature}/`))?.role ?? "unclassified";
200
+ }
201
+ function resolveImport(sourceFile, specifier, discovered) {
202
+ if (!specifier.startsWith(".")) {
203
+ return undefined;
204
+ }
205
+ const base = path.posix.normalize(path.posix.join(path.posix.dirname(sourceFile), specifier));
206
+ if (base.startsWith("../") || path.posix.isAbsolute(base)) {
207
+ throw new InputFailure("configuration", "module.import_escapes_root", `Import ${JSON.stringify(specifier)} from ${JSON.stringify(sourceFile)} escapes the project source root.`, sourceFile);
208
+ }
209
+ for (const candidate of importCandidates(base)) {
210
+ if (discovered.has(candidate)) {
211
+ return candidate;
212
+ }
213
+ }
214
+ const extension = path.posix.extname(base);
215
+ if (extension.length === 0 || sourceExtensions.includes(extension)) {
216
+ throw new InputFailure("configuration", "module.import_unresolved", `Import ${JSON.stringify(specifier)} from ${JSON.stringify(sourceFile)} did not resolve to a discovered source module.`, sourceFile);
217
+ }
218
+ return undefined;
219
+ }
220
+ function importCandidates(base) {
221
+ const extension = path.posix.extname(base);
222
+ if ([".js", ".mjs", ".cjs"].includes(extension)) {
223
+ const stem = base.slice(0, -extension.length);
224
+ return [
225
+ `${stem}.ts`,
226
+ `${stem}.tsx`,
227
+ `${stem}.mts`,
228
+ `${stem}.cts`,
229
+ base,
230
+ ];
231
+ }
232
+ if (extension.length > 0) {
233
+ return [base];
234
+ }
235
+ return [
236
+ ...sourceExtensions.map((candidateExtension) => `${base}${candidateExtension}`),
237
+ ...sourceExtensions.map((candidateExtension) => `${base}/index${candidateExtension}`),
238
+ ];
239
+ }
240
+ function isSourceFile(file) {
241
+ return sourceExtensions.includes(path.posix.extname(file));
242
+ }
243
+ function compareEdges(left, right) {
244
+ return (compareText(left.target, right.target) ||
245
+ compareText(left.specifier, right.specifier) ||
246
+ compareText(left.edgeKind, right.edgeKind) ||
247
+ left.range.start.line - right.range.start.line ||
248
+ left.range.start.character - right.range.start.character);
249
+ }
250
+ function zeroRange() {
251
+ return {
252
+ start: { line: 0, character: 0 },
253
+ end: { line: 0, character: 0 },
254
+ };
255
+ }
256
+ //# sourceMappingURL=module-boundary-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-boundary-rule.js","sourceRoot":"","sources":["../../src/module-boundary-rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Diagnostic, OwnershipRuleContract } from "@0disoft/mensor-contract";
2
+ export interface FeatureOwnerFact {
3
+ readonly id: string;
4
+ readonly root: string;
5
+ }
6
+ export declare function checkOwnershipRules(options: {
7
+ readonly projectContractPath: string;
8
+ readonly projectText: string;
9
+ readonly features: readonly FeatureOwnerFact[];
10
+ readonly rules: readonly OwnershipRuleContract[];
11
+ readonly discoveredFiles: readonly string[];
12
+ }): readonly Diagnostic[];
13
+ //# sourceMappingURL=ownership-rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership-rule.d.ts","sourceRoot":"","sources":["../../src/ownership-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAMlC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACjD,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C,GAAG,SAAS,UAAU,EAAE,CA8CxB"}
@@ -0,0 +1,98 @@
1
+ import { projectOwnershipRuleRange } from "./locations.js";
2
+ import { findFeatureOwner, sortFeatureRoots } from "./feature-roots.js";
3
+ import { assertRelativePosixPath, compareText, InputFailure } from "./paths.js";
4
+ export function checkOwnershipRules(options) {
5
+ validateRules(options.rules);
6
+ const features = sortFeatureRoots(options.features);
7
+ const diagnostics = [];
8
+ options.rules.forEach((rule, ruleIndex) => {
9
+ const expectedSlot = assertRelativePosixPath(rule.withinFeature, "ownershipRules.withinFeature");
10
+ for (const file of [...options.discoveredFiles].sort(compareText)) {
11
+ if (!rule.suffixes.some((suffix) => file.endsWith(suffix))) {
12
+ continue;
13
+ }
14
+ const feature = findFeatureOwner(file, features);
15
+ if (feature === undefined) {
16
+ diagnostics.push(ownershipDiagnostic({
17
+ file,
18
+ actualPath: file,
19
+ featureId: null,
20
+ rule,
21
+ ruleIndex,
22
+ projectContractPath: options.projectContractPath,
23
+ projectText: options.projectText,
24
+ }));
25
+ continue;
26
+ }
27
+ const featurePath = file.slice(feature.root.length + 1);
28
+ if (featurePath.startsWith(`${expectedSlot}/`)) {
29
+ continue;
30
+ }
31
+ diagnostics.push(ownershipDiagnostic({
32
+ file,
33
+ actualPath: featurePath,
34
+ featureId: feature.id,
35
+ rule,
36
+ ruleIndex,
37
+ projectContractPath: options.projectContractPath,
38
+ projectText: options.projectText,
39
+ }));
40
+ }
41
+ });
42
+ return diagnostics;
43
+ }
44
+ function ownershipDiagnostic(options) {
45
+ const owner = options.featureId === null
46
+ ? "outside every declared feature"
47
+ : `outside feature slot ${JSON.stringify(options.rule.withinFeature)}`;
48
+ return {
49
+ code: "file.ownership_mismatch",
50
+ severity: "error",
51
+ category: "project-structure",
52
+ message: `${options.rule.kind} file ${JSON.stringify(options.file)} is ${owner}.`,
53
+ file: options.file,
54
+ range: {
55
+ start: { line: 0, character: 0 },
56
+ end: { line: 0, character: 0 },
57
+ },
58
+ facts: {
59
+ actualPath: options.actualPath,
60
+ expectedWithinFeature: options.rule.withinFeature,
61
+ featureId: options.featureId,
62
+ kind: options.rule.kind,
63
+ ruleId: options.rule.id,
64
+ },
65
+ related: [
66
+ {
67
+ role: "ownership-rule",
68
+ message: "This project contract declares the required feature slot.",
69
+ file: options.projectContractPath,
70
+ range: projectOwnershipRuleRange(options.projectText, options.ruleIndex),
71
+ },
72
+ ],
73
+ repair: {
74
+ strategy: "move-file-to-feature-owner",
75
+ hint: options.featureId === null
76
+ ? `Move the file under its owning feature's ${options.rule.withinFeature} directory.`
77
+ : `Move the file to ${options.rule.withinFeature} inside feature ${options.featureId}.`,
78
+ mustPreserve: [
79
+ `${options.rule.kind} file behavior`,
80
+ `ownership rule ${options.rule.id}`,
81
+ ],
82
+ mustNot: [
83
+ "delete the ownership rule",
84
+ "rename the file only to evade suffix detection",
85
+ ],
86
+ },
87
+ };
88
+ }
89
+ function validateRules(rules) {
90
+ const ids = new Set();
91
+ for (const rule of rules) {
92
+ if (ids.has(rule.id)) {
93
+ throw new InputFailure("configuration", "ownership_rules.duplicate_id", `Ownership rule ${JSON.stringify(rule.id)} is declared more than once.`);
94
+ }
95
+ ids.add(rule.id);
96
+ }
97
+ }
98
+ //# sourceMappingURL=ownership-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership-rule.js","sourceRoot":"","sources":["../../src/ownership-rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function assertRelativePosixPath(value: string, label: string): string;
2
+ export declare function fromProjectPath(root: string, relativePath: string): string;
3
+ export declare function joinProjectPath(...parts: readonly string[]): string;
4
+ export declare function compareText(left: string, right: string): number;
5
+ export declare class InputFailure extends Error {
6
+ readonly kind: "configuration" | "filesystem";
7
+ readonly code: string;
8
+ readonly file?: string;
9
+ constructor(kind: "configuration" | "filesystem", code: string, message: string, file?: string);
10
+ }
11
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAEA,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAqB5E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,eAAe,CAAC,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEnE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,YAAY,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAGrB,IAAI,EAAE,eAAe,GAAG,YAAY,EACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM;CAUhB"}
@@ -0,0 +1,35 @@
1
+ import * as path from "node:path";
2
+ export function assertRelativePosixPath(value, label) {
3
+ if (value.length === 0 || value.includes("\\") || path.posix.isAbsolute(value)) {
4
+ throw new InputFailure("configuration", "path.invalid", `${label} must be a non-empty project-relative POSIX path.`, value);
5
+ }
6
+ const segments = value.split("/");
7
+ if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
8
+ throw new InputFailure("configuration", "path.invalid", `${label} contains an empty, current-directory, or parent-directory segment.`, value);
9
+ }
10
+ return segments.join("/");
11
+ }
12
+ export function fromProjectPath(root, relativePath) {
13
+ return path.join(root, ...relativePath.split("/"));
14
+ }
15
+ export function joinProjectPath(...parts) {
16
+ return parts.filter((part) => part !== "." && part !== "").join("/");
17
+ }
18
+ export function compareText(left, right) {
19
+ return left < right ? -1 : left > right ? 1 : 0;
20
+ }
21
+ export class InputFailure extends Error {
22
+ kind;
23
+ code;
24
+ file;
25
+ constructor(kind, code, message, file) {
26
+ super(message);
27
+ this.name = "InputFailure";
28
+ this.kind = kind;
29
+ this.code = code;
30
+ if (file !== undefined) {
31
+ this.file = file;
32
+ }
33
+ }
34
+ }
35
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,uBAAuB,CAAC,KAAa,EAAE,KAAa;IAClE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,cAAc,EACd,GAAG,KAAK,mDAAmD,EAC3D,KAAK,CACN,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,cAAc,EACd,GAAG,KAAK,qEAAqE,EAC7E,KAAK,CACN,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,YAAoB;IAChE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAG,KAAwB;IACzD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAAa;IACrD,OAAO,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAiC;IACrC,IAAI,CAAS;IACb,IAAI,CAAU;IAEvB,YACE,IAAoC,EACpC,IAAY,EACZ,OAAe,EACf,IAAa;QAEb,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { ContentDigest, RouteIndex } from "@0disoft/mensor-contract";
2
+ import type { SourceFactIndex } from "./source-fact-index.js";
3
+ export declare function verifyRouteIndex(options: {
4
+ readonly routeIndex: RouteIndex;
5
+ readonly discovered: ReadonlySet<string>;
6
+ readonly sourceFacts: SourceFactIndex;
7
+ }): Promise<RouteIndex>;
8
+ export declare function contentDigest(source: string | Uint8Array): ContentDigest;
9
+ //# sourceMappingURL=route-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-index.d.ts","sourceRoot":"","sources":["../../src/route-index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAGX,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;CACvC,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBtB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,CAExE"}
@@ -0,0 +1,31 @@
1
+ import { createHash } from "node:crypto";
2
+ import { InputFailure } from "./paths.js";
3
+ export async function verifyRouteIndex(options) {
4
+ for (const route of options.routeIndex.routes) {
5
+ const file = route.source.file;
6
+ if (!options.discovered.has(file)) {
7
+ throw new InputFailure("configuration", "route_index.source_not_discovered", `RouteIndex source ${JSON.stringify(file)} is not a discovered source file.`, file);
8
+ }
9
+ const source = await options.sourceFacts.source(file);
10
+ if (contentDigest(source) !== route.source.contentDigest) {
11
+ throw new InputFailure("configuration", "route_index.digest_mismatch", `RouteIndex source digest does not match ${JSON.stringify(file)}.`, file);
12
+ }
13
+ assertRangeWithinSource(route.source.range, source, file);
14
+ }
15
+ return options.routeIndex;
16
+ }
17
+ export function contentDigest(source) {
18
+ return `sha256:${createHash("sha256").update(source).digest("hex")}`;
19
+ }
20
+ function assertRangeWithinSource(range, source, file) {
21
+ const lines = source.split(/\r\n|\n|\r/u);
22
+ assertPositionWithinSource(range.start, lines, file);
23
+ assertPositionWithinSource(range.end, lines, file);
24
+ }
25
+ function assertPositionWithinSource(position, lines, file) {
26
+ const line = lines[position.line];
27
+ if (line === undefined || position.character > line.length) {
28
+ throw new InputFailure("configuration", "route_index.range_invalid", `RouteIndex source range falls outside ${JSON.stringify(file)}.`, file);
29
+ }
30
+ }
31
+ //# sourceMappingURL=route-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-index.js","sourceRoot":"","sources":["../../src/route-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAItC;IACC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,mCAAmC,EACnC,qBAAqB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,mCAAmC,EAC5E,IAAI,CACL,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,aAAa,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;YACzD,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,6BAA6B,EAC7B,2CAA2C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAClE,IAAI,CACL,CAAC;QACJ,CAAC;QACD,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAA2B;IACvD,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAkB,EAClB,MAAc,EACd,IAAY;IAEZ,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC1C,0BAA0B,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACrD,0BAA0B,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,0BAA0B,CACjC,QAAwB,EACxB,KAAwB,EACxB,IAAY;IAEZ,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3D,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,2BAA2B,EAC3B,yCAAyC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAChE,IAAI,CACL,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Diagnostic, FeatureContract, RouteIndex } from "@0disoft/mensor-contract";
2
+ export declare function checkFeatureRoutes(options: {
3
+ readonly featureContractPath: string;
4
+ readonly featureText: string;
5
+ readonly feature: FeatureContract;
6
+ readonly projectContractPath: string;
7
+ readonly projectText: string;
8
+ readonly routeIndexPath: string;
9
+ readonly routeIndex: RouteIndex;
10
+ }): readonly Diagnostic[];
11
+ //# sourceMappingURL=route-rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-rule.d.ts","sourceRoot":"","sources":["../../src/route-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAQlC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC,GAAG,SAAS,UAAU,EAAE,CAuDxB"}
@@ -0,0 +1,54 @@
1
+ import { actionRoutePropertyRange, projectRouteIndexRange, } from "./locations.js";
2
+ import { compareText } from "./paths.js";
3
+ export function checkFeatureRoutes(options) {
4
+ const diagnostics = [];
5
+ const indexed = new Set(options.routeIndex.routes.map((route) => `${route.method}\u0000${route.path}`));
6
+ const postPaths = [...new Set(options.routeIndex.routes
7
+ .filter((route) => route.method === "POST")
8
+ .map((route) => route.path))].sort(compareText);
9
+ options.feature.actions.forEach((action, actionIndex) => {
10
+ const key = `${action.route.method}\u0000${action.route.path}`;
11
+ if (indexed.has(key)) {
12
+ return;
13
+ }
14
+ diagnostics.push({
15
+ code: "route.missing",
16
+ severity: "error",
17
+ category: "route-contract",
18
+ message: `RouteIndex does not contain ${action.route.method} ${JSON.stringify(action.route.path)} for action ${JSON.stringify(action.id)}.`,
19
+ file: options.featureContractPath,
20
+ range: actionRoutePropertyRange(options.featureText, actionIndex, "path"),
21
+ facts: {
22
+ actionId: action.id,
23
+ expectedMethod: action.route.method,
24
+ expectedPath: action.route.path,
25
+ routeIndex: options.routeIndexPath,
26
+ sameMethodPaths: postPaths,
27
+ },
28
+ related: [
29
+ {
30
+ role: "route-index-declaration",
31
+ message: "The project contract enables this source-bound RouteIndex.",
32
+ file: options.projectContractPath,
33
+ range: projectRouteIndexRange(options.projectText),
34
+ },
35
+ ],
36
+ repair: {
37
+ strategy: "reconcile-indexed-route",
38
+ hint: `Add ${action.route.method} ${action.route.path} to the application route source and regenerate ${options.routeIndexPath}, or update the action contract when the route change is intentional.`,
39
+ mustPreserve: [
40
+ `action ${action.id}`,
41
+ `form route ${action.route.path}`,
42
+ "source-bound RouteIndex verification",
43
+ ],
44
+ mustNot: [
45
+ "delete the RouteIndex declaration",
46
+ "edit the content digest without regenerating route facts",
47
+ "weaken the form action contract",
48
+ ],
49
+ },
50
+ });
51
+ });
52
+ return diagnostics;
53
+ }
54
+ //# sourceMappingURL=route-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-rule.js","sourceRoot":"","sources":["../../src/route-rule.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,kBAAkB,CAAC,OAQlC;IACC,MAAM,WAAW,GAA6B,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,SAAS,KAAK,CAAC,IAAI,EAAE,CAAC,CAC/E,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAC3B,OAAO,CAAC,UAAU,CAAC,MAAM;aACtB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC;aAC1C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAC9B,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAErB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QACtD,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,eAAe;YACrB,QAAQ,EAAE,OAAO;YACjB,QAAQ,EAAE,gBAAgB;YAC1B,OAAO,EAAE,+BAA+B,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG;YAC3I,IAAI,EAAE,OAAO,CAAC,mBAAmB;YACjC,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC;YACzE,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACnB,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;gBACnC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;gBAC/B,UAAU,EAAE,OAAO,CAAC,cAAc;gBAClC,eAAe,EAAE,SAAS;aAC3B;YACD,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,yBAAyB;oBAC/B,OAAO,EAAE,4DAA4D;oBACrE,IAAI,EAAE,OAAO,CAAC,mBAAmB;oBACjC,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,WAAW,CAAC;iBACnD;aACF;YACD,MAAM,EAAE;gBACN,QAAQ,EAAE,yBAAyB;gBACnC,IAAI,EAAE,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,mDAAmD,OAAO,CAAC,cAAc,uEAAuE;gBACrM,YAAY,EAAE;oBACZ,UAAU,MAAM,CAAC,EAAE,EAAE;oBACrB,cAAc,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;oBACjC,sCAAsC;iBACvC;gBACD,OAAO,EAAE;oBACP,mCAAmC;oBACnC,0DAA0D;oBAC1D,iCAAiC;iBAClC;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { CompilerTiming } from "./compiler-timing.js";
2
+ import { type ModuleFact } from "./typescript-source.js";
3
+ export interface SourceFactIndex {
4
+ readonly get: (file: string) => Promise<ModuleFact>;
5
+ readonly source: (file: string) => Promise<string>;
6
+ }
7
+ export declare function createSourceFactIndex(readSource: (file: string) => Promise<string>, timing?: CompilerTiming): SourceFactIndex;
8
+ //# sourceMappingURL=source-fact-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-fact-index.d.ts","sourceRoot":"","sources":["../../src/source-fact-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC7C,MAAM,CAAC,EAAE,cAAc,GACtB,eAAe,CAwBjB"}
@@ -0,0 +1,38 @@
1
+ import { InputFailure } from "./paths.js";
2
+ import { extractModuleFact } from "./typescript-source.js";
3
+ export function createSourceFactIndex(readSource, timing) {
4
+ const sources = new Map();
5
+ const facts = new Map();
6
+ const source = (file) => {
7
+ let value = sources.get(file);
8
+ if (value === undefined) {
9
+ value = timing === undefined
10
+ ? readSource(file)
11
+ : timing.measure("sourceRead", () => readSource(file));
12
+ sources.set(file, value);
13
+ }
14
+ return value;
15
+ };
16
+ return {
17
+ get(file) {
18
+ let fact = facts.get(file);
19
+ if (fact === undefined) {
20
+ fact = readAndParseSource(source, file, timing);
21
+ facts.set(file, fact);
22
+ }
23
+ return fact;
24
+ },
25
+ source,
26
+ };
27
+ }
28
+ async function readAndParseSource(sourceForFile, file, timing) {
29
+ const sourceText = await sourceForFile(file);
30
+ const fact = timing === undefined
31
+ ? extractModuleFact(sourceText, file)
32
+ : timing.measureSync("typescriptExtraction", () => extractModuleFact(sourceText, file));
33
+ if (fact.syntaxErrors.length > 0) {
34
+ throw new InputFailure("configuration", "typescript.syntax_invalid", `Source ${JSON.stringify(file)} contains unsupported syntax: ${fact.syntaxErrors[0]}`, file);
35
+ }
36
+ return fact;
37
+ }
38
+ //# sourceMappingURL=source-fact-index.js.map