@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.10 → 3.9.0-ultramodern.12
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/dist/cjs/microvertical-api-baseline.cjs +18 -59
- package/dist/cjs/microvertical-api-boundary.cjs +2 -1
- package/dist/cjs/source-analysis.cjs +104 -0
- package/dist/cjs/strict-effect-runtime.cjs +7 -43
- package/dist/esm/microvertical-api-baseline.js +9 -46
- package/dist/esm/microvertical-api-boundary.js +2 -1
- package/dist/esm/source-analysis.js +44 -0
- package/dist/esm/strict-effect-runtime.js +7 -42
- package/dist/esm-node/microvertical-api-baseline.js +9 -46
- package/dist/esm-node/microvertical-api-boundary.js +2 -1
- package/dist/esm-node/source-analysis.js +45 -0
- package/dist/esm-node/strict-effect-runtime.js +7 -42
- package/dist/types/microvertical-api-baseline.d.ts +0 -5
- package/dist/types/source-analysis.d.ts +10 -0
- package/package.json +1 -1
|
@@ -38,63 +38,29 @@ var __webpack_exports__ = {};
|
|
|
38
38
|
__webpack_require__.r(__webpack_exports__);
|
|
39
39
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
40
|
configuredMicroVerticalApiStem: ()=>configuredMicroVerticalApiStem,
|
|
41
|
-
consumerParserPlugins: ()=>consumerParserPlugins,
|
|
42
41
|
microVerticalApiBaselineViolation: ()=>microVerticalApiBaselineViolation
|
|
43
42
|
});
|
|
44
43
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
45
44
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
46
45
|
const external_node_path_namespaceObject = require("node:path");
|
|
47
46
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
48
|
-
const parser_namespaceObject = require("@babel/parser");
|
|
49
|
-
const traverse_namespaceObject = require("@babel/traverse");
|
|
50
|
-
var traverse_default = /*#__PURE__*/ __webpack_require__.n(traverse_namespaceObject);
|
|
51
47
|
const types_namespaceObject = require("@babel/types");
|
|
52
48
|
const external_microvertical_api_owner_cjs_namespaceObject = require("./microvertical-api-owner.cjs");
|
|
53
|
-
const
|
|
54
|
-
"typescript",
|
|
55
|
-
'jsx'
|
|
56
|
-
] : [
|
|
57
|
-
"typescript"
|
|
58
|
-
];
|
|
59
|
-
class ConsumerSyntaxError extends Error {
|
|
60
|
-
}
|
|
61
|
-
class ConsumerValidationHub extends traverse_namespaceObject.Hub {
|
|
62
|
-
buildError(_node, message) {
|
|
63
|
-
return new ConsumerSyntaxError(message);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
49
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
66
50
|
function parseConsumer(filePath) {
|
|
67
51
|
if (external_node_fs_default().statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
file = (0, parser_namespaceObject.parse)(external_node_fs_default().readFileSync(filePath, 'utf8'), {
|
|
71
|
-
sourceType: 'module',
|
|
72
|
-
sourceFilename: filePath,
|
|
73
|
-
plugins: consumerParserPlugins(filePath)
|
|
74
|
-
});
|
|
75
|
-
} catch (error) {
|
|
76
|
-
if ('object' == typeof error && null !== error && 'code' in error && 'BABEL_PARSER_SYNTAX_ERROR' === error.code) throw new ConsumerSyntaxError(error instanceof Error ? error.message : String(error));
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
const program = traverse_namespaceObject.NodePath.get({
|
|
80
|
-
hub: new ConsumerValidationHub(),
|
|
81
|
-
parentPath: void 0,
|
|
82
|
-
parent: file,
|
|
83
|
-
container: file,
|
|
84
|
-
key: 'program'
|
|
85
|
-
});
|
|
86
|
-
program.setContext();
|
|
87
|
-
traverse_default()(file, {
|
|
52
|
+
const file = (0, external_source_analysis_cjs_namespaceObject.parseSource)(external_node_fs_default().readFileSync(filePath, 'utf8'), filePath);
|
|
53
|
+
(0, external_source_analysis_cjs_namespaceObject.traverseSource)(file, {
|
|
88
54
|
AssignmentExpression (p) {
|
|
89
|
-
throw new
|
|
55
|
+
throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
90
56
|
},
|
|
91
57
|
UpdateExpression (p) {
|
|
92
|
-
throw new
|
|
58
|
+
throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
93
59
|
},
|
|
94
60
|
TSModuleDeclaration () {
|
|
95
|
-
throw new
|
|
61
|
+
throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError('contract bindings must not be merged with namespaces');
|
|
96
62
|
}
|
|
97
|
-
}
|
|
63
|
+
});
|
|
98
64
|
return file;
|
|
99
65
|
}
|
|
100
66
|
const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
|
|
@@ -119,24 +85,19 @@ const accessPath = (node)=>{
|
|
|
119
85
|
}
|
|
120
86
|
};
|
|
121
87
|
const isAccessPath = (node, expected)=>accessPath(node)?.join('.') === expected.join('.');
|
|
122
|
-
const unwrapExpression = (expression)=>{
|
|
123
|
-
let current = expression;
|
|
124
|
-
while(types_namespaceObject.isTSAsExpression(current) || types_namespaceObject.isParenthesizedExpression(current) || types_namespaceObject.isTSSatisfiesExpression(current))current = current.expression;
|
|
125
|
-
return current;
|
|
126
|
-
};
|
|
127
88
|
const stringLiteral = (expression)=>{
|
|
128
89
|
if (null == expression) return;
|
|
129
|
-
const unwrapped = unwrapExpression(expression);
|
|
90
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
130
91
|
return types_namespaceObject.isStringLiteral(unwrapped) ? unwrapped.value : void 0;
|
|
131
92
|
};
|
|
132
93
|
const numericLiteral = (expression)=>{
|
|
133
94
|
if (null == expression) return;
|
|
134
|
-
const unwrapped = unwrapExpression(expression);
|
|
95
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
135
96
|
return types_namespaceObject.isNumericLiteral(unwrapped) ? Number(unwrapped.value) : void 0;
|
|
136
97
|
};
|
|
137
98
|
const callExpression = (expression, callee)=>{
|
|
138
99
|
if (null == expression) return;
|
|
139
|
-
const unwrapped = unwrapExpression(expression);
|
|
100
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
140
101
|
return types_namespaceObject.isCallExpression(unwrapped) && isAccessPath(unwrapped.callee, callee) ? unwrapped : void 0;
|
|
141
102
|
};
|
|
142
103
|
const localConst = (sourceFile, name)=>{
|
|
@@ -270,7 +231,7 @@ const resolveBinding = (module, name, scope, readModule, seen)=>{
|
|
|
270
231
|
};
|
|
271
232
|
const objectLiteral = (expression)=>{
|
|
272
233
|
if (null == expression) return;
|
|
273
|
-
const unwrapped = unwrapExpression(expression);
|
|
234
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
274
235
|
return types_namespaceObject.isObjectExpression(unwrapped) ? unwrapped : void 0;
|
|
275
236
|
};
|
|
276
237
|
const propertyAssignments = (properties)=>{
|
|
@@ -289,7 +250,7 @@ const exactCall = (expression, callee, argumentCount)=>{
|
|
|
289
250
|
};
|
|
290
251
|
const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
291
252
|
if (declaration?.init == null) return;
|
|
292
|
-
const initializer = unwrapExpression(declaration.init);
|
|
253
|
+
const initializer = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init);
|
|
293
254
|
if (types_namespaceObject.isIdentifier(initializer) && initializer.name === sharedSchemaName) return {
|
|
294
255
|
assignments: new Map(),
|
|
295
256
|
identity: true
|
|
@@ -313,14 +274,14 @@ const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
|
313
274
|
};
|
|
314
275
|
const directCallChain = (expression)=>{
|
|
315
276
|
if (null == expression) return;
|
|
316
|
-
let current = unwrapExpression(expression);
|
|
277
|
+
let current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
317
278
|
const methods = [];
|
|
318
279
|
while(types_namespaceObject.isCallExpression(current) && types_namespaceObject.isMemberExpression(current.callee) && !current.callee.computed && types_namespaceObject.isIdentifier(current.callee.property) && !types_namespaceObject.isIdentifier(current.callee.object)){
|
|
319
280
|
methods.unshift({
|
|
320
281
|
arguments: current.arguments,
|
|
321
282
|
name: current.callee.property.name
|
|
322
283
|
});
|
|
323
|
-
current = unwrapExpression(current.callee.object);
|
|
284
|
+
current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(current.callee.object);
|
|
324
285
|
}
|
|
325
286
|
if (!types_namespaceObject.isCallExpression(current)) return;
|
|
326
287
|
return {
|
|
@@ -331,7 +292,7 @@ const directCallChain = (expression)=>{
|
|
|
331
292
|
const brandedStringSchemaIsExact = (declaration, brand)=>{
|
|
332
293
|
const initializer = declaration?.init;
|
|
333
294
|
if (null == initializer) return false;
|
|
334
|
-
const pipeCall = unwrapExpression(initializer);
|
|
295
|
+
const pipeCall = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(initializer);
|
|
335
296
|
if (!types_namespaceObject.isCallExpression(pipeCall) || !types_namespaceObject.isMemberExpression(pipeCall.callee) || pipeCall.callee.computed || !types_namespaceObject.isIdentifier(pipeCall.callee.property, {
|
|
336
297
|
name: 'pipe'
|
|
337
298
|
}) || !isAccessPath(pipeCall.callee.object, [
|
|
@@ -431,7 +392,7 @@ const reachableEndpoints = (rootModule, declaration)=>{
|
|
|
431
392
|
let visits = 0;
|
|
432
393
|
const visit = (expression, module, kind, group = '')=>{
|
|
433
394
|
if (!expression) return false;
|
|
434
|
-
const node = unwrapExpression(expression);
|
|
395
|
+
const node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
435
396
|
if (active.has(node) || active.size >= 128 || ++visits > 2048) return false;
|
|
436
397
|
active.add(node);
|
|
437
398
|
try {
|
|
@@ -622,7 +583,7 @@ const readinessSchemaIsShared = (declaration, markerSchemaName, ownerMarkerIsIde
|
|
|
622
583
|
]);
|
|
623
584
|
return void 0 !== schema && (schema.identity && ownerMarkerIsIdentity || 1 === schema.assignments.size && identifierName(schema.assignments.get('marker')?.value) === markerSchemaName);
|
|
624
585
|
};
|
|
625
|
-
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName(unwrapExpression(declaration.init)) === identifier;
|
|
586
|
+
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName((0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init)) === identifier;
|
|
626
587
|
const validateParsedContract = (module, stem, expectation)=>{
|
|
627
588
|
const sourceFile = module.file;
|
|
628
589
|
const exportStem = camelCaseStem(stem);
|
|
@@ -660,16 +621,14 @@ const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
|
660
621
|
path: filePath
|
|
661
622
|
}, stem, expectation);
|
|
662
623
|
} catch (error) {
|
|
663
|
-
if (error instanceof
|
|
624
|
+
if (error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
|
|
664
625
|
throw error;
|
|
665
626
|
}
|
|
666
627
|
};
|
|
667
628
|
exports.configuredMicroVerticalApiStem = __webpack_exports__.configuredMicroVerticalApiStem;
|
|
668
|
-
exports.consumerParserPlugins = __webpack_exports__.consumerParserPlugins;
|
|
669
629
|
exports.microVerticalApiBaselineViolation = __webpack_exports__.microVerticalApiBaselineViolation;
|
|
670
630
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
671
631
|
"configuredMicroVerticalApiStem",
|
|
672
|
-
"consumerParserPlugins",
|
|
673
632
|
"microVerticalApiBaselineViolation"
|
|
674
633
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
675
634
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -50,6 +50,7 @@ const parser_namespaceObject = require("@babel/parser");
|
|
|
50
50
|
const types_namespaceObject = require("@babel/types");
|
|
51
51
|
const external_microvertical_api_baseline_cjs_namespaceObject = require("./microvertical-api-baseline.cjs");
|
|
52
52
|
const external_microvertical_api_owner_cjs_namespaceObject = require("./microvertical-api-owner.cjs");
|
|
53
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
53
54
|
const external_strict_effect_runtime_cjs_namespaceObject = require("./strict-effect-runtime.cjs");
|
|
54
55
|
const ignored = new Set([
|
|
55
56
|
'.git',
|
|
@@ -159,7 +160,7 @@ function check(options, topology) {
|
|
|
159
160
|
const ast = (0, parser_namespaceObject.parse)(read(file), {
|
|
160
161
|
sourceType: 'module',
|
|
161
162
|
sourceFilename: file,
|
|
162
|
-
plugins: (0,
|
|
163
|
+
plugins: (0, external_source_analysis_cjs_namespaceObject.consumerParserPlugins)(file)
|
|
163
164
|
});
|
|
164
165
|
parsed.set(file, ast);
|
|
165
166
|
return ast;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.n = (module)=>{
|
|
5
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
+
__webpack_require__.d(getter, {
|
|
7
|
+
a: getter
|
|
8
|
+
});
|
|
9
|
+
return getter;
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
14
|
+
var define = (defs, kind)=>{
|
|
15
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
[kind]: defs[key]
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
define(getters, "get");
|
|
21
|
+
define(values, "value");
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
(()=>{
|
|
25
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
26
|
+
})();
|
|
27
|
+
(()=>{
|
|
28
|
+
__webpack_require__.r = (exports1)=>{
|
|
29
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
30
|
+
value: 'Module'
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
33
|
+
value: true
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
var __webpack_exports__ = {};
|
|
38
|
+
__webpack_require__.r(__webpack_exports__);
|
|
39
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
40
|
+
SourceSyntaxError: ()=>SourceSyntaxError,
|
|
41
|
+
consumerParserPlugins: ()=>consumerParserPlugins,
|
|
42
|
+
parseSource: ()=>parseSource,
|
|
43
|
+
traverseSource: ()=>traverseSource,
|
|
44
|
+
unwrapExpression: ()=>unwrapExpression
|
|
45
|
+
});
|
|
46
|
+
const parser_namespaceObject = require("@babel/parser");
|
|
47
|
+
const traverse_namespaceObject = require("@babel/traverse");
|
|
48
|
+
var traverse_default = /*#__PURE__*/ __webpack_require__.n(traverse_namespaceObject);
|
|
49
|
+
const types_namespaceObject = require("@babel/types");
|
|
50
|
+
const consumerParserPlugins = (filePath)=>/\.[jt]sx$/u.test(filePath) ? [
|
|
51
|
+
"typescript",
|
|
52
|
+
'jsx'
|
|
53
|
+
] : [
|
|
54
|
+
"typescript"
|
|
55
|
+
];
|
|
56
|
+
class SourceSyntaxError extends Error {
|
|
57
|
+
}
|
|
58
|
+
class SourceValidationHub extends traverse_namespaceObject.Hub {
|
|
59
|
+
buildError(_node, message) {
|
|
60
|
+
return new SourceSyntaxError(message);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function parseSource(source, filename, syntaxMessage) {
|
|
64
|
+
try {
|
|
65
|
+
return (0, parser_namespaceObject.parse)(source, {
|
|
66
|
+
sourceType: 'module',
|
|
67
|
+
sourceFilename: filename,
|
|
68
|
+
plugins: consumerParserPlugins(filename)
|
|
69
|
+
});
|
|
70
|
+
} catch (cause) {
|
|
71
|
+
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw new SourceSyntaxError(syntaxMessage ?? (cause instanceof Error ? cause.message : String(cause)));
|
|
72
|
+
throw cause;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function traverseSource(file, visitor) {
|
|
76
|
+
const program = traverse_namespaceObject.NodePath.get({
|
|
77
|
+
hub: new SourceValidationHub(),
|
|
78
|
+
parentPath: void 0,
|
|
79
|
+
parent: file,
|
|
80
|
+
container: file,
|
|
81
|
+
key: 'program'
|
|
82
|
+
});
|
|
83
|
+
program.setContext();
|
|
84
|
+
traverse_default()(file, visitor, program.scope, void 0, program);
|
|
85
|
+
}
|
|
86
|
+
function unwrapExpression(node, includeAssertions = false) {
|
|
87
|
+
while(types_namespaceObject.isTSAsExpression(node) || types_namespaceObject.isParenthesizedExpression(node) || types_namespaceObject.isTSSatisfiesExpression(node) || includeAssertions && (types_namespaceObject.isTSTypeAssertion(node) || types_namespaceObject.isTSNonNullExpression(node)))node = node.expression;
|
|
88
|
+
return node;
|
|
89
|
+
}
|
|
90
|
+
exports.SourceSyntaxError = __webpack_exports__.SourceSyntaxError;
|
|
91
|
+
exports.consumerParserPlugins = __webpack_exports__.consumerParserPlugins;
|
|
92
|
+
exports.parseSource = __webpack_exports__.parseSource;
|
|
93
|
+
exports.traverseSource = __webpack_exports__.traverseSource;
|
|
94
|
+
exports.unwrapExpression = __webpack_exports__.unwrapExpression;
|
|
95
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
96
|
+
"SourceSyntaxError",
|
|
97
|
+
"consumerParserPlugins",
|
|
98
|
+
"parseSource",
|
|
99
|
+
"traverseSource",
|
|
100
|
+
"unwrapExpression"
|
|
101
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
102
|
+
Object.defineProperty(exports, '__esModule', {
|
|
103
|
+
value: true
|
|
104
|
+
});
|
|
@@ -44,25 +44,12 @@ const external_node_fs_namespaceObject = require("node:fs");
|
|
|
44
44
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
45
45
|
const external_node_path_namespaceObject = require("node:path");
|
|
46
46
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
47
|
-
const parser_namespaceObject = require("@babel/parser");
|
|
48
|
-
const traverse_namespaceObject = require("@babel/traverse");
|
|
49
|
-
var traverse_default = /*#__PURE__*/ __webpack_require__.n(traverse_namespaceObject);
|
|
50
47
|
const types_namespaceObject = require("@babel/types");
|
|
48
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
51
49
|
const edge = '@modern-js/bff-effect/effect-edge';
|
|
52
50
|
const nodeRuntime = '@modern-js/bff-effect/effect';
|
|
53
51
|
const sharedRuntime = /^@[^/]+\/shared-contracts\/server\/effect-bff-runtime$/u;
|
|
54
52
|
const failure = 'Generated API entries must export defineEffectBff(...) or the server-only shared Effect BFF assembly helper with an explicitly composed handler Layer and an unshadowed executable root; entries must implement handlers through HttpApiBuilder.group.';
|
|
55
|
-
const invalidSources = new WeakSet();
|
|
56
|
-
function invalidSource(message) {
|
|
57
|
-
const error = new Error(message);
|
|
58
|
-
invalidSources.add(error);
|
|
59
|
-
return error;
|
|
60
|
-
}
|
|
61
|
-
class SourceValidationHub extends traverse_namespaceObject.Hub {
|
|
62
|
-
buildError(_node, message) {
|
|
63
|
-
return invalidSource(message);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
53
|
function createEffectApiImportResolver(filename) {
|
|
67
54
|
const directory = external_node_fs_default().realpathSync(external_node_path_default().dirname(filename));
|
|
68
55
|
const owner = external_node_fs_default().realpathSync(external_node_path_default().resolve(directory, '..'));
|
|
@@ -94,34 +81,14 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
94
81
|
const load = (input)=>{
|
|
95
82
|
const existing = modules.get(input.id);
|
|
96
83
|
if (existing) return existing;
|
|
97
|
-
if (modules.size >= 64 || input.source.length > 1000000) throw
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
file = (0, parser_namespaceObject.parse)(input.source, {
|
|
101
|
-
sourceType: 'module',
|
|
102
|
-
sourceFilename: input.id,
|
|
103
|
-
plugins: [
|
|
104
|
-
"typescript"
|
|
105
|
-
]
|
|
106
|
-
});
|
|
107
|
-
} catch (cause) {
|
|
108
|
-
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw invalidSource('Invalid API syntax');
|
|
109
|
-
throw cause;
|
|
110
|
-
}
|
|
84
|
+
if (modules.size >= 64 || input.source.length > 1000000) throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError('API source budget exceeded');
|
|
85
|
+
const file = (0, external_source_analysis_cjs_namespaceObject.parseSource)(input.source, input.id, 'Invalid API syntax');
|
|
111
86
|
const module = {
|
|
112
87
|
...input,
|
|
113
88
|
file
|
|
114
89
|
};
|
|
115
90
|
modules.set(input.id, module);
|
|
116
|
-
|
|
117
|
-
hub: new SourceValidationHub(),
|
|
118
|
-
parentPath: void 0,
|
|
119
|
-
parent: file,
|
|
120
|
-
container: file,
|
|
121
|
-
key: 'program'
|
|
122
|
-
});
|
|
123
|
-
program.setContext();
|
|
124
|
-
traverse_default()(file, {
|
|
91
|
+
(0, external_source_analysis_cjs_namespaceObject.traverseSource)(file, {
|
|
125
92
|
enter (nodePath) {
|
|
126
93
|
paths.set(nodePath.node, nodePath);
|
|
127
94
|
owners.set(nodePath.node, module);
|
|
@@ -140,7 +107,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
140
107
|
if (binding) mutated.add(binding);
|
|
141
108
|
}
|
|
142
109
|
}
|
|
143
|
-
}
|
|
110
|
+
});
|
|
144
111
|
return module;
|
|
145
112
|
};
|
|
146
113
|
try {
|
|
@@ -149,10 +116,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
149
116
|
source,
|
|
150
117
|
resolveImport
|
|
151
118
|
});
|
|
152
|
-
const unwrap = (node)=>
|
|
153
|
-
while(types_namespaceObject.isParenthesizedExpression(node) || types_namespaceObject.isTSSatisfiesExpression(node) || types_namespaceObject.isTSAsExpression(node) || types_namespaceObject.isTSTypeAssertion(node) || types_namespaceObject.isTSNonNullExpression(node))node = node.expression;
|
|
154
|
-
return node;
|
|
155
|
-
};
|
|
119
|
+
const unwrap = (node)=>(0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(node, true);
|
|
156
120
|
const binding = (node)=>{
|
|
157
121
|
node = unwrap(node);
|
|
158
122
|
if (!types_namespaceObject.isIdentifier(node)) return;
|
|
@@ -393,7 +357,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
393
357
|
const root = entry.file.program.body.find((statement)=>types_namespaceObject.isExportDefaultDeclaration(statement));
|
|
394
358
|
return root && runtime(root.declaration) ? void 0 : failure;
|
|
395
359
|
} catch (cause) {
|
|
396
|
-
if (
|
|
360
|
+
if (cause instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError) return failure;
|
|
397
361
|
const message = 'object' == typeof cause && null !== cause && 'message' in cause && 'string' == typeof cause.message ? cause.message : String(cause);
|
|
398
362
|
throw new Error(`Strict Effect API analysis failed: ${message}`, {
|
|
399
363
|
cause
|
|
@@ -1,54 +1,22 @@
|
|
|
1
1
|
import node_fs from "node:fs";
|
|
2
2
|
import node_path from "node:path";
|
|
3
|
-
import { parse } from "@babel/parser";
|
|
4
|
-
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
5
3
|
import { baselinePublicIdentityIsExact } from "./microvertical-api-owner.js";
|
|
4
|
+
import { SourceSyntaxError, parseSource, traverseSource, unwrapExpression } from "./source-analysis.js";
|
|
6
5
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
7
|
-
const consumerParserPlugins = (filePath)=>filePath.endsWith('.tsx') || filePath.endsWith('.jsx') ? [
|
|
8
|
-
"typescript",
|
|
9
|
-
'jsx'
|
|
10
|
-
] : [
|
|
11
|
-
"typescript"
|
|
12
|
-
];
|
|
13
|
-
class ConsumerSyntaxError extends Error {
|
|
14
|
-
}
|
|
15
|
-
class ConsumerValidationHub extends Hub {
|
|
16
|
-
buildError(_node, message) {
|
|
17
|
-
return new ConsumerSyntaxError(message);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
6
|
function parseConsumer(filePath) {
|
|
21
7
|
if (node_fs.statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
file = parse(node_fs.readFileSync(filePath, 'utf8'), {
|
|
25
|
-
sourceType: 'module',
|
|
26
|
-
sourceFilename: filePath,
|
|
27
|
-
plugins: consumerParserPlugins(filePath)
|
|
28
|
-
});
|
|
29
|
-
} catch (error) {
|
|
30
|
-
if ('object' == typeof error && null !== error && 'code' in error && 'BABEL_PARSER_SYNTAX_ERROR' === error.code) throw new ConsumerSyntaxError(error instanceof Error ? error.message : String(error));
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
const program = NodePath.get({
|
|
34
|
-
hub: new ConsumerValidationHub(),
|
|
35
|
-
parentPath: void 0,
|
|
36
|
-
parent: file,
|
|
37
|
-
container: file,
|
|
38
|
-
key: 'program'
|
|
39
|
-
});
|
|
40
|
-
program.setContext();
|
|
41
|
-
traverse(file, {
|
|
8
|
+
const file = parseSource(node_fs.readFileSync(filePath, 'utf8'), filePath);
|
|
9
|
+
traverseSource(file, {
|
|
42
10
|
AssignmentExpression (p) {
|
|
43
|
-
throw new
|
|
11
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
44
12
|
},
|
|
45
13
|
UpdateExpression (p) {
|
|
46
|
-
throw new
|
|
14
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
47
15
|
},
|
|
48
16
|
TSModuleDeclaration () {
|
|
49
|
-
throw new
|
|
17
|
+
throw new SourceSyntaxError('contract bindings must not be merged with namespaces');
|
|
50
18
|
}
|
|
51
|
-
}
|
|
19
|
+
});
|
|
52
20
|
return file;
|
|
53
21
|
}
|
|
54
22
|
const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
|
|
@@ -73,11 +41,6 @@ const accessPath = (node)=>{
|
|
|
73
41
|
}
|
|
74
42
|
};
|
|
75
43
|
const isAccessPath = (node, expected)=>accessPath(node)?.join('.') === expected.join('.');
|
|
76
|
-
const unwrapExpression = (expression)=>{
|
|
77
|
-
let current = expression;
|
|
78
|
-
while(__rspack_external__babel_types_6e8337dd.isTSAsExpression(current) || __rspack_external__babel_types_6e8337dd.isParenthesizedExpression(current) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(current))current = current.expression;
|
|
79
|
-
return current;
|
|
80
|
-
};
|
|
81
44
|
const stringLiteral = (expression)=>{
|
|
82
45
|
if (null == expression) return;
|
|
83
46
|
const unwrapped = unwrapExpression(expression);
|
|
@@ -614,8 +577,8 @@ const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
|
614
577
|
path: filePath
|
|
615
578
|
}, stem, expectation);
|
|
616
579
|
} catch (error) {
|
|
617
|
-
if (error instanceof
|
|
580
|
+
if (error instanceof SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
|
|
618
581
|
throw error;
|
|
619
582
|
}
|
|
620
583
|
};
|
|
621
|
-
export { configuredMicroVerticalApiStem,
|
|
584
|
+
export { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import node_fs from "node:fs";
|
|
2
2
|
import node_path from "node:path";
|
|
3
3
|
import { parse } from "@babel/parser";
|
|
4
|
-
import { configuredMicroVerticalApiStem,
|
|
4
|
+
import { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation } from "./microvertical-api-baseline.js";
|
|
5
5
|
import { baselinePackage, resolveBaselinePackageDirectory } from "./microvertical-api-owner.js";
|
|
6
|
+
import { consumerParserPlugins } from "./source-analysis.js";
|
|
6
7
|
import { createEffectApiImportResolver, strictEffectRuntimeTopologyViolation } from "./strict-effect-runtime.js";
|
|
7
8
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
8
9
|
const ignored = new Set([
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { parse } from "@babel/parser";
|
|
2
|
+
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
3
|
+
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
4
|
+
const consumerParserPlugins = (filePath)=>/\.[jt]sx$/u.test(filePath) ? [
|
|
5
|
+
"typescript",
|
|
6
|
+
'jsx'
|
|
7
|
+
] : [
|
|
8
|
+
"typescript"
|
|
9
|
+
];
|
|
10
|
+
class SourceSyntaxError extends Error {
|
|
11
|
+
}
|
|
12
|
+
class SourceValidationHub extends Hub {
|
|
13
|
+
buildError(_node, message) {
|
|
14
|
+
return new SourceSyntaxError(message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function parseSource(source, filename, syntaxMessage) {
|
|
18
|
+
try {
|
|
19
|
+
return parse(source, {
|
|
20
|
+
sourceType: 'module',
|
|
21
|
+
sourceFilename: filename,
|
|
22
|
+
plugins: consumerParserPlugins(filename)
|
|
23
|
+
});
|
|
24
|
+
} catch (cause) {
|
|
25
|
+
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw new SourceSyntaxError(syntaxMessage ?? (cause instanceof Error ? cause.message : String(cause)));
|
|
26
|
+
throw cause;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function traverseSource(file, visitor) {
|
|
30
|
+
const program = NodePath.get({
|
|
31
|
+
hub: new SourceValidationHub(),
|
|
32
|
+
parentPath: void 0,
|
|
33
|
+
parent: file,
|
|
34
|
+
container: file,
|
|
35
|
+
key: 'program'
|
|
36
|
+
});
|
|
37
|
+
program.setContext();
|
|
38
|
+
traverse(file, visitor, program.scope, void 0, program);
|
|
39
|
+
}
|
|
40
|
+
function unwrapExpression(node, includeAssertions = false) {
|
|
41
|
+
while(__rspack_external__babel_types_6e8337dd.isTSAsExpression(node) || __rspack_external__babel_types_6e8337dd.isParenthesizedExpression(node) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(node) || includeAssertions && (__rspack_external__babel_types_6e8337dd.isTSTypeAssertion(node) || __rspack_external__babel_types_6e8337dd.isTSNonNullExpression(node)))node = node.expression;
|
|
42
|
+
return node;
|
|
43
|
+
}
|
|
44
|
+
export { SourceSyntaxError, consumerParserPlugins, parseSource, traverseSource, unwrapExpression };
|
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
import node_fs from "node:fs";
|
|
2
2
|
import node_path from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
3
|
+
import { SourceSyntaxError, parseSource, traverseSource, unwrapExpression } from "./source-analysis.js";
|
|
5
4
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
6
5
|
const edge = '@modern-js/bff-effect/effect-edge';
|
|
7
6
|
const nodeRuntime = '@modern-js/bff-effect/effect';
|
|
8
7
|
const sharedRuntime = /^@[^/]+\/shared-contracts\/server\/effect-bff-runtime$/u;
|
|
9
8
|
const failure = 'Generated API entries must export defineEffectBff(...) or the server-only shared Effect BFF assembly helper with an explicitly composed handler Layer and an unshadowed executable root; entries must implement handlers through HttpApiBuilder.group.';
|
|
10
|
-
const invalidSources = new WeakSet();
|
|
11
|
-
function invalidSource(message) {
|
|
12
|
-
const error = new Error(message);
|
|
13
|
-
invalidSources.add(error);
|
|
14
|
-
return error;
|
|
15
|
-
}
|
|
16
|
-
class SourceValidationHub extends Hub {
|
|
17
|
-
buildError(_node, message) {
|
|
18
|
-
return invalidSource(message);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
9
|
function createEffectApiImportResolver(filename) {
|
|
22
10
|
const directory = node_fs.realpathSync(node_path.dirname(filename));
|
|
23
11
|
const owner = node_fs.realpathSync(node_path.resolve(directory, '..'));
|
|
@@ -49,34 +37,14 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
49
37
|
const load = (input)=>{
|
|
50
38
|
const existing = modules.get(input.id);
|
|
51
39
|
if (existing) return existing;
|
|
52
|
-
if (modules.size >= 64 || input.source.length > 1000000) throw
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
file = parse(input.source, {
|
|
56
|
-
sourceType: 'module',
|
|
57
|
-
sourceFilename: input.id,
|
|
58
|
-
plugins: [
|
|
59
|
-
"typescript"
|
|
60
|
-
]
|
|
61
|
-
});
|
|
62
|
-
} catch (cause) {
|
|
63
|
-
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw invalidSource('Invalid API syntax');
|
|
64
|
-
throw cause;
|
|
65
|
-
}
|
|
40
|
+
if (modules.size >= 64 || input.source.length > 1000000) throw new SourceSyntaxError('API source budget exceeded');
|
|
41
|
+
const file = parseSource(input.source, input.id, 'Invalid API syntax');
|
|
66
42
|
const module = {
|
|
67
43
|
...input,
|
|
68
44
|
file
|
|
69
45
|
};
|
|
70
46
|
modules.set(input.id, module);
|
|
71
|
-
|
|
72
|
-
hub: new SourceValidationHub(),
|
|
73
|
-
parentPath: void 0,
|
|
74
|
-
parent: file,
|
|
75
|
-
container: file,
|
|
76
|
-
key: 'program'
|
|
77
|
-
});
|
|
78
|
-
program.setContext();
|
|
79
|
-
traverse(file, {
|
|
47
|
+
traverseSource(file, {
|
|
80
48
|
enter (nodePath) {
|
|
81
49
|
paths.set(nodePath.node, nodePath);
|
|
82
50
|
owners.set(nodePath.node, module);
|
|
@@ -95,7 +63,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
95
63
|
if (binding) mutated.add(binding);
|
|
96
64
|
}
|
|
97
65
|
}
|
|
98
|
-
}
|
|
66
|
+
});
|
|
99
67
|
return module;
|
|
100
68
|
};
|
|
101
69
|
try {
|
|
@@ -104,10 +72,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
104
72
|
source,
|
|
105
73
|
resolveImport
|
|
106
74
|
});
|
|
107
|
-
const unwrap = (node)=>
|
|
108
|
-
while(__rspack_external__babel_types_6e8337dd.isParenthesizedExpression(node) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(node) || __rspack_external__babel_types_6e8337dd.isTSAsExpression(node) || __rspack_external__babel_types_6e8337dd.isTSTypeAssertion(node) || __rspack_external__babel_types_6e8337dd.isTSNonNullExpression(node))node = node.expression;
|
|
109
|
-
return node;
|
|
110
|
-
};
|
|
75
|
+
const unwrap = (node)=>unwrapExpression(node, true);
|
|
111
76
|
const binding = (node)=>{
|
|
112
77
|
node = unwrap(node);
|
|
113
78
|
if (!__rspack_external__babel_types_6e8337dd.isIdentifier(node)) return;
|
|
@@ -348,7 +313,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
348
313
|
const root = entry.file.program.body.find((statement)=>__rspack_external__babel_types_6e8337dd.isExportDefaultDeclaration(statement));
|
|
349
314
|
return root && runtime(root.declaration) ? void 0 : failure;
|
|
350
315
|
} catch (cause) {
|
|
351
|
-
if (
|
|
316
|
+
if (cause instanceof SourceSyntaxError) return failure;
|
|
352
317
|
const message = 'object' == typeof cause && null !== cause && 'message' in cause && 'string' == typeof cause.message ? cause.message : String(cause);
|
|
353
318
|
throw new Error(`Strict Effect API analysis failed: ${message}`, {
|
|
354
319
|
cause
|
|
@@ -1,55 +1,23 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
|
-
import { parse } from "@babel/parser";
|
|
5
|
-
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
6
4
|
import { baselinePublicIdentityIsExact } from "./microvertical-api-owner.js";
|
|
5
|
+
import { SourceSyntaxError, parseSource, traverseSource, unwrapExpression } from "./source-analysis.js";
|
|
7
6
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
8
|
-
const consumerParserPlugins = (filePath)=>filePath.endsWith('.tsx') || filePath.endsWith('.jsx') ? [
|
|
9
|
-
"typescript",
|
|
10
|
-
'jsx'
|
|
11
|
-
] : [
|
|
12
|
-
"typescript"
|
|
13
|
-
];
|
|
14
|
-
class ConsumerSyntaxError extends Error {
|
|
15
|
-
}
|
|
16
|
-
class ConsumerValidationHub extends Hub {
|
|
17
|
-
buildError(_node, message) {
|
|
18
|
-
return new ConsumerSyntaxError(message);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
7
|
function parseConsumer(filePath) {
|
|
22
8
|
if (node_fs.statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
file = parse(node_fs.readFileSync(filePath, 'utf8'), {
|
|
26
|
-
sourceType: 'module',
|
|
27
|
-
sourceFilename: filePath,
|
|
28
|
-
plugins: consumerParserPlugins(filePath)
|
|
29
|
-
});
|
|
30
|
-
} catch (error) {
|
|
31
|
-
if ('object' == typeof error && null !== error && 'code' in error && 'BABEL_PARSER_SYNTAX_ERROR' === error.code) throw new ConsumerSyntaxError(error instanceof Error ? error.message : String(error));
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
const program = NodePath.get({
|
|
35
|
-
hub: new ConsumerValidationHub(),
|
|
36
|
-
parentPath: void 0,
|
|
37
|
-
parent: file,
|
|
38
|
-
container: file,
|
|
39
|
-
key: 'program'
|
|
40
|
-
});
|
|
41
|
-
program.setContext();
|
|
42
|
-
traverse(file, {
|
|
9
|
+
const file = parseSource(node_fs.readFileSync(filePath, 'utf8'), filePath);
|
|
10
|
+
traverseSource(file, {
|
|
43
11
|
AssignmentExpression (p) {
|
|
44
|
-
throw new
|
|
12
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
45
13
|
},
|
|
46
14
|
UpdateExpression (p) {
|
|
47
|
-
throw new
|
|
15
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
48
16
|
},
|
|
49
17
|
TSModuleDeclaration () {
|
|
50
|
-
throw new
|
|
18
|
+
throw new SourceSyntaxError('contract bindings must not be merged with namespaces');
|
|
51
19
|
}
|
|
52
|
-
}
|
|
20
|
+
});
|
|
53
21
|
return file;
|
|
54
22
|
}
|
|
55
23
|
const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
|
|
@@ -74,11 +42,6 @@ const accessPath = (node)=>{
|
|
|
74
42
|
}
|
|
75
43
|
};
|
|
76
44
|
const isAccessPath = (node, expected)=>accessPath(node)?.join('.') === expected.join('.');
|
|
77
|
-
const unwrapExpression = (expression)=>{
|
|
78
|
-
let current = expression;
|
|
79
|
-
while(__rspack_external__babel_types_6e8337dd.isTSAsExpression(current) || __rspack_external__babel_types_6e8337dd.isParenthesizedExpression(current) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(current))current = current.expression;
|
|
80
|
-
return current;
|
|
81
|
-
};
|
|
82
45
|
const stringLiteral = (expression)=>{
|
|
83
46
|
if (null == expression) return;
|
|
84
47
|
const unwrapped = unwrapExpression(expression);
|
|
@@ -615,8 +578,8 @@ const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
|
615
578
|
path: filePath
|
|
616
579
|
}, stem, expectation);
|
|
617
580
|
} catch (error) {
|
|
618
|
-
if (error instanceof
|
|
581
|
+
if (error instanceof SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
|
|
619
582
|
throw error;
|
|
620
583
|
}
|
|
621
584
|
};
|
|
622
|
-
export { configuredMicroVerticalApiStem,
|
|
585
|
+
export { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation };
|
|
@@ -2,8 +2,9 @@ import "node:module";
|
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
4
|
import { parse } from "@babel/parser";
|
|
5
|
-
import { configuredMicroVerticalApiStem,
|
|
5
|
+
import { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation } from "./microvertical-api-baseline.js";
|
|
6
6
|
import { baselinePackage, resolveBaselinePackageDirectory } from "./microvertical-api-owner.js";
|
|
7
|
+
import { consumerParserPlugins } from "./source-analysis.js";
|
|
7
8
|
import { createEffectApiImportResolver, strictEffectRuntimeTopologyViolation } from "./strict-effect-runtime.js";
|
|
8
9
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
9
10
|
const ignored = new Set([
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { parse } from "@babel/parser";
|
|
3
|
+
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
4
|
+
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
5
|
+
const consumerParserPlugins = (filePath)=>/\.[jt]sx$/u.test(filePath) ? [
|
|
6
|
+
"typescript",
|
|
7
|
+
'jsx'
|
|
8
|
+
] : [
|
|
9
|
+
"typescript"
|
|
10
|
+
];
|
|
11
|
+
class SourceSyntaxError extends Error {
|
|
12
|
+
}
|
|
13
|
+
class SourceValidationHub extends Hub {
|
|
14
|
+
buildError(_node, message) {
|
|
15
|
+
return new SourceSyntaxError(message);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function parseSource(source, filename, syntaxMessage) {
|
|
19
|
+
try {
|
|
20
|
+
return parse(source, {
|
|
21
|
+
sourceType: 'module',
|
|
22
|
+
sourceFilename: filename,
|
|
23
|
+
plugins: consumerParserPlugins(filename)
|
|
24
|
+
});
|
|
25
|
+
} catch (cause) {
|
|
26
|
+
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw new SourceSyntaxError(syntaxMessage ?? (cause instanceof Error ? cause.message : String(cause)));
|
|
27
|
+
throw cause;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function traverseSource(file, visitor) {
|
|
31
|
+
const program = NodePath.get({
|
|
32
|
+
hub: new SourceValidationHub(),
|
|
33
|
+
parentPath: void 0,
|
|
34
|
+
parent: file,
|
|
35
|
+
container: file,
|
|
36
|
+
key: 'program'
|
|
37
|
+
});
|
|
38
|
+
program.setContext();
|
|
39
|
+
traverse(file, visitor, program.scope, void 0, program);
|
|
40
|
+
}
|
|
41
|
+
function unwrapExpression(node, includeAssertions = false) {
|
|
42
|
+
while(__rspack_external__babel_types_6e8337dd.isTSAsExpression(node) || __rspack_external__babel_types_6e8337dd.isParenthesizedExpression(node) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(node) || includeAssertions && (__rspack_external__babel_types_6e8337dd.isTSTypeAssertion(node) || __rspack_external__babel_types_6e8337dd.isTSNonNullExpression(node)))node = node.expression;
|
|
43
|
+
return node;
|
|
44
|
+
}
|
|
45
|
+
export { SourceSyntaxError, consumerParserPlugins, parseSource, traverseSource, unwrapExpression };
|
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import traverse, { Hub, NodePath } from "@babel/traverse";
|
|
4
|
+
import { SourceSyntaxError, parseSource, traverseSource, unwrapExpression } from "./source-analysis.js";
|
|
6
5
|
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
7
6
|
const edge = '@modern-js/bff-effect/effect-edge';
|
|
8
7
|
const nodeRuntime = '@modern-js/bff-effect/effect';
|
|
9
8
|
const sharedRuntime = /^@[^/]+\/shared-contracts\/server\/effect-bff-runtime$/u;
|
|
10
9
|
const failure = 'Generated API entries must export defineEffectBff(...) or the server-only shared Effect BFF assembly helper with an explicitly composed handler Layer and an unshadowed executable root; entries must implement handlers through HttpApiBuilder.group.';
|
|
11
|
-
const invalidSources = new WeakSet();
|
|
12
|
-
function invalidSource(message) {
|
|
13
|
-
const error = new Error(message);
|
|
14
|
-
invalidSources.add(error);
|
|
15
|
-
return error;
|
|
16
|
-
}
|
|
17
|
-
class SourceValidationHub extends Hub {
|
|
18
|
-
buildError(_node, message) {
|
|
19
|
-
return invalidSource(message);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
10
|
function createEffectApiImportResolver(filename) {
|
|
23
11
|
const directory = node_fs.realpathSync(node_path.dirname(filename));
|
|
24
12
|
const owner = node_fs.realpathSync(node_path.resolve(directory, '..'));
|
|
@@ -50,34 +38,14 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
50
38
|
const load = (input)=>{
|
|
51
39
|
const existing = modules.get(input.id);
|
|
52
40
|
if (existing) return existing;
|
|
53
|
-
if (modules.size >= 64 || input.source.length > 1000000) throw
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
file = parse(input.source, {
|
|
57
|
-
sourceType: 'module',
|
|
58
|
-
sourceFilename: input.id,
|
|
59
|
-
plugins: [
|
|
60
|
-
"typescript"
|
|
61
|
-
]
|
|
62
|
-
});
|
|
63
|
-
} catch (cause) {
|
|
64
|
-
if ('object' == typeof cause && null !== cause && 'code' in cause && 'BABEL_PARSER_SYNTAX_ERROR' === cause.code && 'reasonCode' in cause && 'string' == typeof cause.reasonCode) throw invalidSource('Invalid API syntax');
|
|
65
|
-
throw cause;
|
|
66
|
-
}
|
|
41
|
+
if (modules.size >= 64 || input.source.length > 1000000) throw new SourceSyntaxError('API source budget exceeded');
|
|
42
|
+
const file = parseSource(input.source, input.id, 'Invalid API syntax');
|
|
67
43
|
const module = {
|
|
68
44
|
...input,
|
|
69
45
|
file
|
|
70
46
|
};
|
|
71
47
|
modules.set(input.id, module);
|
|
72
|
-
|
|
73
|
-
hub: new SourceValidationHub(),
|
|
74
|
-
parentPath: void 0,
|
|
75
|
-
parent: file,
|
|
76
|
-
container: file,
|
|
77
|
-
key: 'program'
|
|
78
|
-
});
|
|
79
|
-
program.setContext();
|
|
80
|
-
traverse(file, {
|
|
48
|
+
traverseSource(file, {
|
|
81
49
|
enter (nodePath) {
|
|
82
50
|
paths.set(nodePath.node, nodePath);
|
|
83
51
|
owners.set(nodePath.node, module);
|
|
@@ -96,7 +64,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
96
64
|
if (binding) mutated.add(binding);
|
|
97
65
|
}
|
|
98
66
|
}
|
|
99
|
-
}
|
|
67
|
+
});
|
|
100
68
|
return module;
|
|
101
69
|
};
|
|
102
70
|
try {
|
|
@@ -105,10 +73,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
105
73
|
source,
|
|
106
74
|
resolveImport
|
|
107
75
|
});
|
|
108
|
-
const unwrap = (node)=>
|
|
109
|
-
while(__rspack_external__babel_types_6e8337dd.isParenthesizedExpression(node) || __rspack_external__babel_types_6e8337dd.isTSSatisfiesExpression(node) || __rspack_external__babel_types_6e8337dd.isTSAsExpression(node) || __rspack_external__babel_types_6e8337dd.isTSTypeAssertion(node) || __rspack_external__babel_types_6e8337dd.isTSNonNullExpression(node))node = node.expression;
|
|
110
|
-
return node;
|
|
111
|
-
};
|
|
76
|
+
const unwrap = (node)=>unwrapExpression(node, true);
|
|
112
77
|
const binding = (node)=>{
|
|
113
78
|
node = unwrap(node);
|
|
114
79
|
if (!__rspack_external__babel_types_6e8337dd.isIdentifier(node)) return;
|
|
@@ -349,7 +314,7 @@ function strictEffectRuntimeTopologyViolation(source, resolveImport) {
|
|
|
349
314
|
const root = entry.file.program.body.find((statement)=>__rspack_external__babel_types_6e8337dd.isExportDefaultDeclaration(statement));
|
|
350
315
|
return root && runtime(root.declaration) ? void 0 : failure;
|
|
351
316
|
} catch (cause) {
|
|
352
|
-
if (
|
|
317
|
+
if (cause instanceof SourceSyntaxError) return failure;
|
|
353
318
|
const message = 'object' == typeof cause && null !== cause && 'message' in cause && 'string' == typeof cause.message ? cause.message : String(cause);
|
|
354
319
|
throw new Error(`Strict Effect API analysis failed: ${message}`, {
|
|
355
320
|
cause
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Only `.tsx` is JSX. Enabling JSX for a `.ts` file misreads a generic arrow
|
|
3
|
-
* such as `const f = <T>(value: T) => value` as an unclosed JSX element.
|
|
4
|
-
*/
|
|
5
|
-
export declare const consumerParserPlugins: (filePath: string) => ('typescript' | 'jsx')[];
|
|
6
1
|
export interface MicroVerticalApiBaselineExpectation {
|
|
7
2
|
/** Optional override for operation IDs outside reachable endpoint naming conventions. */
|
|
8
3
|
readonly operationPaths?: Readonly<Record<string, string>>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Visitor } from '@babel/traverse';
|
|
2
|
+
import * as t from '@babel/types';
|
|
3
|
+
/** Only JSX extensions enable JSX: generic arrows in .ts must remain valid. */
|
|
4
|
+
export declare const consumerParserPlugins: (filePath: string) => ('typescript' | 'jsx')[];
|
|
5
|
+
/** Only parser/binder diagnostics are policy violations; tool failures escape. */
|
|
6
|
+
export declare class SourceSyntaxError extends Error {
|
|
7
|
+
}
|
|
8
|
+
export declare function parseSource(source: string, filename: string, syntaxMessage?: string): t.File;
|
|
9
|
+
export declare function traverseSource(file: t.File, visitor: Visitor): void;
|
|
10
|
+
export declare function unwrapExpression(node: t.Node, includeAssertions?: boolean): t.Node;
|