gitnexus 1.6.4-rc.100 → 1.6.4-rc.102
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/_shared/index.d.ts +2 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +2 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/integrations/understand-quickly.d.ts +79 -0
- package/dist/_shared/integrations/understand-quickly.d.ts.map +1 -0
- package/dist/_shared/integrations/understand-quickly.js +139 -0
- package/dist/_shared/integrations/understand-quickly.js.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/publish.d.ts +29 -0
- package/dist/cli/publish.js +174 -0
- package/dist/core/ingestion/call-processor.js +6 -4
- package/dist/core/ingestion/cpp-ue-preprocessor.d.ts +12 -0
- package/dist/core/ingestion/cpp-ue-preprocessor.js +260 -0
- package/dist/core/ingestion/heritage-processor.js +9 -4
- package/dist/core/ingestion/import-processor.js +3 -2
- package/dist/core/ingestion/language-provider.d.ts +32 -0
- package/dist/core/ingestion/languages/c-cpp.js +2 -0
- package/dist/core/ingestion/parsing-processor.js +4 -0
- package/dist/core/ingestion/workers/parse-worker.js +4 -0
- package/package.json +1 -1
package/dist/_shared/index.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export { buildScopeTree, canParentScope, ScopeTreeInvariantError, } from './scop
|
|
|
48
48
|
export type { ScopeTree } from './scope-resolution/scope-tree.js';
|
|
49
49
|
export { buildPositionIndex } from './scope-resolution/position-index.js';
|
|
50
50
|
export type { PositionIndex } from './scope-resolution/position-index.js';
|
|
51
|
+
export { UNDERSTAND_QUICKLY_DISPATCH_URL, UNDERSTAND_QUICKLY_EVENT_TYPE, UNDERSTAND_QUICKLY_TOKEN_ENV, buildUqDispatchPayload, isValidOwnerRepo, parseOwnerRepoFromRemote, stripGitSuffix, } from './integrations/understand-quickly.js';
|
|
52
|
+
export type { UqDispatchPayload } from './integrations/understand-quickly.js';
|
|
51
53
|
export { diffResolutions } from './scope-resolution/shadow/diff.js';
|
|
52
54
|
export type { ShadowAgreement, ShadowCallsite, ShadowDiff, } from './scope-resolution/shadow/diff.js';
|
|
53
55
|
export { aggregateDiffs } from './scope-resolution/shadow/aggregate.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/_shared/index.js
CHANGED
|
@@ -33,6 +33,8 @@ export { CLASS_KINDS, METHOD_KINDS, FIELD_KINDS } from './scope-resolution/regis
|
|
|
33
33
|
export { makeScopeId, clearScopeIdInternPool } from './scope-resolution/scope-id.js';
|
|
34
34
|
export { buildScopeTree, canParentScope, ScopeTreeInvariantError, } from './scope-resolution/scope-tree.js';
|
|
35
35
|
export { buildPositionIndex } from './scope-resolution/position-index.js';
|
|
36
|
+
// Understand-Quickly registry integration (opt-in)
|
|
37
|
+
export { UNDERSTAND_QUICKLY_DISPATCH_URL, UNDERSTAND_QUICKLY_EVENT_TYPE, UNDERSTAND_QUICKLY_TOKEN_ENV, buildUqDispatchPayload, isValidOwnerRepo, parseOwnerRepoFromRemote, stripGitSuffix, } from './integrations/understand-quickly.js';
|
|
36
38
|
// Shadow-mode diff + aggregation (RFC §6.3; Ring 2 SHARED #918)
|
|
37
39
|
export { diffResolutions } from './scope-resolution/shadow/diff.js';
|
|
38
40
|
export { aggregateDiffs } from './scope-resolution/shadow/aggregate.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAiCjG,8DAA8D;AAC9D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AAGvD,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,gEAAgE;AAChE,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAOxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,uEAAuE;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAUpE,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAKvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAKrF,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEpG,OAAO,EACL,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQlG,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,gEAAgE;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAMpE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAiCjG,8DAA8D;AAC9D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AAGvD,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,gEAAgE;AAChE,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAOxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,uEAAuE;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAUpE,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAKvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAKrF,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEpG,OAAO,EACL,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQlG,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,mDAAmD;AACnD,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,sCAAsC,CAAC;AAG9C,gEAAgE;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAMpE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Understand-Quickly registry integration helpers.
|
|
3
|
+
*
|
|
4
|
+
* Pure, runtime-agnostic logic for opting in to publishing a GitNexus
|
|
5
|
+
* index to the [`looptech-ai/understand-quickly`](https://github.com/looptech-ai/understand-quickly)
|
|
6
|
+
* registry. Lives in `gitnexus-shared` so both the Node CLI and any
|
|
7
|
+
* future browser-side surface can construct identical dispatch payloads.
|
|
8
|
+
*
|
|
9
|
+
* Network I/O lives in the CLI command (`gitnexus/src/cli/publish.ts`)
|
|
10
|
+
* to keep this module free of Node-only imports — see the comment at
|
|
11
|
+
* the top of `gitnexus-shared/src/graph/types.ts`.
|
|
12
|
+
*
|
|
13
|
+
* The protocol contract (single dispatch event, no graph upload) is
|
|
14
|
+
* documented at:
|
|
15
|
+
* https://github.com/looptech-ai/understand-quickly/blob/main/docs/integrations/protocol.md
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* URL of the registry repo's repository_dispatch endpoint. Hardcoded
|
|
19
|
+
* because the registry is the canonical home for this integration —
|
|
20
|
+
* users who want a private registry can fork and patch.
|
|
21
|
+
*/
|
|
22
|
+
export declare const UNDERSTAND_QUICKLY_DISPATCH_URL = "https://api.github.com/repos/looptech-ai/understand-quickly/dispatches";
|
|
23
|
+
/**
|
|
24
|
+
* Event type the registry's sync workflow listens for.
|
|
25
|
+
* See `looptech-ai/understand-quickly/.github/workflows/sync.yml`.
|
|
26
|
+
*/
|
|
27
|
+
export declare const UNDERSTAND_QUICKLY_EVENT_TYPE = "sync-entry";
|
|
28
|
+
/** Environment variable that gates the dispatch. */
|
|
29
|
+
export declare const UNDERSTAND_QUICKLY_TOKEN_ENV = "UNDERSTAND_QUICKLY_TOKEN";
|
|
30
|
+
export interface UqDispatchPayload {
|
|
31
|
+
event_type: typeof UNDERSTAND_QUICKLY_EVENT_TYPE;
|
|
32
|
+
client_payload: {
|
|
33
|
+
/** `<owner>/<repo>` shape — must match the registered entry. */
|
|
34
|
+
id: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build the JSON body for the `repository_dispatch` ping. Pure — no
|
|
39
|
+
* env reads, no network. Validates that `id` looks like `owner/repo`
|
|
40
|
+
* (one slash, no whitespace, both halves non-empty) so a misconfigured
|
|
41
|
+
* caller fails loudly before the round-trip.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildUqDispatchPayload(id: string): UqDispatchPayload;
|
|
44
|
+
/**
|
|
45
|
+
* `owner/repo` validation. Conservative on purpose: GitHub's actual
|
|
46
|
+
* naming rules are looser, but we want to catch local paths
|
|
47
|
+
* (`/Users/...`), bare slugs (`my-repo`), and accidental whitespace.
|
|
48
|
+
*
|
|
49
|
+
* Matches GitHub's published slug rules:
|
|
50
|
+
* owner: starts with alnum, then alnum/hyphen only, must end with
|
|
51
|
+
* alnum (no trailing hyphen — GitHub rejects this at account
|
|
52
|
+
* creation, so a `my-org-/repo` input would otherwise pass us
|
|
53
|
+
* and 422 from GitHub). No underscore, no dot. Length cap 39.
|
|
54
|
+
* repo: any of alnum/dot/hyphen/underscore. Length cap 100.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isValidOwnerRepo(id: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Strip a single trailing `.git` (case-insensitive) and any trailing
|
|
59
|
+
* slashes from a URL-ish string. Bounded linear: each character is
|
|
60
|
+
* visited at most twice, no backtracking.
|
|
61
|
+
*
|
|
62
|
+
* Replaces `s.replace(/\.git\/*$/i, '').replace(/\/+$/, '')` which
|
|
63
|
+
* CodeQL's polynomial-regex check (codeql/js/polynomial-redos) flags as
|
|
64
|
+
* a worst-case O(n²) on adversarial input like "////.../x".
|
|
65
|
+
*/
|
|
66
|
+
export declare function stripGitSuffix(input: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Parse `owner/repo` out of a git remote URL. Mirrors the heuristic in
|
|
69
|
+
* `gitnexus/src/storage/git.ts:parseRepoNameFromUrl` but keeps both
|
|
70
|
+
* halves so we can build a registry id. Returns `null` on shapes we
|
|
71
|
+
* don't recognise.
|
|
72
|
+
*
|
|
73
|
+
* Examples:
|
|
74
|
+
* git@github.com:looptech-ai/understand-quickly.git
|
|
75
|
+
* https://github.com/looptech-ai/understand-quickly
|
|
76
|
+
* ssh://git@github.com/looptech-ai/understand-quickly.git
|
|
77
|
+
*/
|
|
78
|
+
export declare function parseOwnerRepoFromRemote(url: string | null | undefined): string | null;
|
|
79
|
+
//# sourceMappingURL=understand-quickly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"understand-quickly.d.ts","sourceRoot":"","sources":["../../src/integrations/understand-quickly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,2EAC8B,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,6BAA6B,eAAe,CAAC;AAE1D,oDAAoD;AACpD,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,OAAO,6BAA6B,CAAC;IACjD,cAAc,EAAE;QACd,gEAAgE;QAChE,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,CAYpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAsCtF"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Understand-Quickly registry integration helpers.
|
|
3
|
+
*
|
|
4
|
+
* Pure, runtime-agnostic logic for opting in to publishing a GitNexus
|
|
5
|
+
* index to the [`looptech-ai/understand-quickly`](https://github.com/looptech-ai/understand-quickly)
|
|
6
|
+
* registry. Lives in `gitnexus-shared` so both the Node CLI and any
|
|
7
|
+
* future browser-side surface can construct identical dispatch payloads.
|
|
8
|
+
*
|
|
9
|
+
* Network I/O lives in the CLI command (`gitnexus/src/cli/publish.ts`)
|
|
10
|
+
* to keep this module free of Node-only imports — see the comment at
|
|
11
|
+
* the top of `gitnexus-shared/src/graph/types.ts`.
|
|
12
|
+
*
|
|
13
|
+
* The protocol contract (single dispatch event, no graph upload) is
|
|
14
|
+
* documented at:
|
|
15
|
+
* https://github.com/looptech-ai/understand-quickly/blob/main/docs/integrations/protocol.md
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* URL of the registry repo's repository_dispatch endpoint. Hardcoded
|
|
19
|
+
* because the registry is the canonical home for this integration —
|
|
20
|
+
* users who want a private registry can fork and patch.
|
|
21
|
+
*/
|
|
22
|
+
export const UNDERSTAND_QUICKLY_DISPATCH_URL = 'https://api.github.com/repos/looptech-ai/understand-quickly/dispatches';
|
|
23
|
+
/**
|
|
24
|
+
* Event type the registry's sync workflow listens for.
|
|
25
|
+
* See `looptech-ai/understand-quickly/.github/workflows/sync.yml`.
|
|
26
|
+
*/
|
|
27
|
+
export const UNDERSTAND_QUICKLY_EVENT_TYPE = 'sync-entry';
|
|
28
|
+
/** Environment variable that gates the dispatch. */
|
|
29
|
+
export const UNDERSTAND_QUICKLY_TOKEN_ENV = 'UNDERSTAND_QUICKLY_TOKEN';
|
|
30
|
+
/**
|
|
31
|
+
* Build the JSON body for the `repository_dispatch` ping. Pure — no
|
|
32
|
+
* env reads, no network. Validates that `id` looks like `owner/repo`
|
|
33
|
+
* (one slash, no whitespace, both halves non-empty) so a misconfigured
|
|
34
|
+
* caller fails loudly before the round-trip.
|
|
35
|
+
*/
|
|
36
|
+
export function buildUqDispatchPayload(id) {
|
|
37
|
+
if (!isValidOwnerRepo(id)) {
|
|
38
|
+
throw new Error(`[understand-quickly] expected id of the form "owner/repo", got "${id}". ` +
|
|
39
|
+
`The registry uses this string to look up your entry in registry.json — ` +
|
|
40
|
+
`it must match the GitHub owner/repo of the source code, not a local path.`);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
event_type: UNDERSTAND_QUICKLY_EVENT_TYPE,
|
|
44
|
+
client_payload: { id },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `owner/repo` validation. Conservative on purpose: GitHub's actual
|
|
49
|
+
* naming rules are looser, but we want to catch local paths
|
|
50
|
+
* (`/Users/...`), bare slugs (`my-repo`), and accidental whitespace.
|
|
51
|
+
*
|
|
52
|
+
* Matches GitHub's published slug rules:
|
|
53
|
+
* owner: starts with alnum, then alnum/hyphen only, must end with
|
|
54
|
+
* alnum (no trailing hyphen — GitHub rejects this at account
|
|
55
|
+
* creation, so a `my-org-/repo` input would otherwise pass us
|
|
56
|
+
* and 422 from GitHub). No underscore, no dot. Length cap 39.
|
|
57
|
+
* repo: any of alnum/dot/hyphen/underscore. Length cap 100.
|
|
58
|
+
*/
|
|
59
|
+
export function isValidOwnerRepo(id) {
|
|
60
|
+
return /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?\/[A-Za-z0-9._-]{1,100}$/.test(id);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Strip a single trailing `.git` (case-insensitive) and any trailing
|
|
64
|
+
* slashes from a URL-ish string. Bounded linear: each character is
|
|
65
|
+
* visited at most twice, no backtracking.
|
|
66
|
+
*
|
|
67
|
+
* Replaces `s.replace(/\.git\/*$/i, '').replace(/\/+$/, '')` which
|
|
68
|
+
* CodeQL's polynomial-regex check (codeql/js/polynomial-redos) flags as
|
|
69
|
+
* a worst-case O(n²) on adversarial input like "////.../x".
|
|
70
|
+
*/
|
|
71
|
+
export function stripGitSuffix(input) {
|
|
72
|
+
let end = input.length;
|
|
73
|
+
// Trim trailing '/'.
|
|
74
|
+
while (end > 0 && input.charCodeAt(end - 1) === 0x2f)
|
|
75
|
+
end--;
|
|
76
|
+
// Drop one trailing '.git' (case-insensitive).
|
|
77
|
+
if (end >= 4) {
|
|
78
|
+
const tail = input.slice(end - 4, end).toLowerCase();
|
|
79
|
+
if (tail === '.git')
|
|
80
|
+
end -= 4;
|
|
81
|
+
}
|
|
82
|
+
// Trim trailing '/' that may have sat between '.git' and the rest.
|
|
83
|
+
while (end > 0 && input.charCodeAt(end - 1) === 0x2f)
|
|
84
|
+
end--;
|
|
85
|
+
return input.slice(0, end);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parse `owner/repo` out of a git remote URL. Mirrors the heuristic in
|
|
89
|
+
* `gitnexus/src/storage/git.ts:parseRepoNameFromUrl` but keeps both
|
|
90
|
+
* halves so we can build a registry id. Returns `null` on shapes we
|
|
91
|
+
* don't recognise.
|
|
92
|
+
*
|
|
93
|
+
* Examples:
|
|
94
|
+
* git@github.com:looptech-ai/understand-quickly.git
|
|
95
|
+
* https://github.com/looptech-ai/understand-quickly
|
|
96
|
+
* ssh://git@github.com/looptech-ai/understand-quickly.git
|
|
97
|
+
*/
|
|
98
|
+
export function parseOwnerRepoFromRemote(url) {
|
|
99
|
+
if (!url)
|
|
100
|
+
return null;
|
|
101
|
+
const trimmed = url.trim();
|
|
102
|
+
if (!trimmed)
|
|
103
|
+
return null;
|
|
104
|
+
// Strip a trailing `.git` (case-insensitive) and any trailing slashes
|
|
105
|
+
// so https://h/o/r and https://h/o/r.git collapse to the same id.
|
|
106
|
+
// Bounded-linear helper avoids the polynomial-regex CodeQL alert.
|
|
107
|
+
const stripped = stripGitSuffix(trimmed);
|
|
108
|
+
// SCP-form SSH (`git@host:owner/repo`). Capture host so we can reject
|
|
109
|
+
// non-GitHub remotes — a GitLab origin like
|
|
110
|
+
// `https://gitlab.example.com/group/sub/project.git` would otherwise
|
|
111
|
+
// silently dispatch the wrong id (LOW 9).
|
|
112
|
+
const ssh = stripped.match(/^[^@]+@([^:]+):([^/]+)\/([^/]+)$/);
|
|
113
|
+
if (ssh) {
|
|
114
|
+
const host = ssh[1].toLowerCase();
|
|
115
|
+
if (host !== 'github.com' && host !== 'www.github.com')
|
|
116
|
+
return null;
|
|
117
|
+
return `${ssh[2]}/${ssh[3]}`;
|
|
118
|
+
}
|
|
119
|
+
// URL forms (https://, ssh://, git://, file://) — last two path segments.
|
|
120
|
+
const url2 = stripped.match(/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/([^/]+)\/(.+)$/);
|
|
121
|
+
if (url2) {
|
|
122
|
+
// Strip optional `userinfo@` (e.g. `ssh://git@github.com/...`).
|
|
123
|
+
const authority = url2[1];
|
|
124
|
+
const atIdx = authority.lastIndexOf('@');
|
|
125
|
+
const hostAndPort = atIdx >= 0 ? authority.slice(atIdx + 1) : authority;
|
|
126
|
+
// Strip `:port` suffix if present.
|
|
127
|
+
const colonIdx = hostAndPort.indexOf(':');
|
|
128
|
+
const host = (colonIdx >= 0 ? hostAndPort.slice(0, colonIdx) : hostAndPort).toLowerCase();
|
|
129
|
+
if (host !== 'github.com' && host !== 'www.github.com')
|
|
130
|
+
return null;
|
|
131
|
+
const segments = url2[2].split('/').filter(Boolean);
|
|
132
|
+
if (segments.length >= 2) {
|
|
133
|
+
const [owner, repo] = segments.slice(-2);
|
|
134
|
+
return `${owner}/${repo}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=understand-quickly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"understand-quickly.js","sourceRoot":"","sources":["../../src/integrations/understand-quickly.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -106,6 +106,15 @@ program
|
|
|
106
106
|
.command('augment <pattern>')
|
|
107
107
|
.description('Augment a search pattern with knowledge graph context (used by hooks)')
|
|
108
108
|
.action(createLazyAction(() => import('./augment.js'), 'augmentCommand'));
|
|
109
|
+
program
|
|
110
|
+
.command('publish [path]')
|
|
111
|
+
.description('Notify the understand-quickly registry that this repo has a fresh GitNexus index. ' +
|
|
112
|
+
'Opt-in: requires UNDERSTAND_QUICKLY_TOKEN (fine-grained PAT with ' +
|
|
113
|
+
'`Repository dispatches: write` on looptech-ai/understand-quickly). ' +
|
|
114
|
+
'No-op without the token. See https://github.com/looptech-ai/understand-quickly.')
|
|
115
|
+
.option('--id <owner/repo>', 'Override the registry id (defaults to the origin remote)')
|
|
116
|
+
.option('--skip-git', 'Treat cwd as the repo root and skip parent git-root discovery')
|
|
117
|
+
.action(createLazyAction(() => import('./publish.js'), 'publishCommand'));
|
|
109
118
|
// ─── Direct Tool Commands (no MCP overhead) ────────────────────────
|
|
110
119
|
// These invoke LocalBackend directly for use in eval, scripts, and CI.
|
|
111
120
|
program
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gitnexus publish` — opt-in ping to the understand-quickly registry.
|
|
3
|
+
*
|
|
4
|
+
* Fires a single `repository_dispatch` event at
|
|
5
|
+
* `looptech-ai/understand-quickly` so the registry knows to refresh its
|
|
6
|
+
* entry for the current repo. Does NOT upload anything: per the
|
|
7
|
+
* understand-quickly protocol, the registry pulls the graph from a
|
|
8
|
+
* raw-GitHub URL the user controls.
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/looptech-ai/understand-quickly/blob/main/docs/integrations/protocol.md
|
|
11
|
+
*
|
|
12
|
+
* Defaults:
|
|
13
|
+
* - Without `UNDERSTAND_QUICKLY_TOKEN` in the env, this is a no-op
|
|
14
|
+
* (prints one informational line, exit 0). Same shape as the
|
|
15
|
+
* `--publish` patterns in sibling tools.
|
|
16
|
+
* - With the token, fires the dispatch and reports the response code.
|
|
17
|
+
*
|
|
18
|
+
* The `id` is derived from the repo's `origin` remote unless the caller
|
|
19
|
+
* passes `--id <owner/repo>` explicitly. We deliberately do NOT auto-add
|
|
20
|
+
* the repo to the registry — registration is one-time and uses the
|
|
21
|
+
* `npx @understand-quickly/cli add` path documented in the protocol.
|
|
22
|
+
*/
|
|
23
|
+
export interface PublishOptions {
|
|
24
|
+
/** Override the auto-derived `owner/repo` id. */
|
|
25
|
+
id?: string;
|
|
26
|
+
/** Treat the cwd as the repo root (skip git-root walk). */
|
|
27
|
+
skipGit?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare const publishCommand: (inputPath?: string, options?: PublishOptions) => Promise<void>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gitnexus publish` — opt-in ping to the understand-quickly registry.
|
|
3
|
+
*
|
|
4
|
+
* Fires a single `repository_dispatch` event at
|
|
5
|
+
* `looptech-ai/understand-quickly` so the registry knows to refresh its
|
|
6
|
+
* entry for the current repo. Does NOT upload anything: per the
|
|
7
|
+
* understand-quickly protocol, the registry pulls the graph from a
|
|
8
|
+
* raw-GitHub URL the user controls.
|
|
9
|
+
*
|
|
10
|
+
* https://github.com/looptech-ai/understand-quickly/blob/main/docs/integrations/protocol.md
|
|
11
|
+
*
|
|
12
|
+
* Defaults:
|
|
13
|
+
* - Without `UNDERSTAND_QUICKLY_TOKEN` in the env, this is a no-op
|
|
14
|
+
* (prints one informational line, exit 0). Same shape as the
|
|
15
|
+
* `--publish` patterns in sibling tools.
|
|
16
|
+
* - With the token, fires the dispatch and reports the response code.
|
|
17
|
+
*
|
|
18
|
+
* The `id` is derived from the repo's `origin` remote unless the caller
|
|
19
|
+
* passes `--id <owner/repo>` explicitly. We deliberately do NOT auto-add
|
|
20
|
+
* the repo to the registry — registration is one-time and uses the
|
|
21
|
+
* `npx @understand-quickly/cli add` path documented in the protocol.
|
|
22
|
+
*/
|
|
23
|
+
import path from 'path';
|
|
24
|
+
import { UNDERSTAND_QUICKLY_DISPATCH_URL, UNDERSTAND_QUICKLY_TOKEN_ENV, buildUqDispatchPayload, isValidOwnerRepo, parseOwnerRepoFromRemote, } from '../_shared/index.js';
|
|
25
|
+
import { getGitRoot, getRemoteOriginUrl, getCurrentCommit } from '../storage/git.js';
|
|
26
|
+
import { hasIndex } from '../storage/repo-manager.js';
|
|
27
|
+
import { cliInfo, cliError } from './cli-message.js';
|
|
28
|
+
const REGISTER_HINT = 'Register your repo once with: npx @understand-quickly/cli add\n' +
|
|
29
|
+
'Or use the wizard: https://looptech-ai.github.io/understand-quickly/add.html';
|
|
30
|
+
/**
|
|
31
|
+
* Hard cap on the dispatch fetch to keep CI publish steps from stalling
|
|
32
|
+
* for the OS TCP timeout (~2 min) when api.github.com is unreachable.
|
|
33
|
+
* Matches the pattern used in `src/core/embeddings/http-client.ts`.
|
|
34
|
+
*/
|
|
35
|
+
const DISPATCH_TIMEOUT_MS = 15_000;
|
|
36
|
+
export const publishCommand = async (inputPath, options = {}) => {
|
|
37
|
+
// ── 0. Token gate FIRST — guarantees true no-op without the token. ──
|
|
38
|
+
// The README, CLI --help, and PR body all promise "exit 0 without
|
|
39
|
+
// UNDERSTAND_QUICKLY_TOKEN". Doing the index/repo-root checks before
|
|
40
|
+
// the token gate would make those promises false for users who haven't
|
|
41
|
+
// run `gitnexus analyze` yet but want to verify the command is wired.
|
|
42
|
+
const token = process.env[UNDERSTAND_QUICKLY_TOKEN_ENV];
|
|
43
|
+
if (!token) {
|
|
44
|
+
cliInfo(`[understand-quickly] ${UNDERSTAND_QUICKLY_TOKEN_ENV} is not set — skipping dispatch.\n` +
|
|
45
|
+
`Set it to a fine-grained PAT with "Repository dispatches: write" on ` +
|
|
46
|
+
`looptech-ai/understand-quickly to enable instant resync.\n` +
|
|
47
|
+
`(Without the token, the registry's nightly sync still picks up your entry.)`, { skipped: 'no-token' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// ── 1. Resolve the repo root (same precedence as `analyze`) ──────────
|
|
51
|
+
let repoPath;
|
|
52
|
+
if (inputPath) {
|
|
53
|
+
repoPath = path.resolve(inputPath);
|
|
54
|
+
}
|
|
55
|
+
else if (options.skipGit) {
|
|
56
|
+
repoPath = path.resolve(process.cwd());
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const gitRoot = getGitRoot(process.cwd());
|
|
60
|
+
if (!gitRoot) {
|
|
61
|
+
cliError('[understand-quickly] not inside a git repository.\n' +
|
|
62
|
+
'Run from a repo, or pass --skip-git to publish from the current directory.');
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
repoPath = gitRoot;
|
|
67
|
+
}
|
|
68
|
+
// ── 2. Confirm a GitNexus index exists ───────────────────────────────
|
|
69
|
+
// Publishing without an index is almost always a mistake — the
|
|
70
|
+
// registry's nightly sync would fetch a stale or missing graph file
|
|
71
|
+
// and mark the entry `missing`. Refuse loudly with a fix-it hint.
|
|
72
|
+
if (!(await hasIndex(repoPath))) {
|
|
73
|
+
cliError(`[understand-quickly] no GitNexus index found at ${repoPath}/.gitnexus.\n` +
|
|
74
|
+
'Run `gitnexus analyze` first, then re-run `gitnexus publish`.');
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// ── 3. Derive the registry id ─────────────────────────────────────────
|
|
79
|
+
const id = options.id ?? parseOwnerRepoFromRemote(getRemoteOriginUrl(repoPath) ?? undefined) ?? null;
|
|
80
|
+
if (!id || !isValidOwnerRepo(id)) {
|
|
81
|
+
cliError(`[understand-quickly] could not derive a registry id from this repo.\n` +
|
|
82
|
+
`Pass --id <owner/repo> explicitly (e.g. --id looptech-ai/${path.basename(repoPath)}).\n` +
|
|
83
|
+
REGISTER_HINT);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// ── 4. Fire the dispatch ─────────────────────────────────────────────
|
|
88
|
+
const payload = buildUqDispatchPayload(id);
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await fetch(UNDERSTAND_QUICKLY_DISPATCH_URL, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: {
|
|
94
|
+
Accept: 'application/vnd.github+json',
|
|
95
|
+
Authorization: `Bearer ${token}`,
|
|
96
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
'User-Agent': 'gitnexus-cli',
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify(payload),
|
|
101
|
+
signal: AbortSignal.timeout(DISPATCH_TIMEOUT_MS),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
// `AbortSignal.timeout()` throws a `DOMException` with `name ===
|
|
106
|
+
// 'TimeoutError'` on Node 18.14+ (and on browsers/Bun). It is NOT
|
|
107
|
+
// a plain `AbortError`. Match the pattern used in
|
|
108
|
+
// gitnexus/src/core/embeddings/http-client.ts so the user sees the
|
|
109
|
+
// targeted "timed out" message instead of a generic "operation
|
|
110
|
+
// was aborted".
|
|
111
|
+
const isTimeout = err instanceof DOMException && err.name === 'TimeoutError';
|
|
112
|
+
if (isTimeout) {
|
|
113
|
+
cliError(`[understand-quickly] dispatch timed out after ${DISPATCH_TIMEOUT_MS}ms. ` +
|
|
114
|
+
`Check network access to api.github.com and retry.`, { id });
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
118
|
+
cliError(`[understand-quickly] dispatch network error: ${msg}`, { id });
|
|
119
|
+
}
|
|
120
|
+
process.exitCode = 1;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// GitHub returns 204 on success. Distinct branches for 401/403/404/422
|
|
124
|
+
// so users debug without checking the docs.
|
|
125
|
+
if (response.status === 204) {
|
|
126
|
+
await response.body?.cancel().catch(() => { });
|
|
127
|
+
// `getCurrentCommit` is only meaningful in the success path — moving
|
|
128
|
+
// it inside this branch removes a wasted child-process spawn on every
|
|
129
|
+
// error response (LOW 7).
|
|
130
|
+
const commit = getCurrentCommit(repoPath);
|
|
131
|
+
cliInfo(`[understand-quickly] dispatched sync-entry for ${id}` +
|
|
132
|
+
(commit ? ` @ ${commit.slice(0, 7)}` : '') +
|
|
133
|
+
'.\n' +
|
|
134
|
+
`Note: a 204 only confirms GitHub accepted the dispatch. Whether the ` +
|
|
135
|
+
`registry workflow finds an entry for "${id}" is logged at ` +
|
|
136
|
+
`https://github.com/looptech-ai/understand-quickly/actions/workflows/sync.yml`, { id, commit, status: response.status });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (response.status === 401) {
|
|
140
|
+
cliError(`[understand-quickly] dispatch returned 401 — the ${UNDERSTAND_QUICKLY_TOKEN_ENV} value is invalid or expired.\n` +
|
|
141
|
+
`Regenerate a fine-grained PAT at https://github.com/settings/personal-access-tokens ` +
|
|
142
|
+
`with Repository access scoped to looptech-ai/understand-quickly and the ` +
|
|
143
|
+
`"Repository dispatches: write" permission, then retry.`, { id, status: response.status });
|
|
144
|
+
process.exitCode = 1;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (response.status === 403) {
|
|
148
|
+
cliError(`[understand-quickly] dispatch returned 403 — the token authenticated but ` +
|
|
149
|
+
`lacks the "Repository dispatches: write" permission on ` +
|
|
150
|
+
`looptech-ai/understand-quickly. Edit the PAT scopes and retry.`, { id, status: response.status });
|
|
151
|
+
process.exitCode = 1;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (response.status === 404) {
|
|
155
|
+
cliError(`[understand-quickly] dispatch returned 404 — the token cannot reach ` +
|
|
156
|
+
`looptech-ai/understand-quickly. Verify the PAT has Repository access to ` +
|
|
157
|
+
`that exact repo (not just your own org).`, { id, status: response.status });
|
|
158
|
+
process.exitCode = 1;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (response.status === 422) {
|
|
162
|
+
// Malformed event_type / client_payload — a code bug in this CLI,
|
|
163
|
+
// not a user mistake. Surface so we get bug reports.
|
|
164
|
+
const body422 = await response.text().catch(() => '');
|
|
165
|
+
cliError(`[understand-quickly] dispatch returned 422 (this is a CLI bug; please report).\n` +
|
|
166
|
+
`Body: ${body422 || '(empty)'}`, { id, status: response.status });
|
|
167
|
+
process.exitCode = 1;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// 5xx and anything else → bubble the body so the user has something to act on.
|
|
171
|
+
const body = await response.text().catch(() => '');
|
|
172
|
+
cliError(`[understand-quickly] dispatch failed with HTTP ${response.status}: ${body || '(empty body)'}`, { id, status: response.status });
|
|
173
|
+
process.exitCode = 1;
|
|
174
|
+
};
|
|
@@ -612,9 +612,10 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
612
612
|
await loadLanguage(language, file.path);
|
|
613
613
|
let tree = astCache.get(file.path);
|
|
614
614
|
if (!tree) {
|
|
615
|
+
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
615
616
|
try {
|
|
616
|
-
tree = parser.parse(
|
|
617
|
-
bufferSize: getTreeSitterBufferSize(
|
|
617
|
+
tree = parser.parse(parseContent, undefined, {
|
|
618
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
618
619
|
});
|
|
619
620
|
}
|
|
620
621
|
catch (parseError) {
|
|
@@ -2583,9 +2584,10 @@ export const extractFetchCallsFromFiles = async (files, astCache) => {
|
|
|
2583
2584
|
await loadLanguage(language, file.path);
|
|
2584
2585
|
let tree = astCache.get(file.path);
|
|
2585
2586
|
if (!tree) {
|
|
2587
|
+
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
2586
2588
|
try {
|
|
2587
|
-
tree = parser.parse(
|
|
2588
|
-
bufferSize: getTreeSitterBufferSize(
|
|
2589
|
+
tree = parser.parse(parseContent, undefined, {
|
|
2590
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
2589
2591
|
});
|
|
2590
2592
|
}
|
|
2591
2593
|
catch {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip Unreal Engine reflection macros from C++ source, length-preserving.
|
|
3
|
+
*
|
|
4
|
+
* Returns the original string unchanged if no strong UE marker is detected,
|
|
5
|
+
* so non-UE C++ files (including ones that contain `*_API`-suffixed
|
|
6
|
+
* identifiers like `REST_API` or `HTTP_API`) incur only a single regex test.
|
|
7
|
+
*
|
|
8
|
+
* The `_filePath` parameter is part of the `LanguageProvider.preprocessSource`
|
|
9
|
+
* contract but is unused — UE detection is purely content-based. Accepted and
|
|
10
|
+
* ignored here so the function matches the hook signature exactly.
|
|
11
|
+
*/
|
|
12
|
+
export declare function stripUeMacros(source: string, _filePath?: string): string;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unreal Engine reflection-macro preprocessor for C++ source.
|
|
3
|
+
*
|
|
4
|
+
* Tree-sitter does not expand C preprocessor macros, so Unreal's reflection
|
|
5
|
+
* markers (`UCLASS(...)`, `UFUNCTION(...)`, `MODULENAME_API`, ...) are parsed
|
|
6
|
+
* verbatim. The result is mis-parsed declarations: in `class BRAWLUI_API
|
|
7
|
+
* UMyClass : public UObject`, tree-sitter-cpp captures `BRAWLUI_API` as the
|
|
8
|
+
* class name and the rest of the declaration becomes structurally wrong.
|
|
9
|
+
*
|
|
10
|
+
* This module elides those macros from the source text BEFORE tree-sitter
|
|
11
|
+
* parses it. Replacement is **length-preserving** (each elided byte becomes
|
|
12
|
+
* a space, newlines preserved) so byte offsets and line/column positions
|
|
13
|
+
* tree-sitter reports remain identical to the original file. Symbol
|
|
14
|
+
* locations in the graph stay accurate.
|
|
15
|
+
*
|
|
16
|
+
* A cheap detection guard short-circuits files that don't look like UE
|
|
17
|
+
* sources, so non-UE C++ codebases pay no cost.
|
|
18
|
+
*
|
|
19
|
+
* Pure function — no tree-sitter dependency, safe for worker threads.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Strong UE markers — reflection macros that only Unreal Engine projects use.
|
|
23
|
+
* Presence of one of these is sufficient evidence that the file is a UE source
|
|
24
|
+
* and that `MODULENAME_API` tokens in it are intended as export macros.
|
|
25
|
+
*
|
|
26
|
+
* Importantly, `_API` tokens are NOT in this guard — `REST_API`, `HTTP_API`,
|
|
27
|
+
* `MY_LIB_API` and similar identifiers appear in plenty of non-UE C++ codebases
|
|
28
|
+
* as constants/enums/parameter names. We must not erase them just because the
|
|
29
|
+
* file mentions an `_API` token.
|
|
30
|
+
*/
|
|
31
|
+
const HAS_UE_HINT = /\b(?:UCLASS|UFUNCTION|UPROPERTY|USTRUCT|UENUM|UINTERFACE|GENERATED_BODY|GENERATED_[A-Z_]+_BODY|UE_DEPRECATED|DECLARE_(?:DYNAMIC_)?(?:MULTICAST_)?DELEGATE)/;
|
|
32
|
+
const SIMPLE_MACROS_NO_ARGS = [
|
|
33
|
+
'GENERATED_BODY',
|
|
34
|
+
'GENERATED_UCLASS_BODY',
|
|
35
|
+
'GENERATED_USTRUCT_BODY',
|
|
36
|
+
'GENERATED_UINTERFACE_BODY',
|
|
37
|
+
'GENERATED_IINTERFACE_BODY',
|
|
38
|
+
'DECLARE_CLASS',
|
|
39
|
+
'GENERATED_BODY_LEGACY',
|
|
40
|
+
];
|
|
41
|
+
const PARENTHESIZED_MACROS = [
|
|
42
|
+
'UCLASS',
|
|
43
|
+
'UFUNCTION',
|
|
44
|
+
'UPROPERTY',
|
|
45
|
+
'USTRUCT',
|
|
46
|
+
'UENUM',
|
|
47
|
+
'UINTERFACE',
|
|
48
|
+
'UMETA',
|
|
49
|
+
'UE_DEPRECATED',
|
|
50
|
+
];
|
|
51
|
+
const DELEGATE_MACRO_RE = /\bDECLARE_(?:DYNAMIC_)?(?:MULTICAST_)?DELEGATE(?:_(?:RetVal_OneParam|RetVal_TwoParams|RetVal_ThreeParams|RetVal_FourParams|RetVal_FiveParams|RetVal_SixParams|RetVal_SevenParams|RetVal_EightParams|RetVal_NineParams|RetVal|OneParam|TwoParams|ThreeParams|FourParams|FiveParams|SixParams|SevenParams|EightParams|NineParams|TenParams))?(?=\s*\()/g;
|
|
52
|
+
/**
|
|
53
|
+
* Module export tokens like `BRAWLUI_API`, `ENGINE_API`, `COREUOBJECT_API`.
|
|
54
|
+
* Pattern: ALL_CAPS identifier ending in `_API`. The leading word boundary
|
|
55
|
+
* (`\b`) prevents matching mid-identifier.
|
|
56
|
+
*/
|
|
57
|
+
const API_MACRO_RE = /\b[A-Z][A-Z0-9_]*_API\b/g;
|
|
58
|
+
/** Replace `[start, end)` of `chars` with spaces, preserving newlines. */
|
|
59
|
+
function eraseRange(chars, start, end) {
|
|
60
|
+
for (let i = start; i < end; i++) {
|
|
61
|
+
if (chars[i] !== '\n' && chars[i] !== '\r') {
|
|
62
|
+
chars[i] = ' ';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find the matching close paren for an opening paren at index `openIdx`.
|
|
68
|
+
* Returns the index of `)` (inclusive end), or -1 if unbalanced.
|
|
69
|
+
*
|
|
70
|
+
* Handles nested parens and string/char literals so commas/parens inside
|
|
71
|
+
* strings don't throw off the match. Does not attempt to handle raw string
|
|
72
|
+
* literals (`R"(...)"`); UE reflection-macro arguments do not use them in
|
|
73
|
+
* practice.
|
|
74
|
+
*/
|
|
75
|
+
function findMatchingParen(source, openIdx) {
|
|
76
|
+
if (source.charCodeAt(openIdx) !== 0x28)
|
|
77
|
+
return -1;
|
|
78
|
+
let depth = 1;
|
|
79
|
+
let i = openIdx + 1;
|
|
80
|
+
const len = source.length;
|
|
81
|
+
while (i < len && depth > 0) {
|
|
82
|
+
const ch = source.charCodeAt(i);
|
|
83
|
+
// String literal
|
|
84
|
+
if (ch === 0x22) {
|
|
85
|
+
i++;
|
|
86
|
+
while (i < len) {
|
|
87
|
+
const c = source.charCodeAt(i);
|
|
88
|
+
if (c === 0x5c) {
|
|
89
|
+
i += 2;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (c === 0x22) {
|
|
93
|
+
i++;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
i++;
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// Char literal
|
|
101
|
+
if (ch === 0x27) {
|
|
102
|
+
i++;
|
|
103
|
+
while (i < len) {
|
|
104
|
+
const c = source.charCodeAt(i);
|
|
105
|
+
if (c === 0x5c) {
|
|
106
|
+
i += 2;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (c === 0x27) {
|
|
110
|
+
i++;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Line comment
|
|
118
|
+
if (ch === 0x2f && source.charCodeAt(i + 1) === 0x2f) {
|
|
119
|
+
while (i < len && source.charCodeAt(i) !== 0x0a)
|
|
120
|
+
i++;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Block comment
|
|
124
|
+
if (ch === 0x2f && source.charCodeAt(i + 1) === 0x2a) {
|
|
125
|
+
i += 2;
|
|
126
|
+
while (i < len) {
|
|
127
|
+
if (source.charCodeAt(i) === 0x2a && source.charCodeAt(i + 1) === 0x2f) {
|
|
128
|
+
i += 2;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (ch === 0x28)
|
|
136
|
+
depth++;
|
|
137
|
+
else if (ch === 0x29) {
|
|
138
|
+
depth--;
|
|
139
|
+
if (depth === 0)
|
|
140
|
+
return i;
|
|
141
|
+
}
|
|
142
|
+
i++;
|
|
143
|
+
}
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
/** Match a whole-word identifier at `idx`. Returns the byte after the identifier, or -1 on miss. */
|
|
147
|
+
function matchIdentifierAt(source, idx, name) {
|
|
148
|
+
if (idx > 0) {
|
|
149
|
+
const prev = source.charCodeAt(idx - 1);
|
|
150
|
+
if ((prev >= 0x30 && prev <= 0x39) ||
|
|
151
|
+
(prev >= 0x41 && prev <= 0x5a) ||
|
|
152
|
+
(prev >= 0x61 && prev <= 0x7a) ||
|
|
153
|
+
prev === 0x5f) {
|
|
154
|
+
return -1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (let k = 0; k < name.length; k++) {
|
|
158
|
+
if (source.charCodeAt(idx + k) !== name.charCodeAt(k))
|
|
159
|
+
return -1;
|
|
160
|
+
}
|
|
161
|
+
const after = idx + name.length;
|
|
162
|
+
if (after < source.length) {
|
|
163
|
+
const next = source.charCodeAt(after);
|
|
164
|
+
if ((next >= 0x30 && next <= 0x39) ||
|
|
165
|
+
(next >= 0x41 && next <= 0x5a) ||
|
|
166
|
+
(next >= 0x61 && next <= 0x7a) ||
|
|
167
|
+
next === 0x5f) {
|
|
168
|
+
return -1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return after;
|
|
172
|
+
}
|
|
173
|
+
/** Skip ASCII whitespace forward from `idx`. Returns the next non-whitespace byte index. */
|
|
174
|
+
function skipWhitespace(source, idx) {
|
|
175
|
+
const len = source.length;
|
|
176
|
+
while (idx < len) {
|
|
177
|
+
const ch = source.charCodeAt(idx);
|
|
178
|
+
if (ch === 0x20 || ch === 0x09 || ch === 0x0a || ch === 0x0d) {
|
|
179
|
+
idx++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
return idx;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Strip Unreal Engine reflection macros from C++ source, length-preserving.
|
|
188
|
+
*
|
|
189
|
+
* Returns the original string unchanged if no strong UE marker is detected,
|
|
190
|
+
* so non-UE C++ files (including ones that contain `*_API`-suffixed
|
|
191
|
+
* identifiers like `REST_API` or `HTTP_API`) incur only a single regex test.
|
|
192
|
+
*
|
|
193
|
+
* The `_filePath` parameter is part of the `LanguageProvider.preprocessSource`
|
|
194
|
+
* contract but is unused — UE detection is purely content-based. Accepted and
|
|
195
|
+
* ignored here so the function matches the hook signature exactly.
|
|
196
|
+
*/
|
|
197
|
+
export function stripUeMacros(source, _filePath) {
|
|
198
|
+
if (!HAS_UE_HINT.test(source))
|
|
199
|
+
return source;
|
|
200
|
+
const chars = source.split('');
|
|
201
|
+
for (const macro of PARENTHESIZED_MACROS) {
|
|
202
|
+
let searchFrom = 0;
|
|
203
|
+
while (true) {
|
|
204
|
+
const hit = source.indexOf(macro, searchFrom);
|
|
205
|
+
if (hit < 0)
|
|
206
|
+
break;
|
|
207
|
+
searchFrom = hit + 1;
|
|
208
|
+
const after = matchIdentifierAt(source, hit, macro);
|
|
209
|
+
if (after < 0)
|
|
210
|
+
continue;
|
|
211
|
+
const parenIdx = skipWhitespace(source, after);
|
|
212
|
+
if (source.charCodeAt(parenIdx) !== 0x28)
|
|
213
|
+
continue;
|
|
214
|
+
const close = findMatchingParen(source, parenIdx);
|
|
215
|
+
if (close < 0)
|
|
216
|
+
continue;
|
|
217
|
+
eraseRange(chars, hit, close + 1);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const macro of SIMPLE_MACROS_NO_ARGS) {
|
|
221
|
+
let searchFrom = 0;
|
|
222
|
+
while (true) {
|
|
223
|
+
const hit = source.indexOf(macro, searchFrom);
|
|
224
|
+
if (hit < 0)
|
|
225
|
+
break;
|
|
226
|
+
searchFrom = hit + 1;
|
|
227
|
+
const after = matchIdentifierAt(source, hit, macro);
|
|
228
|
+
if (after < 0)
|
|
229
|
+
continue;
|
|
230
|
+
const parenIdx = skipWhitespace(source, after);
|
|
231
|
+
if (source.charCodeAt(parenIdx) === 0x28) {
|
|
232
|
+
const close = findMatchingParen(source, parenIdx);
|
|
233
|
+
if (close < 0)
|
|
234
|
+
continue;
|
|
235
|
+
eraseRange(chars, hit, close + 1);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
eraseRange(chars, hit, after);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
for (const re of [DELEGATE_MACRO_RE, API_MACRO_RE]) {
|
|
243
|
+
re.lastIndex = 0;
|
|
244
|
+
let match;
|
|
245
|
+
while ((match = re.exec(source)) !== null) {
|
|
246
|
+
const start = match.index;
|
|
247
|
+
let end = start + match[0].length;
|
|
248
|
+
if (re === DELEGATE_MACRO_RE) {
|
|
249
|
+
const parenIdx = skipWhitespace(source, end);
|
|
250
|
+
if (source.charCodeAt(parenIdx) === 0x28) {
|
|
251
|
+
const close = findMatchingParen(source, parenIdx);
|
|
252
|
+
if (close >= 0)
|
|
253
|
+
end = close + 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
eraseRange(chars, start, end);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return chars.join('');
|
|
260
|
+
}
|
|
@@ -147,9 +147,13 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
147
147
|
let tree = astCache.get(file.path);
|
|
148
148
|
if (!tree) {
|
|
149
149
|
// Use larger bufferSize for files > 32KB
|
|
150
|
+
// Per-language source preprocessor (length-preserving, e.g. UE macro
|
|
151
|
+
// stripping for C++). MUST mirror parsing-processor on cache miss so
|
|
152
|
+
// re-parses see the same input as the cached AST.
|
|
153
|
+
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
150
154
|
try {
|
|
151
|
-
tree = parser.parse(
|
|
152
|
-
bufferSize: getTreeSitterBufferSize(
|
|
155
|
+
tree = parser.parse(parseContent, undefined, {
|
|
156
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
153
157
|
});
|
|
154
158
|
}
|
|
155
159
|
catch (parseError) {
|
|
@@ -294,9 +298,10 @@ export async function extractExtractedHeritageFromFiles(files, astCache) {
|
|
|
294
298
|
await loadLanguage(language, file.path);
|
|
295
299
|
let tree = astCache.get(file.path);
|
|
296
300
|
if (!tree) {
|
|
301
|
+
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
297
302
|
try {
|
|
298
|
-
tree = parser.parse(
|
|
299
|
-
bufferSize: getTreeSitterBufferSize(
|
|
303
|
+
tree = parser.parse(parseContent, undefined, {
|
|
304
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
300
305
|
});
|
|
301
306
|
}
|
|
302
307
|
catch {
|
|
@@ -241,9 +241,10 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
|
|
|
241
241
|
let tree = astCache.get(file.path);
|
|
242
242
|
let wasReparsed = false;
|
|
243
243
|
if (!tree) {
|
|
244
|
+
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
244
245
|
try {
|
|
245
|
-
tree = parser.parse(
|
|
246
|
-
bufferSize: getTreeSitterBufferSize(
|
|
246
|
+
tree = parser.parse(parseContent, undefined, {
|
|
247
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
247
248
|
});
|
|
248
249
|
}
|
|
249
250
|
catch (parseError) {
|
|
@@ -74,6 +74,38 @@ interface LanguageProviderConfig {
|
|
|
74
74
|
/** Tree-sitter query strings for definitions, imports, calls, heritage.
|
|
75
75
|
* Required for tree-sitter languages; empty string for standalone processors. */
|
|
76
76
|
readonly treeSitterQueries: string;
|
|
77
|
+
/**
|
|
78
|
+
* Optional source-text transform that runs **before** tree-sitter parses the file.
|
|
79
|
+
*
|
|
80
|
+
* Used to elide language constructs that confuse the grammar without affecting
|
|
81
|
+
* source-position fidelity — e.g., Unreal Engine reflection macros (`UCLASS`,
|
|
82
|
+
* `UFUNCTION`, `MODULENAME_API`) in C++ headers that prevent the parser from
|
|
83
|
+
* recognising class/function names correctly.
|
|
84
|
+
*
|
|
85
|
+
* **Length / position preservation:** the returned string MUST have the same
|
|
86
|
+
* JavaScript `.length` as the input AND preserve every newline (`\n`/`\r`)
|
|
87
|
+
* position byte-for-byte. Implementations replace elided characters with
|
|
88
|
+
* ASCII spaces while leaving newlines untouched. With this contract:
|
|
89
|
+
*
|
|
90
|
+
* - tree-sitter's reported `startPosition.row`/`startPosition.column`
|
|
91
|
+
* match the original file exactly (line/column come from newline counts)
|
|
92
|
+
* - `startIndex`/`endIndex` byte offsets match the original file exactly
|
|
93
|
+
* **when the elided range is pure ASCII** (UTF-16 `.length` equals UTF-8
|
|
94
|
+
* byte length only for ASCII).
|
|
95
|
+
*
|
|
96
|
+
* Implementations targeting languages where elided ranges may contain
|
|
97
|
+
* non-ASCII content must therefore preserve byte length, not just `.length`,
|
|
98
|
+
* if downstream code uses `startIndex` to slice the original UTF-8 bytes.
|
|
99
|
+
* The current C++ UE-macro preprocessor relies on the practical fact that
|
|
100
|
+
* UE reflection macros and module-export tokens are ASCII-only.
|
|
101
|
+
*
|
|
102
|
+
* Must be a pure function — same input always yields the same output. Called
|
|
103
|
+
* once per file, on every code path that re-parses (parsing-processor, import
|
|
104
|
+
* processor, heritage processor, call processor, parse worker).
|
|
105
|
+
*
|
|
106
|
+
* Default: undefined (no preprocessing — `file.content` is parsed verbatim).
|
|
107
|
+
*/
|
|
108
|
+
readonly preprocessSource?: (sourceText: string, filePath: string) => string;
|
|
77
109
|
/** Type extraction: declarations, initializers, for-loop bindings */
|
|
78
110
|
readonly typeConfig: LanguageTypeConfig;
|
|
79
111
|
/** Export detection: is this AST node a public/exported symbol? */
|
|
@@ -36,6 +36,7 @@ import { cVariableConfig, cppVariableConfig } from '../variable-extractors/confi
|
|
|
36
36
|
import { createCallExtractor } from '../call-extractors/generic.js';
|
|
37
37
|
import { cCallConfig, cppCallConfig } from '../call-extractors/configs/c-cpp.js';
|
|
38
38
|
import { createHeritageExtractor } from '../heritage-extractors/generic.js';
|
|
39
|
+
import { stripUeMacros } from '../cpp-ue-preprocessor.js';
|
|
39
40
|
const C_BUILT_INS = new Set([
|
|
40
41
|
'printf',
|
|
41
42
|
'fprintf',
|
|
@@ -380,6 +381,7 @@ export const cppProvider = defineLanguage({
|
|
|
380
381
|
},
|
|
381
382
|
],
|
|
382
383
|
treeSitterQueries: CPP_QUERIES,
|
|
384
|
+
preprocessSource: stripUeMacros,
|
|
383
385
|
typeConfig: cCppConfig,
|
|
384
386
|
exportChecker: cCppExportChecker,
|
|
385
387
|
importResolver: createImportResolver(cppImportConfig),
|
|
@@ -262,6 +262,10 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
262
262
|
lineOffset = extracted.lineOffset;
|
|
263
263
|
isVueSetup = extracted.isSetup;
|
|
264
264
|
}
|
|
265
|
+
// Per-language source-text transform (e.g., UE macro stripping for C++).
|
|
266
|
+
// Length-preserving — see LanguageProvider.preprocessSource contract.
|
|
267
|
+
parseContent =
|
|
268
|
+
getProvider(language).preprocessSource?.(parseContent, file.path) ?? parseContent;
|
|
265
269
|
try {
|
|
266
270
|
await loadLanguage(language, file.path);
|
|
267
271
|
}
|
|
@@ -1019,6 +1019,10 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1019
1019
|
lineOffset = extracted.lineOffset;
|
|
1020
1020
|
isVueSetup = extracted.isSetup;
|
|
1021
1021
|
}
|
|
1022
|
+
// Per-language source-text transform (e.g., UE macro stripping for C++).
|
|
1023
|
+
// Length-preserving — see LanguageProvider.preprocessSource contract.
|
|
1024
|
+
parseContent =
|
|
1025
|
+
getProvider(language).preprocessSource?.(parseContent, file.path) ?? parseContent;
|
|
1022
1026
|
clearCaches(); // Reset memoization before each new file
|
|
1023
1027
|
let tree;
|
|
1024
1028
|
try {
|
package/package.json
CHANGED