@shapeshift-labs/frontier-lang-compiler 0.2.106 → 0.2.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/declarations/import-adapter-options-native.d.ts +3 -0
- package/dist/declarations/native-project.d.ts +3 -2
- package/dist/internal/index-impl/createNativeProjectImportResult.js +9 -5
- package/dist/internal/index-impl/createTypeScriptCompilerNativeImporterAdapter.js +4 -0
- package/dist/internal/index-impl/projectSymbolGraphModuleResolution.js +33 -0
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +2 -1
- package/dist/internal/index-impl/typeScriptDeclaration.js +62 -9
- package/dist/internal/index-impl/visitTypeScriptAstNode.js +1 -0
- package/package.json +1 -1
|
@@ -76,6 +76,9 @@ export interface TypeScriptCompilerNativeImporterAdapterOptions {
|
|
|
76
76
|
readonly diagnostics?: readonly NativeImporterAdapterDiagnostic[];
|
|
77
77
|
readonly typescript?: unknown;
|
|
78
78
|
readonly ts?: unknown;
|
|
79
|
+
readonly program?: { readonly getTypeChecker?: () => unknown } | unknown;
|
|
80
|
+
readonly typeChecker?: unknown;
|
|
81
|
+
readonly checker?: unknown;
|
|
79
82
|
readonly sourceFile?: unknown;
|
|
80
83
|
readonly createSourceFile?: (input: NativeImporterAdapterParseInput, typescript?: unknown) => unknown;
|
|
81
84
|
readonly scriptTarget?: unknown;
|
|
@@ -78,8 +78,6 @@ export interface ImportNativeProjectOptions {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export type NativeProjectSymbolGraphRemainingField =
|
|
81
|
-
| 'moduleEdges[].resolvedModulePath'
|
|
82
|
-
| 'moduleEdges[].targetDocumentId'
|
|
83
81
|
| 'moduleEdges[].resolvedTargetSymbolId'
|
|
84
82
|
| 'moduleEdges[].resolutionKind'
|
|
85
83
|
| 'moduleEdges[].packageName'
|
|
@@ -112,6 +110,9 @@ export interface NativeProjectSymbolGraphModuleEdgeRecord {
|
|
|
112
110
|
readonly sourcePath?: string;
|
|
113
111
|
readonly sourceHash?: string;
|
|
114
112
|
readonly moduleSpecifier?: string;
|
|
113
|
+
readonly resolvedModulePath?: string;
|
|
114
|
+
readonly targetDocumentId?: string;
|
|
115
|
+
readonly resolutionKind?: 'relative-source' | 'relative-missing' | string;
|
|
115
116
|
readonly importKind?: string;
|
|
116
117
|
readonly exportKind?: string;
|
|
117
118
|
readonly importedName?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import{idFragment,uniqueByEvidenceId,uniqueByLossId,uniqueStrings}from'../../native-import-utils.js';import{createDocument,createPatch,createUniversalAstEnvelope}from'@shapeshift-labs/frontier-lang-kernel';
|
|
2
2
|
import{createNativeImportResultContract}from'./createNativeImportResultContract.js';import{createProjectImportAdmissionRecord}from'./createProjectImportAdmissionRecord.js';import{mergeSemanticIndexes}from'./mergeSemanticIndexes.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';import{summarizeProjectSourcePreservation}from'./summarizeProjectSourcePreservation.js';
|
|
3
|
+
import{resolveRelativeProjectModule}from'./projectSymbolGraphModuleResolution.js';
|
|
3
4
|
export function createNativeProjectImportResult(input, imports) {
|
|
4
5
|
const idPart = idFragment(input.id ?? input.projectRoot ?? 'native_project');
|
|
5
6
|
const nodes = {};
|
|
@@ -140,8 +141,6 @@ export function createNativeProjectImportResult(input, imports) {
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
const PROJECT_SYMBOL_GRAPH_REMAINING_FIELDS = Object.freeze([
|
|
143
|
-
'moduleEdges[].resolvedModulePath',
|
|
144
|
-
'moduleEdges[].targetDocumentId',
|
|
145
144
|
'moduleEdges[].resolvedTargetSymbolId',
|
|
146
145
|
'moduleEdges[].resolutionKind',
|
|
147
146
|
'moduleEdges[].packageName',
|
|
@@ -158,16 +157,17 @@ function createProjectSymbolGraphSummary(semanticIndex, imports, input) {
|
|
|
158
157
|
const documents = semanticIndex?.documents ?? [];
|
|
159
158
|
const symbolsById = new Map((semanticIndex?.symbols ?? []).map((symbol) => [symbol.id, symbol]));
|
|
160
159
|
const documentsById = new Map(documents.map((document) => [document.id, document]));
|
|
160
|
+
const documentsByPath = new Map(documents.filter((document) => document.path).map((document) => [document.path, document]));
|
|
161
161
|
const facts = semanticIndex?.facts ?? [];
|
|
162
162
|
const moduleEdgeFacts = facts.filter((fact) => fact.predicate === 'moduleEdge');
|
|
163
163
|
const moduleEdgeByRelation = new Map(moduleEdgeFacts.map((fact) => [fact.subjectId, fact]));
|
|
164
164
|
const relations = semanticIndex?.relations ?? [];
|
|
165
165
|
const importEdges = relations
|
|
166
166
|
.filter((relation) => relation.predicate === 'imports')
|
|
167
|
-
.map((relation) => moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById));
|
|
167
|
+
.map((relation) => moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById, documentsByPath));
|
|
168
168
|
const exportEdges = relations
|
|
169
169
|
.filter((relation) => relation.predicate === 'exports')
|
|
170
|
-
.map((relation) => moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById));
|
|
170
|
+
.map((relation) => moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById, documentsByPath));
|
|
171
171
|
const reExportIdentities = uniqueRecords([
|
|
172
172
|
...facts
|
|
173
173
|
.filter((fact) => fact.predicate === 'reExportIdentity' && fact.value)
|
|
@@ -213,7 +213,7 @@ function createProjectSymbolGraphSummary(semanticIndex, imports, input) {
|
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
function moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById) {
|
|
216
|
+
function moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documentsById, documentsByPath) {
|
|
217
217
|
const fact = moduleEdgeByRelation.get(relation.id);
|
|
218
218
|
const value = objectValue(fact?.value);
|
|
219
219
|
const metadata = objectValue(relation.metadata);
|
|
@@ -228,6 +228,7 @@ function moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documents
|
|
|
228
228
|
symbolMetadata.moduleSpecifier,
|
|
229
229
|
symbol?.kind === 'module' ? symbol.name : undefined
|
|
230
230
|
);
|
|
231
|
+
const resolution = resolveRelativeProjectModule(document?.path, moduleSpecifier, documentsByPath);
|
|
231
232
|
return compactRecord({
|
|
232
233
|
id: relation.id,
|
|
233
234
|
sourceDocumentId: relation.sourceId,
|
|
@@ -237,6 +238,9 @@ function moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documents
|
|
|
237
238
|
sourcePath: document?.path,
|
|
238
239
|
sourceHash: document?.sourceHash,
|
|
239
240
|
moduleSpecifier,
|
|
241
|
+
resolvedModulePath: resolution?.path,
|
|
242
|
+
targetDocumentId: resolution?.documentId,
|
|
243
|
+
resolutionKind: resolution?.kind,
|
|
240
244
|
importKind: firstString(moduleEdge.importKind, value.importKind),
|
|
241
245
|
exportKind: firstString(moduleEdge.exportKind, value.exportKind),
|
|
242
246
|
importedName: firstString(moduleEdge.importedName, value.importedName),
|
|
@@ -25,6 +25,8 @@ export function createTypeScriptCompilerNativeImporterAdapter(options = {}) {
|
|
|
25
25
|
diagnostics: options.diagnostics,
|
|
26
26
|
parse(input) {
|
|
27
27
|
const ts = options.typescript ?? options.ts ?? input.options?.typescript ?? input.options?.ts;
|
|
28
|
+
const program = options.program ?? input.options?.program;
|
|
29
|
+
const typeChecker = options.typeChecker ?? options.checker ?? input.options?.typeChecker ?? input.options?.checker ?? program?.getTypeChecker?.();
|
|
28
30
|
const sourceFile = input.options?.sourceFile ?? input.options?.ast ?? options.sourceFile ?? createTypeScriptSourceFile(ts, input, options);
|
|
29
31
|
if (!sourceFile) {
|
|
30
32
|
return missingInjectedParserResult(input, {
|
|
@@ -37,6 +39,8 @@ export function createTypeScriptCompilerNativeImporterAdapter(options = {}) {
|
|
|
37
39
|
parser: options.parser ?? 'typescript-compiler-api',
|
|
38
40
|
astFormat: 'typescript-compiler-api',
|
|
39
41
|
ts,
|
|
42
|
+
program,
|
|
43
|
+
typeChecker,
|
|
40
44
|
maxNodes: options.maxNodes,
|
|
41
45
|
includeTokens: options.includeTokens
|
|
42
46
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function resolveRelativeProjectModule(sourcePath, moduleSpecifier, documentsByPath) {
|
|
2
|
+
if (!sourcePath || !moduleSpecifier || !moduleSpecifier.startsWith('.')) return undefined;
|
|
3
|
+
const base = sourcePath.includes('/') ? sourcePath.slice(0, sourcePath.lastIndexOf('/')) : '';
|
|
4
|
+
const unresolvedPath = normalizeProjectPath(`${base}/${moduleSpecifier}`);
|
|
5
|
+
const target = moduleTargetDocument(unresolvedPath, documentsByPath);
|
|
6
|
+
return {
|
|
7
|
+
path: target?.path ?? unresolvedPath,
|
|
8
|
+
documentId: target?.id,
|
|
9
|
+
kind: target ? 'relative-source' : 'relative-missing'
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function moduleTargetDocument(path, documentsByPath) {
|
|
14
|
+
for (const candidate of modulePathCandidates(path)) {
|
|
15
|
+
const document = documentsByPath.get(candidate);
|
|
16
|
+
if (document) return document;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function modulePathCandidates(path) {
|
|
22
|
+
return [path, `${path}.js`, `${path}.ts`, `${path}.tsx`, `${path}.jsx`, `${path}/index.js`, `${path}/index.ts`];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeProjectPath(path) {
|
|
26
|
+
const parts = [];
|
|
27
|
+
for (const part of String(path).split('/')) {
|
|
28
|
+
if (!part || part === '.') continue;
|
|
29
|
+
if (part === '..') parts.pop();
|
|
30
|
+
else parts.push(part);
|
|
31
|
+
}
|
|
32
|
+
return parts.join('/');
|
|
33
|
+
}
|
|
@@ -35,6 +35,7 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
35
35
|
};
|
|
36
36
|
declaration.nativeNode.metadata = {
|
|
37
37
|
...declaration.nativeNode.metadata,
|
|
38
|
+
...declaration.metadata,
|
|
38
39
|
ownershipRegionId: ownershipRegion.id,
|
|
39
40
|
ownershipRegionKey: ownershipRegion.key,
|
|
40
41
|
ownershipRegionKind: ownershipRegion.regionKind,
|
|
@@ -47,7 +48,7 @@ export function semanticIndexFromNativeDeclarations(declarations, input, options
|
|
|
47
48
|
kind: declaration.symbolKind,
|
|
48
49
|
language: input.language,
|
|
49
50
|
nativeAstNodeId: declaration.nativeNode.id,
|
|
50
|
-
signatureHash: hashSemanticValue([input.language, declaration.nativeNode.kind, declaration.name, declaration.nativeNode.fields ?? {}]),
|
|
51
|
+
signatureHash: declaration.signatureHash ?? hashSemanticValue([input.language, declaration.nativeNode.kind, declaration.name, declaration.nativeNode.fields ?? {}]),
|
|
51
52
|
definitionSpan: declaration.nativeNode.span,
|
|
52
53
|
metadata: {
|
|
53
54
|
...declaration.nativeNode.metadata,
|
|
@@ -1,14 +1,67 @@
|
|
|
1
|
-
import{
|
|
2
|
-
|
|
1
|
+
import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';import{idFragment}from'../../native-import-utils.js';
|
|
2
|
+
import{declarationRecord}from'./declarationRecord.js';import{identifierName}from'./identifierName.js';import{namedDeclaration}from'./namedDeclaration.js';import{stringFromTsExpression}from'./stringFromTsExpression.js';
|
|
3
|
+
export function typeScriptDeclaration(node, kind, nativeNodeId, input, options = {}) {
|
|
4
|
+
const enrich = (declaration, symbolNode = node.name ?? node) => enrichTypeScriptDeclaration(node, symbolNode, declaration, input, options);
|
|
3
5
|
if (kind === 'ImportDeclaration' || kind === 'ImportEqualsDeclaration') {
|
|
4
6
|
const name = stringFromTsExpression(node.moduleSpecifier) ?? stringFromTsExpression(node.externalModuleReference?.expression);
|
|
5
|
-
if (name) return declarationRecord(input, nativeNodeId, name, 'module', 'import');
|
|
7
|
+
if (name) return enrich(declarationRecord(input, nativeNodeId, name, 'module', 'import'), node.moduleSpecifier ?? node.externalModuleReference?.expression ?? node);
|
|
6
8
|
}
|
|
7
|
-
if (kind === 'FunctionDeclaration') return namedDeclaration(input, nativeNodeId, node.name, 'function');
|
|
8
|
-
if (kind === 'ClassDeclaration') return namedDeclaration(input, nativeNodeId, node.name, 'class');
|
|
9
|
-
if (kind === 'InterfaceDeclaration') return namedDeclaration(input, nativeNodeId, node.name, 'interface');
|
|
10
|
-
if (kind === 'TypeAliasDeclaration' || kind === 'EnumDeclaration') return namedDeclaration(input, nativeNodeId, node.name, 'type');
|
|
11
|
-
if (kind === 'VariableDeclaration') return namedDeclaration(input, nativeNodeId, node.name, 'variable');
|
|
12
|
-
if (kind === 'MethodDeclaration' || kind === 'MethodSignature') return namedDeclaration(input, nativeNodeId, node.name, 'method');
|
|
9
|
+
if (kind === 'FunctionDeclaration') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'function'));
|
|
10
|
+
if (kind === 'ClassDeclaration') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'class'));
|
|
11
|
+
if (kind === 'InterfaceDeclaration') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'interface'));
|
|
12
|
+
if (kind === 'TypeAliasDeclaration' || kind === 'EnumDeclaration') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'type'));
|
|
13
|
+
if (kind === 'VariableDeclaration') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'variable'));
|
|
14
|
+
if (kind === 'MethodDeclaration' || kind === 'MethodSignature') return enrich(namedDeclaration(input, nativeNodeId, node.name, 'method'));
|
|
13
15
|
return undefined;
|
|
14
16
|
}
|
|
17
|
+
|
|
18
|
+
function enrichTypeScriptDeclaration(node, symbolNode, declaration, input, options) {
|
|
19
|
+
if (!declaration) return declaration;
|
|
20
|
+
const checker = options.typeChecker ?? options.checker ?? options.program?.getTypeChecker?.();
|
|
21
|
+
const symbol = safeCall(checker?.getSymbolAtLocation, checker, symbolNode) ?? safeCall(checker?.getSymbolAtLocation, checker, node.name);
|
|
22
|
+
if (!symbol) return declaration;
|
|
23
|
+
const aliasedSymbol = safeCall(checker?.getAliasedSymbol, checker, symbol);
|
|
24
|
+
const targetSymbol = aliasedSymbol && aliasedSymbol !== symbol ? aliasedSymbol : undefined;
|
|
25
|
+
const identitySymbol = targetSymbol ?? symbol;
|
|
26
|
+
const fullyQualifiedName = stringValue(safeCall(checker?.getFullyQualifiedName, checker, identitySymbol));
|
|
27
|
+
const localName = stringValue(symbol.escapedName ?? symbol.name) ?? declaration.name;
|
|
28
|
+
const targetName = targetSymbol ? stringValue(targetSymbol.escapedName ?? targetSymbol.name) : undefined;
|
|
29
|
+
const identity = fullyQualifiedName ?? targetName ?? localName;
|
|
30
|
+
const compilerSymbol = compactRecord({
|
|
31
|
+
parser: options.parser,
|
|
32
|
+
localName,
|
|
33
|
+
targetName,
|
|
34
|
+
fullyQualifiedName,
|
|
35
|
+
flags: numberValue(symbol.flags),
|
|
36
|
+
targetFlags: numberValue(targetSymbol?.flags),
|
|
37
|
+
declarations: Array.isArray(identitySymbol.declarations) ? identitySymbol.declarations.length : undefined,
|
|
38
|
+
aliased: Boolean(targetSymbol)
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
...declaration,
|
|
42
|
+
symbolId: `symbol:${input.language}:compiler:${declaration.role === 'import' ? 'import:' : ''}${idFragment(identity)}`,
|
|
43
|
+
signatureHash: hashSemanticValue([input.language, declaration.symbolKind, identity, compilerSymbol]),
|
|
44
|
+
metadata: {
|
|
45
|
+
...declaration.metadata,
|
|
46
|
+
compilerSymbol,
|
|
47
|
+
compilerSymbolIdentityHash: hashSemanticValue(compilerSymbol)
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function safeCall(fn, receiver, ...args) {
|
|
53
|
+
if (typeof fn !== 'function') return undefined;
|
|
54
|
+
try { return fn.apply(receiver, args); } catch { return undefined; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function stringValue(value) {
|
|
58
|
+
return value === undefined || value === null || value === '' ? undefined : String(value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function numberValue(value) {
|
|
62
|
+
return Number.isFinite(value) ? value : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function compactRecord(record) {
|
|
66
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
67
|
+
}
|
|
@@ -33,6 +33,7 @@ export function visitTypeScriptAstNode(node, sourceFile, context, propertyPath,
|
|
|
33
33
|
fields: primitiveTypeScriptFields(node, kind),
|
|
34
34
|
children,
|
|
35
35
|
metadata: {
|
|
36
|
+
...declaration?.metadata,
|
|
36
37
|
astFormat: context.options.astFormat,
|
|
37
38
|
propertyPath,
|
|
38
39
|
pos: numberOrUndefined(node.pos),
|
package/package.json
CHANGED