@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,7 @@
1
+ #!/usr/bin/env node
2
+ import { runMicroVerticalApiCheckCli } from '../dist/esm-node/cli/microvertical-api-check.js';
3
+
4
+ process.exitCode = await runMicroVerticalApiCheckCli(
5
+ process.argv.slice(2),
6
+ true,
7
+ );
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runMicroVerticalApiCheckCli } from '../dist/esm-node/cli/microvertical-api-check.js';
3
+
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();
@@ -0,0 +1,100 @@
1
+ "use strict";
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
+ (()=>{
13
+ __webpack_require__.d = (exports1, getters, values)=>{
14
+ var define = (defs, kind)=>{
15
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
16
+ enumerable: true,
17
+ [kind]: defs[key]
18
+ });
19
+ };
20
+ define(getters, "get");
21
+ define(values, "value");
22
+ };
23
+ })();
24
+ (()=>{
25
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
26
+ })();
27
+ (()=>{
28
+ __webpack_require__.r = (exports1)=>{
29
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
30
+ value: 'Module'
31
+ });
32
+ Object.defineProperty(exports1, '__esModule', {
33
+ value: true
34
+ });
35
+ };
36
+ })();
37
+ var __webpack_exports__ = {};
38
+ __webpack_require__.r(__webpack_exports__);
39
+ __webpack_require__.d(__webpack_exports__, {
40
+ runMicroVerticalApiCheckCli: ()=>runMicroVerticalApiCheckCli
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");
45
+ const external_microvertical_api_boundary_cjs_namespaceObject = require("../microvertical-api-boundary.cjs");
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) {
57
+ let workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd();
58
+ let baselinePackageDirectory;
59
+ const ruleFiles = [];
60
+ for(let index = 0; index < args.length; index += 1){
61
+ const argument = args[index];
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 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.`);
64
+ return 0;
65
+ }
66
+ if (!flags.includes(argument ?? '') || !args[index + 1] || args[index + 1]?.startsWith('--')) {
67
+ console.error(`Invalid argument: ${argument ?? ''}. Use --help.`);
68
+ return 2;
69
+ }
70
+ const value = args[++index];
71
+ if ('--workspace-root' === argument) workspaceRoot = value;
72
+ else if ('--rules' === argument) ruleFiles.push(value);
73
+ else baselinePackageDirectory = value;
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
+ }
82
+ const result = (filesOnly ? external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiConsumerFiles : external_microvertical_api_boundary_cjs_namespaceObject.checkMicroVerticalApiBoundaries)({
83
+ workspaceRoot,
84
+ baselinePackageDirectory,
85
+ contractRules
86
+ });
87
+ for (const diagnostic of result.diagnostics)console.error(`API violation: ${diagnostic}`);
88
+ for (const error of result.toolErrors)console.error(`API tool error: ${error}`);
89
+ if (result.toolErrors.length) return 2;
90
+ if (result.diagnostics.length) return 1;
91
+ console.log(`UltraModern API ${filesOnly ? 'consumer files' : 'boundary'} check passed.`);
92
+ return 0;
93
+ }
94
+ exports.runMicroVerticalApiCheckCli = __webpack_exports__.runMicroVerticalApiCheckCli;
95
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
96
+ "runMicroVerticalApiCheckCli"
97
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
98
+ Object.defineProperty(exports, '__esModule', {
99
+ value: true
100
+ });
@@ -121,22 +121,26 @@ const runOxlintRules = ({ cwd, targets, rules })=>{
121
121
  stdout: '',
122
122
  stderr: ''
123
123
  };
124
+ const pluginPath = resolvePluginPath();
124
125
  const tempDir = external_node_fs_default().mkdtempSync(external_node_path_default().join(external_node_os_default().tmpdir(), 'modern-code-tools-oxlint-'));
125
126
  const configPath = external_node_path_default().join(tempDir, 'oxlint.config.mjs');
126
- const pluginPath = resolvePluginPath();
127
- external_node_fs_default().writeFileSync(configPath, `export default {
128
- jsPlugins: [${JSON.stringify(pluginPath)}],
127
+ const adapterPath = external_node_path_default().join(tempDir, 'oxlint-plugin.mjs');
128
+ try {
129
+ external_node_fs_default().writeFileSync(adapterPath, `import plugin from ${JSON.stringify((0, external_node_url_namespaceObject.pathToFileURL)(pluginPath).href)};
130
+ export default plugin.rules ? plugin : plugin.default;
131
+ `, 'utf-8');
132
+ external_node_fs_default().writeFileSync(configPath, `export default {
133
+ jsPlugins: [${JSON.stringify(adapterPath)}],
129
134
  rules: ${JSON.stringify(rules, null, 2)}
130
135
  };
131
136
  `, 'utf-8');
132
- try {
133
137
  const result = (0, external_node_child_process_namespaceObject.spawnSync)(process.execPath, [
134
138
  resolveOxlintBin(),
135
139
  ...resolvedTargets,
136
140
  '--config',
137
141
  configPath,
138
142
  '--format',
139
- 'unix',
143
+ 'default',
140
144
  '--quiet'
141
145
  ], {
142
146
  cwd,
@@ -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