@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.9 → 3.9.3-ultramodern.2
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 +81 -244
- package/dist/cjs/microvertical-api-boundary.cjs +352 -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 +350 -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 +350 -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 +0 -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)=>{
|
|
@@ -38,74 +29,18 @@ var __webpack_exports__ = {};
|
|
|
38
29
|
__webpack_require__.r(__webpack_exports__);
|
|
39
30
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
31
|
configuredMicroVerticalApiStem: ()=>configuredMicroVerticalApiStem,
|
|
41
|
-
consumerParserPlugins: ()=>consumerParserPlugins,
|
|
42
32
|
microVerticalApiBaselineViolation: ()=>microVerticalApiBaselineViolation
|
|
43
33
|
});
|
|
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
34
|
const types_namespaceObject = require("@babel/types");
|
|
52
35
|
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
|
-
}
|
|
36
|
+
const external_module_graph_cjs_namespaceObject = require("./module-graph.cjs");
|
|
37
|
+
const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
|
|
100
38
|
const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
|
|
101
39
|
const pascalCaseStem = (stem)=>{
|
|
102
40
|
const camelStem = camelCaseStem(stem);
|
|
103
41
|
return `${camelStem.slice(0, 1).toUpperCase()}${camelStem.slice(1)}`;
|
|
104
42
|
};
|
|
105
43
|
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
44
|
const accessPath = (node)=>{
|
|
110
45
|
if (types_namespaceObject.isIdentifier(node)) return [
|
|
111
46
|
node.name
|
|
@@ -119,165 +54,31 @@ const accessPath = (node)=>{
|
|
|
119
54
|
}
|
|
120
55
|
};
|
|
121
56
|
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
57
|
const stringLiteral = (expression)=>{
|
|
128
58
|
if (null == expression) return;
|
|
129
|
-
const unwrapped = unwrapExpression(expression);
|
|
59
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
130
60
|
return types_namespaceObject.isStringLiteral(unwrapped) ? unwrapped.value : void 0;
|
|
131
61
|
};
|
|
132
62
|
const numericLiteral = (expression)=>{
|
|
133
63
|
if (null == expression) return;
|
|
134
|
-
const unwrapped = unwrapExpression(expression);
|
|
64
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
135
65
|
return types_namespaceObject.isNumericLiteral(unwrapped) ? Number(unwrapped.value) : void 0;
|
|
136
66
|
};
|
|
137
67
|
const callExpression = (expression, callee)=>{
|
|
138
68
|
if (null == expression) return;
|
|
139
|
-
const unwrapped = unwrapExpression(expression);
|
|
69
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
140
70
|
return types_namespaceObject.isCallExpression(unwrapped) && isAccessPath(unwrapped.callee, callee) ? unwrapped : void 0;
|
|
141
71
|
};
|
|
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
72
|
const objectLiteral = (expression)=>{
|
|
272
73
|
if (null == expression) return;
|
|
273
|
-
const unwrapped = unwrapExpression(expression);
|
|
74
|
+
const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
274
75
|
return types_namespaceObject.isObjectExpression(unwrapped) ? unwrapped : void 0;
|
|
275
76
|
};
|
|
276
77
|
const propertyAssignments = (properties)=>{
|
|
277
78
|
const assignments = new Map();
|
|
278
79
|
for (const property of properties){
|
|
279
80
|
if (!types_namespaceObject.isObjectProperty(property) || property.computed || property.shorthand) return;
|
|
280
|
-
const name = propertyName(property.key);
|
|
81
|
+
const name = (0, external_module_graph_cjs_namespaceObject.propertyName)(property.key);
|
|
281
82
|
if (void 0 === name || assignments.has(name)) return;
|
|
282
83
|
assignments.set(name, property);
|
|
283
84
|
}
|
|
@@ -289,7 +90,7 @@ const exactCall = (expression, callee, argumentCount)=>{
|
|
|
289
90
|
};
|
|
290
91
|
const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
291
92
|
if (declaration?.init == null) return;
|
|
292
|
-
const initializer = unwrapExpression(declaration.init);
|
|
93
|
+
const initializer = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init);
|
|
293
94
|
if (types_namespaceObject.isIdentifier(initializer) && initializer.name === sharedSchemaName) return {
|
|
294
95
|
assignments: new Map(),
|
|
295
96
|
identity: true
|
|
@@ -313,14 +114,14 @@ const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
|
|
|
313
114
|
};
|
|
314
115
|
const directCallChain = (expression)=>{
|
|
315
116
|
if (null == expression) return;
|
|
316
|
-
let current = unwrapExpression(expression);
|
|
117
|
+
let current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
317
118
|
const methods = [];
|
|
318
119
|
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
120
|
methods.unshift({
|
|
320
121
|
arguments: current.arguments,
|
|
321
122
|
name: current.callee.property.name
|
|
322
123
|
});
|
|
323
|
-
current = unwrapExpression(current.callee.object);
|
|
124
|
+
current = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(current.callee.object);
|
|
324
125
|
}
|
|
325
126
|
if (!types_namespaceObject.isCallExpression(current)) return;
|
|
326
127
|
return {
|
|
@@ -331,7 +132,7 @@ const directCallChain = (expression)=>{
|
|
|
331
132
|
const brandedStringSchemaIsExact = (declaration, brand)=>{
|
|
332
133
|
const initializer = declaration?.init;
|
|
333
134
|
if (null == initializer) return false;
|
|
334
|
-
const pipeCall = unwrapExpression(initializer);
|
|
135
|
+
const pipeCall = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(initializer);
|
|
335
136
|
if (!types_namespaceObject.isCallExpression(pipeCall) || !types_namespaceObject.isMemberExpression(pipeCall.callee) || pipeCall.callee.computed || !types_namespaceObject.isIdentifier(pipeCall.callee.property, {
|
|
336
137
|
name: 'pipe'
|
|
337
138
|
}) || !isAccessPath(pipeCall.callee.object, [
|
|
@@ -367,14 +168,21 @@ const singleAddedArgument = (expression, factory, names)=>{
|
|
|
367
168
|
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
169
|
return method.arguments[0];
|
|
369
170
|
};
|
|
370
|
-
const
|
|
371
|
-
|
|
171
|
+
const rootGroupExpression = (graph, expression)=>{
|
|
172
|
+
if (void 0 === expression) return;
|
|
173
|
+
const node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
174
|
+
if (!types_namespaceObject.isIdentifier(node)) return node;
|
|
175
|
+
const resolved = graph.resolve(graph.root, node.name, 'local');
|
|
176
|
+
return resolved?.kind === 'declaration' && resolved.module === graph.root ? (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(resolved.expression) : void 0;
|
|
177
|
+
};
|
|
178
|
+
const foundationGroup = (graph, declaration, stem, readinessSchemaName)=>{
|
|
179
|
+
const group = rootGroupExpression(graph, singleAddedArgument(declaration?.init, [
|
|
372
180
|
'HttpApi',
|
|
373
181
|
'make'
|
|
374
182
|
], [
|
|
375
183
|
`${pascalCaseStem(stem)}FoundationApi`,
|
|
376
184
|
`${pascalCaseStem(stem)}ApiFoundation`
|
|
377
|
-
]);
|
|
185
|
+
]));
|
|
378
186
|
const endpointExpression = singleAddedArgument(group, [
|
|
379
187
|
'HttpApiGroup',
|
|
380
188
|
'make'
|
|
@@ -387,17 +195,24 @@ const foundationIsExact = (declaration, stem, readinessSchemaName)=>{
|
|
|
387
195
|
], 3);
|
|
388
196
|
const endpointOptions = objectLiteral(endpoint?.arguments[2]);
|
|
389
197
|
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;
|
|
198
|
+
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
199
|
};
|
|
392
|
-
const rootComposesFoundation = (
|
|
200
|
+
const rootComposesFoundation = (graph, declaration, stem, foundationName, foundation)=>{
|
|
201
|
+
const sourceFile = graph.root.file;
|
|
393
202
|
const chain = directCallChain(declaration?.init);
|
|
394
203
|
const first = chain?.methods[0];
|
|
204
|
+
const firstArgument = first?.arguments[0];
|
|
395
205
|
return void 0 !== chain && isAccessPath(chain.base.callee, [
|
|
396
206
|
'HttpApi',
|
|
397
207
|
'make'
|
|
398
|
-
]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>
|
|
208
|
+
]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>{
|
|
209
|
+
const combinatorArity = nonEndpointCombinators.api[method.name];
|
|
210
|
+
if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
|
|
211
|
+
if ('add' === method.name) return method.arguments.length > 0;
|
|
212
|
+
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
213
|
'identity'
|
|
400
|
-
]))
|
|
214
|
+
]));
|
|
215
|
+
}) && void 0 !== firstArgument && (first?.name === 'addHttpApi' && identifierName(firstArgument) === foundationName || first?.name === 'add' && types_namespaceObject.isIdentifier(firstArgument) && rootGroupExpression(graph, firstArgument) === foundation);
|
|
401
216
|
};
|
|
402
217
|
const nonEndpointCombinators = {
|
|
403
218
|
api: {
|
|
@@ -413,8 +228,7 @@ const nonEndpointCombinators = {
|
|
|
413
228
|
middleware: 1
|
|
414
229
|
}
|
|
415
230
|
};
|
|
416
|
-
const reachableEndpoints = (
|
|
417
|
-
const readModule = createModuleReader(rootModule);
|
|
231
|
+
const reachableEndpoints = (graph, declaration)=>{
|
|
418
232
|
const active = new Set();
|
|
419
233
|
const endpoints = [];
|
|
420
234
|
const identities = new Set();
|
|
@@ -431,13 +245,13 @@ const reachableEndpoints = (rootModule, declaration)=>{
|
|
|
431
245
|
let visits = 0;
|
|
432
246
|
const visit = (expression, module, kind, group = '')=>{
|
|
433
247
|
if (!expression) return false;
|
|
434
|
-
const node = unwrapExpression(expression);
|
|
248
|
+
const node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
|
|
435
249
|
if (active.has(node) || active.size >= 128 || ++visits > 2048) return false;
|
|
436
250
|
active.add(node);
|
|
437
251
|
try {
|
|
438
252
|
if (types_namespaceObject.isIdentifier(node)) {
|
|
439
|
-
const resolved =
|
|
440
|
-
return
|
|
253
|
+
const resolved = graph.resolve(module, node.name, 'local');
|
|
254
|
+
return resolved?.kind === 'declaration' && visit(resolved.expression, resolved.module, kind, group);
|
|
441
255
|
}
|
|
442
256
|
if ('endpoint' === kind) {
|
|
443
257
|
if (!types_namespaceObject.isCallExpression(node) || node.arguments.length < 2 || node.arguments.length > 3) return false;
|
|
@@ -481,18 +295,36 @@ const reachableEndpoints = (rootModule, declaration)=>{
|
|
|
481
295
|
}
|
|
482
296
|
const combinatorArity = combinators[method.name];
|
|
483
297
|
if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
|
|
298
|
+
if ('add' === method.name) return method.arguments.length > 0 && method.arguments.every((argument)=>visitAdded(argument, module, 'api' === kind ? 'group' : 'endpoint', 'group' === kind ? name : ''));
|
|
484
299
|
if (1 !== method.arguments.length) return false;
|
|
485
300
|
if ('pipe' === method.name) return 'identity' === identifierName(method.arguments[0]) && importsExactBindings(module.file, 'effect', [
|
|
486
301
|
'identity'
|
|
487
302
|
]);
|
|
488
|
-
if ('add' === method.name) return visit(method.arguments[0], module, 'api' === kind ? 'group' : 'endpoint', 'group' === kind ? name : '');
|
|
489
303
|
return 'api' === kind && 'addHttpApi' === method.name && visit(method.arguments[0], module, 'api');
|
|
490
304
|
});
|
|
491
305
|
} finally{
|
|
492
306
|
active.delete(node);
|
|
493
307
|
}
|
|
494
308
|
};
|
|
495
|
-
|
|
309
|
+
const visitAdded = (argument, module, kind, group)=>{
|
|
310
|
+
if (!types_namespaceObject.isSpreadElement(argument)) return visit(argument, module, kind, group);
|
|
311
|
+
let node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(argument.argument);
|
|
312
|
+
let owner = module;
|
|
313
|
+
if (types_namespaceObject.isIdentifier(node)) {
|
|
314
|
+
const resolved = graph.resolve(module, node.name, 'local');
|
|
315
|
+
if (resolved?.kind !== 'declaration') return false;
|
|
316
|
+
node = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(resolved.expression);
|
|
317
|
+
owner = resolved.module;
|
|
318
|
+
}
|
|
319
|
+
if (!types_namespaceObject.isArrayExpression(node) || active.has(node) || ++visits > 2048) return false;
|
|
320
|
+
active.add(node);
|
|
321
|
+
try {
|
|
322
|
+
return node.elements.every((element)=>null !== element && visitAdded(element, owner, kind, group));
|
|
323
|
+
} finally{
|
|
324
|
+
active.delete(node);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
return visit(declaration?.init, graph.root, 'api') ? endpoints : void 0;
|
|
496
328
|
};
|
|
497
329
|
const operationContextFields = (property)=>{
|
|
498
330
|
const constructorCall = exactCall(property.value, [
|
|
@@ -585,7 +417,7 @@ const markerSchemaIsShared = (sourceFile, declaration)=>{
|
|
|
585
417
|
'version'
|
|
586
418
|
]);
|
|
587
419
|
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);
|
|
420
|
+
const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact((0, external_module_graph_cjs_namespaceObject.localConst)(sourceFile, `${brand}Schema`), brand);
|
|
589
421
|
const validators = new Map([
|
|
590
422
|
[
|
|
591
423
|
'appId',
|
|
@@ -622,14 +454,14 @@ const readinessSchemaIsShared = (declaration, markerSchemaName, ownerMarkerIsIde
|
|
|
622
454
|
]);
|
|
623
455
|
return void 0 !== schema && (schema.identity && ownerMarkerIsIdentity || 1 === schema.assignments.size && identifierName(schema.assignments.get('marker')?.value) === markerSchemaName);
|
|
624
456
|
};
|
|
625
|
-
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName(unwrapExpression(declaration.init)) === identifier;
|
|
626
|
-
const validateParsedContract = (
|
|
627
|
-
const sourceFile =
|
|
457
|
+
const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName((0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init)) === identifier;
|
|
458
|
+
const validateParsedContract = (graph, stem, expectation)=>{
|
|
459
|
+
const sourceFile = graph.root.file;
|
|
628
460
|
const exportStem = camelCaseStem(stem);
|
|
629
461
|
const foundationName = `${exportStem}FoundationApi`;
|
|
630
462
|
const markerSchemaName = `${exportStem}MarkerSchema`;
|
|
631
463
|
const readinessSchemaName = `${exportStem}ReadinessSchema`;
|
|
632
|
-
const markerDeclaration = exportedConst(sourceFile, markerSchemaName);
|
|
464
|
+
const markerDeclaration = (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, markerSchemaName);
|
|
633
465
|
if (!importsExactBindings(sourceFile, expectation.effectClientPackage, [
|
|
634
466
|
'HttpApi',
|
|
635
467
|
'HttpApiEndpoint',
|
|
@@ -638,13 +470,14 @@ const validateParsedContract = (module, stem, expectation)=>{
|
|
|
638
470
|
])) return 'MicroVertical root contract must import exact Effect API primitives from the framework client package';
|
|
639
471
|
if (!importsSharedBaselinePrimitives(sourceFile, expectation.baselinePackage)) return 'MicroVertical root contract must import exact baseline primitives from the framework baseline package';
|
|
640
472
|
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
|
-
|
|
473
|
+
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';
|
|
474
|
+
const foundation = foundationGroup(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, foundationName), stem, readinessSchemaName);
|
|
475
|
+
if (void 0 === foundation) return 'MicroVertical readiness foundation API must directly compose its exact readiness endpoint and foundation identity';
|
|
476
|
+
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';
|
|
477
|
+
const endpoints = reachableEndpoints(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}Api`));
|
|
645
478
|
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';
|
|
479
|
+
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';
|
|
480
|
+
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
481
|
};
|
|
649
482
|
const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
|
|
650
483
|
const topologyVertical = verticals.find((vertical)=>(vertical.path ?? `verticals/${vertical.id}`) === verticalPath);
|
|
@@ -653,23 +486,27 @@ const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
|
|
|
653
486
|
};
|
|
654
487
|
const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
655
488
|
try {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
489
|
+
const modules = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)();
|
|
490
|
+
const graph = {
|
|
491
|
+
...modules,
|
|
492
|
+
root: modules.module(filePath)
|
|
493
|
+
};
|
|
494
|
+
const [mutation] = graph.root.mutations;
|
|
495
|
+
if (mutation) return `MicroVertical root contract must be valid TypeScript syntax (contract bindings must be immutable at ${mutation.start})`;
|
|
496
|
+
let identityMismatch;
|
|
497
|
+
if (!(0, external_microvertical_api_owner_cjs_namespaceObject.baselinePublicIdentityIsExact)(filePath, expectation, (message)=>{
|
|
498
|
+
identityMismatch = message;
|
|
499
|
+
})) return `MicroVertical baseline imports must resolve the exact framework owner public export and schema identity${identityMismatch ? ` (${identityMismatch})` : ''}`;
|
|
500
|
+
return validateParsedContract(graph, stem, expectation);
|
|
662
501
|
} catch (error) {
|
|
663
|
-
if (error instanceof
|
|
502
|
+
if (error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
|
|
664
503
|
throw error;
|
|
665
504
|
}
|
|
666
505
|
};
|
|
667
506
|
exports.configuredMicroVerticalApiStem = __webpack_exports__.configuredMicroVerticalApiStem;
|
|
668
|
-
exports.consumerParserPlugins = __webpack_exports__.consumerParserPlugins;
|
|
669
507
|
exports.microVerticalApiBaselineViolation = __webpack_exports__.microVerticalApiBaselineViolation;
|
|
670
508
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
671
509
|
"configuredMicroVerticalApiStem",
|
|
672
|
-
"consumerParserPlugins",
|
|
673
510
|
"microVerticalApiBaselineViolation"
|
|
674
511
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
675
512
|
Object.defineProperty(exports, '__esModule', {
|