@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.2 → 3.9.0-ultramodern.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/bin/modern-api-check-files.mjs +7 -0
  2. package/bin/modern-api-check.mjs +4 -0
  3. package/bin/modern-i18n-check.mjs +4 -0
  4. package/dist/cjs/cli/microvertical-api-check.cjs +100 -0
  5. package/dist/cjs/cli/oxlint.cjs +9 -5
  6. package/dist/cjs/cli/workspace-source-check.cjs +90 -17
  7. package/dist/cjs/microvertical-api-baseline.cjs +505 -0
  8. package/dist/cjs/microvertical-api-boundary.cjs +586 -0
  9. package/dist/cjs/microvertical-api-owner.cjs +217 -0
  10. package/dist/cjs/module-graph.cjs +321 -0
  11. package/dist/cjs/oxlint-plugin/rules/strict-effect-api-boundaries.cjs +8 -6
  12. package/dist/cjs/source-analysis.cjs +104 -0
  13. package/dist/cjs/strict-effect-runtime.cjs +376 -0
  14. package/dist/esm/cli/microvertical-api-check.js +52 -0
  15. package/dist/esm/cli/oxlint.js +10 -6
  16. package/dist/esm/cli/workspace-source-check.js +86 -13
  17. package/dist/esm/microvertical-api-baseline.js +464 -0
  18. package/dist/esm/microvertical-api-boundary.js +525 -0
  19. package/dist/esm/microvertical-api-owner.js +162 -0
  20. package/dist/esm/module-graph.js +260 -0
  21. package/dist/esm/oxlint-plugin/rules/strict-effect-api-boundaries.js +8 -6
  22. package/dist/esm/source-analysis.js +44 -0
  23. package/dist/esm/strict-effect-runtime.js +324 -0
  24. package/dist/esm-node/cli/microvertical-api-check.js +53 -0
  25. package/dist/esm-node/cli/oxlint.js +10 -6
  26. package/dist/esm-node/cli/workspace-source-check.js +86 -13
  27. package/dist/esm-node/microvertical-api-baseline.js +465 -0
  28. package/dist/esm-node/microvertical-api-boundary.js +526 -0
  29. package/dist/esm-node/microvertical-api-owner.js +163 -0
  30. package/dist/esm-node/module-graph.js +261 -0
  31. package/dist/esm-node/oxlint-plugin/rules/strict-effect-api-boundaries.js +8 -6
  32. package/dist/esm-node/source-analysis.js +45 -0
  33. package/dist/esm-node/strict-effect-runtime.js +325 -0
  34. package/dist/types/cli/microvertical-api-check.d.ts +1 -0
  35. package/dist/types/cli/workspace-source-check.d.ts +1 -1
  36. package/dist/types/microvertical-api-baseline.d.ts +23 -0
  37. package/dist/types/microvertical-api-boundary.d.ts +46 -0
  38. package/dist/types/microvertical-api-owner.d.ts +6 -0
  39. package/dist/types/module-graph.d.ts +52 -0
  40. package/dist/types/source-analysis.d.ts +10 -0
  41. package/dist/types/strict-effect-runtime.d.ts +10 -0
  42. package/package.json +29 -6
@@ -0,0 +1,465 @@
1
+ import "node:module";
2
+ import { baselinePublicIdentityIsExact } from "./microvertical-api-owner.js";
3
+ import { createModuleGraph, exportedConst, localConst, propertyName } from "./module-graph.js";
4
+ import { SourceSyntaxError, unwrapExpression } from "./source-analysis.js";
5
+ import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
6
+ const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
7
+ const pascalCaseStem = (stem)=>{
8
+ const camelStem = camelCaseStem(stem);
9
+ return `${camelStem.slice(0, 1).toUpperCase()}${camelStem.slice(1)}`;
10
+ };
11
+ const identifierName = (node)=>void 0 !== node && __rspack_external__babel_types_6e8337dd.isIdentifier(node) ? node.name : void 0;
12
+ const accessPath = (node)=>{
13
+ if (__rspack_external__babel_types_6e8337dd.isIdentifier(node)) return [
14
+ node.name
15
+ ];
16
+ if (__rspack_external__babel_types_6e8337dd.isMemberExpression(node) && !node.computed && __rspack_external__babel_types_6e8337dd.isIdentifier(node.property)) {
17
+ const parent = accessPath(node.object);
18
+ return void 0 === parent ? void 0 : [
19
+ ...parent,
20
+ node.property.name
21
+ ];
22
+ }
23
+ };
24
+ const isAccessPath = (node, expected)=>accessPath(node)?.join('.') === expected.join('.');
25
+ const stringLiteral = (expression)=>{
26
+ if (null == expression) return;
27
+ const unwrapped = unwrapExpression(expression);
28
+ return __rspack_external__babel_types_6e8337dd.isStringLiteral(unwrapped) ? unwrapped.value : void 0;
29
+ };
30
+ const numericLiteral = (expression)=>{
31
+ if (null == expression) return;
32
+ const unwrapped = unwrapExpression(expression);
33
+ return __rspack_external__babel_types_6e8337dd.isNumericLiteral(unwrapped) ? Number(unwrapped.value) : void 0;
34
+ };
35
+ const callExpression = (expression, callee)=>{
36
+ if (null == expression) return;
37
+ const unwrapped = unwrapExpression(expression);
38
+ return __rspack_external__babel_types_6e8337dd.isCallExpression(unwrapped) && isAccessPath(unwrapped.callee, callee) ? unwrapped : void 0;
39
+ };
40
+ const objectLiteral = (expression)=>{
41
+ if (null == expression) return;
42
+ const unwrapped = unwrapExpression(expression);
43
+ return __rspack_external__babel_types_6e8337dd.isObjectExpression(unwrapped) ? unwrapped : void 0;
44
+ };
45
+ const propertyAssignments = (properties)=>{
46
+ const assignments = new Map();
47
+ for (const property of properties){
48
+ if (!__rspack_external__babel_types_6e8337dd.isObjectProperty(property) || property.computed || property.shorthand) return;
49
+ const name = propertyName(property.key);
50
+ if (void 0 === name || assignments.has(name)) return;
51
+ assignments.set(name, property);
52
+ }
53
+ return assignments;
54
+ };
55
+ const exactCall = (expression, callee, argumentCount)=>{
56
+ const call = callExpression(expression, callee);
57
+ return call?.arguments.length === argumentCount ? call : void 0;
58
+ };
59
+ const sharedSchemaObject = (declaration, sharedSchemaName, protectedFields)=>{
60
+ if (declaration?.init == null) return;
61
+ const initializer = unwrapExpression(declaration.init);
62
+ if (__rspack_external__babel_types_6e8337dd.isIdentifier(initializer) && initializer.name === sharedSchemaName) return {
63
+ assignments: new Map(),
64
+ identity: true
65
+ };
66
+ const struct = exactCall(initializer, [
67
+ 'Schema',
68
+ 'Struct'
69
+ ], 1);
70
+ const schemaObject = objectLiteral(struct?.arguments[0]);
71
+ if (void 0 === schemaObject) return;
72
+ const spreads = schemaObject.properties.filter(__rspack_external__babel_types_6e8337dd.isSpreadElement);
73
+ const assignments = propertyAssignments(schemaObject.properties.filter((property)=>!__rspack_external__babel_types_6e8337dd.isSpreadElement(property)));
74
+ if (1 !== spreads.length || !spreads.every((spread)=>isAccessPath(spread.argument, [
75
+ sharedSchemaName,
76
+ 'fields'
77
+ ])) || void 0 === assignments || protectedFields.some((field)=>assignments.has(field))) return;
78
+ return {
79
+ assignments,
80
+ identity: false
81
+ };
82
+ };
83
+ const directCallChain = (expression)=>{
84
+ if (null == expression) return;
85
+ let current = unwrapExpression(expression);
86
+ const methods = [];
87
+ while(__rspack_external__babel_types_6e8337dd.isCallExpression(current) && __rspack_external__babel_types_6e8337dd.isMemberExpression(current.callee) && !current.callee.computed && __rspack_external__babel_types_6e8337dd.isIdentifier(current.callee.property) && !__rspack_external__babel_types_6e8337dd.isIdentifier(current.callee.object)){
88
+ methods.unshift({
89
+ arguments: current.arguments,
90
+ name: current.callee.property.name
91
+ });
92
+ current = unwrapExpression(current.callee.object);
93
+ }
94
+ if (!__rspack_external__babel_types_6e8337dd.isCallExpression(current)) return;
95
+ return {
96
+ base: current,
97
+ methods
98
+ };
99
+ };
100
+ const brandedStringSchemaIsExact = (declaration, brand)=>{
101
+ const initializer = declaration?.init;
102
+ if (null == initializer) return false;
103
+ const pipeCall = unwrapExpression(initializer);
104
+ if (!__rspack_external__babel_types_6e8337dd.isCallExpression(pipeCall) || !__rspack_external__babel_types_6e8337dd.isMemberExpression(pipeCall.callee) || pipeCall.callee.computed || !__rspack_external__babel_types_6e8337dd.isIdentifier(pipeCall.callee.property, {
105
+ name: 'pipe'
106
+ }) || !isAccessPath(pipeCall.callee.object, [
107
+ 'Schema',
108
+ 'String'
109
+ ]) || 1 !== pipeCall.arguments.length) return false;
110
+ const brandCall = exactCall(pipeCall.arguments[0], [
111
+ 'Schema',
112
+ 'brand'
113
+ ], 1);
114
+ return stringLiteral(brandCall?.arguments[0]) === brand;
115
+ };
116
+ const importedRuntimeNames = (statement, expectedPackage)=>{
117
+ if (!__rspack_external__babel_types_6e8337dd.isImportDeclaration(statement) || statement.source.value !== expectedPackage || 'type' === statement.importKind) return [];
118
+ return statement.specifiers.flatMap((value)=>__rspack_external__babel_types_6e8337dd.isImportSpecifier(value) && 'type' !== value.importKind && __rspack_external__babel_types_6e8337dd.isIdentifier(value.imported) && value.imported.name === value.local.name ? [
119
+ value.local.name
120
+ ] : []);
121
+ };
122
+ const importsExactBindings = (sourceFile, expectedPackage, expectedBindings)=>{
123
+ const names = new Set(sourceFile.program.body.flatMap((statement)=>importedRuntimeNames(statement, expectedPackage)));
124
+ return expectedBindings.every((name)=>names.has(name));
125
+ };
126
+ const baselineBindings = [
127
+ 'MicroVerticalBuildMarkerSchema',
128
+ 'MicroVerticalReadinessSchema',
129
+ 'createMicroVerticalOperationContext'
130
+ ];
131
+ const importsSharedBaselinePrimitives = (sourceFile, expectedPackage)=>importsExactBindings(sourceFile, expectedPackage, baselineBindings);
132
+ const singleAddedArgument = (expression, factory, names)=>{
133
+ const chain = directCallChain(expression);
134
+ if (void 0 === chain || !isAccessPath(chain.base.callee, factory)) return;
135
+ const [method] = chain.methods;
136
+ 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;
137
+ return method.arguments[0];
138
+ };
139
+ const rootGroupExpression = (graph, expression)=>{
140
+ if (void 0 === expression) return;
141
+ const node = unwrapExpression(expression);
142
+ if (!__rspack_external__babel_types_6e8337dd.isIdentifier(node)) return node;
143
+ const resolved = graph.resolve(graph.root, node.name, 'local');
144
+ return resolved?.kind === 'declaration' && resolved.module === graph.root ? unwrapExpression(resolved.expression) : void 0;
145
+ };
146
+ const foundationGroup = (graph, declaration, stem, readinessSchemaName)=>{
147
+ const group = rootGroupExpression(graph, singleAddedArgument(declaration?.init, [
148
+ 'HttpApi',
149
+ 'make'
150
+ ], [
151
+ `${pascalCaseStem(stem)}FoundationApi`,
152
+ `${pascalCaseStem(stem)}ApiFoundation`
153
+ ]));
154
+ const endpointExpression = singleAddedArgument(group, [
155
+ 'HttpApiGroup',
156
+ 'make'
157
+ ], [
158
+ 'foundation'
159
+ ]);
160
+ const endpoint = exactCall(endpointExpression, [
161
+ 'HttpApiEndpoint',
162
+ 'get'
163
+ ], 3);
164
+ const endpointOptions = objectLiteral(endpoint?.arguments[2]);
165
+ const endpointProperties = void 0 === endpointOptions ? void 0 : propertyAssignments(endpointOptions.properties);
166
+ 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;
167
+ };
168
+ const rootComposesFoundation = (graph, declaration, stem, foundationName, foundation)=>{
169
+ const sourceFile = graph.root.file;
170
+ const chain = directCallChain(declaration?.init);
171
+ const first = chain?.methods[0];
172
+ const firstArgument = first?.arguments[0];
173
+ return void 0 !== chain && isAccessPath(chain.base.callee, [
174
+ 'HttpApi',
175
+ 'make'
176
+ ]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>{
177
+ const combinatorArity = nonEndpointCombinators.api[method.name];
178
+ if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
179
+ if ('add' === method.name) return method.arguments.length > 0;
180
+ return 1 === method.arguments.length && ('addHttpApi' === method.name || index === chain.methods.length - 1 && 'pipe' === method.name && 'identity' === identifierName(method.arguments[0]) && importsExactBindings(sourceFile, 'effect', [
181
+ 'identity'
182
+ ]));
183
+ }) && void 0 !== firstArgument && (first?.name === 'addHttpApi' && identifierName(firstArgument) === foundationName || first?.name === 'add' && __rspack_external__babel_types_6e8337dd.isIdentifier(firstArgument) && rootGroupExpression(graph, firstArgument) === foundation);
184
+ };
185
+ const nonEndpointCombinators = {
186
+ api: {
187
+ annotate: 2,
188
+ annotateMerge: 1,
189
+ middleware: 1
190
+ },
191
+ group: {
192
+ annotate: 2,
193
+ annotateEndpoints: 2,
194
+ annotateEndpointsMerge: 1,
195
+ annotateMerge: 1,
196
+ middleware: 1
197
+ }
198
+ };
199
+ const reachableEndpoints = (graph, declaration)=>{
200
+ const active = new Set();
201
+ const endpoints = [];
202
+ const identities = new Set();
203
+ const verbs = {
204
+ get: 'GET',
205
+ post: 'POST',
206
+ put: 'PUT',
207
+ patch: 'PATCH',
208
+ del: 'DELETE',
209
+ delete: 'DELETE',
210
+ head: 'HEAD',
211
+ options: 'OPTIONS'
212
+ };
213
+ let visits = 0;
214
+ const visit = (expression, module, kind, group = '')=>{
215
+ if (!expression) return false;
216
+ const node = unwrapExpression(expression);
217
+ if (active.has(node) || active.size >= 128 || ++visits > 2048) return false;
218
+ active.add(node);
219
+ try {
220
+ if (__rspack_external__babel_types_6e8337dd.isIdentifier(node)) {
221
+ const resolved = graph.resolve(module, node.name, 'local');
222
+ return resolved?.kind === 'declaration' && visit(resolved.expression, resolved.module, kind, group);
223
+ }
224
+ if ('endpoint' === kind) {
225
+ if (!__rspack_external__babel_types_6e8337dd.isCallExpression(node) || node.arguments.length < 2 || node.arguments.length > 3) return false;
226
+ const callee = accessPath(node.callee);
227
+ const method = callee?.length === 2 && 'HttpApiEndpoint' === callee[0] ? verbs[callee[1]] : void 0;
228
+ const name = stringLiteral(node.arguments[0]);
229
+ const routePath = stringLiteral(node.arguments[1]);
230
+ if (!method || !name || !routePath) return false;
231
+ const identity = `${group}:${name}`;
232
+ if (identities.has(identity)) return false;
233
+ identities.add(identity);
234
+ endpoints.push({
235
+ group,
236
+ name,
237
+ method,
238
+ routePath
239
+ });
240
+ return true;
241
+ }
242
+ const chain = directCallChain(node);
243
+ if (!chain || !isAccessPath(chain.base.callee, [
244
+ 'api' === kind ? 'HttpApi' : 'HttpApiGroup',
245
+ 'make'
246
+ ]) || 1 !== chain.base.arguments.length) return false;
247
+ const name = stringLiteral(chain.base.arguments[0]);
248
+ if (!name) return false;
249
+ const chainStart = endpoints.length;
250
+ const combinators = nonEndpointCombinators[kind];
251
+ return chain.methods.every((method)=>{
252
+ if ('prefix' === method.name) {
253
+ const prefix = stringLiteral(method.arguments[0]);
254
+ if (1 !== method.arguments.length || !prefix?.startsWith('/')) return false;
255
+ for(let index = chainStart; index < endpoints.length; index += 1){
256
+ const endpoint = endpoints[index];
257
+ endpoints[index] = {
258
+ ...endpoint,
259
+ routePath: `${prefix}${endpoint.routePath}`
260
+ };
261
+ }
262
+ return true;
263
+ }
264
+ const combinatorArity = combinators[method.name];
265
+ if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
266
+ if ('add' === method.name) return method.arguments.length > 0 && method.arguments.every((argument)=>visitAdded(argument, module, 'api' === kind ? 'group' : 'endpoint', 'group' === kind ? name : ''));
267
+ if (1 !== method.arguments.length) return false;
268
+ if ('pipe' === method.name) return 'identity' === identifierName(method.arguments[0]) && importsExactBindings(module.file, 'effect', [
269
+ 'identity'
270
+ ]);
271
+ return 'api' === kind && 'addHttpApi' === method.name && visit(method.arguments[0], module, 'api');
272
+ });
273
+ } finally{
274
+ active.delete(node);
275
+ }
276
+ };
277
+ const visitAdded = (argument, module, kind, group)=>{
278
+ if (!__rspack_external__babel_types_6e8337dd.isSpreadElement(argument)) return visit(argument, module, kind, group);
279
+ let node = unwrapExpression(argument.argument);
280
+ let owner = module;
281
+ if (__rspack_external__babel_types_6e8337dd.isIdentifier(node)) {
282
+ const resolved = graph.resolve(module, node.name, 'local');
283
+ if (resolved?.kind !== 'declaration') return false;
284
+ node = unwrapExpression(resolved.expression);
285
+ owner = resolved.module;
286
+ }
287
+ if (!__rspack_external__babel_types_6e8337dd.isArrayExpression(node) || active.has(node) || ++visits > 2048) return false;
288
+ active.add(node);
289
+ try {
290
+ return node.elements.every((element)=>null !== element && visitAdded(element, owner, kind, group));
291
+ } finally{
292
+ active.delete(node);
293
+ }
294
+ };
295
+ return visit(declaration?.init, graph.root, 'api') ? endpoints : void 0;
296
+ };
297
+ const operationContextFields = (property)=>{
298
+ const constructorCall = exactCall(property.value, [
299
+ 'createMicroVerticalOperationContext'
300
+ ], 1);
301
+ const input = objectLiteral(constructorCall?.arguments[0]);
302
+ return void 0 === input ? void 0 : propertyAssignments(input.properties);
303
+ };
304
+ const operationContextIdentity = (property)=>{
305
+ const fields = operationContextFields(property);
306
+ const method = stringLiteral(fields?.get('method')?.value);
307
+ const operationId = stringLiteral(fields?.get('operationId')?.value);
308
+ const routePath = stringLiteral(fields?.get('routePath')?.value);
309
+ if (fields?.size !== 3 || void 0 === method || void 0 === operationId || void 0 === routePath) return;
310
+ return {
311
+ method,
312
+ operationId,
313
+ routePath
314
+ };
315
+ };
316
+ const operationContextIsConstructed = (property, stem, propertyKey, operationPaths, endpoints)=>{
317
+ const identity = operationContextIdentity(property);
318
+ if (void 0 === identity) return false;
319
+ const { method, operationId, routePath } = identity;
320
+ if (!/^[A-Z]+$/u.test(method) || !/^\/(?!.*(?:^|\/)\.\.?\/)[^\s?#]*$/u.test(routePath)) return false;
321
+ const apiName = `${pascalCaseStem(stem)}Api`;
322
+ if ('readiness' === propertyKey && ('GET' !== method || routePath !== `/${stem}/readiness`)) return false;
323
+ return operationId === `${apiName}:${routePath}` || operationPaths[operationId] === routePath || endpoints.some((endpoint)=>endpoint.name === propertyKey && endpoint.method === method && endpoint.routePath === routePath && (operationId === `${apiName}:${endpoint.group}:${propertyKey}` || 'readiness' === propertyKey && operationId === `${apiName}:${camelCaseStem(stem)}:readiness`));
324
+ };
325
+ const operationMapIsConnected = (declaration, stem, operationPaths, endpoints)=>{
326
+ const map = objectLiteral(declaration?.init);
327
+ const properties = void 0 === map ? void 0 : propertyAssignments(map.properties);
328
+ return void 0 !== properties && properties.has('readiness') && [
329
+ ...properties
330
+ ].every(([key, property])=>operationContextIsConstructed(property, stem, key, operationPaths, endpoints));
331
+ };
332
+ const constAssertionObject = (declaration)=>{
333
+ const initializer = declaration?.init;
334
+ if (null == initializer || !__rspack_external__babel_types_6e8337dd.isTSAsExpression(initializer) || !__rspack_external__babel_types_6e8337dd.isTSTypeReference(initializer.typeAnnotation) || !__rspack_external__babel_types_6e8337dd.isIdentifier(initializer.typeAnnotation.typeName, {
335
+ name: 'const'
336
+ })) return;
337
+ return objectLiteral(initializer.expression);
338
+ };
339
+ const metadataIsExact = (declaration, expectation, endpoints)=>{
340
+ const object = constAssertionObject(declaration);
341
+ const fields = void 0 === object ? void 0 : propertyAssignments(object.properties);
342
+ const expectedFields = [
343
+ [
344
+ 'apiPrefix',
345
+ expectation.apiPrefix
346
+ ],
347
+ [
348
+ 'basePath',
349
+ expectation.basePath
350
+ ],
351
+ [
352
+ 'ownerId',
353
+ expectation.ownerId
354
+ ],
355
+ [
356
+ 'readinessPath',
357
+ expectation.readinessPath
358
+ ]
359
+ ];
360
+ if (!fields || !expectedFields.every(([field, value])=>stringLiteral(fields.get(field)?.value) === value)) return false;
361
+ const common = new Set(expectedFields.map(([field])=>field));
362
+ return [
363
+ ...fields
364
+ ].every(([field, property])=>{
365
+ if (common.has(field)) return true;
366
+ const value = stringLiteral(property.value);
367
+ if (void 0 === value) return false;
368
+ const explicit = expectation.additionalPaths[field];
369
+ if (void 0 !== explicit) return value === explicit;
370
+ if (!value.startsWith(`${expectation.apiPrefix}/`) || /[\s?#]/u.test(value) || value.split('/').some((segment)=>'.' === segment || '..' === segment)) return false;
371
+ return endpoints.some((endpoint)=>{
372
+ const route = `${expectation.apiPrefix}${endpoint.routePath}`;
373
+ return route === value || route.startsWith(`${value}/`);
374
+ });
375
+ });
376
+ };
377
+ const markerSchemaIsShared = (sourceFile, declaration)=>{
378
+ const schema = sharedSchemaObject(declaration, 'MicroVerticalBuildMarkerSchema', [
379
+ 'build',
380
+ 'buildMarker',
381
+ 'deployProfile',
382
+ 'packageName',
383
+ 'sourceRevision',
384
+ 'surface',
385
+ 'version'
386
+ ]);
387
+ if (void 0 === schema || schema.identity) return schema?.identity === true;
388
+ const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact(localConst(sourceFile, `${brand}Schema`), brand);
389
+ const validators = new Map([
390
+ [
391
+ 'appId',
392
+ (property)=>brandedField(property, 'AppId')
393
+ ],
394
+ [
395
+ 'unitId',
396
+ (property)=>brandedField(property, 'UnitId')
397
+ ],
398
+ [
399
+ 'kind',
400
+ (property)=>'microvertical-delivery-unit' === stringLiteral(exactCall(property.value, [
401
+ 'Schema',
402
+ 'Literal'
403
+ ], 1)?.arguments[0])
404
+ ],
405
+ [
406
+ 'schemaVersion',
407
+ (property)=>1 === numericLiteral(exactCall(property.value, [
408
+ 'Schema',
409
+ 'Literal'
410
+ ], 1)?.arguments[0])
411
+ ]
412
+ ]);
413
+ return [
414
+ ...schema.assignments
415
+ ].every(([field, property])=>validators.get(field)?.(property) === true);
416
+ };
417
+ const readinessSchemaIsShared = (declaration, markerSchemaName, ownerMarkerIsIdentity)=>{
418
+ const schema = sharedSchemaObject(declaration, 'MicroVerticalReadinessSchema', [
419
+ 'checks',
420
+ 'status',
421
+ 'versionSkew'
422
+ ]);
423
+ return void 0 !== schema && (schema.identity && ownerMarkerIsIdentity || 1 === schema.assignments.size && identifierName(schema.assignments.get('marker')?.value) === markerSchemaName);
424
+ };
425
+ const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName(unwrapExpression(declaration.init)) === identifier;
426
+ const validateParsedContract = (graph, stem, expectation)=>{
427
+ const sourceFile = graph.root.file;
428
+ const exportStem = camelCaseStem(stem);
429
+ const foundationName = `${exportStem}FoundationApi`;
430
+ const markerSchemaName = `${exportStem}MarkerSchema`;
431
+ const readinessSchemaName = `${exportStem}ReadinessSchema`;
432
+ const markerDeclaration = exportedConst(sourceFile, markerSchemaName);
433
+ if (!importsExactBindings(sourceFile, expectation.effectClientPackage, [
434
+ 'HttpApi',
435
+ 'HttpApiEndpoint',
436
+ 'HttpApiGroup',
437
+ 'Schema'
438
+ ])) return 'MicroVertical root contract must import exact Effect API primitives from the framework client package';
439
+ if (!importsSharedBaselinePrimitives(sourceFile, expectation.baselinePackage)) return 'MicroVertical root contract must import exact baseline primitives from the framework baseline package';
440
+ if (!markerSchemaIsShared(sourceFile, markerDeclaration)) return 'MicroVertical root contract must consume the shared build marker schema without overriding shared fields';
441
+ if (!readinessSchemaIsShared(exportedConst(sourceFile, readinessSchemaName), markerSchemaName, declarationIsIdentifier(markerDeclaration, 'MicroVerticalBuildMarkerSchema'))) return 'MicroVertical readiness schema must consume the shared readiness schema without overriding shared fields';
442
+ const foundation = foundationGroup(graph, exportedConst(sourceFile, foundationName), stem, readinessSchemaName);
443
+ if (void 0 === foundation) return 'MicroVertical readiness foundation API must directly compose its exact readiness endpoint and foundation identity';
444
+ if (!rootComposesFoundation(graph, exportedConst(sourceFile, `${exportStem}Api`), stem, foundationName, foundation)) return 'MicroVertical root API must explicitly compose its readiness foundation API';
445
+ const endpoints = reachableEndpoints(graph, exportedConst(sourceFile, `${exportStem}Api`));
446
+ if (!endpoints) return 'MicroVertical root API must compose bounded native endpoint declarations without ambiguous identities';
447
+ if (!operationMapIsConnected(exportedConst(sourceFile, `${exportStem}OperationContexts`), stem, expectation.operationPaths ?? {}, endpoints)) return 'MicroVertical operation map must construct every operation with the shared context constructor';
448
+ if (!metadataIsExact(exportedConst(sourceFile, `${exportStem}ApiContract`), expectation, endpoints)) return 'MicroVertical root contract must keep exact owner and API path metadata without forbidden fields';
449
+ };
450
+ const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
451
+ const topologyVertical = verticals.find((vertical)=>(vertical.path ?? `verticals/${vertical.id}`) === verticalPath);
452
+ const endpoint = topologyVertical?.api?.readiness?.endpoint;
453
+ return endpoint?.match(/^\/([a-z0-9]+(?:-[a-z0-9]+)*)\/readiness$/u)?.[1];
454
+ };
455
+ const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
456
+ try {
457
+ const graph = createModuleGraph(filePath);
458
+ if (!baselinePublicIdentityIsExact(filePath, expectation)) return 'MicroVertical baseline imports must resolve the exact framework owner public export and schema identity';
459
+ return validateParsedContract(graph, stem, expectation);
460
+ } catch (error) {
461
+ if (error instanceof SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
462
+ throw error;
463
+ }
464
+ };
465
+ export { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation };