homegraph 1.6.2 → 1.6.4
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 +26 -0
- package/dist/bin/homegraph.js +15 -9
- package/dist/db/index.d.ts +21 -0
- package/dist/db/index.js +56 -0
- package/dist/directory.d.ts +17 -0
- package/dist/directory.js +40 -0
- package/dist/extraction/grammars.js +7 -0
- package/dist/extraction/index.d.ts +5 -0
- package/dist/extraction/index.js +162 -116
- package/dist/extraction/jsdoc-type-tags.d.ts +19 -0
- package/dist/extraction/jsdoc-type-tags.js +115 -0
- package/dist/extraction/languages/arkts.js +198 -31
- package/dist/extraction/store-flush-guard.d.ts +11 -0
- package/dist/extraction/store-flush-guard.js +19 -0
- package/dist/extraction/store-worker.d.ts +3 -2
- package/dist/extraction/store-worker.js +3 -2
- package/dist/extraction/tree-sitter.d.ts +8 -1
- package/dist/extraction/tree-sitter.js +52 -11
- package/dist/index.js +31 -1
- package/dist/resolution/callback-synthesizer.d.ts +12 -0
- package/dist/resolution/callback-synthesizer.js +5 -8
- package/dist/resolution/name-matcher.d.ts +5 -0
- package/dist/resolution/name-matcher.js +60 -1
- package/package.json +3 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 0066 — parse JSDoc `@returns` / `@param` type tags as a fallback when
|
|
3
|
+
* the signature has no usable return/param type name. Docstring text still
|
|
4
|
+
* lives on `nodes.docstring` (Spec 0020); this only extracts type *names*.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Unwrap Promise/Array/… and strip arrays/generics to a bare type identifier.
|
|
8
|
+
* Returns undefined for empty / primitive / void-like results.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractBaseTypeName(raw: string | undefined | null): string | undefined;
|
|
11
|
+
/** `@returns {Type}` or `@return Type` → base type name. */
|
|
12
|
+
export declare function parseJsdocReturns(docstring: string | undefined | null): string | undefined;
|
|
13
|
+
export interface JsdocParamType {
|
|
14
|
+
paramName: string;
|
|
15
|
+
typeName: string;
|
|
16
|
+
}
|
|
17
|
+
/** `@param {Type} name` entries with a resolvable type name. */
|
|
18
|
+
export declare function parseJsdocParams(docstring: string | undefined | null): JsdocParamType[];
|
|
19
|
+
//# sourceMappingURL=jsdoc-type-tags.d.ts.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Spec 0066 — parse JSDoc `@returns` / `@param` type tags as a fallback when
|
|
4
|
+
* the signature has no usable return/param type name. Docstring text still
|
|
5
|
+
* lives on `nodes.docstring` (Spec 0020); this only extracts type *names*.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.extractBaseTypeName = extractBaseTypeName;
|
|
9
|
+
exports.parseJsdocReturns = parseJsdocReturns;
|
|
10
|
+
exports.parseJsdocParams = parseJsdocParams;
|
|
11
|
+
const PRIMITIVE_OR_VOID = new Set([
|
|
12
|
+
'void',
|
|
13
|
+
'undefined',
|
|
14
|
+
'null',
|
|
15
|
+
'never',
|
|
16
|
+
'any',
|
|
17
|
+
'unknown',
|
|
18
|
+
'object',
|
|
19
|
+
'Object',
|
|
20
|
+
'string',
|
|
21
|
+
'String',
|
|
22
|
+
'number',
|
|
23
|
+
'Number',
|
|
24
|
+
'boolean',
|
|
25
|
+
'Boolean',
|
|
26
|
+
'bigint',
|
|
27
|
+
'symbol',
|
|
28
|
+
'Symbol',
|
|
29
|
+
'this',
|
|
30
|
+
'self',
|
|
31
|
+
'static',
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Unwrap Promise/Array/… and strip arrays/generics to a bare type identifier.
|
|
35
|
+
* Returns undefined for empty / primitive / void-like results.
|
|
36
|
+
*/
|
|
37
|
+
function extractBaseTypeName(raw) {
|
|
38
|
+
if (!raw)
|
|
39
|
+
return undefined;
|
|
40
|
+
let t = raw.trim();
|
|
41
|
+
if (!t)
|
|
42
|
+
return undefined;
|
|
43
|
+
// Drop leading `readonly` / `export` noise occasionally glued into tags.
|
|
44
|
+
t = t.replace(/^(?:readonly|export|declare)\s+/i, '').trim();
|
|
45
|
+
// Take the first union arm: `Foo | null` → `Foo`.
|
|
46
|
+
if (t.includes('|')) {
|
|
47
|
+
t = t.split('|')[0].trim();
|
|
48
|
+
}
|
|
49
|
+
// Function type → skip (no single type node).
|
|
50
|
+
if (t.includes('=>'))
|
|
51
|
+
return undefined;
|
|
52
|
+
if (t.endsWith('[]')) {
|
|
53
|
+
t = t.slice(0, -2).trim();
|
|
54
|
+
}
|
|
55
|
+
const wrapper = t.match(/^(?:Promise|Array|ReadonlyArray|Callback|Set|Iterable|Partial|Required|Readonly)\s*<\s*(.+)\s*>$/i);
|
|
56
|
+
if (wrapper?.[1]) {
|
|
57
|
+
t = wrapper[1].trim();
|
|
58
|
+
// Nested commas in Map/Record — take last type arg when present.
|
|
59
|
+
if (t.includes(',')) {
|
|
60
|
+
const mapLike = t.match(/^(?:Map|Record)\s*<[^,]+,\s*(.+)>$/i);
|
|
61
|
+
if (mapLike?.[1])
|
|
62
|
+
t = mapLike[1].trim();
|
|
63
|
+
else
|
|
64
|
+
t = t.split(',').pop().trim();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const mapMatch = t.match(/^(?:Map|Record)\s*<[^,]+,\s*(.+)>$/i);
|
|
68
|
+
if (mapMatch?.[1])
|
|
69
|
+
t = mapMatch[1].trim();
|
|
70
|
+
// Strip remaining generics: `Foo<T>` → `Foo`
|
|
71
|
+
t = t.replace(/<[^>]*>/g, '').replace(/\[\]/g, '').trim();
|
|
72
|
+
if (!t)
|
|
73
|
+
return undefined;
|
|
74
|
+
// Qualified → trailing simple name (`ns.Bar` → `Bar`)
|
|
75
|
+
const simple = t.split('.').filter(Boolean).pop() ?? t;
|
|
76
|
+
if (!simple || PRIMITIVE_OR_VOID.has(simple))
|
|
77
|
+
return undefined;
|
|
78
|
+
// Must look like an identifier (PascalCase preferred but allow any word).
|
|
79
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(simple))
|
|
80
|
+
return undefined;
|
|
81
|
+
return simple;
|
|
82
|
+
}
|
|
83
|
+
/** `@returns {Type}` or `@return Type` → base type name. */
|
|
84
|
+
function parseJsdocReturns(docstring) {
|
|
85
|
+
if (!docstring)
|
|
86
|
+
return undefined;
|
|
87
|
+
const re = /@returns?\s+(?:\{([^}]+)\}|([A-Za-z_][\w.<>[\],\s|]*))/gi;
|
|
88
|
+
let m;
|
|
89
|
+
while ((m = re.exec(docstring)) !== null) {
|
|
90
|
+
const raw = (m[1] ?? m[2] ?? '').trim();
|
|
91
|
+
const base = extractBaseTypeName(raw);
|
|
92
|
+
if (base)
|
|
93
|
+
return base;
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
/** `@param {Type} name` entries with a resolvable type name. */
|
|
98
|
+
function parseJsdocParams(docstring) {
|
|
99
|
+
if (!docstring)
|
|
100
|
+
return [];
|
|
101
|
+
const out = [];
|
|
102
|
+
const re = /@param(?:eter)?\s+(?:\{([^}]+)\}\s+)?\[?(\w+)\]?/gi;
|
|
103
|
+
let m;
|
|
104
|
+
while ((m = re.exec(docstring)) !== null) {
|
|
105
|
+
const typeRaw = m[1]?.trim();
|
|
106
|
+
const paramName = m[2];
|
|
107
|
+
if (!typeRaw || !paramName)
|
|
108
|
+
continue;
|
|
109
|
+
const typeName = extractBaseTypeName(typeRaw);
|
|
110
|
+
if (typeName)
|
|
111
|
+
out.push({ paramName, typeName });
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=jsdoc-type-tags.js.map
|
|
@@ -141,6 +141,7 @@ const liveness_watchdog_1 = require("../../mcp/liveness-watchdog");
|
|
|
141
141
|
const migrate_semantics_1 = require("../../arkui/migrate-semantics");
|
|
142
142
|
const migrate_passage_1 = require("../../arkui/migrate-passage");
|
|
143
143
|
const tree_sitter_helpers_1 = require("../tree-sitter-helpers");
|
|
144
|
+
const jsdoc_type_tags_1 = require("../jsdoc-type-tags");
|
|
144
145
|
const wasm_runtime_flags_1 = require("../wasm-runtime-flags");
|
|
145
146
|
const ignore_1 = __importDefault(require("ignore"));
|
|
146
147
|
/** Primitive / void return types — not stored in nodes.return_type (inference-only column). */
|
|
@@ -2026,6 +2027,47 @@ function filesHaveArkUiEntries(files) {
|
|
|
2026
2027
|
// ArkUI ViewTree — component tree, @Prop/@Link transfer, event bindings
|
|
2027
2028
|
// =============================================================================
|
|
2028
2029
|
const VIEWTREE_CALLBACK_ATTRS = new Set(arkanalyzer_1.CALLBACK_METHOD_NAME);
|
|
2030
|
+
/**
|
|
2031
|
+
* Framework decorators with no project-local definition. Emitting them as
|
|
2032
|
+
* unresolved `decorates` refs lets name-matcher bind @State → enum State, etc.
|
|
2033
|
+
*/
|
|
2034
|
+
const ARKUI_BUILTIN_DECORATORS = new Set([
|
|
2035
|
+
'State',
|
|
2036
|
+
'Prop',
|
|
2037
|
+
'Link',
|
|
2038
|
+
'Provide',
|
|
2039
|
+
'Consume',
|
|
2040
|
+
'Watch',
|
|
2041
|
+
'Builder',
|
|
2042
|
+
'BuilderParam',
|
|
2043
|
+
'Styles',
|
|
2044
|
+
'Extend',
|
|
2045
|
+
'AnimatableExtend',
|
|
2046
|
+
'Component',
|
|
2047
|
+
'ComponentV2',
|
|
2048
|
+
'Entry',
|
|
2049
|
+
'CustomDialog',
|
|
2050
|
+
'Observed',
|
|
2051
|
+
'ObservedV2',
|
|
2052
|
+
'ObjectLink',
|
|
2053
|
+
'LocalStorageLink',
|
|
2054
|
+
'LocalStorageProp',
|
|
2055
|
+
'StorageLink',
|
|
2056
|
+
'StorageProp',
|
|
2057
|
+
'Track',
|
|
2058
|
+
'Require',
|
|
2059
|
+
'Once',
|
|
2060
|
+
'Reusable',
|
|
2061
|
+
'Concurrent',
|
|
2062
|
+
'Sendable',
|
|
2063
|
+
'Local',
|
|
2064
|
+
'Param',
|
|
2065
|
+
'Event',
|
|
2066
|
+
'Monitor',
|
|
2067
|
+
'Computed',
|
|
2068
|
+
'Trace',
|
|
2069
|
+
'Type',
|
|
2070
|
+
]);
|
|
2029
2071
|
/** State decorator kinds on a field (@State, @Prop, @Link, …) from arkanalyzer. */
|
|
2030
2072
|
function stateDecoratorKinds(field) {
|
|
2031
2073
|
const decs = field.getStateDecorators?.();
|
|
@@ -2727,6 +2769,11 @@ class ArkTSAdapter {
|
|
|
2727
2769
|
continue;
|
|
2728
2770
|
if (!this.scanned.has(rel) || !isArkAnalyzerSourcePath(rel))
|
|
2729
2771
|
continue;
|
|
2772
|
+
// Already indexed (usually streamed to DB). Re-running indexScannedFile
|
|
2773
|
+
// would hit addNode's nodeIds short-circuit and leave an empty shell;
|
|
2774
|
+
// live IR rebind is handled by bindLiveMapsFromResident.
|
|
2775
|
+
if (this.nodeIds.has(`file:${rel}`))
|
|
2776
|
+
continue;
|
|
2730
2777
|
this.indexScannedFile(arkFile);
|
|
2731
2778
|
if (this.fileResults.has(rel))
|
|
2732
2779
|
seeded.push(rel);
|
|
@@ -3279,6 +3326,20 @@ class ArkTSAdapter {
|
|
|
3279
3326
|
const result = this.fileResults.get(relativePath);
|
|
3280
3327
|
return result?.nodes.some((n) => n.id === nodeId) ?? false;
|
|
3281
3328
|
}
|
|
3329
|
+
/**
|
|
3330
|
+
* Same-file edges stay on the file's ExtractionResult (persistFileResult FK
|
|
3331
|
+
* filter). Cross-file edges go to crossFileEdges and are inserted after all
|
|
3332
|
+
* modules persist — do not require nodeIds.has(target) at emit time (target
|
|
3333
|
+
* may be indexed later in the same batch).
|
|
3334
|
+
*/
|
|
3335
|
+
addMaybeCrossFileEdge(result, callerFile, edge) {
|
|
3336
|
+
if (this.nodeInFile(edge.target, callerFile)) {
|
|
3337
|
+
result.edges.push(edge);
|
|
3338
|
+
}
|
|
3339
|
+
else {
|
|
3340
|
+
this.crossFileEdges.push(edge);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3282
3343
|
ensureFileResult(relativePath, lineCount) {
|
|
3283
3344
|
let result = this.fileResults.get(relativePath);
|
|
3284
3345
|
if (!result) {
|
|
@@ -3431,6 +3492,10 @@ class ArkTSAdapter {
|
|
|
3431
3492
|
const kind = dec.getKind();
|
|
3432
3493
|
if (!kind)
|
|
3433
3494
|
continue;
|
|
3495
|
+
// Built-in ArkUI/ArkTS decorators have no project definition; name-match
|
|
3496
|
+
// would falsely link @State → enum State, @Builder → class Builder, etc.
|
|
3497
|
+
if (ARKUI_BUILTIN_DECORATORS.has(kind))
|
|
3498
|
+
continue;
|
|
3434
3499
|
result.unresolvedReferences.push({
|
|
3435
3500
|
fromNodeId,
|
|
3436
3501
|
referenceName: kind,
|
|
@@ -3529,17 +3594,62 @@ class ArkTSAdapter {
|
|
|
3529
3594
|
if (superName) {
|
|
3530
3595
|
const superCls = cls.getHeritageClass(superName);
|
|
3531
3596
|
if (superCls && !superCls.isDefaultArkClass()) {
|
|
3532
|
-
const superId = this.classToId.get(superCls);
|
|
3597
|
+
const superId = this.classToId.get(superCls) ?? this.resolveClassNodeId(superCls);
|
|
3598
|
+
const edgeKind = superCls.getCategory() === CLASS_CATEGORY.INTERFACE ? 'implements' : 'extends';
|
|
3533
3599
|
if (superId) {
|
|
3534
|
-
|
|
3535
|
-
|
|
3600
|
+
this.addMaybeCrossFileEdge(result, relativePath, arkEdge(classNode.id, superId, edgeKind));
|
|
3601
|
+
}
|
|
3602
|
+
else {
|
|
3603
|
+
const simple = superName.includes('.') ? superName.split('.').pop() : superName;
|
|
3604
|
+
if (simple && simple !== 'Object') {
|
|
3605
|
+
result.unresolvedReferences.push({
|
|
3606
|
+
fromNodeId: classNode.id,
|
|
3607
|
+
referenceName: simple,
|
|
3608
|
+
referenceKind: edgeKind,
|
|
3609
|
+
line,
|
|
3610
|
+
column: col,
|
|
3611
|
+
filePath: relativePath,
|
|
3612
|
+
language,
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
else if (superName && superName !== 'Object') {
|
|
3618
|
+
const simple = superName.includes('.') ? superName.split('.').pop() : superName;
|
|
3619
|
+
if (simple) {
|
|
3620
|
+
result.unresolvedReferences.push({
|
|
3621
|
+
fromNodeId: classNode.id,
|
|
3622
|
+
referenceName: simple,
|
|
3623
|
+
referenceKind: 'extends',
|
|
3624
|
+
line,
|
|
3625
|
+
column: col,
|
|
3626
|
+
filePath: relativePath,
|
|
3627
|
+
language,
|
|
3628
|
+
});
|
|
3536
3629
|
}
|
|
3537
3630
|
}
|
|
3538
3631
|
}
|
|
3539
3632
|
for (const ifaceName of cls.getImplementedInterfaceNames()) {
|
|
3540
3633
|
const iface = cls.getImplementedInterface(ifaceName);
|
|
3541
|
-
|
|
3542
|
-
|
|
3634
|
+
const ifaceId = iface
|
|
3635
|
+
? (this.classToId.get(iface) ?? this.resolveClassNodeId(iface))
|
|
3636
|
+
: null;
|
|
3637
|
+
if (ifaceId) {
|
|
3638
|
+
this.addMaybeCrossFileEdge(result, relativePath, arkEdge(classNode.id, ifaceId, 'implements'));
|
|
3639
|
+
}
|
|
3640
|
+
else if (ifaceName) {
|
|
3641
|
+
const simple = ifaceName.includes('.') ? ifaceName.split('.').pop() : ifaceName;
|
|
3642
|
+
if (simple) {
|
|
3643
|
+
result.unresolvedReferences.push({
|
|
3644
|
+
fromNodeId: classNode.id,
|
|
3645
|
+
referenceName: simple,
|
|
3646
|
+
referenceKind: 'implements',
|
|
3647
|
+
line,
|
|
3648
|
+
column: col,
|
|
3649
|
+
filePath: relativePath,
|
|
3650
|
+
language,
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3543
3653
|
}
|
|
3544
3654
|
}
|
|
3545
3655
|
for (const method of cls.getMethods(true)) {
|
|
@@ -3886,29 +3996,18 @@ class ArkTSAdapter {
|
|
|
3886
3996
|
this.crossFileEdges.push(edge);
|
|
3887
3997
|
}
|
|
3888
3998
|
}
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
// fall through
|
|
3902
|
-
}
|
|
3903
|
-
if (shouldSkipArkMethod(method) && !isAnonymousArkMethod(method))
|
|
3904
|
-
return null;
|
|
3905
|
-
const displayName = arkMethodDisplayName(method);
|
|
3906
|
-
if (!displayName)
|
|
3907
|
-
return null;
|
|
3908
|
-
const cls = method.getDeclaringArkClass();
|
|
3909
|
-
const kind = cls.isDefaultArkClass() ? 'function' : 'method';
|
|
3910
|
-
this.indexMethod(relativePath, languageForArkAnalyzerPath(relativePath), result, method, parentId, kind, displayName);
|
|
3911
|
-
return this.methodToId.get(method) ?? null;
|
|
3999
|
+
/**
|
|
4000
|
+
* Lazily index a method for ViewTree (and any caller that used to pass the
|
|
4001
|
+
* ViewTree owner path). Attribution always follows the method's declaring
|
|
4002
|
+
* ArkFile / class — same as {@link resolveMethodNodeId} — so nested ViewTree
|
|
4003
|
+
* walks cannot pin `%AM*` handlers onto the importer (Spec 0064).
|
|
4004
|
+
*
|
|
4005
|
+
* `relativePath` / `result` / `parentId` from the caller are ignored for the
|
|
4006
|
+
* node row (kept on the signature so ViewTree call sites stay unchanged);
|
|
4007
|
+
* ViewTree *edges* still use the importer via {@link addViewTreeEdge}.
|
|
4008
|
+
*/
|
|
4009
|
+
ensureMethodNode(method, _relativePath, _result, _parentId) {
|
|
4010
|
+
return this.resolveMethodNodeId(method);
|
|
3912
4011
|
}
|
|
3913
4012
|
indexMethod(relativePath, language, result, method, parentId, forcedKind, forcedDisplayName) {
|
|
3914
4013
|
const displayName = forcedDisplayName ?? resolveMethodDisplayName(method);
|
|
@@ -3948,6 +4047,52 @@ class ArkTSAdapter {
|
|
|
3948
4047
|
result.edges.push(arkEdge(parentId, methodNode.id, 'contains'));
|
|
3949
4048
|
this.indexDecorators(result, methodNode.id, method, relativePath, language, line);
|
|
3950
4049
|
this.indexNativeNapiCalls(method, methodNode.id, relativePath, language, result);
|
|
4050
|
+
// Spec 0066: return/param types as resolvable `returns` / `type_of` refs.
|
|
4051
|
+
this.emitMethodTypeEdges(method, methodNode.id, relativePath, language, line, returnType, methodNode.docstring, result);
|
|
4052
|
+
}
|
|
4053
|
+
/**
|
|
4054
|
+
* Spec 0066 — push unresolved `returns` / `type_of` from signature types,
|
|
4055
|
+
* falling back to JSDoc `@returns` / `@param` when the signature lacks them.
|
|
4056
|
+
*/
|
|
4057
|
+
emitMethodTypeEdges(method, fromNodeId, relativePath, language, line, returnType, docstring, result) {
|
|
4058
|
+
const push = (referenceName, referenceKind) => {
|
|
4059
|
+
result.unresolvedReferences.push({
|
|
4060
|
+
fromNodeId,
|
|
4061
|
+
referenceName,
|
|
4062
|
+
referenceKind,
|
|
4063
|
+
line,
|
|
4064
|
+
column: 0,
|
|
4065
|
+
filePath: relativePath,
|
|
4066
|
+
language,
|
|
4067
|
+
});
|
|
4068
|
+
};
|
|
4069
|
+
if (returnType) {
|
|
4070
|
+
push(returnType, 'returns');
|
|
4071
|
+
}
|
|
4072
|
+
else {
|
|
4073
|
+
const fromDoc = (0, jsdoc_type_tags_1.parseJsdocReturns)(docstring);
|
|
4074
|
+
if (fromDoc)
|
|
4075
|
+
push(fromDoc, 'returns');
|
|
4076
|
+
}
|
|
4077
|
+
let emittedParam = false;
|
|
4078
|
+
try {
|
|
4079
|
+
for (const p of method.getParameters()) {
|
|
4080
|
+
const raw = p.getType()?.toString();
|
|
4081
|
+
const base = normalizeArktsReturnType(raw);
|
|
4082
|
+
if (base) {
|
|
4083
|
+
push(base, 'type_of');
|
|
4084
|
+
emittedParam = true;
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
catch {
|
|
4089
|
+
// parameters unavailable
|
|
4090
|
+
}
|
|
4091
|
+
if (!emittedParam) {
|
|
4092
|
+
for (const p of (0, jsdoc_type_tags_1.parseJsdocParams)(docstring)) {
|
|
4093
|
+
push(p.typeName, 'type_of');
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
3951
4096
|
}
|
|
3952
4097
|
indexNativeNapiCalls(method, fromNodeId, relativePath, language, result) {
|
|
3953
4098
|
const code = method.getCode();
|
|
@@ -4017,12 +4162,34 @@ class ArkTSAdapter {
|
|
|
4017
4162
|
const targetFile = exportInfo.getDeclaringArkFile();
|
|
4018
4163
|
if (targetFile) {
|
|
4019
4164
|
const targetRel = this.normalizeRelPath(targetFile.getFilePath());
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4165
|
+
if (targetRel) {
|
|
4166
|
+
const targetFileId = `file:${targetRel}`;
|
|
4167
|
+
this.addMaybeCrossFileEdge(result, relativePath, arkEdge(importNode.id, targetFileId, 'imports', {
|
|
4023
4168
|
metadata: { synthesizedBy: 'arkanalyzer', module: modulePath },
|
|
4024
4169
|
}));
|
|
4025
4170
|
}
|
|
4171
|
+
else if (modulePath) {
|
|
4172
|
+
result.unresolvedReferences.push({
|
|
4173
|
+
fromNodeId: importNode.id,
|
|
4174
|
+
referenceName: modulePath,
|
|
4175
|
+
referenceKind: 'imports',
|
|
4176
|
+
line,
|
|
4177
|
+
column: 0,
|
|
4178
|
+
filePath: relativePath,
|
|
4179
|
+
language,
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
else if (modulePath) {
|
|
4184
|
+
result.unresolvedReferences.push({
|
|
4185
|
+
fromNodeId: importNode.id,
|
|
4186
|
+
referenceName: modulePath,
|
|
4187
|
+
referenceKind: 'imports',
|
|
4188
|
+
line,
|
|
4189
|
+
column: 0,
|
|
4190
|
+
filePath: relativePath,
|
|
4191
|
+
language,
|
|
4192
|
+
});
|
|
4026
4193
|
}
|
|
4027
4194
|
}
|
|
4028
4195
|
else if (modulePath) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store-phase flush / backpressure guards (Spec 0065).
|
|
3
|
+
*
|
|
4
|
+
* When `flushOrdered` records a store failure in `flushError` but returns a
|
|
5
|
+
* resolved promise, the feed backpressure `while` would otherwise spin on
|
|
6
|
+
* `await Promise.resolve()` forever (100% CPU hang). Call this at the top of
|
|
7
|
+
* that loop (and anywhere else that waits on flush progress).
|
|
8
|
+
*/
|
|
9
|
+
/** Throw if the ordered store flush already failed or the run was aborted. */
|
|
10
|
+
export declare function throwIfStoreFlushFailed(aborted: boolean, flushError: unknown): void;
|
|
11
|
+
//# sourceMappingURL=store-flush-guard.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Store-phase flush / backpressure guards (Spec 0065).
|
|
4
|
+
*
|
|
5
|
+
* When `flushOrdered` records a store failure in `flushError` but returns a
|
|
6
|
+
* resolved promise, the feed backpressure `while` would otherwise spin on
|
|
7
|
+
* `await Promise.resolve()` forever (100% CPU hang). Call this at the top of
|
|
8
|
+
* that loop (and anywhere else that waits on flush progress).
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.throwIfStoreFlushFailed = throwIfStoreFlushFailed;
|
|
12
|
+
/** Throw if the ordered store flush already failed or the run was aborted. */
|
|
13
|
+
function throwIfStoreFlushFailed(aborted, flushError) {
|
|
14
|
+
if (flushError)
|
|
15
|
+
throw flushError;
|
|
16
|
+
if (aborted)
|
|
17
|
+
throw new Error('Aborted');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=store-flush-guard.js.map
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* connection: the orchestrator posts one message per file (in file order) and
|
|
7
7
|
* the worker applies them in arrival order, which preserves the #1015
|
|
8
8
|
* insertion-order determinism exactly as if the main thread had run the same
|
|
9
|
-
* calls.
|
|
10
|
-
*
|
|
9
|
+
* calls. Spec 0065: the main connection is closed for the worker's lifetime
|
|
10
|
+
* (`exclusiveHandoff`) — an idle open handle on MEMORY/non-WAL backends was
|
|
11
|
+
* enough to surface SQLITE_BUSY during ArkTS→store handoff.
|
|
11
12
|
*
|
|
12
13
|
* Protocol (main → worker):
|
|
13
14
|
* {type:'open', dbPath, fastInit} → open connection, reply {type:'ready'}
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* connection: the orchestrator posts one message per file (in file order) and
|
|
8
8
|
* the worker applies them in arrival order, which preserves the #1015
|
|
9
9
|
* insertion-order determinism exactly as if the main thread had run the same
|
|
10
|
-
* calls.
|
|
11
|
-
*
|
|
10
|
+
* calls. Spec 0065: the main connection is closed for the worker's lifetime
|
|
11
|
+
* (`exclusiveHandoff`) — an idle open handle on MEMORY/non-WAL backends was
|
|
12
|
+
* enough to surface SQLITE_BUSY during ArkTS→store handoff.
|
|
12
13
|
*
|
|
13
14
|
* Protocol (main → worker):
|
|
14
15
|
* {type:'open', dbPath, fastInit} → open connection, reply {type:'ready'}
|
|
@@ -595,9 +595,15 @@ export declare class TreeSitterExtractor {
|
|
|
595
595
|
private readonly BUILTIN_TYPES;
|
|
596
596
|
/**
|
|
597
597
|
* Extract type references from type annotations on a function/method/field node.
|
|
598
|
-
*
|
|
598
|
+
* Spec 0066: parameter / field types → `type_of`; return types → `returns`.
|
|
599
|
+
* Dart / Scala mixed signature walks stay `references` (out of this Spec).
|
|
599
600
|
*/
|
|
600
601
|
private extractTypeAnnotations;
|
|
602
|
+
/**
|
|
603
|
+
* Spec 0066: when the AST omitted return/param types, emit unresolved
|
|
604
|
+
* `returns` / `type_of` refs from JSDoc `@returns` / `@param {Type}`.
|
|
605
|
+
*/
|
|
606
|
+
private emitJsdocTypeFallbacks;
|
|
601
607
|
/**
|
|
602
608
|
* Extract C# type references from a node that owns a type position —
|
|
603
609
|
* a method/constructor declaration, a property declaration, or a
|
|
@@ -647,6 +653,7 @@ export declare class TreeSitterExtractor {
|
|
|
647
653
|
/**
|
|
648
654
|
* Recursively walk a subtree and extract all type_identifier references.
|
|
649
655
|
* Handles unions, intersections, generics, arrays, etc.
|
|
656
|
+
* Spec 0066: callers pass `returns` / `type_of` for signature positions.
|
|
650
657
|
*/
|
|
651
658
|
private extractTypeRefsFromSubtree;
|
|
652
659
|
/**
|