@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.17 → 3.9.0-ultramodern.18

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.
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { runMicroVerticalApiCheckCli } from '../dist/esm-node/cli/microvertical-api-check.js';
3
3
 
4
- process.exitCode = runMicroVerticalApiCheckCli(process.argv.slice(2), true);
4
+ process.exitCode = await runMicroVerticalApiCheckCli(
5
+ process.argv.slice(2),
6
+ true,
7
+ );
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
  import { runMicroVerticalApiCheckCli } from '../dist/esm-node/cli/microvertical-api-check.js';
3
3
 
4
- process.exitCode = runMicroVerticalApiCheckCli();
4
+ process.exitCode = await runMicroVerticalApiCheckCli();
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runWorkspaceSourceCheckCli } from '../dist/esm-node/cli/workspace-source-check.js';
3
+
4
+ process.exitCode = runWorkspaceSourceCheckCli();
@@ -1,5 +1,14 @@
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
+ })();
3
12
  (()=>{
4
13
  __webpack_require__.d = (exports1, getters, values)=>{
5
14
  var define = (defs, kind)=>{
@@ -30,30 +39,50 @@ __webpack_require__.r(__webpack_exports__);
30
39
  __webpack_require__.d(__webpack_exports__, {
31
40
  runMicroVerticalApiCheckCli: ()=>runMicroVerticalApiCheckCli
32
41
  });
42
+ const external_node_path_namespaceObject = require("node:path");
43
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
44
+ const external_node_url_namespaceObject = require("node:url");
33
45
  const external_microvertical_api_boundary_cjs_namespaceObject = require("../microvertical-api-boundary.cjs");
34
- function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOnly = false) {
46
+ const flags = [
47
+ '--workspace-root',
48
+ '--baseline-package-directory',
49
+ '--rules'
50
+ ];
51
+ async function loadContractRules(file) {
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 contract rule functions, e.g. \`export default [myRule]\``);
54
+ return rules;
55
+ }
56
+ async function runMicroVerticalApiCheckCli(args = process.argv.slice(2), filesOnly = false) {
35
57
  let workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd();
36
58
  let baselinePackageDirectory;
59
+ const ruleFiles = [];
37
60
  for(let index = 0; index < args.length; index += 1){
38
61
  const argument = args[index];
39
62
  if ('--help' === argument || '-h' === argument) {
40
- console.log(`${filesOnly ? 'modern-api-check-files' : 'modern-api-check'} [--workspace-root <path>] [--baseline-package-directory <path>]\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.'}\nWorkspace defaults to ULTRAMODERN_WORKSPACE_ROOT then cwd. Exit codes: 0 valid, 1 consumer violation, 2 tool/configuration failure.`);
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 contract rules; each rule receives the module graph of every API contract.\nWorkspace defaults to ULTRAMODERN_WORKSPACE_ROOT then cwd. Exit codes: 0 valid, 1 consumer violation, 2 tool/configuration failure.`);
41
64
  return 0;
42
65
  }
43
- if (![
44
- '--workspace-root',
45
- '--baseline-package-directory'
46
- ].includes(argument ?? '') || !args[index + 1] || args[index + 1]?.startsWith('--')) {
66
+ if (!flags.includes(argument ?? '') || !args[index + 1] || args[index + 1]?.startsWith('--')) {
47
67
  console.error(`Invalid argument: ${argument ?? ''}. Use --help.`);
48
68
  return 2;
49
69
  }
50
70
  const value = args[++index];
51
71
  if ('--workspace-root' === argument) workspaceRoot = value;
72
+ else if ('--rules' === argument) ruleFiles.push(value);
52
73
  else baselinePackageDirectory = value;
53
74
  }
75
+ const contractRules = [];
76
+ for (const file of ruleFiles)try {
77
+ contractRules.push(...await loadContractRules(file));
78
+ } catch (error) {
79
+ console.error(`API tool error: --rules ${error instanceof Error ? error.message : String(error)}`);
80
+ return 2;
81
+ }
54
82
  const result = (filesOnly ? external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiConsumerFiles : external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiBoundaries)({
55
83
  workspaceRoot,
56
- baselinePackageDirectory
84
+ baselinePackageDirectory,
85
+ contractRules
57
86
  });
58
87
  for (const diagnostic of result.diagnostics)console.error(`API violation: ${diagnostic}`);
59
88
  for (const error of result.toolErrors)console.error(`API tool error: ${error}`);
@@ -37,8 +37,8 @@ var __webpack_require__ = {};
37
37
  var __webpack_exports__ = {};
38
38
  __webpack_require__.r(__webpack_exports__);
39
39
  __webpack_require__.d(__webpack_exports__, {
40
- main: ()=>main,
41
- runWorkspaceSourceCheck: ()=>runWorkspaceSourceCheck
40
+ runWorkspaceSourceCheck: ()=>runWorkspaceSourceCheck,
41
+ runWorkspaceSourceCheckCli: ()=>runWorkspaceSourceCheckCli
42
42
  });
43
43
  const external_node_fs_namespaceObject = require("node:fs");
44
44
  var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
@@ -50,6 +50,11 @@ const DEFAULT_LOCALES = [
50
50
  'en',
51
51
  'cs'
52
52
  ];
53
+ const DEFAULT_SOURCE_ROOTS = [
54
+ 'apps',
55
+ 'verticals',
56
+ 'packages'
57
+ ];
53
58
  const ignoredDirectories = new Set([
54
59
  '.modern',
55
60
  '.modernjs',
@@ -83,6 +88,8 @@ const createLocaleJsonMatcher = (locales)=>{
83
88
  const resolvePluralCategories = (locale, overrides)=>overrides?.[locale] ?? new Intl.PluralRules(locale).resolvedOptions().pluralCategories;
84
89
  const readText = (filePath)=>external_node_fs_default().readFileSync(filePath, 'utf-8');
85
90
  const localeImportPattern = (locale)=>new RegExp(`import\\s+(?:\\*\\s+as\\s+)?[A-Za-z_$][\\w$]*\\s+from\\s+['"]\\.\\./locales/${escapeRegExp(locale)}/[^'"]+\\.json['"]`, 'u');
91
+ class SourceViolation extends Error {
92
+ }
86
93
  const checkRuntimeResources = (root, filePath, text, locales)=>{
87
94
  const relative = relativePath(root, filePath);
88
95
  if (!relative.endsWith('/src/modern.runtime.ts')) return;
@@ -90,7 +97,7 @@ const checkRuntimeResources = (root, filePath, text, locales)=>{
90
97
  const registersResources = /initOptions\s*:\s*\{[\s\S]*?\bresources\s*[,:}]/u.test(text);
91
98
  if (missingLocales.length > 0 || !registersResources) {
92
99
  const detail = missingLocales.length > 0 ? `missing locale JSON imports for: ${missingLocales.join(', ')}` : 'initOptions does not register a `resources` entry';
93
- throw new Error(`${relative} must register locale JSON resources in modern.runtime.ts so Worker SSR and hydration use the same first-render translations (${detail}).`);
100
+ throw new SourceViolation(`${relative} must register locale JSON resources in modern.runtime.ts so Worker SSR and hydration use the same first-render translations (${detail}).`);
94
101
  }
95
102
  };
96
103
  const visitLocaleKeys = (value, visitor, pathParts = [])=>{
@@ -110,7 +117,7 @@ const checkPluralResources = (root, filePath, json, requiredSuffixes, pluralSuff
110
117
  visitLocaleKeys(json, (key, value, pathParts)=>{
111
118
  if ('string' != typeof value || !value.includes('{{count}}')) return;
112
119
  const suffixMatch = key.match(pluralSuffixPattern);
113
- if (!suffixMatch) throw new Error(`${relative} key ${pathParts.join('.')} contains {{count}} but is not plural-suffixed.`);
120
+ if (!suffixMatch) throw new SourceViolation(`${relative} key ${pathParts.join('.')} contains {{count}} but is not plural-suffixed.`);
114
121
  const [, base = '', suffix = ''] = suffixMatch;
115
122
  const parentPath = pathParts.slice(0, -1).join('.');
116
123
  const groupKey = `${parentPath}.${base}`;
@@ -118,7 +125,7 @@ const checkPluralResources = (root, filePath, json, requiredSuffixes, pluralSuff
118
125
  existing.add(suffix);
119
126
  groups.set(groupKey, existing);
120
127
  });
121
- for (const [group, suffixes] of groups)for (const suffix of requiredSuffixes)if (!suffixes.has(suffix)) throw new Error(`${relative} plural group ${group} is missing _${suffix}.`);
128
+ for (const [group, suffixes] of groups)for (const suffix of requiredSuffixes)if (!suffixes.has(suffix)) throw new SourceViolation(`${relative} plural group ${group} is missing _${suffix}.`);
122
129
  };
123
130
  const runRuntimeAndLocaleResourceChecks = (root, sourceRoots, locales, pluralCategories)=>{
124
131
  if (0 === locales.length) return;
@@ -140,11 +147,7 @@ const runRuntimeAndLocaleResourceChecks = (root, sourceRoots, locales, pluralCat
140
147
  checkPluralResources(root, filePath, JSON.parse(readText(filePath)), localeCategories.get(language) ?? [], pluralSuffixPattern);
141
148
  }
142
149
  };
143
- const runWorkspaceSourceCheck = ({ cwd = process.cwd(), sourceRoots = [
144
- 'apps',
145
- 'verticals',
146
- 'packages'
147
- ], locales = DEFAULT_LOCALES, pluralCategories } = {})=>{
150
+ const runWorkspaceSourceCheck = ({ cwd = process.cwd(), sourceRoots = DEFAULT_SOURCE_ROOTS, locales = DEFAULT_LOCALES, pluralCategories } = {})=>{
148
151
  const oxlintResult = (0, external_oxlint_cjs_namespaceObject.runOxlintRules)({
149
152
  cwd,
150
153
  targets: sourceRoots,
@@ -177,20 +180,90 @@ const runWorkspaceSourceCheck = ({ cwd = process.cwd(), sourceRoots = [
177
180
  try {
178
181
  runRuntimeAndLocaleResourceChecks(cwd, sourceRoots, locales, pluralCategories);
179
182
  } catch (error) {
180
- console.error(error instanceof Error ? error.message : 'UltraModern workspace source checks failed.');
181
- return 1;
183
+ console.error(error instanceof Error ? error.message : String(error));
184
+ return error instanceof SourceViolation ? 1 : 2;
182
185
  }
183
186
  console.log(WORKSPACE_SOURCE_SUCCESS);
184
187
  return 0;
185
188
  };
186
- const main = ()=>{
187
- process.exitCode = runWorkspaceSourceCheck();
189
+ const USAGE = `modern-i18n-check [--workspace-root <path>]
190
+ Runs the UltraModern i18n and boundary source checks for a workspace.
191
+ Workspace defaults to ULTRAMODERN_WORKSPACE_ROOT then cwd. Options come from
192
+ package.json "modernjs.i18nCheck": { sourceRoots, locales, pluralCategories }.
193
+ Exit codes: 0 valid, 1 source violation, 2 tool/configuration failure.`;
194
+ const isStringArray = (value)=>Array.isArray(value) && value.every((entry)=>'string' == typeof entry && entry.length > 0);
195
+ const isLocaleArray = (value)=>{
196
+ if (!isStringArray(value)) return false;
197
+ try {
198
+ Intl.getCanonicalLocales(value);
199
+ return true;
200
+ } catch {
201
+ return false;
202
+ }
203
+ };
204
+ const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
205
+ const isWorkspaceDirectory = (root, entry)=>{
206
+ if (external_node_path_default().isAbsolute(entry)) return false;
207
+ const target = external_node_path_default().resolve(root, entry);
208
+ if (!external_node_fs_default().existsSync(target) || !external_node_fs_default().statSync(target).isDirectory()) return false;
209
+ const relative = external_node_path_default().relative(external_node_fs_default().realpathSync(root), external_node_fs_default().realpathSync(target));
210
+ return '' !== relative && '..' !== relative && !relative.startsWith(`..${external_node_path_default().sep}`) && !external_node_path_default().isAbsolute(relative);
211
+ };
212
+ const CLDR_PLURAL_CATEGORIES = new Set([
213
+ 'zero',
214
+ 'one',
215
+ 'two',
216
+ 'few',
217
+ 'many',
218
+ 'other'
219
+ ]);
220
+ const isPluralCategories = (value)=>isRecord(value) && Object.values(value).every((categories)=>isStringArray(categories) && categories.includes('other') && categories.every((category)=>CLDR_PLURAL_CATEGORIES.has(category)));
221
+ const readWorkspaceCheckOptions = (root)=>{
222
+ const manifestPath = external_node_path_default().join(root, 'package.json');
223
+ const modernjs = JSON.parse(readText(manifestPath)).modernjs;
224
+ const config = isRecord(modernjs) && Object.hasOwn(modernjs, 'i18nCheck') ? modernjs.i18nCheck : {};
225
+ const invalid = (field, expected)=>new Error(`${manifestPath} "modernjs.i18nCheck${field}" must be ${expected}.`);
226
+ if (!isRecord(config)) throw invalid('', 'an object');
227
+ const { locales, pluralCategories } = config;
228
+ if (void 0 !== locales && !isLocaleArray(locales)) throw invalid('.locales', 'an array of BCP 47 locale codes');
229
+ if (void 0 !== pluralCategories && !isPluralCategories(pluralCategories)) throw invalid('.pluralCategories', 'an object of locale -> CLDR plural categories including "other"');
230
+ const sourceRoots = Object.hasOwn(config, 'sourceRoots') ? config.sourceRoots : DEFAULT_SOURCE_ROOTS.filter((entry)=>isWorkspaceDirectory(root, entry));
231
+ if (!isStringArray(sourceRoots) || 0 === sourceRoots.length || !sourceRoots.every((entry)=>isWorkspaceDirectory(root, entry))) throw invalid('.sourceRoots', `a non-empty array of existing workspace-relative directories (default: whichever of ${DEFAULT_SOURCE_ROOTS.join(', ')} exist)`);
232
+ return {
233
+ cwd: root,
234
+ sourceRoots,
235
+ locales,
236
+ pluralCategories
237
+ };
238
+ };
239
+ const runWorkspaceSourceCheckCli = (args = process.argv.slice(2))=>{
240
+ let workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd();
241
+ for(let index = 0; index < args.length; index += 1){
242
+ const argument = args[index];
243
+ if ('--help' === argument || '-h' === argument) {
244
+ console.log(USAGE);
245
+ return 0;
246
+ }
247
+ const value = args[index + 1];
248
+ if ('--workspace-root' !== argument || !value || value.startsWith('--')) {
249
+ console.error(`Invalid argument: ${argument ?? ''}. Use --help.`);
250
+ return 2;
251
+ }
252
+ workspaceRoot = value;
253
+ index += 1;
254
+ }
255
+ try {
256
+ return runWorkspaceSourceCheck(readWorkspaceCheckOptions(external_node_path_default().resolve(workspaceRoot)));
257
+ } catch (error) {
258
+ console.error(error instanceof Error ? error.message : String(error));
259
+ return 2;
260
+ }
188
261
  };
189
- exports.main = __webpack_exports__.main;
190
262
  exports.runWorkspaceSourceCheck = __webpack_exports__.runWorkspaceSourceCheck;
263
+ exports.runWorkspaceSourceCheckCli = __webpack_exports__.runWorkspaceSourceCheckCli;
191
264
  for(var __rspack_i in __webpack_exports__)if (-1 === [
192
- "main",
193
- "runWorkspaceSourceCheck"
265
+ "runWorkspaceSourceCheck",
266
+ "runWorkspaceSourceCheckCli"
194
267
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
195
268
  Object.defineProperty(exports, '__esModule', {
196
269
  value: true
@@ -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)=>{
@@ -40,40 +31,16 @@ __webpack_require__.d(__webpack_exports__, {
40
31
  configuredMicroVerticalApiStem: ()=>configuredMicroVerticalApiStem,
41
32
  microVerticalApiBaselineViolation: ()=>microVerticalApiBaselineViolation
42
33
  });
43
- const external_node_fs_namespaceObject = require("node:fs");
44
- var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
45
- const external_node_module_namespaceObject = require("node:module");
46
- const external_node_path_namespaceObject = require("node:path");
47
- var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
48
34
  const types_namespaceObject = require("@babel/types");
49
- const external_resolve_exports_namespaceObject = require("resolve.exports");
50
35
  const external_microvertical_api_owner_cjs_namespaceObject = require("./microvertical-api-owner.cjs");
36
+ const external_module_graph_cjs_namespaceObject = require("./module-graph.cjs");
51
37
  const external_source_analysis_cjs_namespaceObject = require("./source-analysis.cjs");
52
- function parseConsumer(filePath) {
53
- if (external_node_fs_default().statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
54
- const file = (0, external_source_analysis_cjs_namespaceObject.parseSource)(external_node_fs_default().readFileSync(filePath, 'utf8'), filePath);
55
- (0, external_source_analysis_cjs_namespaceObject.traverseSource)(file, {
56
- AssignmentExpression (p) {
57
- throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
58
- },
59
- UpdateExpression (p) {
60
- throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
61
- },
62
- TSModuleDeclaration () {
63
- throw new external_source_analysis_cjs_namespaceObject.SourceSyntaxError('contract bindings must not be merged with namespaces');
64
- }
65
- });
66
- return file;
67
- }
68
38
  const camelCaseStem = (stem)=>stem.replaceAll(/-([a-z0-9])/gu, (_match, letter)=>letter.toUpperCase());
69
39
  const pascalCaseStem = (stem)=>{
70
40
  const camelStem = camelCaseStem(stem);
71
41
  return `${camelStem.slice(0, 1).toUpperCase()}${camelStem.slice(1)}`;
72
42
  };
73
43
  const identifierName = (node)=>void 0 !== node && types_namespaceObject.isIdentifier(node) ? node.name : void 0;
74
- const propertyName = (node)=>{
75
- 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);
76
- };
77
44
  const accessPath = (node)=>{
78
45
  if (types_namespaceObject.isIdentifier(node)) return [
79
46
  node.name
@@ -102,201 +69,6 @@ const callExpression = (expression, callee)=>{
102
69
  const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
103
70
  return types_namespaceObject.isCallExpression(unwrapped) && isAccessPath(unwrapped.callee, callee) ? unwrapped : void 0;
104
71
  };
105
- const localConst = (sourceFile, name)=>{
106
- for (const item of sourceFile.program.body){
107
- const statement = types_namespaceObject.isExportNamedDeclaration(item) ? item.declaration : item;
108
- if (!types_namespaceObject.isVariableDeclaration(statement) || 'const' !== statement.kind) continue;
109
- const matches = statement.declarations.filter((declaration)=>types_namespaceObject.isIdentifier(declaration.id, {
110
- name
111
- }));
112
- if (1 === matches.length) return matches[0];
113
- }
114
- };
115
- const exportedConst = (sourceFile, name)=>{
116
- for (const statement of sourceFile.program.body)if (types_namespaceObject.isExportNamedDeclaration(statement) && 'type' !== statement.exportKind) {
117
- if (types_namespaceObject.isVariableDeclaration(statement.declaration) && 'const' === statement.declaration.kind) {
118
- const declaration = statement.declaration.declarations.find((value)=>types_namespaceObject.isIdentifier(value.id, {
119
- name
120
- }));
121
- if (declaration) return declaration;
122
- }
123
- if (!statement.source && statement.specifiers.some((value)=>types_namespaceObject.isExportSpecifier(value) && 'type' !== value.exportKind && types_namespaceObject.isIdentifier(value.local, {
124
- name
125
- }) && types_namespaceObject.isIdentifier(value.exported, {
126
- name
127
- }))) return localConst(sourceFile, name);
128
- }
129
- };
130
- const inside = (file, boundary)=>file === boundary || file.startsWith(`${boundary}${external_node_path_default().sep}`);
131
- const containingWorkspace = (file)=>{
132
- for(let directory = external_node_path_default().dirname(file);; directory = external_node_path_default().dirname(directory)){
133
- if (external_node_fs_default().existsSync(external_node_path_default().join(directory, 'pnpm-workspace.yaml'))) return external_node_fs_default().realpathSync(directory);
134
- if (directory === external_node_path_default().dirname(directory)) return;
135
- }
136
- };
137
- const sourceBoundary = (file, workspace)=>{
138
- for(let directory = external_node_path_default().dirname(file);; directory = external_node_path_default().dirname(directory)){
139
- if (external_node_fs_default().existsSync(external_node_path_default().join(directory, 'package.json')) && directory !== workspace) return external_node_fs_default().realpathSync(directory);
140
- if (directory === workspace || directory === external_node_path_default().dirname(directory)) return external_node_fs_default().realpathSync(external_node_path_default().dirname(file));
141
- }
142
- };
143
- const sourceFileAt = (target, boundary)=>{
144
- const stem = target.replace(/\.(?:[cm]?[jt]sx?)$/u, '');
145
- for (const candidate of [
146
- `${stem}.ts`,
147
- `${stem}.tsx`,
148
- `${stem}.mts`,
149
- `${stem}.cts`,
150
- target,
151
- external_node_path_default().join(target, 'index.ts'),
152
- external_node_path_default().join(target, 'index.tsx')
153
- ])try {
154
- const real = external_node_fs_default().realpathSync(candidate);
155
- if (inside(real, boundary) && external_node_fs_default().statSync(real).isFile()) return real;
156
- } catch {}
157
- };
158
- const packageEntry = (specifier)=>{
159
- if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) return;
160
- const parts = specifier.split('/');
161
- const count = specifier.startsWith('@') ? 2 : 1;
162
- if (parts.length < count || parts.slice(0, count).some((part)=>!part)) return;
163
- return {
164
- name: parts.slice(0, count).join('/'),
165
- exportKey: parts.length === count ? '.' : `./${parts.slice(count).join('/')}`
166
- };
167
- };
168
- const resolveModulePath = (module, specifier, workspace)=>{
169
- if (/^\.\.?\//u.test(specifier)) {
170
- const file = sourceFileAt(external_node_path_default().resolve(external_node_path_default().dirname(module.path), specifier), module.boundary);
171
- return void 0 === file ? void 0 : {
172
- path: file,
173
- boundary: module.boundary
174
- };
175
- }
176
- const entry = packageEntry(specifier);
177
- if (!entry || !workspace) return;
178
- const paths = (0, external_node_module_namespaceObject.createRequire)(module.path).resolve.paths(entry.name) ?? [];
179
- for (const lookup of paths){
180
- const directory = external_node_path_default().join(lookup, entry.name);
181
- const manifest = external_node_path_default().join(directory, 'package.json');
182
- if (!external_node_fs_default().existsSync(manifest)) continue;
183
- const boundary = external_node_fs_default().realpathSync(directory);
184
- if (!inside(boundary, workspace) || boundary.split(external_node_path_default().sep).includes('node_modules')) break;
185
- const pkg = JSON.parse(external_node_fs_default().readFileSync(manifest, 'utf8'));
186
- if (pkg.name !== entry.name || void 0 === pkg.exports) break;
187
- let target;
188
- try {
189
- const targets = (0, external_resolve_exports_namespaceObject.exports)(pkg, entry.exportKey, {
190
- conditions: [
191
- 'modern:source'
192
- ]
193
- });
194
- target = Array.isArray(targets) ? targets[0] : void 0;
195
- } catch {
196
- break;
197
- }
198
- if (!target || !target.startsWith('./')) break;
199
- const file = sourceFileAt(external_node_path_default().resolve(boundary, target), boundary);
200
- return void 0 === file ? void 0 : {
201
- path: file,
202
- boundary
203
- };
204
- }
205
- };
206
- const createModuleReader = (root)=>{
207
- const modules = new Map([
208
- [
209
- root.path,
210
- root
211
- ]
212
- ]);
213
- return (filePath, boundary)=>{
214
- if (modules.has(filePath)) return modules.get(filePath);
215
- if (modules.size >= 256) return;
216
- let module;
217
- try {
218
- module = {
219
- file: parseConsumer(filePath),
220
- path: filePath,
221
- boundary
222
- };
223
- } catch {
224
- module = void 0;
225
- }
226
- modules.set(filePath, module);
227
- return module;
228
- };
229
- };
230
- const importedBinding = (module, name)=>{
231
- for (const statement of module.file.program.body)if (types_namespaceObject.isImportDeclaration(statement) && 'type' !== statement.importKind) {
232
- for (const specifier of statement.specifiers)if (types_namespaceObject.isIdentifier(specifier.local, {
233
- name
234
- })) {
235
- if (types_namespaceObject.isImportSpecifier(specifier) && 'type' !== specifier.importKind) return {
236
- imported: propertyName(specifier.imported) ?? name,
237
- specifier: statement.source.value
238
- };
239
- if (types_namespaceObject.isImportDefaultSpecifier(specifier)) return {
240
- imported: 'default',
241
- specifier: statement.source.value
242
- };
243
- }
244
- }
245
- };
246
- const reexportedBinding = (module, name)=>{
247
- for (const statement of module.file.program.body){
248
- if (!types_namespaceObject.isExportNamedDeclaration(statement) || 'type' === statement.exportKind) continue;
249
- const specifier = statement.specifiers.find((value)=>types_namespaceObject.isExportSpecifier(value) && 'type' !== value.exportKind && propertyName(value.exported) === name);
250
- if (void 0 !== specifier && types_namespaceObject.isExportSpecifier(specifier)) return {
251
- local: types_namespaceObject.isIdentifier(specifier.local) ? specifier.local.name : specifier.local.value,
252
- ...statement.source ? {
253
- specifier: statement.source.value
254
- } : {}
255
- };
256
- }
257
- };
258
- const defaultExport = (module)=>{
259
- for (const statement of module.file.program.body){
260
- if (!types_namespaceObject.isExportDefaultDeclaration(statement)) continue;
261
- const declaration = statement.declaration;
262
- if (types_namespaceObject.isIdentifier(declaration)) return declaration.name;
263
- return types_namespaceObject.isExpression(declaration) ? declaration : void 0;
264
- }
265
- };
266
- const resolveBinding = (module, name, scope, readModule, workspace, seen)=>{
267
- const key = `${scope}:${module.path}#${name}`;
268
- if (seen.has(key) || seen.size >= 512) return;
269
- seen.add(key);
270
- const declaration = 'export' === scope ? exportedConst(module.file, name) : localConst(module.file, name);
271
- if (declaration?.init) return {
272
- expression: declaration.init,
273
- module
274
- };
275
- const throughModule = (specifier, imported)=>{
276
- const resolved = resolveModulePath(module, specifier, workspace);
277
- const target = resolved && readModule(resolved.path, resolved.boundary);
278
- return void 0 === target ? void 0 : resolveBinding(target, imported, 'export', readModule, workspace, seen);
279
- };
280
- if ('local' === scope) {
281
- const imported = importedBinding(module, name);
282
- return void 0 === imported ? void 0 : throughModule(imported.specifier, imported.imported);
283
- }
284
- if ('default' === name) {
285
- const exported = defaultExport(module);
286
- if ('string' == typeof exported) return resolveBinding(module, exported, 'local', readModule, workspace, seen);
287
- return void 0 === exported ? void 0 : {
288
- expression: exported,
289
- module
290
- };
291
- }
292
- const reexported = reexportedBinding(module, name);
293
- if (void 0 !== reexported) return void 0 === reexported.specifier ? resolveBinding(module, reexported.local, 'local', readModule, workspace, seen) : throughModule(reexported.specifier, reexported.local);
294
- for (const statement of module.file.program.body){
295
- if (!types_namespaceObject.isExportAllDeclaration(statement) || 'type' === statement.exportKind) continue;
296
- const resolved = throughModule(statement.source.value, name);
297
- if (void 0 !== resolved) return resolved;
298
- }
299
- };
300
72
  const objectLiteral = (expression)=>{
301
73
  if (null == expression) return;
302
74
  const unwrapped = (0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(expression);
@@ -306,7 +78,7 @@ const propertyAssignments = (properties)=>{
306
78
  const assignments = new Map();
307
79
  for (const property of properties){
308
80
  if (!types_namespaceObject.isObjectProperty(property) || property.computed || property.shorthand) return;
309
- const name = propertyName(property.key);
81
+ const name = (0, external_module_graph_cjs_namespaceObject.propertyName)(property.key);
310
82
  if (void 0 === name || assignments.has(name)) return;
311
83
  assignments.set(name, property);
312
84
  }
@@ -424,9 +196,13 @@ const rootComposesFoundation = (sourceFile, declaration, stem, foundationName)=>
424
196
  return void 0 !== chain && isAccessPath(chain.base.callee, [
425
197
  'HttpApi',
426
198
  'make'
427
- ]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>1 === method.arguments.length && ('add' === method.name || 'addHttpApi' === method.name || index === chain.methods.length - 1 && 'pipe' === method.name && 'identity' === identifierName(method.arguments[0]) && importsExactBindings(sourceFile, 'effect', [
199
+ ]) && 1 === chain.base.arguments.length && stringLiteral(chain.base.arguments[0]) === `${pascalCaseStem(stem)}Api` && chain.methods.length > 0 && chain.methods.every((method, index)=>{
200
+ const combinatorArity = nonEndpointCombinators.api[method.name];
201
+ if (void 0 !== combinatorArity) return method.arguments.length === combinatorArity;
202
+ return 1 === method.arguments.length && ('add' === method.name || 'addHttpApi' === method.name || index === chain.methods.length - 1 && 'pipe' === method.name && 'identity' === identifierName(method.arguments[0]) && importsExactBindings(sourceFile, 'effect', [
428
203
  'identity'
429
- ]))) && first?.name === 'addHttpApi' && identifierName(first.arguments[0]) === foundationName;
204
+ ]));
205
+ }) && first?.name === 'addHttpApi' && identifierName(first.arguments[0]) === foundationName;
430
206
  };
431
207
  const nonEndpointCombinators = {
432
208
  api: {
@@ -442,9 +218,7 @@ const nonEndpointCombinators = {
442
218
  middleware: 1
443
219
  }
444
220
  };
445
- const reachableEndpoints = (rootModule, declaration)=>{
446
- const readModule = createModuleReader(rootModule);
447
- const workspace = containingWorkspace(rootModule.path);
221
+ const reachableEndpoints = (graph, declaration)=>{
448
222
  const active = new Set();
449
223
  const endpoints = [];
450
224
  const identities = new Set();
@@ -466,8 +240,8 @@ const reachableEndpoints = (rootModule, declaration)=>{
466
240
  active.add(node);
467
241
  try {
468
242
  if (types_namespaceObject.isIdentifier(node)) {
469
- const resolved = resolveBinding(module, node.name, 'local', readModule, workspace, new Set());
470
- return void 0 !== resolved && visit(resolved.expression, resolved.module, kind, group);
243
+ const resolved = graph.resolve(module, node.name, 'local');
244
+ return resolved?.kind === 'declaration' && visit(resolved.expression, resolved.module, kind, group);
471
245
  }
472
246
  if ('endpoint' === kind) {
473
247
  if (!types_namespaceObject.isCallExpression(node) || node.arguments.length < 2 || node.arguments.length > 3) return false;
@@ -522,7 +296,7 @@ const reachableEndpoints = (rootModule, declaration)=>{
522
296
  active.delete(node);
523
297
  }
524
298
  };
525
- return visit(declaration?.init, rootModule, 'api') ? endpoints : void 0;
299
+ return visit(declaration?.init, graph.root, 'api') ? endpoints : void 0;
526
300
  };
527
301
  const operationContextFields = (property)=>{
528
302
  const constructorCall = exactCall(property.value, [
@@ -615,7 +389,7 @@ const markerSchemaIsShared = (sourceFile, declaration)=>{
615
389
  'version'
616
390
  ]);
617
391
  if (void 0 === schema || schema.identity) return schema?.identity === true;
618
- const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact(localConst(sourceFile, `${brand}Schema`), brand);
392
+ const brandedField = (property, brand)=>identifierName(property.value) === `${brand}Schema` && brandedStringSchemaIsExact((0, external_module_graph_cjs_namespaceObject.localConst)(sourceFile, `${brand}Schema`), brand);
619
393
  const validators = new Map([
620
394
  [
621
395
  'appId',
@@ -653,13 +427,13 @@ const readinessSchemaIsShared = (declaration, markerSchemaName, ownerMarkerIsIde
653
427
  return void 0 !== schema && (schema.identity && ownerMarkerIsIdentity || 1 === schema.assignments.size && identifierName(schema.assignments.get('marker')?.value) === markerSchemaName);
654
428
  };
655
429
  const declarationIsIdentifier = (declaration, identifier)=>declaration?.init != null && identifierName((0, external_source_analysis_cjs_namespaceObject.unwrapExpression)(declaration.init)) === identifier;
656
- const validateParsedContract = (module, stem, expectation)=>{
657
- const sourceFile = module.file;
430
+ const validateParsedContract = (graph, stem, expectation)=>{
431
+ const sourceFile = graph.root.file;
658
432
  const exportStem = camelCaseStem(stem);
659
433
  const foundationName = `${exportStem}FoundationApi`;
660
434
  const markerSchemaName = `${exportStem}MarkerSchema`;
661
435
  const readinessSchemaName = `${exportStem}ReadinessSchema`;
662
- const markerDeclaration = exportedConst(sourceFile, markerSchemaName);
436
+ const markerDeclaration = (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, markerSchemaName);
663
437
  if (!importsExactBindings(sourceFile, expectation.effectClientPackage, [
664
438
  'HttpApi',
665
439
  'HttpApiEndpoint',
@@ -668,13 +442,13 @@ const validateParsedContract = (module, stem, expectation)=>{
668
442
  ])) return 'MicroVertical root contract must import exact Effect API primitives from the framework client package';
669
443
  if (!importsSharedBaselinePrimitives(sourceFile, expectation.baselinePackage)) return 'MicroVertical root contract must import exact baseline primitives from the framework baseline package';
670
444
  if (!markerSchemaIsShared(sourceFile, markerDeclaration)) return 'MicroVertical root contract must consume the shared build marker schema without overriding shared fields';
671
- if (!readinessSchemaIsShared(exportedConst(sourceFile, readinessSchemaName), markerSchemaName, declarationIsIdentifier(markerDeclaration, 'MicroVerticalBuildMarkerSchema'))) return 'MicroVertical readiness schema must consume the shared readiness schema without overriding shared fields';
672
- if (!foundationIsExact(exportedConst(sourceFile, foundationName), stem, readinessSchemaName)) return 'MicroVertical readiness foundation API must directly compose its exact readiness endpoint and foundation identity';
673
- if (!rootComposesFoundation(sourceFile, exportedConst(sourceFile, `${exportStem}Api`), stem, foundationName)) return 'MicroVertical root API must explicitly compose its readiness foundation API';
674
- const endpoints = reachableEndpoints(module, exportedConst(sourceFile, `${exportStem}Api`));
445
+ 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';
446
+ if (!foundationIsExact((0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, foundationName), stem, readinessSchemaName)) return 'MicroVertical readiness foundation API must directly compose its exact readiness endpoint and foundation identity';
447
+ if (!rootComposesFoundation(sourceFile, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}Api`), stem, foundationName)) return 'MicroVertical root API must explicitly compose its readiness foundation API';
448
+ const endpoints = reachableEndpoints(graph, (0, external_module_graph_cjs_namespaceObject.exportedConst)(sourceFile, `${exportStem}Api`));
675
449
  if (!endpoints) return 'MicroVertical root API must compose bounded native endpoint declarations without ambiguous identities';
676
- if (!operationMapIsConnected(exportedConst(sourceFile, `${exportStem}OperationContexts`), stem, expectation.operationPaths ?? {}, endpoints)) return 'MicroVertical operation map must construct every operation with the shared context constructor';
677
- if (!metadataIsExact(exportedConst(sourceFile, `${exportStem}ApiContract`), expectation, endpoints)) return 'MicroVertical root contract must keep exact owner and API path metadata without forbidden fields';
450
+ 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';
451
+ 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';
678
452
  };
679
453
  const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
680
454
  const topologyVertical = verticals.find((vertical)=>(vertical.path ?? `verticals/${vertical.id}`) === verticalPath);
@@ -683,14 +457,9 @@ const configuredMicroVerticalApiStem = (verticalPath, verticals)=>{
683
457
  };
684
458
  const microVerticalApiBaselineViolation = (stem, filePath, expectation)=>{
685
459
  try {
686
- const realPath = external_node_fs_default().realpathSync(filePath);
687
- const sourceFile = parseConsumer(realPath);
460
+ const graph = (0, external_module_graph_cjs_namespaceObject.createModuleGraph)(filePath);
688
461
  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';
689
- return validateParsedContract({
690
- file: sourceFile,
691
- path: realPath,
692
- boundary: sourceBoundary(realPath, containingWorkspace(realPath))
693
- }, stem, expectation);
462
+ return validateParsedContract(graph, stem, expectation);
694
463
  } catch (error) {
695
464
  if (error instanceof external_source_analysis_cjs_namespaceObject.SourceSyntaxError) return `MicroVertical root contract must be valid TypeScript syntax (${error.message})`;
696
465
  throw error;