@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.23 → 3.9.0-ultramodern.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/microvertical-api-check.cjs +6 -6
- package/dist/cjs/microvertical-api-baseline.cjs +7 -1
- package/dist/cjs/microvertical-api-boundary.cjs +21 -21
- package/dist/cjs/module-graph.cjs +1588 -89
- package/dist/cjs/source-analysis.cjs +6 -2
- package/dist/esm/cli/microvertical-api-check.js +6 -6
- package/dist/esm/microvertical-api-baseline.js +7 -1
- package/dist/esm/microvertical-api-boundary.js +21 -21
- package/dist/esm/module-graph.js +1590 -88
- package/dist/esm/source-analysis.js +6 -2
- package/dist/esm-node/cli/microvertical-api-check.js +6 -6
- package/dist/esm-node/microvertical-api-baseline.js +7 -1
- package/dist/esm-node/microvertical-api-boundary.js +21 -21
- package/dist/esm-node/module-graph.js +1590 -88
- package/dist/esm-node/source-analysis.js +6 -2
- package/dist/types/microvertical-api-boundary.d.ts +11 -11
- package/dist/types/module-graph.d.ts +50 -10
- package/dist/types/source-analysis.d.ts +5 -2
- package/package.json +1 -1
|
@@ -48,9 +48,9 @@ const flags = [
|
|
|
48
48
|
'--baseline-package-directory',
|
|
49
49
|
'--rules'
|
|
50
50
|
];
|
|
51
|
-
async function
|
|
51
|
+
async function loadSourceRules(file) {
|
|
52
52
|
const rules = (await import((0, external_node_url_namespaceObject.pathToFileURL)(external_node_path_default().resolve(file)).href)).default;
|
|
53
|
-
if (!Array.isArray(rules) || !rules.every((rule)=>'function' == typeof rule)) throw new Error(`${file}: default export must be an array of
|
|
53
|
+
if (!Array.isArray(rules) || !rules.every((rule)=>'function' == typeof rule)) throw new Error(`${file}: default export must be an array of source rule functions, e.g. \`export default [myRule]\``);
|
|
54
54
|
return rules;
|
|
55
55
|
}
|
|
56
56
|
async function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOnly = false) {
|
|
@@ -60,7 +60,7 @@ async function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOn
|
|
|
60
60
|
for(let index = 0; index < args.length; index += 1){
|
|
61
61
|
const argument = args[index];
|
|
62
62
|
if ('--help' === argument || '-h' === argument) {
|
|
63
|
-
console.log(`${filesOnly ? 'modern-api-check-files' : 'modern-api-check'} [--workspace-root <path>] [--baseline-package-directory <path>] [--rules <module>]...\n${filesOnly ? 'Checks consumer files, contracts, package exports and owner identity. Does not analyze runtime topology; run the strict Effect source phase separately.' : 'Checks consumer files, contracts, package exports, owner identity and runtime topology once per API entry.'}\n--rules loads a module whose default export is an array of
|
|
63
|
+
console.log(`${filesOnly ? 'modern-api-check-files' : 'modern-api-check'} [--workspace-root <path>] [--baseline-package-directory <path>] [--rules <module>]...\n${filesOnly ? 'Checks consumer files, contracts, package exports and owner identity. Does not analyze runtime topology; run the strict Effect source phase separately.' : 'Checks consumer files, contracts, package exports, owner identity and runtime topology once per API entry.'}\n--rules loads a module whose default export is an array of source rules; each rule runs once per workspace source file with the shared module graph.\nWorkspace defaults to ULTRAMODERN_WORKSPACE_ROOT then cwd. Exit codes: 0 valid, 1 consumer violation, 2 tool/configuration failure.`);
|
|
64
64
|
return 0;
|
|
65
65
|
}
|
|
66
66
|
if (!flags.includes(argument ?? '') || !args[index + 1] || args[index + 1]?.startsWith('--')) {
|
|
@@ -72,9 +72,9 @@ async function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOn
|
|
|
72
72
|
else if ('--rules' === argument) ruleFiles.push(value);
|
|
73
73
|
else baselinePackageDirectory = value;
|
|
74
74
|
}
|
|
75
|
-
const
|
|
75
|
+
const sourceRules = [];
|
|
76
76
|
for (const file of ruleFiles)try {
|
|
77
|
-
|
|
77
|
+
sourceRules.push(...await loadSourceRules(file));
|
|
78
78
|
} catch (error) {
|
|
79
79
|
console.error(`API tool error: --rules ${error instanceof Error ? error.message : String(error)}`);
|
|
80
80
|
return 2;
|
|
@@ -82,7 +82,7 @@ async function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOn
|
|
|
82
82
|
const result = (filesOnly ? external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiConsumerFiles : external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiBoundaries)({
|
|
83
83
|
workspaceRoot,
|
|
84
84
|
baselinePackageDirectory,
|
|
85
|
-
|
|
85
|
+
sourceRules
|
|
86
86
|
});
|
|
87
87
|
for (const diagnostic of result.diagnostics)console.error(`API violation: ${diagnostic}`);
|
|
88
88
|
for (const error of result.toolErrors)console.error(`API tool error: ${error}`);
|
|
@@ -486,7 +486,13 @@ const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
|
|
|
486
486
|
};
|
|
487
487
|
const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
|
|
488
488
|
try {
|
|
489
|
-
const
|
|
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})`;
|
|
490
496
|
if (!(0, external_microvertical_api_owner_cjs_namespaceObject.baselinePublicIdentityIsExact)(filePath, expectation)) return 'MicroVertical baseline imports must resolve the exact framework owner public export and schema identity';
|
|
491
497
|
return validateParsedContract(graph, stem, expectation);
|
|
492
498
|
} catch (error) {
|
|
@@ -455,27 +455,6 @@ function check(options, topology) {
|
|
|
455
455
|
const violation = (0, external_microvertical_api_baseline_cjs_namespaceObject.microVerticalApiBaselineViolation)(stem, absolute(contract), expectation);
|
|
456
456
|
if (violation) diagnostics.push(`${contract}: ${violation}`);
|
|
457
457
|
}
|
|
458
|
-
if (options.contractRules?.length && exists(contract)) {
|
|
459
|
-
let graph;
|
|
460
|
-
try {
|
|
461
|
-
graph = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)(absolute(contract));
|
|
462
|
-
} catch (error) {
|
|
463
|
-
if (!(error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError)) throw error;
|
|
464
|
-
diagnostics.push(`${contract}: contract rules need a parseable contract with immutable bindings (${error.message})`);
|
|
465
|
-
}
|
|
466
|
-
if (graph) {
|
|
467
|
-
const context = {
|
|
468
|
-
appPath,
|
|
469
|
-
protocol: rpc ? 'rpc' : 'rest',
|
|
470
|
-
graph
|
|
471
|
-
};
|
|
472
|
-
for (const rule of options.contractRules)guarded(`${contract} (rule ${rule.name || 'anonymous'})`, ()=>{
|
|
473
|
-
const messages = rule(context);
|
|
474
|
-
if (!Array.isArray(messages) || !messages.every((message)=>'string' == typeof message)) throw new Error('contract rule must return an array of violation messages (return [] when the contract passes)');
|
|
475
|
-
for (const message of messages)diagnostics.push(`${contract}: ${message}`);
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
458
|
if (client) {
|
|
480
459
|
const relativeContract = external_node_path_default().posix.relative(external_node_path_default().posix.dirname(client), contract);
|
|
481
460
|
moduleShape(client, [
|
|
@@ -535,6 +514,27 @@ function check(options, topology) {
|
|
|
535
514
|
]
|
|
536
515
|
]);
|
|
537
516
|
});
|
|
517
|
+
const sourceRules = options.sourceRules ?? [];
|
|
518
|
+
const graph = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)();
|
|
519
|
+
for (const file of sourceRules.length ? sourceFiles : [])if (/\.[cm]?[jt]sx?$/u.test(file)) guarded(file, ()=>{
|
|
520
|
+
let module;
|
|
521
|
+
try {
|
|
522
|
+
module = graph.module(absolute(file));
|
|
523
|
+
} catch (error) {
|
|
524
|
+
if (!(error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError)) throw error;
|
|
525
|
+
diagnostics.push(`${file}: source rules need parseable source (${error.message})`);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
for (const rule of sourceRules){
|
|
529
|
+
const messages = rule({
|
|
530
|
+
file,
|
|
531
|
+
module,
|
|
532
|
+
graph
|
|
533
|
+
});
|
|
534
|
+
if (!Array.isArray(messages) || !messages.every((message)=>'string' == typeof message)) throw new Error(`rule ${rule.name || 'anonymous'} must return an array of violation messages (return [] when the file passes)`);
|
|
535
|
+
for (const message of messages)diagnostics.push(`${file}: ${message}`);
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
538
|
const shell = 'apps/shell-super-app';
|
|
539
539
|
const verticals = apps.filter((app)=>app.path.startsWith('verticals/') && apiApp(app));
|
|
540
540
|
if (exists(shell) && verticals.length) {
|