@shapeshift-labs/frontier-lang-compiler 0.2.59 → 0.2.60
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/internal/index-impl/createLightweightNativeImport.js +12 -0
- package/dist/internal/index-impl/createLightweightSemanticLayers.js +1 -1
- package/dist/lightweight-dependency-language.js +223 -0
- package/dist/lightweight-dependency-relations.js +18 -151
- package/dist/semantic-import-source-preservation.js +2 -2
- package/package.json +1 -1
|
@@ -109,6 +109,18 @@ export function createLightweightNativeImport(input) {
|
|
|
109
109
|
occurrences.push(...dependencies.occurrences);
|
|
110
110
|
relations.push(...dependencies.relations);
|
|
111
111
|
facts.push(...dependencies.facts);
|
|
112
|
+
for (const occurrence of dependencies.occurrences) {
|
|
113
|
+
mappings.push({
|
|
114
|
+
id: `map_${idFragment(occurrence.id)}`,
|
|
115
|
+
nativeAstNodeId: occurrence.nativeAstNodeId,
|
|
116
|
+
semanticSymbolId: occurrence.symbolId,
|
|
117
|
+
semanticOccurrenceId: occurrence.id,
|
|
118
|
+
sourceSpan: occurrence.span,
|
|
119
|
+
evidenceIds: [evidenceId],
|
|
120
|
+
lossIds: [],
|
|
121
|
+
precision: 'line'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
112
124
|
losses.push(...lightweightCoverageLosses(input, declarations, input.sourcePreservation));
|
|
113
125
|
|
|
114
126
|
const semanticIndex = createSemanticIndexRecord({
|
|
@@ -48,7 +48,7 @@ export function createLightweightSemanticLayers(input) {
|
|
|
48
48
|
})),
|
|
49
49
|
evaluationModels: [evaluationModel(input, evidenceIds)],
|
|
50
50
|
effectRegions: effectRegions(input, evidenceIds),
|
|
51
|
-
loweringRecords: mappings.
|
|
51
|
+
loweringRecords: mappings.map((mapping) => ({
|
|
52
52
|
id: `lowering_${mapping.id}`,
|
|
53
53
|
kind: 'nativeSourceToFrontierSemanticIndex',
|
|
54
54
|
sourceMapId: mapping.sourceMapId,
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
const ignoredIdentifiers = new Set([
|
|
2
|
+
'abstract', 'alias', 'and', 'as', 'async', 'await', 'break', 'case', 'catch',
|
|
3
|
+
'class', 'const', 'continue', 'def', 'default', 'defer', 'delete', 'do',
|
|
4
|
+
'else', 'enum', 'export', 'extends', 'false', 'finally', 'fn', 'for', 'from',
|
|
5
|
+
'func', 'function', 'if', 'impl', 'import', 'in', 'interface', 'let', 'match',
|
|
6
|
+
'mod', 'module', 'namespace', 'new', 'nil', 'none', 'not', 'null', 'or',
|
|
7
|
+
'package', 'pass', 'protocol', 'pub', 'public', 'return', 'self', 'static',
|
|
8
|
+
'struct', 'super', 'switch', 'this', 'throw', 'trait', 'true', 'try', 'type',
|
|
9
|
+
'undefined', 'use', 'using', 'var', 'void', 'while', 'with', 'yield'
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export function dependencyIdentifiers(input, declaration, line) {
|
|
13
|
+
const identifiers = new Set();
|
|
14
|
+
addIdentifier(identifiers, declaration.name);
|
|
15
|
+
for (const part of splitIdentifierPath(declaration.name)) addIdentifier(identifiers, part);
|
|
16
|
+
for (const field of ['methodName', 'propertyName', 'owner']) addIdentifier(identifiers, declaration.fields?.[field]);
|
|
17
|
+
if (declaration.role === 'import') {
|
|
18
|
+
for (const identifier of importLineIdentifiers(input, line)) addIdentifier(identifiers, identifier);
|
|
19
|
+
for (const identifier of importPathIdentifiers(declaration.importPath ?? declaration.name)) addIdentifier(identifiers, identifier);
|
|
20
|
+
}
|
|
21
|
+
return [...identifiers];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function addIdentifier(set, value) {
|
|
25
|
+
if (isDependencyIdentifier(value)) set.add(String(value));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isDependencyIdentifier(value) {
|
|
29
|
+
const text = String(value ?? '');
|
|
30
|
+
return /^[A-Za-z_$][\w$]*$/.test(text) && !ignoredIdentifiers.has(text.toLowerCase());
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function dependencyScanRanges(input, declarations, lines) {
|
|
34
|
+
const ordered = [...(declarations ?? [])].sort((left, right) => (left.span?.startLine ?? 0) - (right.span?.startLine ?? 0));
|
|
35
|
+
return ordered
|
|
36
|
+
.filter((declaration) => declaration?.symbolId && declaration.role !== 'import')
|
|
37
|
+
.map((declaration, index) => ({
|
|
38
|
+
declaration,
|
|
39
|
+
startLine: declaration.span?.startLine ?? 1,
|
|
40
|
+
endLine: dependencyScanEndLine(input, declaration, lines, ordered[index + 1]?.span?.startLine)
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function maskDependencyLine(input, line, state) {
|
|
45
|
+
const language = String(input.language ?? '').toLowerCase();
|
|
46
|
+
const text = String(line ?? '');
|
|
47
|
+
let output = '';
|
|
48
|
+
let quote;
|
|
49
|
+
let escaped = false;
|
|
50
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
51
|
+
const char = text[index];
|
|
52
|
+
const next = text[index + 1];
|
|
53
|
+
if (state.inBlockComment) {
|
|
54
|
+
output += ' ';
|
|
55
|
+
if (char === '*' && next === '/') {
|
|
56
|
+
output += ' ';
|
|
57
|
+
index += 1;
|
|
58
|
+
state.inBlockComment = false;
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (quote) {
|
|
63
|
+
output += ' ';
|
|
64
|
+
if (escaped) escaped = false;
|
|
65
|
+
else if (char === '\\') escaped = true;
|
|
66
|
+
else if (char === quote) quote = undefined;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (char === '/' && next === '*') {
|
|
70
|
+
output += ' ';
|
|
71
|
+
index += 1;
|
|
72
|
+
state.inBlockComment = true;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (startsLineComment(language, char, next, text, index)) break;
|
|
76
|
+
if (char === '\'' || char === '"' || char === '`') {
|
|
77
|
+
output += ' ';
|
|
78
|
+
quote = char;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
output += char;
|
|
82
|
+
}
|
|
83
|
+
return output;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function emptyDependencySummary() {
|
|
87
|
+
return { total: 0, calls: 0, uses: 0 };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function importLineIdentifiers(input, line) {
|
|
91
|
+
const language = String(input.language ?? '').toLowerCase();
|
|
92
|
+
const source = String(line ?? '').trim();
|
|
93
|
+
if (language === 'python') return pythonImportIdentifiers(source);
|
|
94
|
+
if (language === 'rust') return rustImportIdentifiers(source);
|
|
95
|
+
if (language === 'go') return aliasedPathImportIdentifiers(source);
|
|
96
|
+
if (language === 'javascript' || language === 'typescript') return jsImportIdentifiers(source);
|
|
97
|
+
if (language === 'haskell') return haskellImportIdentifiers(source);
|
|
98
|
+
return aliasedPathImportIdentifiers(source);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function jsImportIdentifiers(source) {
|
|
102
|
+
const identifiers = [];
|
|
103
|
+
let match = source.match(/^import\s+([A-Za-z_$][\w$]*)\s+from\b/);
|
|
104
|
+
if (match) identifiers.push(match[1]);
|
|
105
|
+
match = source.match(/^import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\b/);
|
|
106
|
+
if (match) identifiers.push(match[1]);
|
|
107
|
+
match = source.match(/^import\s+[^,{]+,\s*\{([^}]+)\}\s+from\b|^import\s+\{([^}]+)\}\s+from\b/);
|
|
108
|
+
if (match) identifiers.push(...namedImportIdentifiers(match[1] ?? match[2]));
|
|
109
|
+
return identifiers;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function pythonImportIdentifiers(source) {
|
|
113
|
+
const identifiers = [];
|
|
114
|
+
const importMatch = source.match(/^import\s+(.+)$/);
|
|
115
|
+
if (importMatch) identifiers.push(...commaParts(importMatch[1]).map((part) => part.split(/\s+as\s+/i).pop()));
|
|
116
|
+
const fromMatch = source.match(/^from\s+\S+\s+import\s+(.+)$/);
|
|
117
|
+
if (fromMatch) identifiers.push(...namedImportIdentifiers(fromMatch[1]));
|
|
118
|
+
return identifiers;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function rustImportIdentifiers(source) {
|
|
122
|
+
const match = source.match(/^use\s+(.+?);?$/);
|
|
123
|
+
if (!match) return [];
|
|
124
|
+
const raw = match[1].replace(/[{}]/g, ' ');
|
|
125
|
+
return raw.split(/::|,|\s+as\s+/i).map((part) => part.trim()).filter(Boolean);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function haskellImportIdentifiers(source) {
|
|
129
|
+
const match = source.match(/^import\s+(?:qualified\s+)?([A-Za-z_][\w.]*)(?:\s+as\s+([A-Za-z_]\w*))?/);
|
|
130
|
+
return match ? [match[2], ...splitIdentifierPath(match[1])].filter(Boolean) : [];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function aliasedPathImportIdentifiers(source) {
|
|
134
|
+
const alias = source.match(/^(?:import|using|use)\s+([A-Za-z_$][\w$]*)\s*=/)?.[1]
|
|
135
|
+
?? source.match(/^(?:import|using|use)\s+([A-Za-z_$][\w$]*)\s+["']/)?.[1]
|
|
136
|
+
?? source.match(/\bas\s+([A-Za-z_$][\w$]*)\b/)?.[1];
|
|
137
|
+
return alias ? [alias] : [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function namedImportIdentifiers(raw) {
|
|
141
|
+
return commaParts(raw).map((part) => part.trim().split(/\s+as\s+/i).pop()?.trim()).filter(Boolean);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function importPathIdentifiers(value) {
|
|
145
|
+
return splitIdentifierPath(String(value ?? '').replace(/['";]/g, ''));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function splitIdentifierPath(value) {
|
|
149
|
+
return String(value ?? '').split(/[^A-Za-z0-9_$]+/).filter(isDependencyIdentifier);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function commaParts(raw) {
|
|
153
|
+
return String(raw ?? '').split(',').map((part) => part.trim()).filter(Boolean);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function dependencyScanEndLine(input, declaration, lines, nextStartLine) {
|
|
157
|
+
const startLine = declaration.span?.startLine ?? 1;
|
|
158
|
+
if (!declaration.metadata?.hasBody) return startLine;
|
|
159
|
+
if (usesIndentationBlocks(input)) {
|
|
160
|
+
return indentationRegionEndLine(lines, startLine);
|
|
161
|
+
}
|
|
162
|
+
const balancedEnd = balancedRegionEndLine(lines, startLine);
|
|
163
|
+
const fallbackEnd = nextStartLine ? nextStartLine - 1 : lines.length;
|
|
164
|
+
return Math.max(startLine, Math.min(balancedEnd > startLine ? balancedEnd : fallbackEnd, lines.length));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function usesIndentationBlocks(input) {
|
|
168
|
+
return ['python'].includes(String(input.language ?? '').toLowerCase());
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function indentationRegionEndLine(lines, startLine) {
|
|
172
|
+
const header = lines[startLine - 1]?.line ?? '';
|
|
173
|
+
const baseIndent = indentationWidth(header);
|
|
174
|
+
let lastBodyLine = startLine;
|
|
175
|
+
let sawBodyLine = false;
|
|
176
|
+
for (let index = startLine; index < lines.length; index += 1) {
|
|
177
|
+
const line = lines[index]?.line ?? '';
|
|
178
|
+
if (!line.trim()) {
|
|
179
|
+
if (sawBodyLine) lastBodyLine = index + 1;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const indent = indentationWidth(line);
|
|
183
|
+
if (indent <= baseIndent) return Math.max(startLine, lastBodyLine);
|
|
184
|
+
sawBodyLine = true;
|
|
185
|
+
lastBodyLine = index + 1;
|
|
186
|
+
}
|
|
187
|
+
return lastBodyLine;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function indentationWidth(line) {
|
|
191
|
+
let width = 0;
|
|
192
|
+
for (const char of String(line ?? '')) {
|
|
193
|
+
if (char === ' ') width += 1;
|
|
194
|
+
else if (char === '\t') width += 4;
|
|
195
|
+
else break;
|
|
196
|
+
}
|
|
197
|
+
return width;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function balancedRegionEndLine(lines, startLine) {
|
|
201
|
+
const state = { inBlockComment: false };
|
|
202
|
+
let depth = 0;
|
|
203
|
+
let opened = false;
|
|
204
|
+
for (let index = Math.max(0, startLine - 1); index < lines.length; index += 1) {
|
|
205
|
+
for (const char of maskDependencyLine({ language: 'javascript' }, lines[index].line, state)) {
|
|
206
|
+
if (char === '{' || char === '[' || char === '(') {
|
|
207
|
+
depth += 1;
|
|
208
|
+
opened = true;
|
|
209
|
+
} else if (char === '}' || char === ']' || char === ')') {
|
|
210
|
+
depth -= 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (opened && depth <= 0) return lines[index].number;
|
|
214
|
+
}
|
|
215
|
+
return startLine;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function startsLineComment(language, char, next, text, index) {
|
|
219
|
+
if (char === '/' && next === '/') return true;
|
|
220
|
+
if (char === '#' && !['csharp'].includes(language)) return true;
|
|
221
|
+
if (char === '-' && next === '-' && ['sql', 'haskell', 'lua'].includes(language)) return true;
|
|
222
|
+
return text.startsWith('rem ', index) && language === 'shell';
|
|
223
|
+
}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import { idFragment } from './native-import-utils.js';
|
|
2
|
+
import {
|
|
3
|
+
addIdentifier,
|
|
4
|
+
dependencyIdentifiers,
|
|
5
|
+
dependencyScanRanges,
|
|
6
|
+
emptyDependencySummary,
|
|
7
|
+
isDependencyIdentifier,
|
|
8
|
+
maskDependencyLine
|
|
9
|
+
} from './lightweight-dependency-language.js';
|
|
2
10
|
import { sourceLines } from './native-region-scanner-core.js';
|
|
3
11
|
|
|
4
|
-
const jsLikeLanguages = new Set(['javascript', 'typescript']);
|
|
5
|
-
const ignoredIdentifiers = new Set([
|
|
6
|
-
'async', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'default',
|
|
7
|
-
'delete', 'do', 'else', 'export', 'extends', 'false', 'finally', 'for', 'from',
|
|
8
|
-
'function', 'if', 'import', 'in', 'instanceof', 'let', 'new', 'null', 'of',
|
|
9
|
-
'return', 'static', 'super', 'switch', 'this', 'throw', 'true', 'try', 'typeof',
|
|
10
|
-
'undefined', 'var', 'void', 'while', 'with', 'yield'
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
12
|
export function lightweightDependencyRelations(input, declarations, documentId) {
|
|
14
|
-
if (
|
|
15
|
-
return { relations: [], occurrences: [], facts: [], summary: emptySummary() };
|
|
16
|
-
}
|
|
13
|
+
if (typeof input.sourceText !== 'string') return { relations: [], occurrences: [], facts: [], summary: emptyDependencySummary() };
|
|
17
14
|
const lines = sourceLines(input.sourceText);
|
|
18
15
|
const identifiers = declarationIdentifierMap(input, declarations, lines);
|
|
19
16
|
const records = { relations: [], occurrences: [], facts: [], seen: new Set() };
|
|
20
|
-
for (const scan of
|
|
17
|
+
for (const scan of dependencyScanRanges(input, declarations, lines)) {
|
|
21
18
|
scanDeclarationDependencies(input, documentId, scan, identifiers, lines, records);
|
|
22
19
|
}
|
|
23
20
|
return {
|
|
@@ -52,101 +49,27 @@ function declarationIdentifierMap(input, declarations, lines) {
|
|
|
52
49
|
|
|
53
50
|
function identifiersForDeclaration(input, declaration, lines) {
|
|
54
51
|
const identifiers = new Set();
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
if (declaration.role === 'import') {
|
|
59
|
-
const line = lines[(declaration.span?.startLine ?? 1) - 1]?.line ?? '';
|
|
60
|
-
for (const identifier of importLocalIdentifiers(line)) addIdentifier(identifiers, identifier);
|
|
61
|
-
addIdentifier(identifiers, packageIdentifier(declaration.importPath ?? declaration.name));
|
|
52
|
+
const line = lines[(declaration.span?.startLine ?? 1) - 1]?.line ?? '';
|
|
53
|
+
for (const identifier of dependencyIdentifiers(input, declaration, line)) {
|
|
54
|
+
addIdentifier(identifiers, identifier);
|
|
62
55
|
}
|
|
63
56
|
return [...identifiers];
|
|
64
57
|
}
|
|
65
58
|
|
|
66
|
-
function importLocalIdentifiers(line) {
|
|
67
|
-
const source = String(line ?? '');
|
|
68
|
-
const identifiers = [];
|
|
69
|
-
let match = source.match(/^import\s+([A-Za-z_$][\w$]*)\s+from\b/);
|
|
70
|
-
if (match) identifiers.push(match[1]);
|
|
71
|
-
match = source.match(/^import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\b/);
|
|
72
|
-
if (match) identifiers.push(match[1]);
|
|
73
|
-
match = source.match(/^import\s+[^,{]+,\s*\{([^}]+)\}\s+from\b/);
|
|
74
|
-
if (match) identifiers.push(...namedImportIdentifiers(match[1]));
|
|
75
|
-
match = source.match(/^import\s+\{([^}]+)\}\s+from\b/);
|
|
76
|
-
if (match) identifiers.push(...namedImportIdentifiers(match[1]));
|
|
77
|
-
return identifiers;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function namedImportIdentifiers(raw) {
|
|
81
|
-
return String(raw ?? '')
|
|
82
|
-
.split(',')
|
|
83
|
-
.map((part) => part.trim().split(/\s+as\s+/i).pop()?.trim())
|
|
84
|
-
.filter(Boolean);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function packageIdentifier(value) {
|
|
88
|
-
const parts = String(value ?? '').split('/').filter(Boolean);
|
|
89
|
-
const last = parts[parts.length - 1] ?? value;
|
|
90
|
-
return String(last).replace(/[^A-Za-z0-9_$]/g, '');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
59
|
function addIdentifierTarget(map, identifier, target) {
|
|
94
|
-
if (!
|
|
60
|
+
if (!isDependencyIdentifier(identifier)) return;
|
|
95
61
|
const existing = map.get(identifier) ?? [];
|
|
96
62
|
if (!existing.some((entry) => entry.symbolId === target.symbolId)) existing.push(target);
|
|
97
63
|
map.set(identifier, existing);
|
|
98
64
|
}
|
|
99
65
|
|
|
100
|
-
function addIdentifier(set, value) {
|
|
101
|
-
if (isIdentifier(value)) set.add(value);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function isIdentifier(value) {
|
|
105
|
-
const text = String(value ?? '');
|
|
106
|
-
return /^[A-Za-z_$][\w$]*$/.test(text) && !ignoredIdentifiers.has(text);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function declarationScanRanges(declarations, lines) {
|
|
110
|
-
return (declarations ?? [])
|
|
111
|
-
.filter((declaration) => declaration?.symbolId && declaration.role !== 'import')
|
|
112
|
-
.map((declaration) => ({
|
|
113
|
-
declaration,
|
|
114
|
-
startLine: declaration.span?.startLine ?? 1,
|
|
115
|
-
endLine: declarationScanEndLine(declaration, lines)
|
|
116
|
-
}));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function declarationScanEndLine(declaration, lines) {
|
|
120
|
-
const startLine = declaration.span?.startLine ?? 1;
|
|
121
|
-
if (!declaration.metadata?.hasBody || declaration.kind === 'ClassDeclaration') return startLine;
|
|
122
|
-
return balancedRegionEndLine(lines, startLine);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function balancedRegionEndLine(lines, startLine) {
|
|
126
|
-
const state = { inBlockComment: false, inTemplateString: false };
|
|
127
|
-
let depth = 0;
|
|
128
|
-
let opened = false;
|
|
129
|
-
for (let index = Math.max(0, startLine - 1); index < lines.length; index += 1) {
|
|
130
|
-
for (const char of maskReferenceLine(lines[index].line, state)) {
|
|
131
|
-
if (char === '{' || char === '[' || char === '(') {
|
|
132
|
-
depth += 1;
|
|
133
|
-
opened = true;
|
|
134
|
-
} else if (char === '}' || char === ']' || char === ')') {
|
|
135
|
-
depth -= 1;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (opened && depth <= 0) return lines[index].number;
|
|
139
|
-
}
|
|
140
|
-
return startLine;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
66
|
function scanDeclarationDependencies(input, documentId, scan, identifiers, lines, records) {
|
|
144
|
-
const state = { inBlockComment: false
|
|
67
|
+
const state = { inBlockComment: false };
|
|
145
68
|
for (let lineNumber = scan.startLine; lineNumber <= scan.endLine; lineNumber += 1) {
|
|
146
|
-
const scanLine =
|
|
69
|
+
const scanLine = maskDependencyLine(input, lines[lineNumber - 1]?.line ?? '', state);
|
|
147
70
|
for (const match of scanLine.matchAll(/[A-Za-z_$][\w$]*/g)) {
|
|
148
71
|
const name = match[0];
|
|
149
|
-
if (
|
|
72
|
+
if (!isDependencyIdentifier(name) || !identifiers.has(name)) continue;
|
|
150
73
|
const targets = identifiers.get(name).filter((target) => target.symbolId !== scan.declaration.symbolId);
|
|
151
74
|
for (const target of targets) {
|
|
152
75
|
addDependencyRecord(input, documentId, scan.declaration, target, {
|
|
@@ -197,7 +120,7 @@ function addDependencyRecord(input, documentId, caller, target, occurrence, reco
|
|
|
197
120
|
nativeAstNodeId: caller.nodeId
|
|
198
121
|
});
|
|
199
122
|
records.facts.push({
|
|
200
|
-
id: `fact_${idFragment(relationId)}_lightweight_dependency`,
|
|
123
|
+
id: `fact_${idFragment(relationId)}_${records.facts.length + 1}_lightweight_dependency`,
|
|
201
124
|
predicate: 'lightweightDependency',
|
|
202
125
|
subjectId: caller.symbolId,
|
|
203
126
|
value: {
|
|
@@ -213,59 +136,3 @@ function addDependencyRecord(input, documentId, caller, target, occurrence, reco
|
|
|
213
136
|
function isCallReference(line, afterIdentifierIndex) {
|
|
214
137
|
return /^\s*\(/.test(String(line ?? '').slice(afterIdentifierIndex));
|
|
215
138
|
}
|
|
216
|
-
|
|
217
|
-
function maskReferenceLine(line, state) {
|
|
218
|
-
const text = String(line ?? '');
|
|
219
|
-
let output = '';
|
|
220
|
-
let quote;
|
|
221
|
-
let escaped = false;
|
|
222
|
-
for (let index = 0; index < text.length; index += 1) {
|
|
223
|
-
const char = text[index];
|
|
224
|
-
const next = text[index + 1];
|
|
225
|
-
if (state.inBlockComment) {
|
|
226
|
-
output += ' ';
|
|
227
|
-
if (char === '*' && next === '/') {
|
|
228
|
-
output += ' ';
|
|
229
|
-
index += 1;
|
|
230
|
-
state.inBlockComment = false;
|
|
231
|
-
}
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (state.inTemplateString) {
|
|
235
|
-
output += ' ';
|
|
236
|
-
if (char === '`' && !escaped) state.inTemplateString = false;
|
|
237
|
-
escaped = char === '\\' && !escaped;
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
if (quote) {
|
|
241
|
-
output += ' ';
|
|
242
|
-
if (escaped) escaped = false;
|
|
243
|
-
else if (char === '\\') escaped = true;
|
|
244
|
-
else if (char === quote) quote = undefined;
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
if (char === '/' && next === '/') break;
|
|
248
|
-
if (char === '/' && next === '*') {
|
|
249
|
-
output += ' ';
|
|
250
|
-
index += 1;
|
|
251
|
-
state.inBlockComment = true;
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
if (char === '\'' || char === '"') {
|
|
255
|
-
output += ' ';
|
|
256
|
-
quote = char;
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
if (char === '`') {
|
|
260
|
-
output += ' ';
|
|
261
|
-
state.inTemplateString = true;
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
output += char;
|
|
265
|
-
}
|
|
266
|
-
return output;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function emptySummary() {
|
|
270
|
-
return { total: 0, calls: 0, uses: 0 };
|
|
271
|
-
}
|
|
@@ -46,9 +46,9 @@ function createKernelSourcePreservationRecords(input) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
for (const sourceMap of input.sourceMaps ?? []) {
|
|
49
|
-
for (const mapping of sourceMap.mappings ?? []) {
|
|
49
|
+
for (const [index, mapping] of (sourceMap.mappings ?? []).entries()) {
|
|
50
50
|
records.push(explainSourcePreservation({
|
|
51
|
-
id: `source_preservation_${idFragment(sourceMap.id)}_${idFragment(mapping.id)}`,
|
|
51
|
+
id: `source_preservation_${idFragment(sourceMap.id)}_${index + 1}_${idFragment(mapping.id)}`,
|
|
52
52
|
sourceMap,
|
|
53
53
|
mapping,
|
|
54
54
|
level: mapping.preservation,
|
package/package.json
CHANGED