@beignet/cli 0.0.48 → 0.0.50
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/CHANGELOG.md +54 -0
- package/README.md +117 -22
- package/dist/analysis/contract-factories.d.ts +17 -0
- package/dist/analysis/contract-factories.d.ts.map +1 -0
- package/dist/analysis/contract-factories.js +176 -0
- package/dist/analysis/contract-factories.js.map +1 -0
- package/dist/analysis/layers.d.ts +5 -0
- package/dist/analysis/layers.d.ts.map +1 -0
- package/dist/analysis/layers.js +172 -0
- package/dist/analysis/layers.js.map +1 -0
- package/dist/analysis/port-wiring.d.ts +23 -0
- package/dist/analysis/port-wiring.d.ts.map +1 -0
- package/dist/analysis/port-wiring.js +379 -0
- package/dist/analysis/port-wiring.js.map +1 -0
- package/dist/analysis/source-index.d.ts +5 -0
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +171 -42
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace.d.ts +11 -4
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +78 -8
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map-changes.d.ts +103 -0
- package/dist/app-map-changes.d.ts.map +1 -0
- package/dist/app-map-changes.js +949 -0
- package/dist/app-map-changes.js.map +1 -0
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +311 -92
- package/dist/app-map.js.map +1 -1
- package/dist/check.js +37 -3
- package/dist/check.js.map +1 -1
- package/dist/explain.js +4 -4
- package/dist/explain.js.map +1 -1
- package/dist/git-changes.d.ts +30 -0
- package/dist/git-changes.d.ts.map +1 -0
- package/dist/git-changes.js +367 -0
- package/dist/git-changes.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +706 -186
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +3 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +309 -487
- package/dist/lint.js.map +1 -1
- package/dist/make/inbox.d.ts.map +1 -1
- package/dist/make/inbox.js +11 -4
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.js +2 -2
- package/dist/make/shared.d.ts.map +1 -1
- package/dist/make/shared.js +31 -27
- package/dist/make/shared.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +144 -8
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +43 -21
- package/dist/mcp.js.map +1 -1
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +142 -7
- package/dist/provider-add.js.map +1 -1
- package/dist/registry-edits.d.ts +7 -0
- package/dist/registry-edits.d.ts.map +1 -1
- package/dist/registry-edits.js +237 -53
- package/dist/registry-edits.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +37 -1
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +13 -2
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +2 -0
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +1 -0
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +3 -2
- package/dist/templates/shared.js.map +1 -1
- package/package.json +7 -6
- package/skills/app-structure/SKILL.md +71 -7
- package/src/analysis/contract-factories.ts +256 -0
- package/src/analysis/layers.ts +266 -0
- package/src/analysis/port-wiring.ts +506 -0
- package/src/analysis/source-index.ts +225 -57
- package/src/analysis/workspace.ts +134 -9
- package/src/app-map-changes.ts +1462 -0
- package/src/app-map.ts +418 -109
- package/src/check.ts +51 -3
- package/src/explain.ts +4 -4
- package/src/git-changes.ts +511 -0
- package/src/index.ts +39 -1
- package/src/inspect.ts +1005 -238
- package/src/lib.ts +21 -0
- package/src/lint.ts +393 -643
- package/src/make/inbox.ts +11 -4
- package/src/make/payments.ts +2 -2
- package/src/make/shared.ts +31 -27
- package/src/make.ts +225 -8
- package/src/mcp.ts +51 -24
- package/src/provider-add.ts +186 -7
- package/src/registry-edits.ts +313 -63
- package/src/templates/agents.ts +37 -1
- package/src/templates/base.ts +13 -2
- package/src/templates/server.ts +2 -0
- package/src/templates/shared.ts +3 -2
|
@@ -27,12 +27,19 @@ export type LocalImportReference = {
|
|
|
27
27
|
column: number;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
export type ModuleReference = LocalImportReference & {
|
|
31
|
+
syntax: "dynamic-import" | "export" | "import" | "import-equals" | "require";
|
|
32
|
+
staticallyResolvable: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
30
35
|
type ImportBinding =
|
|
31
36
|
| { kind: "named"; file: string; exportName: string }
|
|
32
37
|
| { kind: "namespace"; file: string };
|
|
33
38
|
|
|
34
39
|
type FileIndex = {
|
|
35
40
|
declarations: Map<string, ts.Declaration>;
|
|
41
|
+
localExports: Map<string, string>;
|
|
42
|
+
locals: Map<string, ts.Declaration>;
|
|
36
43
|
imports: Map<string, ImportBinding>;
|
|
37
44
|
reexports: Map<string, { file: string; exportName: string }>;
|
|
38
45
|
exportStars: string[];
|
|
@@ -68,6 +75,8 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
68
75
|
const sourceFile = await workspace.readSourceFile(file);
|
|
69
76
|
const index: FileIndex = {
|
|
70
77
|
declarations: new Map(),
|
|
78
|
+
localExports: new Map(),
|
|
79
|
+
locals: new Map(),
|
|
71
80
|
imports: new Map(),
|
|
72
81
|
reexports: new Map(),
|
|
73
82
|
exportStars: [],
|
|
@@ -115,6 +124,22 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
115
124
|
const target = source
|
|
116
125
|
? resolveLocalSourceFile(workspace, file, source)
|
|
117
126
|
: undefined;
|
|
127
|
+
|
|
128
|
+
if (!statement.moduleSpecifier) {
|
|
129
|
+
if (
|
|
130
|
+
statement.exportClause &&
|
|
131
|
+
ts.isNamedExports(statement.exportClause)
|
|
132
|
+
) {
|
|
133
|
+
for (const element of statement.exportClause.elements) {
|
|
134
|
+
if (statement.isTypeOnly || element.isTypeOnly) continue;
|
|
135
|
+
index.localExports.set(
|
|
136
|
+
element.name.text,
|
|
137
|
+
element.propertyName?.text ?? element.name.text,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
118
143
|
if (!target) continue;
|
|
119
144
|
|
|
120
145
|
if (!statement.exportClause) {
|
|
@@ -133,10 +158,13 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
133
158
|
continue;
|
|
134
159
|
}
|
|
135
160
|
|
|
136
|
-
if (ts.isVariableStatement(statement)
|
|
161
|
+
if (ts.isVariableStatement(statement)) {
|
|
137
162
|
for (const declaration of statement.declarationList.declarations) {
|
|
138
163
|
if (ts.isIdentifier(declaration.name)) {
|
|
139
|
-
index.
|
|
164
|
+
index.locals.set(declaration.name.text, declaration);
|
|
165
|
+
if (hasExportModifier(statement)) {
|
|
166
|
+
index.declarations.set(declaration.name.text, declaration);
|
|
167
|
+
}
|
|
140
168
|
}
|
|
141
169
|
}
|
|
142
170
|
continue;
|
|
@@ -148,10 +176,12 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
148
176
|
ts.isInterfaceDeclaration(statement) ||
|
|
149
177
|
ts.isTypeAliasDeclaration(statement) ||
|
|
150
178
|
ts.isEnumDeclaration(statement)) &&
|
|
151
|
-
hasExportModifier(statement) &&
|
|
152
179
|
statement.name
|
|
153
180
|
) {
|
|
154
|
-
index.
|
|
181
|
+
index.locals.set(statement.name.text, statement);
|
|
182
|
+
if (hasExportModifier(statement)) {
|
|
183
|
+
index.declarations.set(statement.name.text, statement);
|
|
184
|
+
}
|
|
155
185
|
}
|
|
156
186
|
}
|
|
157
187
|
|
|
@@ -171,6 +201,14 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
171
201
|
const declaration = index.declarations.get(exportName);
|
|
172
202
|
if (declaration) return { file, exportName, declaration };
|
|
173
203
|
|
|
204
|
+
const localName = index.localExports.get(exportName);
|
|
205
|
+
const localDeclaration = localName
|
|
206
|
+
? index.locals.get(localName)
|
|
207
|
+
: undefined;
|
|
208
|
+
if (localDeclaration) {
|
|
209
|
+
return { file, exportName, declaration: localDeclaration };
|
|
210
|
+
}
|
|
211
|
+
|
|
174
212
|
const reexport = index.reexports.get(exportName);
|
|
175
213
|
if (reexport) {
|
|
176
214
|
return (
|
|
@@ -192,7 +230,7 @@ export function createSourceIndex(workspace: AnalysisWorkspace): SourceIndex {
|
|
|
192
230
|
return {
|
|
193
231
|
async resolveName(file, name) {
|
|
194
232
|
const index = await readIndex(file);
|
|
195
|
-
const local = index.
|
|
233
|
+
const local = index.locals.get(name);
|
|
196
234
|
if (local) {
|
|
197
235
|
return { file, exportName: name, declaration: local };
|
|
198
236
|
}
|
|
@@ -267,20 +305,48 @@ export function exportedVariableDeclarations(
|
|
|
267
305
|
declaration: ts.VariableDeclaration;
|
|
268
306
|
}> = [];
|
|
269
307
|
|
|
308
|
+
const locals = new Map<string, ts.VariableDeclaration>();
|
|
309
|
+
const seen = new Set<string>();
|
|
310
|
+
const addDeclaration = (
|
|
311
|
+
exportName: string,
|
|
312
|
+
declaration: ts.VariableDeclaration,
|
|
313
|
+
) => {
|
|
314
|
+
const key = `${exportName}:${declaration.pos}`;
|
|
315
|
+
if (seen.has(key)) return;
|
|
316
|
+
seen.add(key);
|
|
317
|
+
declarations.push({ exportName, declaration });
|
|
318
|
+
};
|
|
319
|
+
|
|
270
320
|
for (const statement of sourceFile.statements) {
|
|
271
|
-
if (!ts.isVariableStatement(statement)
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
321
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
274
322
|
for (const declaration of statement.declarationList.declarations) {
|
|
275
323
|
if (ts.isIdentifier(declaration.name)) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
declaration,
|
|
279
|
-
}
|
|
324
|
+
locals.set(declaration.name.text, declaration);
|
|
325
|
+
if (hasExportModifier(statement)) {
|
|
326
|
+
addDeclaration(declaration.name.text, declaration);
|
|
327
|
+
}
|
|
280
328
|
}
|
|
281
329
|
}
|
|
282
330
|
}
|
|
283
331
|
|
|
332
|
+
for (const statement of sourceFile.statements) {
|
|
333
|
+
if (
|
|
334
|
+
!ts.isExportDeclaration(statement) ||
|
|
335
|
+
statement.moduleSpecifier ||
|
|
336
|
+
statement.isTypeOnly ||
|
|
337
|
+
!statement.exportClause ||
|
|
338
|
+
!ts.isNamedExports(statement.exportClause)
|
|
339
|
+
) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
for (const element of statement.exportClause.elements) {
|
|
343
|
+
if (element.isTypeOnly) continue;
|
|
344
|
+
const localName = element.propertyName?.text ?? element.name.text;
|
|
345
|
+
const declaration = locals.get(localName);
|
|
346
|
+
if (declaration) addDeclaration(element.name.text, declaration);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
284
350
|
return declarations;
|
|
285
351
|
}
|
|
286
352
|
|
|
@@ -321,64 +387,166 @@ export async function localImportReferences(
|
|
|
321
387
|
workspace: AnalysisWorkspace,
|
|
322
388
|
file: string,
|
|
323
389
|
): Promise<LocalImportReference[]> {
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
? resolveLocalSourceFile(workspace, file, importPath)
|
|
339
|
-
: undefined;
|
|
340
|
-
if (
|
|
341
|
-
!importPath ||
|
|
342
|
-
(!resolvedFile && !isLocalModuleSpecifier(workspace, file, importPath))
|
|
343
|
-
) {
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
390
|
+
const references = await moduleReferences(workspace, file);
|
|
391
|
+
|
|
392
|
+
return references
|
|
393
|
+
.filter(
|
|
394
|
+
(reference) =>
|
|
395
|
+
reference.staticallyResolvable &&
|
|
396
|
+
(reference.resolvedFile ||
|
|
397
|
+
isLocalModuleSpecifier(workspace, file, reference.importPath)),
|
|
398
|
+
)
|
|
399
|
+
.map(
|
|
400
|
+
({ syntax: _syntax, staticallyResolvable: _static, ...reference }) =>
|
|
401
|
+
reference,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
346
404
|
|
|
405
|
+
export async function moduleReferences(
|
|
406
|
+
workspace: AnalysisWorkspace,
|
|
407
|
+
file: string,
|
|
408
|
+
): Promise<ModuleReference[]> {
|
|
409
|
+
const sourceFile = await workspace.readSourceFile(file);
|
|
410
|
+
const references: ModuleReference[] = [];
|
|
411
|
+
|
|
412
|
+
const addReference = ({
|
|
413
|
+
importPath,
|
|
414
|
+
kind,
|
|
415
|
+
node,
|
|
416
|
+
staticallyResolvable,
|
|
417
|
+
syntax,
|
|
418
|
+
}: {
|
|
419
|
+
importPath: string;
|
|
420
|
+
kind: "type" | "value";
|
|
421
|
+
node: ts.Node;
|
|
422
|
+
staticallyResolvable: boolean;
|
|
423
|
+
syntax: ModuleReference["syntax"];
|
|
424
|
+
}) => {
|
|
347
425
|
const position = sourceFile.getLineAndCharacterOfPosition(
|
|
348
|
-
|
|
426
|
+
node.getStart(sourceFile),
|
|
349
427
|
);
|
|
350
|
-
const typeOnly = ts.isImportDeclaration(statement)
|
|
351
|
-
? Boolean(
|
|
352
|
-
statement.importClause?.isTypeOnly ||
|
|
353
|
-
(statement.importClause?.namedBindings &&
|
|
354
|
-
ts.isNamedImports(statement.importClause.namedBindings) &&
|
|
355
|
-
statement.importClause.namedBindings.elements.length > 0 &&
|
|
356
|
-
statement.importClause.namedBindings.elements.every(
|
|
357
|
-
(element) => element.isTypeOnly,
|
|
358
|
-
)),
|
|
359
|
-
)
|
|
360
|
-
: statement.isTypeOnly ||
|
|
361
|
-
(statement.exportClause &&
|
|
362
|
-
ts.isNamedExports(statement.exportClause) &&
|
|
363
|
-
statement.exportClause.elements.length > 0 &&
|
|
364
|
-
statement.exportClause.elements.every(
|
|
365
|
-
(element) => element.isTypeOnly,
|
|
366
|
-
));
|
|
367
428
|
references.push({
|
|
368
429
|
file,
|
|
369
430
|
importPath,
|
|
370
|
-
|
|
371
|
-
|
|
431
|
+
...(staticallyResolvable
|
|
432
|
+
? { resolvedFile: resolveLocalSourceFile(workspace, file, importPath) }
|
|
433
|
+
: {}),
|
|
434
|
+
kind,
|
|
372
435
|
line: position.line + 1,
|
|
373
436
|
column: position.character + 1,
|
|
437
|
+
syntax,
|
|
438
|
+
staticallyResolvable,
|
|
374
439
|
});
|
|
375
|
-
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
const visit = (node: ts.Node) => {
|
|
443
|
+
if (ts.isImportDeclaration(node) && node.moduleSpecifier) {
|
|
444
|
+
const importPath = moduleText(node.moduleSpecifier);
|
|
445
|
+
if (importPath) {
|
|
446
|
+
addReference({
|
|
447
|
+
importPath,
|
|
448
|
+
kind: importDeclarationKind(node),
|
|
449
|
+
node,
|
|
450
|
+
staticallyResolvable: true,
|
|
451
|
+
syntax: "import",
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
} else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
|
|
455
|
+
const importPath = moduleText(node.moduleSpecifier);
|
|
456
|
+
if (importPath) {
|
|
457
|
+
addReference({
|
|
458
|
+
importPath,
|
|
459
|
+
kind: exportDeclarationKind(node),
|
|
460
|
+
node,
|
|
461
|
+
staticallyResolvable: true,
|
|
462
|
+
syntax: "export",
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
} else if (
|
|
466
|
+
ts.isImportEqualsDeclaration(node) &&
|
|
467
|
+
ts.isExternalModuleReference(node.moduleReference) &&
|
|
468
|
+
node.moduleReference.expression
|
|
469
|
+
) {
|
|
470
|
+
const importPath = moduleText(node.moduleReference.expression);
|
|
471
|
+
if (importPath) {
|
|
472
|
+
addReference({
|
|
473
|
+
importPath,
|
|
474
|
+
kind: node.isTypeOnly ? "type" : "value",
|
|
475
|
+
node,
|
|
476
|
+
staticallyResolvable: true,
|
|
477
|
+
syntax: "import-equals",
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
} else if (ts.isCallExpression(node)) {
|
|
481
|
+
const syntax =
|
|
482
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword
|
|
483
|
+
? "dynamic-import"
|
|
484
|
+
: ts.isIdentifier(node.expression) &&
|
|
485
|
+
node.expression.text === "require"
|
|
486
|
+
? "require"
|
|
487
|
+
: undefined;
|
|
488
|
+
if (syntax) {
|
|
489
|
+
const argument = node.arguments[0];
|
|
490
|
+
const importPath = moduleText(argument);
|
|
491
|
+
addReference({
|
|
492
|
+
importPath:
|
|
493
|
+
importPath ?? argument?.getText(sourceFile) ?? "<missing>",
|
|
494
|
+
kind: "value",
|
|
495
|
+
node,
|
|
496
|
+
staticallyResolvable: importPath !== undefined,
|
|
497
|
+
syntax,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
ts.forEachChild(node, visit);
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
visit(sourceFile);
|
|
376
506
|
|
|
377
507
|
return references;
|
|
378
508
|
}
|
|
379
509
|
|
|
380
|
-
function
|
|
381
|
-
|
|
510
|
+
function importDeclarationKind(
|
|
511
|
+
declaration: ts.ImportDeclaration,
|
|
512
|
+
): "type" | "value" {
|
|
513
|
+
const clause = declaration.importClause;
|
|
514
|
+
if (!clause) return "value";
|
|
515
|
+
if (clause.isTypeOnly) return "type";
|
|
516
|
+
if (clause.name) return "value";
|
|
517
|
+
|
|
518
|
+
const bindings = clause.namedBindings;
|
|
519
|
+
if (
|
|
520
|
+
bindings &&
|
|
521
|
+
ts.isNamedImports(bindings) &&
|
|
522
|
+
bindings.elements.length > 0 &&
|
|
523
|
+
bindings.elements.every((element) => element.isTypeOnly)
|
|
524
|
+
) {
|
|
525
|
+
return "type";
|
|
526
|
+
}
|
|
527
|
+
return "value";
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function exportDeclarationKind(
|
|
531
|
+
declaration: ts.ExportDeclaration,
|
|
532
|
+
): "type" | "value" {
|
|
533
|
+
if (declaration.isTypeOnly) return "type";
|
|
534
|
+
if (
|
|
535
|
+
declaration.exportClause &&
|
|
536
|
+
ts.isNamedExports(declaration.exportClause) &&
|
|
537
|
+
declaration.exportClause.elements.length > 0 &&
|
|
538
|
+
declaration.exportClause.elements.every((element) => element.isTypeOnly)
|
|
539
|
+
) {
|
|
540
|
+
return "type";
|
|
541
|
+
}
|
|
542
|
+
return "value";
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function moduleText(node: ts.Expression | undefined): string | undefined {
|
|
546
|
+
return node &&
|
|
547
|
+
(ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
|
|
548
|
+
? node.text
|
|
549
|
+
: undefined;
|
|
382
550
|
}
|
|
383
551
|
|
|
384
552
|
function hasExportModifier(node: ts.Node): boolean {
|
|
@@ -2,9 +2,11 @@ import { readdir, readFile, stat } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import {
|
|
5
|
+
type BeignetConfig,
|
|
5
6
|
loadBeignetConfig,
|
|
6
7
|
normalizePath,
|
|
7
8
|
type ResolvedBeignetConfig,
|
|
9
|
+
resolveConfig,
|
|
8
10
|
} from "../config.js";
|
|
9
11
|
|
|
10
12
|
const ignoredDirectoryNames = new Set([
|
|
@@ -22,19 +24,36 @@ export type AnalysisWorkspace = {
|
|
|
22
24
|
fileSet: Set<string>;
|
|
23
25
|
config: ResolvedBeignetConfig;
|
|
24
26
|
compilerOptions: ts.CompilerOptions;
|
|
27
|
+
compilerConfigFiles: string[];
|
|
28
|
+
moduleResolutionCache: ts.ModuleResolutionCache;
|
|
25
29
|
readSource(file: string): Promise<string>;
|
|
26
30
|
readSourceFile(file: string): Promise<ts.SourceFile>;
|
|
27
31
|
};
|
|
28
32
|
|
|
33
|
+
type AnalysisWorkspaceOptions = {
|
|
34
|
+
config?: BeignetConfig;
|
|
35
|
+
};
|
|
36
|
+
|
|
29
37
|
export async function createAnalysisWorkspace(
|
|
30
38
|
cwd = process.cwd(),
|
|
39
|
+
options: AnalysisWorkspaceOptions = {},
|
|
31
40
|
): Promise<AnalysisWorkspace> {
|
|
32
41
|
const targetDir = path.resolve(cwd);
|
|
33
42
|
await assertDirectory(targetDir);
|
|
34
43
|
const files = await listProjectFiles(targetDir);
|
|
35
44
|
const fileSet = new Set(files);
|
|
36
|
-
const config =
|
|
37
|
-
|
|
45
|
+
const config = options.config
|
|
46
|
+
? resolveConfig(options.config)
|
|
47
|
+
: await loadBeignetConfig(targetDir, files);
|
|
48
|
+
const { compilerConfigFiles, compilerOptions } =
|
|
49
|
+
resolveCompilerConfiguration(targetDir);
|
|
50
|
+
const moduleResolutionCache = ts.createModuleResolutionCache(
|
|
51
|
+
targetDir,
|
|
52
|
+
ts.sys.useCaseSensitiveFileNames
|
|
53
|
+
? (fileName) => fileName
|
|
54
|
+
: (fileName) => fileName.toLowerCase(),
|
|
55
|
+
compilerOptions,
|
|
56
|
+
);
|
|
38
57
|
const sources = new Map<string, string>();
|
|
39
58
|
const sourceFiles = new Map<string, ts.SourceFile>();
|
|
40
59
|
|
|
@@ -53,6 +72,8 @@ export async function createAnalysisWorkspace(
|
|
|
53
72
|
fileSet,
|
|
54
73
|
config,
|
|
55
74
|
compilerOptions,
|
|
75
|
+
compilerConfigFiles,
|
|
76
|
+
moduleResolutionCache,
|
|
56
77
|
readSource,
|
|
57
78
|
async readSourceFile(file) {
|
|
58
79
|
const cached = sourceFiles.get(file);
|
|
@@ -111,7 +132,7 @@ export async function listProjectFiles(targetDir: string): Promise<string[]> {
|
|
|
111
132
|
export function resolveLocalSourceFile(
|
|
112
133
|
workspace: Pick<
|
|
113
134
|
AnalysisWorkspace,
|
|
114
|
-
"compilerOptions" | "fileSet" | "targetDir"
|
|
135
|
+
"compilerOptions" | "fileSet" | "moduleResolutionCache" | "targetDir"
|
|
115
136
|
>,
|
|
116
137
|
importerFile: string,
|
|
117
138
|
importPath: string,
|
|
@@ -126,10 +147,62 @@ export function resolveLocalSourceFile(
|
|
|
126
147
|
return workspace.fileSet.has(file) ? file : undefined;
|
|
127
148
|
}
|
|
128
149
|
|
|
150
|
+
export function resolveLocalModulePath(
|
|
151
|
+
workspace: Pick<
|
|
152
|
+
AnalysisWorkspace,
|
|
153
|
+
"compilerOptions" | "fileSet" | "moduleResolutionCache" | "targetDir"
|
|
154
|
+
>,
|
|
155
|
+
importerFile: string,
|
|
156
|
+
importPath: string,
|
|
157
|
+
): string | undefined {
|
|
158
|
+
const resolvedFile = resolveLocalSourceFile(
|
|
159
|
+
workspace,
|
|
160
|
+
importerFile,
|
|
161
|
+
importPath,
|
|
162
|
+
);
|
|
163
|
+
if (resolvedFile) return resolvedFile;
|
|
164
|
+
|
|
165
|
+
if (!isLocalModuleSpecifier(workspace, importerFile, importPath)) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (importPath.startsWith(".")) {
|
|
170
|
+
return normalizePath(path.join(path.dirname(importerFile), importPath));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const baseUrl = compilerPathsBase(
|
|
174
|
+
workspace.compilerOptions,
|
|
175
|
+
workspace.targetDir,
|
|
176
|
+
);
|
|
177
|
+
for (const [pattern, targets] of Object.entries(
|
|
178
|
+
workspace.compilerOptions.paths ?? {},
|
|
179
|
+
)) {
|
|
180
|
+
if (pattern === "*") continue;
|
|
181
|
+
const wildcardValue = modulePatternWildcard(pattern, importPath);
|
|
182
|
+
if (wildcardValue === undefined) continue;
|
|
183
|
+
|
|
184
|
+
for (const target of targets) {
|
|
185
|
+
const substituted = target.replace("*", wildcardValue);
|
|
186
|
+
const absolute = path.resolve(baseUrl, substituted);
|
|
187
|
+
const relative = normalizePath(
|
|
188
|
+
path.relative(workspace.targetDir, absolute),
|
|
189
|
+
);
|
|
190
|
+
if (relative !== ".." && !relative.startsWith("../")) return relative;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const relative = normalizePath(
|
|
195
|
+
path.relative(workspace.targetDir, path.resolve(baseUrl, importPath)),
|
|
196
|
+
);
|
|
197
|
+
return relative !== ".." && !relative.startsWith("../")
|
|
198
|
+
? relative
|
|
199
|
+
: undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
129
202
|
export function isLocalModuleSpecifier(
|
|
130
203
|
workspace: Pick<
|
|
131
204
|
AnalysisWorkspace,
|
|
132
|
-
"compilerOptions" | "fileSet" | "targetDir"
|
|
205
|
+
"compilerOptions" | "fileSet" | "moduleResolutionCache" | "targetDir"
|
|
133
206
|
>,
|
|
134
207
|
importerFile: string,
|
|
135
208
|
importPath: string,
|
|
@@ -180,7 +253,10 @@ export function isLocalModuleSpecifier(
|
|
|
180
253
|
}
|
|
181
254
|
|
|
182
255
|
function resolveModule(
|
|
183
|
-
workspace: Pick<
|
|
256
|
+
workspace: Pick<
|
|
257
|
+
AnalysisWorkspace,
|
|
258
|
+
"compilerOptions" | "moduleResolutionCache" | "targetDir"
|
|
259
|
+
>,
|
|
184
260
|
importerFile: string,
|
|
185
261
|
importPath: string,
|
|
186
262
|
): ts.ResolvedModuleFull | undefined {
|
|
@@ -189,6 +265,7 @@ function resolveModule(
|
|
|
189
265
|
path.join(workspace.targetDir, importerFile),
|
|
190
266
|
workspace.compilerOptions,
|
|
191
267
|
ts.sys,
|
|
268
|
+
workspace.moduleResolutionCache,
|
|
192
269
|
).resolvedModule;
|
|
193
270
|
}
|
|
194
271
|
|
|
@@ -201,16 +278,64 @@ function modulePatternMatches(pattern: string, importPath: string): boolean {
|
|
|
201
278
|
);
|
|
202
279
|
}
|
|
203
280
|
|
|
204
|
-
function
|
|
205
|
-
|
|
281
|
+
function modulePatternWildcard(
|
|
282
|
+
pattern: string,
|
|
283
|
+
importPath: string,
|
|
284
|
+
): string | undefined {
|
|
285
|
+
const wildcard = pattern.indexOf("*");
|
|
286
|
+
if (wildcard === -1) return pattern === importPath ? "" : undefined;
|
|
287
|
+
|
|
288
|
+
const prefix = pattern.slice(0, wildcard);
|
|
289
|
+
const suffix = pattern.slice(wildcard + 1);
|
|
290
|
+
if (!importPath.startsWith(prefix) || !importPath.endsWith(suffix)) {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
return importPath.slice(prefix.length, importPath.length - suffix.length);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function resolveCompilerConfiguration(targetDir: string): {
|
|
297
|
+
compilerConfigFiles: string[];
|
|
298
|
+
compilerOptions: ts.CompilerOptions;
|
|
299
|
+
} {
|
|
300
|
+
const compilerConfigFiles = new Set<string>();
|
|
301
|
+
const configPath = path.join(targetDir, "tsconfig.json");
|
|
302
|
+
const compilerOptions =
|
|
206
303
|
ts.getParsedCommandLineOfConfigFile(
|
|
207
|
-
|
|
304
|
+
configPath,
|
|
208
305
|
{},
|
|
209
306
|
{
|
|
210
307
|
...ts.sys,
|
|
308
|
+
readFile(file) {
|
|
309
|
+
compilerConfigFiles.add(path.resolve(file));
|
|
310
|
+
return ts.sys.readFile(file);
|
|
311
|
+
},
|
|
211
312
|
onUnRecoverableConfigFileDiagnostic: () => {},
|
|
212
313
|
},
|
|
213
|
-
)?.options ?? {}
|
|
314
|
+
)?.options ?? {};
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
compilerConfigFiles: [...compilerConfigFiles].sort(),
|
|
318
|
+
compilerOptions: compilerOptions.paths
|
|
319
|
+
? compilerOptions
|
|
320
|
+
: {
|
|
321
|
+
...compilerOptions,
|
|
322
|
+
baseUrl: compilerOptions.baseUrl ?? targetDir,
|
|
323
|
+
paths: {
|
|
324
|
+
"@/*": ["*"],
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function compilerPathsBase(
|
|
331
|
+
compilerOptions: ts.CompilerOptions,
|
|
332
|
+
targetDir: string,
|
|
333
|
+
): string {
|
|
334
|
+
const optionsWithPathBase = compilerOptions as ts.CompilerOptions & {
|
|
335
|
+
pathsBasePath?: string;
|
|
336
|
+
};
|
|
337
|
+
return (
|
|
338
|
+
compilerOptions.baseUrl ?? optionsWithPathBase.pathsBasePath ?? targetDir
|
|
214
339
|
);
|
|
215
340
|
}
|
|
216
341
|
|