@bleedingdev/modern-js-code-tools 3.9.0-ultramodern.16 → 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.
- package/bin/modern-api-check-files.mjs +4 -1
- package/bin/modern-api-check.mjs +1 -1
- package/bin/modern-i18n-check.mjs +4 -0
- package/dist/cjs/cli/microvertical-api-check.cjs +36 -7
- package/dist/cjs/cli/workspace-source-check.cjs +90 -17
- package/dist/cjs/microvertical-api-baseline.cjs +24 -255
- package/dist/cjs/microvertical-api-boundary.cjs +25 -0
- package/dist/cjs/module-graph.cjs +321 -0
- package/dist/esm/cli/microvertical-api-check.js +26 -7
- package/dist/esm/cli/workspace-source-check.js +86 -13
- package/dist/esm/microvertical-api-baseline.js +17 -237
- package/dist/esm/microvertical-api-boundary.js +24 -2
- package/dist/esm/module-graph.js +260 -0
- package/dist/esm-node/cli/microvertical-api-check.js +26 -7
- package/dist/esm-node/cli/workspace-source-check.js +86 -13
- package/dist/esm-node/microvertical-api-baseline.js +17 -237
- package/dist/esm-node/microvertical-api-boundary.js +24 -2
- package/dist/esm-node/module-graph.js +261 -0
- package/dist/types/cli/microvertical-api-check.d.ts +1 -1
- package/dist/types/cli/workspace-source-check.d.ts +1 -1
- package/dist/types/microvertical-api-boundary.d.ts +14 -0
- package/dist/types/module-graph.d.ts +52 -0
- package/package.json +4 -3
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_fs from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import node_path from "node:path";
|
|
5
|
+
import { exports as external_resolve_exports_exports } from "resolve.exports";
|
|
6
|
+
import { SourceSyntaxError, parseSource, traverseSource } from "./source-analysis.js";
|
|
7
|
+
import * as __rspack_external__babel_types_6e8337dd from "@babel/types";
|
|
8
|
+
const MAX_MODULES = 256;
|
|
9
|
+
const MAX_LOOKUPS = 512;
|
|
10
|
+
function parseConsumer(filePath) {
|
|
11
|
+
if (node_fs.statSync(filePath).size > 1000000) throw new Error(`${filePath}: consumer source exceeds 1 MB analysis budget`);
|
|
12
|
+
const file = parseSource(node_fs.readFileSync(filePath, 'utf8'), filePath);
|
|
13
|
+
traverseSource(file, {
|
|
14
|
+
AssignmentExpression (p) {
|
|
15
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
16
|
+
},
|
|
17
|
+
UpdateExpression (p) {
|
|
18
|
+
throw new SourceSyntaxError(`contract bindings must be immutable at ${p.node.start}`);
|
|
19
|
+
},
|
|
20
|
+
TSModuleDeclaration () {
|
|
21
|
+
throw new SourceSyntaxError('contract bindings must not be merged with namespaces');
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return file;
|
|
25
|
+
}
|
|
26
|
+
const propertyName = (node)=>{
|
|
27
|
+
if (void 0 !== node && (__rspack_external__babel_types_6e8337dd.isIdentifier(node) || __rspack_external__babel_types_6e8337dd.isStringLiteral(node) || __rspack_external__babel_types_6e8337dd.isNumericLiteral(node))) return __rspack_external__babel_types_6e8337dd.isIdentifier(node) ? node.name : String(node.value);
|
|
28
|
+
};
|
|
29
|
+
const localConst = (sourceFile, name)=>{
|
|
30
|
+
for (const item of sourceFile.program.body){
|
|
31
|
+
const statement = __rspack_external__babel_types_6e8337dd.isExportNamedDeclaration(item) ? item.declaration : item;
|
|
32
|
+
if (!__rspack_external__babel_types_6e8337dd.isVariableDeclaration(statement) || 'const' !== statement.kind) continue;
|
|
33
|
+
const matches = statement.declarations.filter((declaration)=>__rspack_external__babel_types_6e8337dd.isIdentifier(declaration.id, {
|
|
34
|
+
name
|
|
35
|
+
}));
|
|
36
|
+
if (1 === matches.length) return matches[0];
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const exportedConst = (sourceFile, name)=>{
|
|
40
|
+
for (const statement of sourceFile.program.body)if (__rspack_external__babel_types_6e8337dd.isExportNamedDeclaration(statement) && 'type' !== statement.exportKind) {
|
|
41
|
+
if (__rspack_external__babel_types_6e8337dd.isVariableDeclaration(statement.declaration) && 'const' === statement.declaration.kind) {
|
|
42
|
+
const declaration = statement.declaration.declarations.find((value)=>__rspack_external__babel_types_6e8337dd.isIdentifier(value.id, {
|
|
43
|
+
name
|
|
44
|
+
}));
|
|
45
|
+
if (declaration) return declaration;
|
|
46
|
+
}
|
|
47
|
+
if (!statement.source && statement.specifiers.some((value)=>__rspack_external__babel_types_6e8337dd.isExportSpecifier(value) && 'type' !== value.exportKind && __rspack_external__babel_types_6e8337dd.isIdentifier(value.local, {
|
|
48
|
+
name
|
|
49
|
+
}) && __rspack_external__babel_types_6e8337dd.isIdentifier(value.exported, {
|
|
50
|
+
name
|
|
51
|
+
}))) return localConst(sourceFile, name);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const inside = (file, boundary)=>file === boundary || file.startsWith(`${boundary}${node_path.sep}`);
|
|
55
|
+
const containingWorkspace = (file)=>{
|
|
56
|
+
for(let directory = node_path.dirname(file);; directory = node_path.dirname(directory)){
|
|
57
|
+
if (node_fs.existsSync(node_path.join(directory, 'pnpm-workspace.yaml'))) return node_fs.realpathSync(directory);
|
|
58
|
+
if (directory === node_path.dirname(directory)) return;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const sourceBoundary = (file, workspace)=>{
|
|
62
|
+
for(let directory = node_path.dirname(file);; directory = node_path.dirname(directory)){
|
|
63
|
+
if (node_fs.existsSync(node_path.join(directory, 'package.json')) && directory !== workspace) return node_fs.realpathSync(directory);
|
|
64
|
+
if (directory === workspace || directory === node_path.dirname(directory)) return node_fs.realpathSync(node_path.dirname(file));
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const sourceFileAt = (target, boundary)=>{
|
|
68
|
+
const stem = target.replace(/\.(?:[cm]?[jt]sx?)$/u, '');
|
|
69
|
+
for (const candidate of [
|
|
70
|
+
`${stem}.ts`,
|
|
71
|
+
`${stem}.tsx`,
|
|
72
|
+
`${stem}.mts`,
|
|
73
|
+
`${stem}.cts`,
|
|
74
|
+
target,
|
|
75
|
+
node_path.join(target, 'index.ts'),
|
|
76
|
+
node_path.join(target, 'index.tsx')
|
|
77
|
+
])try {
|
|
78
|
+
const real = node_fs.realpathSync(candidate);
|
|
79
|
+
if (inside(real, boundary) && node_fs.statSync(real).isFile()) return real;
|
|
80
|
+
} catch {}
|
|
81
|
+
};
|
|
82
|
+
const packageEntry = (specifier)=>{
|
|
83
|
+
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) return;
|
|
84
|
+
const parts = specifier.split('/');
|
|
85
|
+
const count = specifier.startsWith('@') ? 2 : 1;
|
|
86
|
+
if (parts.length < count || parts.slice(0, count).some((part)=>!part)) return;
|
|
87
|
+
return {
|
|
88
|
+
name: parts.slice(0, count).join('/'),
|
|
89
|
+
exportKey: parts.length === count ? '.' : `./${parts.slice(count).join('/')}`
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
const resolveModulePath = (module, specifier, workspace)=>{
|
|
93
|
+
if (/^\.\.?\//u.test(specifier)) {
|
|
94
|
+
const file = sourceFileAt(node_path.resolve(node_path.dirname(module.path), specifier), module.boundary);
|
|
95
|
+
return void 0 === file ? void 0 : {
|
|
96
|
+
kind: 'module',
|
|
97
|
+
path: file,
|
|
98
|
+
boundary: module.boundary
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const entry = packageEntry(specifier);
|
|
102
|
+
if (!entry) return;
|
|
103
|
+
if (!workspace) return {
|
|
104
|
+
kind: 'external'
|
|
105
|
+
};
|
|
106
|
+
const paths = createRequire(module.path).resolve.paths(entry.name) ?? [];
|
|
107
|
+
for (const lookup of paths){
|
|
108
|
+
const directory = node_path.join(lookup, entry.name);
|
|
109
|
+
const manifest = node_path.join(directory, 'package.json');
|
|
110
|
+
if (!node_fs.existsSync(manifest)) continue;
|
|
111
|
+
const boundary = node_fs.realpathSync(directory);
|
|
112
|
+
if (!inside(boundary, workspace) || boundary.split(node_path.sep).includes('node_modules')) break;
|
|
113
|
+
const pkg = JSON.parse(node_fs.readFileSync(manifest, 'utf8'));
|
|
114
|
+
if (pkg.name !== entry.name || void 0 === pkg.exports) return;
|
|
115
|
+
let target;
|
|
116
|
+
try {
|
|
117
|
+
const targets = external_resolve_exports_exports(pkg, entry.exportKey, {
|
|
118
|
+
conditions: [
|
|
119
|
+
'modern:source'
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
target = Array.isArray(targets) ? targets[0] : void 0;
|
|
123
|
+
} catch {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!target || !target.startsWith('./')) return;
|
|
127
|
+
const file = sourceFileAt(node_path.resolve(boundary, target), boundary);
|
|
128
|
+
return void 0 === file ? void 0 : {
|
|
129
|
+
kind: 'module',
|
|
130
|
+
path: file,
|
|
131
|
+
boundary
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
kind: 'external'
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
const importedBinding = (module, name)=>{
|
|
139
|
+
for (const statement of module.file.program.body)if (__rspack_external__babel_types_6e8337dd.isImportDeclaration(statement) && 'type' !== statement.importKind) {
|
|
140
|
+
for (const specifier of statement.specifiers)if (__rspack_external__babel_types_6e8337dd.isIdentifier(specifier.local, {
|
|
141
|
+
name
|
|
142
|
+
})) {
|
|
143
|
+
if (__rspack_external__babel_types_6e8337dd.isImportSpecifier(specifier) && 'type' !== specifier.importKind) return {
|
|
144
|
+
imported: propertyName(specifier.imported) ?? name,
|
|
145
|
+
specifier: statement.source.value
|
|
146
|
+
};
|
|
147
|
+
if (__rspack_external__babel_types_6e8337dd.isImportDefaultSpecifier(specifier)) return {
|
|
148
|
+
imported: 'default',
|
|
149
|
+
specifier: statement.source.value
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const reexportedBinding = (module, name)=>{
|
|
155
|
+
for (const statement of module.file.program.body){
|
|
156
|
+
if (!__rspack_external__babel_types_6e8337dd.isExportNamedDeclaration(statement) || 'type' === statement.exportKind) continue;
|
|
157
|
+
const specifier = statement.specifiers.find((value)=>__rspack_external__babel_types_6e8337dd.isExportSpecifier(value) && 'type' !== value.exportKind && propertyName(value.exported) === name);
|
|
158
|
+
if (void 0 !== specifier && __rspack_external__babel_types_6e8337dd.isExportSpecifier(specifier)) return {
|
|
159
|
+
local: __rspack_external__babel_types_6e8337dd.isIdentifier(specifier.local) ? specifier.local.name : specifier.local.value,
|
|
160
|
+
...statement.source ? {
|
|
161
|
+
specifier: statement.source.value
|
|
162
|
+
} : {}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const defaultExport = (module)=>{
|
|
167
|
+
for (const statement of module.file.program.body){
|
|
168
|
+
if (!__rspack_external__babel_types_6e8337dd.isExportDefaultDeclaration(statement)) continue;
|
|
169
|
+
const declaration = statement.declaration;
|
|
170
|
+
if (__rspack_external__babel_types_6e8337dd.isIdentifier(declaration)) return declaration.name;
|
|
171
|
+
return __rspack_external__babel_types_6e8337dd.isExpression(declaration) ? declaration : void 0;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
function createModuleGraph(filePath) {
|
|
175
|
+
const realPath = node_fs.realpathSync(filePath);
|
|
176
|
+
const workspace = containingWorkspace(realPath);
|
|
177
|
+
const root = {
|
|
178
|
+
file: parseConsumer(realPath),
|
|
179
|
+
path: realPath,
|
|
180
|
+
boundary: sourceBoundary(realPath, workspace)
|
|
181
|
+
};
|
|
182
|
+
const modules = new Map([
|
|
183
|
+
[
|
|
184
|
+
root.path,
|
|
185
|
+
root
|
|
186
|
+
]
|
|
187
|
+
]);
|
|
188
|
+
const readModule = (modulePath, boundary)=>{
|
|
189
|
+
if (modules.has(modulePath)) return modules.get(modulePath);
|
|
190
|
+
if (modules.size >= MAX_MODULES) return;
|
|
191
|
+
let module;
|
|
192
|
+
try {
|
|
193
|
+
module = {
|
|
194
|
+
file: parseConsumer(modulePath),
|
|
195
|
+
path: modulePath,
|
|
196
|
+
boundary
|
|
197
|
+
};
|
|
198
|
+
} catch {
|
|
199
|
+
module = void 0;
|
|
200
|
+
}
|
|
201
|
+
modules.set(modulePath, module);
|
|
202
|
+
return module;
|
|
203
|
+
};
|
|
204
|
+
const resolveBinding = (module, name, scope, chain, seen)=>{
|
|
205
|
+
const key = `${scope}:${module.path}#${name}`;
|
|
206
|
+
if (seen.has(key) || seen.size >= MAX_LOOKUPS) return;
|
|
207
|
+
seen.add(key);
|
|
208
|
+
const last = chain.at(-1);
|
|
209
|
+
const hops = last?.path === module.path && last.name === name ? chain : [
|
|
210
|
+
...chain,
|
|
211
|
+
{
|
|
212
|
+
path: module.path,
|
|
213
|
+
name
|
|
214
|
+
}
|
|
215
|
+
];
|
|
216
|
+
const declaration = 'export' === scope ? exportedConst(module.file, name) : localConst(module.file, name);
|
|
217
|
+
if (declaration?.init) return {
|
|
218
|
+
kind: 'declaration',
|
|
219
|
+
expression: declaration.init,
|
|
220
|
+
module,
|
|
221
|
+
chain: hops
|
|
222
|
+
};
|
|
223
|
+
const throughModule = (specifier, imported, allowExternal)=>{
|
|
224
|
+
const target = resolveModulePath(module, specifier, workspace);
|
|
225
|
+
if (target?.kind === 'external') return allowExternal ? {
|
|
226
|
+
kind: 'external',
|
|
227
|
+
specifier,
|
|
228
|
+
name: imported,
|
|
229
|
+
chain: hops
|
|
230
|
+
} : void 0;
|
|
231
|
+
const next = target && readModule(target.path, target.boundary);
|
|
232
|
+
return void 0 === next ? void 0 : resolveBinding(next, imported, 'export', hops, seen);
|
|
233
|
+
};
|
|
234
|
+
if ('local' === scope) {
|
|
235
|
+
const imported = importedBinding(module, name);
|
|
236
|
+
return void 0 === imported ? void 0 : throughModule(imported.specifier, imported.imported, true);
|
|
237
|
+
}
|
|
238
|
+
if ('default' === name) {
|
|
239
|
+
const exported = defaultExport(module);
|
|
240
|
+
if ('string' == typeof exported) return resolveBinding(module, exported, 'local', hops, seen);
|
|
241
|
+
return void 0 === exported ? void 0 : {
|
|
242
|
+
kind: 'declaration',
|
|
243
|
+
expression: exported,
|
|
244
|
+
module,
|
|
245
|
+
chain: hops
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const reexported = reexportedBinding(module, name);
|
|
249
|
+
if (void 0 !== reexported) return void 0 === reexported.specifier ? resolveBinding(module, reexported.local, 'local', hops, seen) : throughModule(reexported.specifier, reexported.local, true);
|
|
250
|
+
for (const statement of module.file.program.body){
|
|
251
|
+
if (!__rspack_external__babel_types_6e8337dd.isExportAllDeclaration(statement) || 'type' === statement.exportKind) continue;
|
|
252
|
+
const resolved = throughModule(statement.source.value, name, false);
|
|
253
|
+
if (void 0 !== resolved) return resolved;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
return {
|
|
257
|
+
root,
|
|
258
|
+
resolve: (module, name, scope)=>resolveBinding(module, name, scope, [], new Set())
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
export { createModuleGraph, exportedConst, localConst, parseConsumer, propertyName };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function runMicroVerticalApiCheckCli(args?: string[], filesOnly?: boolean): number
|
|
1
|
+
export declare function runMicroVerticalApiCheckCli(args?: string[], filesOnly?: boolean): Promise<number>;
|
|
@@ -17,4 +17,4 @@ export type WorkspaceSourceCheckOptions = {
|
|
|
17
17
|
readonly pluralCategories?: Readonly<Record<string, readonly string[]>>;
|
|
18
18
|
};
|
|
19
19
|
export declare const runWorkspaceSourceCheck: ({ cwd, sourceRoots, locales, pluralCategories, }?: WorkspaceSourceCheckOptions) => number;
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const runWorkspaceSourceCheckCli: (args?: readonly string[]) => number;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { type ModuleGraph } from './module-graph.js';
|
|
1
2
|
export type { MicroVerticalApiBaselineExpectation, MicroVerticalTopologyEntry, } from './microvertical-api-baseline.js';
|
|
2
3
|
export { configuredMicroVerticalApiStem, microVerticalApiBaselineViolation, } from './microvertical-api-baseline.js';
|
|
4
|
+
export type { ModuleGraph, ModuleGraphHop, ResolvedBinding, SourceModule, } from './module-graph.js';
|
|
5
|
+
export { createModuleGraph } from './module-graph.js';
|
|
3
6
|
export interface MicroVerticalConfiguredApp {
|
|
4
7
|
readonly path: string;
|
|
5
8
|
readonly id?: string;
|
|
@@ -15,11 +18,22 @@ export interface MicroVerticalConfiguredApp {
|
|
|
15
18
|
readonly additionalPaths?: Readonly<Record<string, string>>;
|
|
16
19
|
};
|
|
17
20
|
}
|
|
21
|
+
export interface MicroVerticalApiContractRuleContext {
|
|
22
|
+
/** Workspace-relative app directory. */
|
|
23
|
+
readonly appPath: string;
|
|
24
|
+
readonly protocol: 'rest' | 'rpc';
|
|
25
|
+
/** Graph rooted at the app's shared contract (`graph.root`). */
|
|
26
|
+
readonly graph: ModuleGraph;
|
|
27
|
+
}
|
|
28
|
+
/** A consumer-owned contract rule; each returned message is a violation. */
|
|
29
|
+
export type MicroVerticalApiContractRule = (context: MicroVerticalApiContractRuleContext) => readonly string[];
|
|
18
30
|
export interface MicroVerticalApiCheckOptions {
|
|
19
31
|
readonly workspaceRoot: string;
|
|
20
32
|
readonly configuredApps?: readonly MicroVerticalConfiguredApp[];
|
|
21
33
|
/** Explicit expected installed owner, useful for isolated/non-hoisted installations. */
|
|
22
34
|
readonly baselinePackageDirectory?: string;
|
|
35
|
+
/** Rules run once per API app against its shared contract's module graph. */
|
|
36
|
+
readonly contractRules?: readonly MicroVerticalApiContractRule[];
|
|
23
37
|
}
|
|
24
38
|
export interface MicroVerticalApiCheckResult {
|
|
25
39
|
readonly diagnostics: readonly string[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
/** A parsed consumer module and the package directory it may traverse privately. */
|
|
3
|
+
export interface SourceModule {
|
|
4
|
+
readonly file: t.File;
|
|
5
|
+
/** Real absolute path. */
|
|
6
|
+
readonly path: string;
|
|
7
|
+
/** Real package directory; relative imports may not leave it. */
|
|
8
|
+
readonly boundary: string;
|
|
9
|
+
}
|
|
10
|
+
/** One `name` looked up in the module at `path`, in traversal order. */
|
|
11
|
+
export interface ModuleGraphHop {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Where a binding ends up. `declaration` is a workspace `const` initializer;
|
|
17
|
+
* `external` is a named import or re-export from a package outside the
|
|
18
|
+
* workspace source graph. `chain` starts at the requesting module and ends at
|
|
19
|
+
* the declaring module (or the last workspace module before the package).
|
|
20
|
+
*/
|
|
21
|
+
export type ResolvedBinding = {
|
|
22
|
+
readonly kind: 'declaration';
|
|
23
|
+
readonly expression: t.Expression;
|
|
24
|
+
readonly module: SourceModule;
|
|
25
|
+
readonly chain: readonly ModuleGraphHop[];
|
|
26
|
+
} | {
|
|
27
|
+
readonly kind: 'external';
|
|
28
|
+
readonly specifier: string;
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly chain: readonly ModuleGraphHop[];
|
|
31
|
+
};
|
|
32
|
+
export interface ModuleGraph {
|
|
33
|
+
readonly root: SourceModule;
|
|
34
|
+
/**
|
|
35
|
+
* Follow a local binding (`scope: 'local'`) or an export (`'export'`) of
|
|
36
|
+
* `module` through relative imports, re-exports and public workspace
|
|
37
|
+
* package exports. Unresolvable, cyclic or over-budget bindings return
|
|
38
|
+
* undefined so callers fail closed.
|
|
39
|
+
*/
|
|
40
|
+
resolve(module: SourceModule, name: string, scope: 'export' | 'local'): ResolvedBinding | undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Resolution follows `const` bindings, so a module that mutates them is unreadable. */
|
|
43
|
+
export declare function parseConsumer(filePath: string): t.File;
|
|
44
|
+
export declare const propertyName: (node: t.Node | undefined) => string | undefined;
|
|
45
|
+
export declare const localConst: (sourceFile: t.File, name: string) => t.VariableDeclarator | undefined;
|
|
46
|
+
export declare const exportedConst: (sourceFile: t.File, name: string) => t.VariableDeclarator | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* The module graph rooted at `filePath`. Each module is parsed once per graph;
|
|
49
|
+
* an unreadable module stays unresolved instead of assumed valid. Throws
|
|
50
|
+
* `SourceSyntaxError` when the root itself is not a readable consumer module.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createModuleGraph(filePath: string): ModuleGraph;
|
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=20"
|
|
25
25
|
},
|
|
26
|
-
"version": "3.9.0-ultramodern.
|
|
26
|
+
"version": "3.9.0-ultramodern.18",
|
|
27
27
|
"types": "./dist/types/index.d.ts",
|
|
28
28
|
"main": "./dist/esm-node/index.js",
|
|
29
29
|
"typesVersions": {
|
|
@@ -91,11 +91,12 @@
|
|
|
91
91
|
"modern:source": "./src/index.ts",
|
|
92
92
|
"bin": {
|
|
93
93
|
"modern-api-check": "bin/modern-api-check.mjs",
|
|
94
|
-
"modern-api-check-files": "bin/modern-api-check-files.mjs"
|
|
94
|
+
"modern-api-check-files": "bin/modern-api-check-files.mjs",
|
|
95
|
+
"modern-i18n-check": "bin/modern-i18n-check.mjs"
|
|
95
96
|
},
|
|
96
97
|
"scripts": {
|
|
97
98
|
"build": "rm -rf dist && rslib build -c rslib.config.mts",
|
|
98
99
|
"dev": "rslib build -c rslib.config.mts -w",
|
|
99
|
-
"test": "rstest
|
|
100
|
+
"test": "rstest"
|
|
100
101
|
}
|
|
101
102
|
}
|