@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.9 → 3.9.3-ultramodern.10
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/bin/modern-api-check-files.mjs +4 -1
- package/bin/modern-api-check.mjs +1 -1
- package/bin/modern-i18n-check.mjs +4 -0
- package/dist/cjs/cli/microvertical-api-check.cjs +36 -7
- package/dist/cjs/cli/workspace-source-check.cjs +90 -17
- package/dist/cjs/microvertical-api-baseline.cjs +89 -246
- package/dist/cjs/microvertical-api-boundary.cjs +507 -64
- package/dist/cjs/microvertical-api-owner.cjs +5 -2
- package/dist/cjs/module-graph.cjs +1862 -0
- package/dist/cjs/oxlint-plugin/rules/strict-effect-api-boundaries.cjs +1 -1
- package/dist/cjs/source-analysis.cjs +108 -0
- package/dist/cjs/strict-effect-runtime.cjs +75 -57
- package/dist/esm/cli/microvertical-api-check.js +26 -7
- package/dist/esm/cli/workspace-source-check.js +86 -13
- package/dist/esm/microvertical-api-baseline.js +66 -214
- package/dist/esm/microvertical-api-boundary.js +505 -65
- package/dist/esm/microvertical-api-owner.js +5 -2
- package/dist/esm/module-graph.js +1804 -0
- package/dist/esm/oxlint-plugin/rules/strict-effect-api-boundaries.js +1 -1
- package/dist/esm/source-analysis.js +48 -0
- package/dist/esm/strict-effect-runtime.js +75 -56
- package/dist/esm-node/cli/microvertical-api-check.js +26 -7
- package/dist/esm-node/cli/workspace-source-check.js +86 -13
- package/dist/esm-node/microvertical-api-baseline.js +66 -214
- package/dist/esm-node/microvertical-api-boundary.js +505 -65
- package/dist/esm-node/microvertical-api-owner.js +5 -2
- package/dist/esm-node/module-graph.js +1805 -0
- package/dist/esm-node/oxlint-plugin/rules/strict-effect-api-boundaries.js +1 -1
- package/dist/esm-node/source-analysis.js +49 -0
- package/dist/esm-node/strict-effect-runtime.js +75 -56
- package/dist/types/cli/microvertical-api-check.d.ts +1 -1
- package/dist/types/cli/workspace-source-check.d.ts +1 -1
- package/dist/types/microvertical-api-baseline.d.ts +4 -5
- package/dist/types/microvertical-api-boundary.d.ts +17 -2
- package/dist/types/microvertical-api-owner.d.ts +1 -1
- package/dist/types/module-graph.d.ts +100 -0
- package/dist/types/source-analysis.d.ts +13 -0
- package/package.json +17 -13
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
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
3
|
(()=>{
|
|
13
4
|
__webpack_require__.d = (exports1, getters, values)=>{
|
|
14
5
|
var define = (defs, kind)=>{
|
|
@@ -37,75 +28,21 @@ var __webpack_require__ = {};
|
|
|
37
28
|
var __webpack_exports__ = {};
|
|
38
29
|
__webpack_require__.r(__webpack_exports__);
|
|
39
30
|
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
camelCaseStem: ()=>camelCaseStem,
|
|
40
32
|
configuredMicroVerticalApiStem: ()=>configuredMicroVerticalApiStem,
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
microVerticalApiBaselineViolation: ()=>microVerticalApiBaselineViolation,
|
|
34
|
+
pascalCaseStem: ()=>pascalCaseStem
|
|
43
35
|
});
|
|
44
|
-
const external_node_fs_namespaceObject = require("node:fs");
|
|
45
|
-
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
46
|
-
const external_node_path_namespaceObject = require("node:path");
|
|
47
|
-
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
36
|
const types_namespaceObject = require("@babel/types");
|
|
52
37
|
const external_microvertical_api_owner_cjs_namespaceObject = require("./microvertical-api-owner.cjs");
|
|
53
|
-
const
|
|
54
|
-
|
|
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
|
-
}
|
|
66
|
-
function parseConsumer(filePath) {
|
|
67
|
-
if (external_node_fs_default().statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
|
|
68
|
-
let file;
|
|
69
|
-
try {
|
|
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, {
|
|
88
|
-
AssignmentExpression (p) {
|
|
89
|
-
throw new ConsumerSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
90
|
-
},
|
|
91
|
-
UpdateExpression (p) {
|
|
92
|
-
throw new ConsumerSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
93
|
-
},
|
|
94
|
-
TSModuleDeclaration () {
|
|
95
|
-
throw new ConsumerSyntaxError('contract bindings must not be merged with namespaces');
|
|
96
|
-
}
|
|
97
|
-
}, program.scope, void 0, program);
|
|
98
|
-
return file;
|
|
99
|
-
}
|
|
38
|
+
const external_module_graph_cjs_namespaceObject = require("./module-graph.cjs");
|
|
39
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
100
40
|
const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
|
|
101
41
|
const pascalCaseStem = (stem)=>{
|
|
102
42
|
const camelStem = camelCaseStem(stem);
|
|
103
43
|
return `${camelStem.slice(0, 1).toUpperCase()}${camelStem.slice(1)}`;
|
|
104
44
|
};
|
|
105
45
|
const identifierName = (node)=>void 0 !== node && types_namespaceObject.isIdentifier(node) ? node.name : void 0;
|
|
106
|
-
const propertyName = (node)=>{
|
|
107
|
-
if (void 0 !== node && (types_namespaceObject.isIdentifier(node) || types_namespaceObject.isStringLiteral(node) || types_namespaceObject.isNumericLiteral(node))) return types_namespaceObject.isIdentifier(node) ? node.name : String(node.value);
|
|
108
|
-
};
|
|
109
46
|
const accessPath = (node)=>{
|
|
110
47
|
if (types_namespaceObject.isIdentifier(node)) return [
|
|
111
48
|
node.name
|
|
@@ -119,165 +56,31 @@ const accessPath = (node)=>{
|
|
|
119
56
|
}
|
|
120
57
|
};
|
|
121
58
|
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
59
|
const stringLiteral = (expression)=>{
|
|
128
60
|
if (null == expression) return;
|
|
129
|
-
const unwrapped = unwrapExpression(expression);
|
|
61
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
130
62
|
return types_namespaceObject.isStringLiteral(unwrapped) ? unwrapped.value : void 0;
|
|
131
63
|
};
|
|
132
64
|
const numericLiteral = (expression)=>{
|
|
133
65
|
if (null == expression) return;
|
|
134
|
-
const unwrapped = unwrapExpression(expression);
|
|
66
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
135
67
|
return types_namespaceObject.isNumericLiteral(unwrapped) ? Number(unwrapped.value) : void 0;
|
|
136
68
|
};
|
|
137
69
|
const callExpression = (expression, callee)=>{
|
|
138
70
|
if (null == expression) return;
|
|
139
|
-
const unwrapped = unwrapExpression(expression);
|
|
71
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
140
72
|
return types_namespaceObject.isCallExpression(unwrapped) && isAccessPath(unwrapped.callee, callee) ? unwrapped : void 0;
|
|
141
73
|
};
|
|
142
|
-
const localConst = (sourceFile, name)=>{
|
|
143
|
-
for (const item of sourceFile.program.body){
|
|
144
|
-
const statement = types_namespaceObject.isExportNamedDeclaration(item) ? item.declaration : item;
|
|
145
|
-
if (!types_namespaceObject.isVariableDeclaration(statement) || 'const' !== statement.kind) continue;
|
|
146
|
-
const matches = statement.declarations.filter((declaration)=>types_namespaceObject.isIdentifier(declaration.id, {
|
|
147
|
-
name
|
|
148
|
-
}));
|
|
149
|
-
if (1 === matches.length) return matches[0];
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
const exportedConst = (sourceFile, name)=>{
|
|
153
|
-
for (const statement of sourceFile.program.body)if (types_namespaceObject.isExportNamedDeclaration(statement) && 'type' !== statement.exportKind) {
|
|
154
|
-
if (types_namespaceObject.isVariableDeclaration(statement.declaration) && 'const' === statement.declaration.kind) {
|
|
155
|
-
const declaration = statement.declaration.declarations.find((value)=>types_namespaceObject.isIdentifier(value.id, {
|
|
156
|
-
name
|
|
157
|
-
}));
|
|
158
|
-
if (declaration) return declaration;
|
|
159
|
-
}
|
|
160
|
-
if (!statement.source && statement.specifiers.some((value)=>types_namespaceObject.isExportSpecifier(value) && 'type' !== value.exportKind && types_namespaceObject.isIdentifier(value.local, {
|
|
161
|
-
name
|
|
162
|
-
}) && types_namespaceObject.isIdentifier(value.exported, {
|
|
163
|
-
name
|
|
164
|
-
}))) return localConst(sourceFile, name);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
const resolveRelativeModulePath = (fromPath, specifier)=>{
|
|
168
|
-
if (!/^\.\.?\//u.test(specifier)) return;
|
|
169
|
-
const resolved = external_node_path_default().resolve(external_node_path_default().dirname(fromPath), specifier);
|
|
170
|
-
const stem = resolved.replace(/\.(?:[cm]?[jt]sx?)$/u, '');
|
|
171
|
-
for (const candidate of [
|
|
172
|
-
`${stem}.ts`,
|
|
173
|
-
`${stem}.tsx`,
|
|
174
|
-
external_node_path_default().join(stem, 'index.ts'),
|
|
175
|
-
external_node_path_default().join(stem, 'index.tsx')
|
|
176
|
-
])if (external_node_fs_default().existsSync(candidate) && external_node_fs_default().statSync(candidate).isFile()) return candidate;
|
|
177
|
-
};
|
|
178
|
-
const createModuleReader = (root)=>{
|
|
179
|
-
const modules = new Map([
|
|
180
|
-
[
|
|
181
|
-
root.path,
|
|
182
|
-
root
|
|
183
|
-
]
|
|
184
|
-
]);
|
|
185
|
-
return (filePath)=>{
|
|
186
|
-
if (modules.has(filePath)) return modules.get(filePath);
|
|
187
|
-
if (modules.size >= 256) return;
|
|
188
|
-
let module;
|
|
189
|
-
try {
|
|
190
|
-
module = {
|
|
191
|
-
file: parseConsumer(filePath),
|
|
192
|
-
path: filePath
|
|
193
|
-
};
|
|
194
|
-
} catch {
|
|
195
|
-
module = void 0;
|
|
196
|
-
}
|
|
197
|
-
modules.set(filePath, module);
|
|
198
|
-
return module;
|
|
199
|
-
};
|
|
200
|
-
};
|
|
201
|
-
const importedBinding = (module, name)=>{
|
|
202
|
-
for (const statement of module.file.program.body)if (types_namespaceObject.isImportDeclaration(statement) && 'type' !== statement.importKind) {
|
|
203
|
-
for (const specifier of statement.specifiers)if (types_namespaceObject.isIdentifier(specifier.local, {
|
|
204
|
-
name
|
|
205
|
-
})) {
|
|
206
|
-
if (types_namespaceObject.isImportSpecifier(specifier) && 'type' !== specifier.importKind) return {
|
|
207
|
-
imported: propertyName(specifier.imported) ?? name,
|
|
208
|
-
specifier: statement.source.value
|
|
209
|
-
};
|
|
210
|
-
if (types_namespaceObject.isImportDefaultSpecifier(specifier)) return {
|
|
211
|
-
imported: 'default',
|
|
212
|
-
specifier: statement.source.value
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
const reexportedBinding = (module, name)=>{
|
|
218
|
-
for (const statement of module.file.program.body){
|
|
219
|
-
if (!types_namespaceObject.isExportNamedDeclaration(statement) || 'type' === statement.exportKind) continue;
|
|
220
|
-
const specifier = statement.specifiers.find((value)=>types_namespaceObject.isExportSpecifier(value) && 'type' !== value.exportKind && propertyName(value.exported) === name);
|
|
221
|
-
if (void 0 !== specifier && types_namespaceObject.isExportSpecifier(specifier)) return {
|
|
222
|
-
local: specifier.local.name,
|
|
223
|
-
...statement.source ? {
|
|
224
|
-
specifier: statement.source.value
|
|
225
|
-
} : {}
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
const defaultExport = (module)=>{
|
|
230
|
-
for (const statement of module.file.program.body){
|
|
231
|
-
if (!types_namespaceObject.isExportDefaultDeclaration(statement)) continue;
|
|
232
|
-
const declaration = statement.declaration;
|
|
233
|
-
if (types_namespaceObject.isIdentifier(declaration)) return declaration.name;
|
|
234
|
-
return types_namespaceObject.isExpression(declaration) ? declaration : void 0;
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
const resolveBinding = (module, name, scope, readModule, seen)=>{
|
|
238
|
-
const key = `${scope}:${module.path}#${name}`;
|
|
239
|
-
if (seen.has(key) || seen.size >= 512) return;
|
|
240
|
-
seen.add(key);
|
|
241
|
-
const declaration = 'export' === scope ? exportedConst(module.file, name) : localConst(module.file, name);
|
|
242
|
-
if (declaration?.init) return {
|
|
243
|
-
expression: declaration.init,
|
|
244
|
-
module
|
|
245
|
-
};
|
|
246
|
-
const throughModule = (specifier, imported)=>{
|
|
247
|
-
const resolvedPath = resolveRelativeModulePath(module.path, specifier);
|
|
248
|
-
const target = void 0 === resolvedPath ? void 0 : readModule(resolvedPath);
|
|
249
|
-
return void 0 === target ? void 0 : resolveBinding(target, imported, 'export', readModule, seen);
|
|
250
|
-
};
|
|
251
|
-
if ('local' === scope) {
|
|
252
|
-
const imported = importedBinding(module, name);
|
|
253
|
-
return void 0 === imported ? void 0 : throughModule(imported.specifier, imported.imported);
|
|
254
|
-
}
|
|
255
|
-
if ('default' === name) {
|
|
256
|
-
const exported = defaultExport(module);
|
|
257
|
-
if ('string' == typeof exported) return resolveBinding(module, exported, 'local', readModule, seen);
|
|
258
|
-
return void 0 === exported ? void 0 : {
|
|
259
|
-
expression: exported,
|
|
260
|
-
module
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
const reexported = reexportedBinding(module, name);
|
|
264
|
-
if (void 0 !== reexported) return void 0 === reexported.specifier ? resolveBinding(module, reexported.local, 'local', readModule, seen) : throughModule(reexported.specifier, reexported.local);
|
|
265
|
-
for (const statement of module.file.program.body){
|
|
266
|
-
if (!types_namespaceObject.isExportAllDeclaration(statement) || 'type' === statement.exportKind) continue;
|
|
267
|
-
const resolved = throughModule(statement.source.value, name);
|
|
268
|
-
if (void 0 !== resolved) return resolved;
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
74
|
const objectLiteral = (expression)=>{
|
|
272
75
|
if (null == expression) return;
|
|
273
|
-
const unwrapped = unwrapExpression(expression);
|
|
76
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
274
77
|
return types_namespaceObject.isObjectExpression(unwrapped) ? unwrapped : void 0;
|
|
275
78
|
};
|
|
276
79
|
const propertyAssignments = (properties)=>{
|
|
277
80
|
const assignments = new Map();
|
|
278
81
|
for (const property of properties){
|
|
279
82
|
if (!types_namespaceObject.isObjectProperty(property) || property.computed || property.shorthand) return;
|
|
280
|
-
const name = propertyName(property.key);
|
|
83
|
+
const name = (0, external_module_graph_cjs_namespaceObject.propertyName)(property.key);
|
|
281
84
|
if (void 0 === name || assignments.has(name)) return;
|
|
282
85
|
assignments.set(name, property);
|
|
283
86
|
}
|
|
@@ -289,7 +92,7 @@ const exactCall = (expression, callee, argumentCount)=>{
|
|
|
289
92
|
};
|
|
290
93
|
const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
291
94
|
if (declaration?.init == null) return;
|
|
292
|
-
const initializer = unwrapExpression(declaration.init);
|
|
95
|
+
const initializer = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init);
|
|
293
96
|
if (types_namespaceObject.isIdentifier(initializer) && initializer.name === sharedSchemaName) return {
|
|
294
97
|
assignments: new Map(),
|
|
295
98
|
identity: true
|
|
@@ -313,14 +116,14 @@ const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
|
313
116
|
};
|
|
314
117
|
const directCallChain = (expression)=>{
|
|
315
118
|
if (null == expression) return;
|
|
316
|
-
let current = unwrapExpression(expression);
|
|
119
|
+
let current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
317
120
|
const methods = [];
|
|
318
121
|
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
122
|
methods.unshift({
|
|
320
123
|
arguments: current.arguments,
|
|
321
124
|
name: current.callee.property.name
|
|
322
125
|
});
|
|
323
|
-
current = unwrapExpression(current.callee.object);
|
|
126
|
+
current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(current.callee.object);
|
|
324
127
|
}
|
|
325
128
|
if (!types_namespaceObject.isCallExpression(current)) return;
|
|
326
129
|
return {
|
|
@@ -331,7 +134,7 @@ const directCallChain = (expression)=>{
|
|
|
331
134
|
const brandedStringSchemaIsExact = (declaration, brand)=>{
|
|
332
135
|
const initializer = declaration?.init;
|
|
333
136
|
if (null == initializer) return false;
|
|
334
|
-
const pipeCall = unwrapExpression(initializer);
|
|
137
|
+
const pipeCall = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(initializer);
|
|
335
138
|
if (!types_namespaceObject.isCallExpression(pipeCall) || !types_namespaceObject.isMemberExpression(pipeCall.callee) || pipeCall.callee.computed || !types_namespaceObject.isIdentifier(pipeCall.callee.property, {
|
|
336
139
|
name: 'pipe'
|
|
337
140
|
}) || !isAccessPath(pipeCall.callee.object, [
|
|
@@ -367,14 +170,21 @@ const singleAddedArgument = (expression, factory, names)=>{
|
|
|
367
170
|
if (1 !== chain.base.arguments.length || !names.includes(stringLiteral(chain.base.arguments[0]) ?? '') || 1 !== chain.methods.length || method?.name !== 'add' || 1 !== method.arguments.length) return;
|
|
368
171
|
return method.arguments[0];
|
|
369
172
|
};
|
|
370
|
-
const
|
|
371
|
-
|
|
173
|
+
const rootGroupExpression = (graph, expression)=>{
|
|
174
|
+
if (void 0 === expression) return;
|
|
175
|
+
const node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
176
|
+
if (!types_namespaceObject.isIdentifier(node)) return node;
|
|
177
|
+
const resolved = graph.resolve(graph.root, node.name, 'local');
|
|
178
|
+
return resolved?.kind === 'declaration' && resolved.module === graph.root ? (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(resolved.expression) : void 0;
|
|
179
|
+
};
|
|
180
|
+
const foundationGroup = (graph, declaration, stem, readinessSchemaName)=>{
|
|
181
|
+
const group = rootGroupExpression(graph, singleAddedArgument(declaration?.init, [
|
|
372
182
|
'HttpApi',
|
|
373
183
|
'make'
|
|
374
184
|
], [
|
|
375
185
|
`${pascalCaseStem(stem)}FoundationApi`,
|
|
376
186
|
`${pascalCaseStem(stem)}ApiFoundation`
|
|
377
|
-
]);
|
|
187
|
+
]));
|
|
378
188
|
const endpointExpression = singleAddedArgument(group, [
|
|
379
189
|
'HttpApiGroup',
|
|
380
190
|
'make'
|
|
@@ -387,17 +197,24 @@ const foundationIsExact = (declaration, stem, readinessSchemaName)=>{
|
|
|
387
197
|
], 3);
|
|
388
198
|
const endpointOptions = objectLiteral(endpoint?.arguments[2]);
|
|
389
199
|
const endpointProperties = void 0 === endpointOptions ? void 0 : propertyAssignments(endpointOptions.properties);
|
|
390
|
-
return void 0 !== endpoint && 'readiness' === stringLiteral(endpoint.arguments[0]) && stringLiteral(endpoint.arguments[1]) === `/${stem}/readiness` && endpointProperties?.size === 1 && identifierName(endpointProperties.get('success')?.value) === readinessSchemaName;
|
|
200
|
+
return void 0 !== endpoint && 'readiness' === stringLiteral(endpoint.arguments[0]) && stringLiteral(endpoint.arguments[1]) === `/${stem}/readiness` && endpointProperties?.size === 1 && identifierName(endpointProperties.get('success')?.value) === readinessSchemaName ? group : void 0;
|
|
391
201
|
};
|
|
392
|
-
const rootComposesFoundation = (
|
|
202
|
+
const rootComposesFoundation = (graph, declaration, stem, foundationName, foundation)=>{
|
|
203
|
+
const sourceFile = graph.root.file;
|
|
393
204
|
const chain = directCallChain(declaration?.init);
|
|
394
205
|
const first = chain?.methods[0];
|
|
206
|
+
const firstArgument = first?.arguments[0];
|
|
395
207
|
return void 0 !== chain && isAccessPath(chain.base.callee, [
|
|
396
208
|
'HttpApi',
|
|
397
209
|
'make'
|
|
398
|
-
]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>
|
|
210
|
+
]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>{
|
|
211
|
+
const combinatorArity = nonEndpointCombinators.api[method.name];
|
|
212
|
+
if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
|
|
213
|
+
if ('add' === method.name) return method.arguments.length > 0;
|
|
214
|
+
return 1 === method.arguments.length && ('addHttpApi' === method.name || index === chain.methods.length - 1 && 'pipe' === method.name && 'identity' === identifierName(method.arguments[0]) && importsExactBindings(sourceFile, 'effect', [
|
|
399
215
|
'identity'
|
|
400
|
-
]))
|
|
216
|
+
]));
|
|
217
|
+
}) && void 0 !== firstArgument && (first?.name === 'addHttpApi' && identifierName(firstArgument) === foundationName || first?.name === 'add' && types_namespaceObject.isIdentifier(firstArgument) && rootGroupExpression(graph, firstArgument) === foundation);
|
|
401
218
|
};
|
|
402
219
|
const nonEndpointCombinators = {
|
|
403
220
|
api: {
|
|
@@ -413,8 +230,7 @@ const nonEndpointCombinators = {
|
|
|
413
230
|
middleware: 1
|
|
414
231
|
}
|
|
415
232
|
};
|
|
416
|
-
const reachableEndpoints = (
|
|
417
|
-
const readModule = createModuleReader(rootModule);
|
|
233
|
+
const reachableEndpoints = (graph, declaration)=>{
|
|
418
234
|
const active = new Set();
|
|
419
235
|
const endpoints = [];
|
|
420
236
|
const identities = new Set();
|
|
@@ -431,13 +247,13 @@ const reachableEndpoints = (rootModule, declaration)=>{
|
|
|
431
247
|
let visits = 0;
|
|
432
248
|
const visit = (expression, module, kind, group = '')=>{
|
|
433
249
|
if (!expression) return false;
|
|
434
|
-
const node = unwrapExpression(expression);
|
|
250
|
+
const node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
435
251
|
if (active.has(node) || active.size >= 128 || ++visits > 2048) return false;
|
|
436
252
|
active.add(node);
|
|
437
253
|
try {
|
|
438
254
|
if (types_namespaceObject.isIdentifier(node)) {
|
|
439
|
-
const resolved =
|
|
440
|
-
return
|
|
255
|
+
const resolved = graph.resolve(module, node.name, 'local');
|
|
256
|
+
return resolved?.kind === 'declaration' && visit(resolved.expression, resolved.module, kind, group);
|
|
441
257
|
}
|
|
442
258
|
if ('endpoint' === kind) {
|
|
443
259
|
if (!types_namespaceObject.isCallExpression(node) || node.arguments.length < 2 || node.arguments.length > 3) return false;
|
|
@@ -481,18 +297,36 @@ const reachableEndpoints = (rootModule, declaration)=>{
|
|
|
481
297
|
}
|
|
482
298
|
const combinatorArity = combinators[method.name];
|
|
483
299
|
if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
|
|
300
|
+
if ('add' === method.name) return method.arguments.length > 0 && method.arguments.every((argument)=>visitAdded(argument, module, 'api' === kind ? 'group' : 'endpoint', 'group' === kind ? name : ''));
|
|
484
301
|
if (1 !== method.arguments.length) return false;
|
|
485
302
|
if ('pipe' === method.name) return 'identity' === identifierName(method.arguments[0]) && importsExactBindings(module.file, 'effect', [
|
|
486
303
|
'identity'
|
|
487
304
|
]);
|
|
488
|
-
if ('add' === method.name) return visit(method.arguments[0], module, 'api' === kind ? 'group' : 'endpoint', 'group' === kind ? name : '');
|
|
489
305
|
return 'api' === kind && 'addHttpApi' === method.name && visit(method.arguments[0], module, 'api');
|
|
490
306
|
});
|
|
491
307
|
} finally{
|
|
492
308
|
active.delete(node);
|
|
493
309
|
}
|
|
494
310
|
};
|
|
495
|
-
|
|
311
|
+
const visitAdded = (argument, module, kind, group)=>{
|
|
312
|
+
if (!types_namespaceObject.isSpreadElement(argument)) return visit(argument, module, kind, group);
|
|
313
|
+
let node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(argument.argument);
|
|
314
|
+
let owner = module;
|
|
315
|
+
if (types_namespaceObject.isIdentifier(node)) {
|
|
316
|
+
const resolved = graph.resolve(module, node.name, 'local');
|
|
317
|
+
if (resolved?.kind !== 'declaration') return false;
|
|
318
|
+
node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(resolved.expression);
|
|
319
|
+
owner = resolved.module;
|
|
320
|
+
}
|
|
321
|
+
if (!types_namespaceObject.isArrayExpression(node) || active.has(node) || ++visits > 2048) return false;
|
|
322
|
+
active.add(node);
|
|
323
|
+
try {
|
|
324
|
+
return node.elements.every((element)=>null !== element && visitAdded(element, owner, kind, group));
|
|
325
|
+
} finally{
|
|
326
|
+
active.delete(node);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
return visit(declaration?.init, graph.root, 'api') ? endpoints : void 0;
|
|
496
330
|
};
|
|
497
331
|
const operationContextFields = (property)=>{
|
|
498
332
|
const constructorCall = exactCall(property.value, [
|
|
@@ -585,7 +419,7 @@ const markerSchemaIsShared = (sourceFile, declaration)=>{
|
|
|
585
419
|
'version'
|
|
586
420
|
]);
|
|
587
421
|
if (void 0 === schema || schema.identity) return schema?.identity === true;
|
|
588
|
-
const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact(localConst(sourceFile, `${brand}Schema`), brand);
|
|
422
|
+
const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact((0, external_module_graph_cjs_namespaceObject.localConst)(sourceFile, `${brand}Schema`), brand);
|
|
589
423
|
const validators = new Map([
|
|
590
424
|
[
|
|
591
425
|
'appId',
|
|
@@ -622,14 +456,14 @@ const readinessSchemaIsShared = (declaration, markerSchemaName, ownerMarkerIsIde
|
|
|
622
456
|
]);
|
|
623
457
|
return void 0 !== schema && (schema.identity && ownerMarkerIsIdentity || 1 === schema.assignments.size && identifierName(schema.assignments.get('marker')?.value) === markerSchemaName);
|
|
624
458
|
};
|
|
625
|
-
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName(unwrapExpression(declaration.init)) === identifier;
|
|
626
|
-
const validateParsedContract = (
|
|
627
|
-
const sourceFile =
|
|
459
|
+
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName((0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init)) === identifier;
|
|
460
|
+
const validateParsedContract = (graph, stem, expectation)=>{
|
|
461
|
+
const sourceFile = graph.root.file;
|
|
628
462
|
const exportStem = camelCaseStem(stem);
|
|
629
463
|
const foundationName = `${exportStem}FoundationApi`;
|
|
630
464
|
const markerSchemaName = `${exportStem}MarkerSchema`;
|
|
631
465
|
const readinessSchemaName = `${exportStem}ReadinessSchema`;
|
|
632
|
-
const markerDeclaration = exportedConst(sourceFile, markerSchemaName);
|
|
466
|
+
const markerDeclaration = (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, markerSchemaName);
|
|
633
467
|
if (!importsExactBindings(sourceFile, expectation.effectClientPackage, [
|
|
634
468
|
'HttpApi',
|
|
635
469
|
'HttpApiEndpoint',
|
|
@@ -638,13 +472,14 @@ const validateParsedContract = (module, stem, expectation)=>{
|
|
|
638
472
|
])) return 'MicroVertical root contract must import exact Effect API primitives from the framework client package';
|
|
639
473
|
if (!importsSharedBaselinePrimitives(sourceFile, expectation.baselinePackage)) return 'MicroVertical root contract must import exact baseline primitives from the framework baseline package';
|
|
640
474
|
if (!markerSchemaIsShared(sourceFile, markerDeclaration)) return 'MicroVertical root contract must consume the shared build marker schema without overriding shared fields';
|
|
641
|
-
if (!readinessSchemaIsShared(exportedConst(sourceFile, readinessSchemaName), markerSchemaName, declarationIsIdentifier(markerDeclaration, 'MicroVerticalBuildMarkerSchema'))) return 'MicroVertical readiness schema must consume the shared readiness schema without overriding shared fields';
|
|
642
|
-
|
|
643
|
-
if (
|
|
644
|
-
|
|
475
|
+
if (!readinessSchemaIsShared((0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, readinessSchemaName), markerSchemaName, declarationIsIdentifier(markerDeclaration, 'MicroVerticalBuildMarkerSchema'))) return 'MicroVertical readiness schema must consume the shared readiness schema without overriding shared fields';
|
|
476
|
+
const foundation = foundationGroup(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, foundationName), stem, readinessSchemaName);
|
|
477
|
+
if (void 0 === foundation) return 'MicroVertical readiness foundation API must directly compose its exact readiness endpoint and foundation identity';
|
|
478
|
+
if (!rootComposesFoundation(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}Api`), stem, foundationName, foundation)) return 'MicroVertical root API must explicitly compose its readiness foundation API';
|
|
479
|
+
const endpoints = reachableEndpoints(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}Api`));
|
|
645
480
|
if (!endpoints) return 'MicroVertical root API must compose bounded native endpoint declarations without ambiguous identities';
|
|
646
|
-
if (!operationMapIsConnected(exportedConst(sourceFile, `${exportStem}OperationContexts`), stem, expectation.operationPaths ?? {}, endpoints)) return 'MicroVertical operation map must construct every operation with the shared context constructor';
|
|
647
|
-
if (!metadataIsExact(exportedConst(sourceFile, `${exportStem}ApiContract`), expectation, endpoints)) return 'MicroVertical root contract must keep exact owner and API path metadata without forbidden fields';
|
|
481
|
+
if (!operationMapIsConnected((0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}OperationContexts`), stem, expectation.operationPaths ?? {}, endpoints)) return 'MicroVertical operation map must construct every operation with the shared context constructor';
|
|
482
|
+
if (!metadataIsExact((0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}ApiContract`), expectation, endpoints)) return 'MicroVertical root contract must keep exact owner and API path metadata without forbidden fields';
|
|
648
483
|
};
|
|
649
484
|
const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
|
|
650
485
|
const topologyVertical = verticals.find((vertical)=>(vertical.path ?? `verticals/${vertical.id}`) === verticalPath);
|
|
@@ -653,24 +488,32 @@ const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
|
|
|
653
488
|
};
|
|
654
489
|
const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
655
490
|
try {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
491
|
+
const modules = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)();
|
|
492
|
+
const graph = {
|
|
493
|
+
...modules,
|
|
494
|
+
root: modules.module(filePath)
|
|
495
|
+
};
|
|
496
|
+
const [mutation] = graph.root.mutations;
|
|
497
|
+
if (mutation) return `MicroVertical root contract must be valid TypeScript syntax (contract bindings must be immutable at ${mutation.start})`;
|
|
498
|
+
let identityMismatch;
|
|
499
|
+
if (!(0, external_microvertical_api_owner_cjs_namespaceObject.baselinePublicIdentityIsExact)(filePath, expectation, (message)=>{
|
|
500
|
+
identityMismatch = message;
|
|
501
|
+
})) return `MicroVertical baseline imports must resolve the exact framework owner public export and schema identity${identityMismatch ? ` (${identityMismatch})` : ''}`;
|
|
502
|
+
return validateParsedContract(graph, stem, expectation);
|
|
662
503
|
} catch (error) {
|
|
663
|
-
if (error instanceof
|
|
504
|
+
if (error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
|
|
664
505
|
throw error;
|
|
665
506
|
}
|
|
666
507
|
};
|
|
508
|
+
exports.camelCaseStem = __webpack_exports__.camelCaseStem;
|
|
667
509
|
exports.configuredMicroVerticalApiStem = __webpack_exports__.configuredMicroVerticalApiStem;
|
|
668
|
-
exports.consumerParserPlugins = __webpack_exports__.consumerParserPlugins;
|
|
669
510
|
exports.microVerticalApiBaselineViolation = __webpack_exports__.microVerticalApiBaselineViolation;
|
|
511
|
+
exports.pascalCaseStem = __webpack_exports__.pascalCaseStem;
|
|
670
512
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
513
|
+
"camelCaseStem",
|
|
671
514
|
"configuredMicroVerticalApiStem",
|
|
672
|
-
"
|
|
673
|
-
"
|
|
515
|
+
"microVerticalApiBaselineViolation",
|
|
516
|
+
"pascalCaseStem"
|
|
674
517
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
675
518
|
Object.defineProperty(exports, '__esModule', {
|
|
676
519
|
value: true
|