@untangle-code/parser-registry 0.0.0-stage → 0.1.0
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/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +352 -2
- package/THIRD_PARTY_LICENSES.md +91 -0
- package/dist/boundaries/expression.d.ts +10 -0
- package/dist/boundaries/expression.d.ts.map +1 -0
- package/dist/boundaries/expression.js +95 -0
- package/dist/boundaries/expression.js.map +1 -0
- package/dist/boundaries/extract.d.ts +12 -0
- package/dist/boundaries/extract.d.ts.map +1 -0
- package/dist/boundaries/extract.js +259 -0
- package/dist/boundaries/extract.js.map +1 -0
- package/dist/boundaries/python.d.ts +6 -0
- package/dist/boundaries/python.d.ts.map +1 -0
- package/dist/boundaries/python.js +154 -0
- package/dist/boundaries/python.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/astgrep-backend/adapter.d.ts +101 -0
- package/dist/languages/astgrep-backend/adapter.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/adapter.js +130 -0
- package/dist/languages/astgrep-backend/adapter.js.map +1 -0
- package/dist/languages/astgrep-backend/index.d.ts +29 -0
- package/dist/languages/astgrep-backend/index.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/index.js +28 -0
- package/dist/languages/astgrep-backend/index.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/bash.d.ts +38 -0
- package/dist/languages/astgrep-backend/lang/bash.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/bash.js +42 -0
- package/dist/languages/astgrep-backend/lang/bash.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/c.d.ts +33 -0
- package/dist/languages/astgrep-backend/lang/c.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/c.js +85 -0
- package/dist/languages/astgrep-backend/lang/c.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/cpp.d.ts +27 -0
- package/dist/languages/astgrep-backend/lang/cpp.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/cpp.js +38 -0
- package/dist/languages/astgrep-backend/lang/cpp.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/csharp.d.ts +24 -0
- package/dist/languages/astgrep-backend/lang/csharp.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/csharp.js +102 -0
- package/dist/languages/astgrep-backend/lang/csharp.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/index.d.ts +29 -0
- package/dist/languages/astgrep-backend/lang/index.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/index.js +22 -0
- package/dist/languages/astgrep-backend/lang/index.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/java.d.ts +26 -0
- package/dist/languages/astgrep-backend/lang/java.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/java.js +89 -0
- package/dist/languages/astgrep-backend/lang/java.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/kotlin.d.ts +44 -0
- package/dist/languages/astgrep-backend/lang/kotlin.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/kotlin.js +94 -0
- package/dist/languages/astgrep-backend/lang/kotlin.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/php.d.ts +23 -0
- package/dist/languages/astgrep-backend/lang/php.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/php.js +80 -0
- package/dist/languages/astgrep-backend/lang/php.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/ruby.d.ts +37 -0
- package/dist/languages/astgrep-backend/lang/ruby.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/ruby.js +70 -0
- package/dist/languages/astgrep-backend/lang/ruby.js.map +1 -0
- package/dist/languages/astgrep-backend/lang/swift.d.ts +34 -0
- package/dist/languages/astgrep-backend/lang/swift.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/lang/swift.js +86 -0
- package/dist/languages/astgrep-backend/lang/swift.js.map +1 -0
- package/dist/languages/astgrep-backend/languages.d.ts +55 -0
- package/dist/languages/astgrep-backend/languages.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/languages.js +214 -0
- package/dist/languages/astgrep-backend/languages.js.map +1 -0
- package/dist/languages/astgrep-backend/napi.d.ts +71 -0
- package/dist/languages/astgrep-backend/napi.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/napi.js +176 -0
- package/dist/languages/astgrep-backend/napi.js.map +1 -0
- package/dist/languages/astgrep-backend/syntax.d.ts +88 -0
- package/dist/languages/astgrep-backend/syntax.d.ts.map +1 -0
- package/dist/languages/astgrep-backend/syntax.js +180 -0
- package/dist/languages/astgrep-backend/syntax.js.map +1 -0
- package/dist/languages/index.d.ts +14 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +37 -0
- package/dist/languages/index.js.map +1 -0
- package/dist/languages/javascript/index.d.ts +4 -0
- package/dist/languages/javascript/index.d.ts.map +1 -0
- package/dist/languages/javascript/index.js +7 -0
- package/dist/languages/javascript/index.js.map +1 -0
- package/dist/languages/jsx/index.d.ts +4 -0
- package/dist/languages/jsx/index.d.ts.map +1 -0
- package/dist/languages/jsx/index.js +7 -0
- package/dist/languages/jsx/index.js.map +1 -0
- package/dist/languages/prose/index.d.ts +53 -0
- package/dist/languages/prose/index.d.ts.map +1 -0
- package/dist/languages/prose/index.js +172 -0
- package/dist/languages/prose/index.js.map +1 -0
- package/dist/languages/prose/line-bytes.d.ts +31 -0
- package/dist/languages/prose/line-bytes.d.ts.map +1 -0
- package/dist/languages/prose/line-bytes.js +39 -0
- package/dist/languages/prose/line-bytes.js.map +1 -0
- package/dist/languages/python/create-adapter.d.ts +20 -0
- package/dist/languages/python/create-adapter.d.ts.map +1 -0
- package/dist/languages/python/create-adapter.js +9 -0
- package/dist/languages/python/create-adapter.js.map +1 -0
- package/dist/languages/python/index.d.ts +4 -0
- package/dist/languages/python/index.d.ts.map +1 -0
- package/dist/languages/python/index.js +6 -0
- package/dist/languages/python/index.js.map +1 -0
- package/dist/languages/python/profile.d.ts +36 -0
- package/dist/languages/python/profile.d.ts.map +1 -0
- package/dist/languages/python/profile.js +282 -0
- package/dist/languages/python/profile.js.map +1 -0
- package/dist/languages/python/signature.d.ts +53 -0
- package/dist/languages/python/signature.d.ts.map +1 -0
- package/dist/languages/python/signature.js +188 -0
- package/dist/languages/python/signature.js.map +1 -0
- package/dist/languages/python/table.d.ts +46 -0
- package/dist/languages/python/table.d.ts.map +1 -0
- package/dist/languages/python/table.js +88 -0
- package/dist/languages/python/table.js.map +1 -0
- package/dist/languages/shared/call-detection.d.ts +17 -0
- package/dist/languages/shared/call-detection.d.ts.map +1 -0
- package/dist/languages/shared/call-detection.js +86 -0
- package/dist/languages/shared/call-detection.js.map +1 -0
- package/dist/languages/shared/chunks.d.ts +28 -0
- package/dist/languages/shared/chunks.d.ts.map +1 -0
- package/dist/languages/shared/chunks.js +181 -0
- package/dist/languages/shared/chunks.js.map +1 -0
- package/dist/languages/shared/create-adapter.d.ts +11 -0
- package/dist/languages/shared/create-adapter.d.ts.map +1 -0
- package/dist/languages/shared/create-adapter.js +90 -0
- package/dist/languages/shared/create-adapter.js.map +1 -0
- package/dist/languages/shared/decisions.d.ts +45 -0
- package/dist/languages/shared/decisions.d.ts.map +1 -0
- package/dist/languages/shared/decisions.js +141 -0
- package/dist/languages/shared/decisions.js.map +1 -0
- package/dist/languages/shared/dialect.d.ts +18 -0
- package/dist/languages/shared/dialect.d.ts.map +1 -0
- package/dist/languages/shared/dialect.js +37 -0
- package/dist/languages/shared/dialect.js.map +1 -0
- package/dist/languages/shared/doc-binding.d.ts +26 -0
- package/dist/languages/shared/doc-binding.d.ts.map +1 -0
- package/dist/languages/shared/doc-binding.js +50 -0
- package/dist/languages/shared/doc-binding.js.map +1 -0
- package/dist/languages/shared/engine.d.ts +49 -0
- package/dist/languages/shared/engine.d.ts.map +1 -0
- package/dist/languages/shared/engine.js +317 -0
- package/dist/languages/shared/engine.js.map +1 -0
- package/dist/languages/shared/extract-symbols.d.ts +5 -0
- package/dist/languages/shared/extract-symbols.d.ts.map +1 -0
- package/dist/languages/shared/extract-symbols.js +31 -0
- package/dist/languages/shared/extract-symbols.js.map +1 -0
- package/dist/languages/shared/fingerprint.d.ts +7 -0
- package/dist/languages/shared/fingerprint.d.ts.map +1 -0
- package/dist/languages/shared/fingerprint.js +95 -0
- package/dist/languages/shared/fingerprint.js.map +1 -0
- package/dist/languages/shared/grammar-loader.d.ts +15 -0
- package/dist/languages/shared/grammar-loader.d.ts.map +1 -0
- package/dist/languages/shared/grammar-loader.js +48 -0
- package/dist/languages/shared/grammar-loader.js.map +1 -0
- package/dist/languages/shared/import-detection.d.ts +24 -0
- package/dist/languages/shared/import-detection.d.ts.map +1 -0
- package/dist/languages/shared/import-detection.js +138 -0
- package/dist/languages/shared/import-detection.js.map +1 -0
- package/dist/languages/shared/js-family-profile.d.ts +5 -0
- package/dist/languages/shared/js-family-profile.d.ts.map +1 -0
- package/dist/languages/shared/js-family-profile.js +179 -0
- package/dist/languages/shared/js-family-profile.js.map +1 -0
- package/dist/languages/shared/node-kinds.d.ts +78 -0
- package/dist/languages/shared/node-kinds.d.ts.map +1 -0
- package/dist/languages/shared/node-kinds.js +141 -0
- package/dist/languages/shared/node-kinds.js.map +1 -0
- package/dist/languages/shared/node-utils.d.ts +31 -0
- package/dist/languages/shared/node-utils.d.ts.map +1 -0
- package/dist/languages/shared/node-utils.js +89 -0
- package/dist/languages/shared/node-utils.js.map +1 -0
- package/dist/languages/shared/parse-diagnostics.d.ts +44 -0
- package/dist/languages/shared/parse-diagnostics.d.ts.map +1 -0
- package/dist/languages/shared/parse-diagnostics.js +64 -0
- package/dist/languages/shared/parse-diagnostics.js.map +1 -0
- package/dist/languages/shared/parse-limits.d.ts +24 -0
- package/dist/languages/shared/parse-limits.d.ts.map +1 -0
- package/dist/languages/shared/parse-limits.js +134 -0
- package/dist/languages/shared/parse-limits.js.map +1 -0
- package/dist/languages/shared/profile.d.ts +149 -0
- package/dist/languages/shared/profile.d.ts.map +1 -0
- package/dist/languages/shared/profile.js +9 -0
- package/dist/languages/shared/profile.js.map +1 -0
- package/dist/languages/shared/scope-model.d.ts +32 -0
- package/dist/languages/shared/scope-model.d.ts.map +1 -0
- package/dist/languages/shared/scope-model.js +2 -0
- package/dist/languages/shared/scope-model.js.map +1 -0
- package/dist/languages/shared/scope-naming.d.ts +20 -0
- package/dist/languages/shared/scope-naming.d.ts.map +1 -0
- package/dist/languages/shared/scope-naming.js +118 -0
- package/dist/languages/shared/scope-naming.js.map +1 -0
- package/dist/languages/shared/scope-signature.d.ts +14 -0
- package/dist/languages/shared/scope-signature.d.ts.map +1 -0
- package/dist/languages/shared/scope-signature.js +82 -0
- package/dist/languages/shared/scope-signature.js.map +1 -0
- package/dist/languages/shared/signature.d.ts +55 -0
- package/dist/languages/shared/signature.d.ts.map +1 -0
- package/dist/languages/shared/signature.js +147 -0
- package/dist/languages/shared/signature.js.map +1 -0
- package/dist/languages/shared/syntax.d.ts +115 -0
- package/dist/languages/shared/syntax.d.ts.map +1 -0
- package/dist/languages/shared/syntax.js +2 -0
- package/dist/languages/shared/syntax.js.map +1 -0
- package/dist/languages/shared/table-profile-decisions.d.ts +54 -0
- package/dist/languages/shared/table-profile-decisions.d.ts.map +1 -0
- package/dist/languages/shared/table-profile-decisions.js +245 -0
- package/dist/languages/shared/table-profile-decisions.js.map +1 -0
- package/dist/languages/shared/table-profile-module-facts.d.ts +29 -0
- package/dist/languages/shared/table-profile-module-facts.d.ts.map +1 -0
- package/dist/languages/shared/table-profile-module-facts.js +139 -0
- package/dist/languages/shared/table-profile-module-facts.js.map +1 -0
- package/dist/languages/shared/table-profile-queries.d.ts +27 -0
- package/dist/languages/shared/table-profile-queries.d.ts.map +1 -0
- package/dist/languages/shared/table-profile-queries.js +70 -0
- package/dist/languages/shared/table-profile-queries.js.map +1 -0
- package/dist/languages/shared/table-profile-scopes.d.ts +46 -0
- package/dist/languages/shared/table-profile-scopes.d.ts.map +1 -0
- package/dist/languages/shared/table-profile-scopes.js +180 -0
- package/dist/languages/shared/table-profile-scopes.js.map +1 -0
- package/dist/languages/shared/table-profile.d.ts +302 -0
- package/dist/languages/shared/table-profile.d.ts.map +1 -0
- package/dist/languages/shared/table-profile.js +125 -0
- package/dist/languages/shared/table-profile.js.map +1 -0
- package/dist/languages/shared/tree-sitter-types.d.ts +44 -0
- package/dist/languages/shared/tree-sitter-types.d.ts.map +1 -0
- package/dist/languages/shared/tree-sitter-types.js +2 -0
- package/dist/languages/shared/tree-sitter-types.js.map +1 -0
- package/dist/languages/structured-text/index.d.ts +48 -0
- package/dist/languages/structured-text/index.d.ts.map +1 -0
- package/dist/languages/structured-text/index.js +120 -0
- package/dist/languages/structured-text/index.js.map +1 -0
- package/dist/languages/tsx/index.d.ts +4 -0
- package/dist/languages/tsx/index.d.ts.map +1 -0
- package/dist/languages/tsx/index.js +7 -0
- package/dist/languages/tsx/index.js.map +1 -0
- package/dist/languages/typescript/index.d.ts +4 -0
- package/dist/languages/typescript/index.d.ts.map +1 -0
- package/dist/languages/typescript/index.js +7 -0
- package/dist/languages/typescript/index.js.map +1 -0
- package/dist/languages/vue/index.d.ts +21 -0
- package/dist/languages/vue/index.d.ts.map +1 -0
- package/dist/languages/vue/index.js +234 -0
- package/dist/languages/vue/index.js.map +1 -0
- package/dist/languages/vue/mapping.d.ts +11 -0
- package/dist/languages/vue/mapping.d.ts.map +1 -0
- package/dist/languages/vue/mapping.js +77 -0
- package/dist/languages/vue/mapping.js.map +1 -0
- package/dist/registry.d.ts +24 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +42 -0
- package/dist/registry.js.map +1 -0
- package/dist/text/byte-offset-table.d.ts +27 -0
- package/dist/text/byte-offset-table.d.ts.map +1 -0
- package/dist/text/byte-offset-table.js +39 -0
- package/dist/text/byte-offset-table.js.map +1 -0
- package/package.json +125 -3
- package/src/boundaries/expression.ts +95 -0
- package/src/boundaries/extract.ts +307 -0
- package/src/boundaries/python.ts +181 -0
- package/src/index.ts +51 -0
- package/src/languages/__golden__/javascript-basic.json +32 -0
- package/src/languages/__golden__/tsx-basic.json +19 -0
- package/src/languages/__golden__/typescript-basic.json +37 -0
- package/src/languages/astgrep-backend/GRAMMARS.md +86 -0
- package/src/languages/astgrep-backend/README.md +112 -0
- package/src/languages/astgrep-backend/__golden__/bash-basic.sh +53 -0
- package/src/languages/astgrep-backend/__golden__/c-basic.c +64 -0
- package/src/languages/astgrep-backend/__golden__/cpp-basic.cpp +65 -0
- package/src/languages/astgrep-backend/__golden__/csharp-basic.cs +73 -0
- package/src/languages/astgrep-backend/__golden__/go-basic.go +93 -0
- package/src/languages/astgrep-backend/__golden__/java-basic.java +62 -0
- package/src/languages/astgrep-backend/__golden__/kotlin-basic.kt +58 -0
- package/src/languages/astgrep-backend/__golden__/php-basic.php +72 -0
- package/src/languages/astgrep-backend/__golden__/ruby-basic.rb +62 -0
- package/src/languages/astgrep-backend/__golden__/rust-basic.rs +82 -0
- package/src/languages/astgrep-backend/__golden__/swift-basic.swift +73 -0
- package/src/languages/astgrep-backend/adapter.ts +240 -0
- package/src/languages/astgrep-backend/index.ts +44 -0
- package/src/languages/astgrep-backend/lang/README.md +115 -0
- package/src/languages/astgrep-backend/lang/bash.ts +78 -0
- package/src/languages/astgrep-backend/lang/c.ts +119 -0
- package/src/languages/astgrep-backend/lang/cpp.ts +65 -0
- package/src/languages/astgrep-backend/lang/csharp.ts +125 -0
- package/src/languages/astgrep-backend/lang/index.ts +61 -0
- package/src/languages/astgrep-backend/lang/java.ts +115 -0
- package/src/languages/astgrep-backend/lang/kotlin.ts +136 -0
- package/src/languages/astgrep-backend/lang/php.ts +105 -0
- package/src/languages/astgrep-backend/lang/ruby.ts +105 -0
- package/src/languages/astgrep-backend/lang/swift.ts +118 -0
- package/src/languages/astgrep-backend/languages.ts +238 -0
- package/src/languages/astgrep-backend/napi.ts +261 -0
- package/src/languages/astgrep-backend/syntax.ts +242 -0
- package/src/languages/index.ts +53 -0
- package/src/languages/javascript/index.ts +9 -0
- package/src/languages/jsx/index.ts +9 -0
- package/src/languages/prose/index.ts +270 -0
- package/src/languages/prose/line-bytes.ts +52 -0
- package/src/languages/python/README.md +246 -0
- package/src/languages/python/__golden__/python-basic.json +44 -0
- package/src/languages/python/create-adapter.ts +29 -0
- package/src/languages/python/index.ts +8 -0
- package/src/languages/python/profile.ts +341 -0
- package/src/languages/python/signature.ts +183 -0
- package/src/languages/python/table.ts +135 -0
- package/src/languages/shared/__fixtures__/large-over-32kib.ts.txt +1207 -0
- package/src/languages/shared/call-detection.ts +112 -0
- package/src/languages/shared/chunks.ts +255 -0
- package/src/languages/shared/create-adapter.ts +136 -0
- package/src/languages/shared/decisions.ts +204 -0
- package/src/languages/shared/dialect.ts +55 -0
- package/src/languages/shared/doc-binding.ts +78 -0
- package/src/languages/shared/engine.ts +461 -0
- package/src/languages/shared/extract-symbols.ts +35 -0
- package/src/languages/shared/fingerprint.ts +99 -0
- package/src/languages/shared/grammar-loader.ts +67 -0
- package/src/languages/shared/import-detection.ts +154 -0
- package/src/languages/shared/js-family-profile.ts +246 -0
- package/src/languages/shared/node-kinds.ts +153 -0
- package/src/languages/shared/node-utils.ts +120 -0
- package/src/languages/shared/parse-diagnostics.ts +125 -0
- package/src/languages/shared/parse-limits.ts +147 -0
- package/src/languages/shared/profile.ts +184 -0
- package/src/languages/shared/scope-model.ts +43 -0
- package/src/languages/shared/scope-naming.ts +124 -0
- package/src/languages/shared/scope-signature.ts +108 -0
- package/src/languages/shared/signature.ts +149 -0
- package/src/languages/shared/syntax.ts +116 -0
- package/src/languages/shared/table-profile-decisions.ts +251 -0
- package/src/languages/shared/table-profile-module-facts.ts +177 -0
- package/src/languages/shared/table-profile-queries.ts +85 -0
- package/src/languages/shared/table-profile-scopes.ts +198 -0
- package/src/languages/shared/table-profile.ts +427 -0
- package/src/languages/shared/tree-sitter-types.ts +46 -0
- package/src/languages/structured-text/index.ts +192 -0
- package/src/languages/tsx/index.ts +9 -0
- package/src/languages/typescript/index.ts +9 -0
- package/src/languages/vue/index.ts +312 -0
- package/src/languages/vue/mapping.ts +93 -0
- package/src/registry.ts +61 -0
- package/src/text/byte-offset-table.ts +63 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { SupportLevel } from "@untangle-code/domain";
|
|
2
|
+
|
|
3
|
+
import type { GrammarSource } from "./grammar-loader.js";
|
|
4
|
+
|
|
5
|
+
/** Static, per-language configuration for the tree-sitter adapter factory. */
|
|
6
|
+
export interface Dialect {
|
|
7
|
+
languageId: string;
|
|
8
|
+
extensions: string[];
|
|
9
|
+
supportLevel: SupportLevel;
|
|
10
|
+
grammar: GrammarSource;
|
|
11
|
+
/** Whether the grammar has TypeScript type syntax (interfaces, type aliases, enums, type annotations, generics). */
|
|
12
|
+
hasTypes: boolean;
|
|
13
|
+
/** Class field/property-signature node type name, which differs between the JS and TS grammars. */
|
|
14
|
+
fieldDefinitionKind: "field_definition" | "public_field_definition";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const TYPESCRIPT_DIALECT: Dialect = {
|
|
18
|
+
languageId: "typescript",
|
|
19
|
+
extensions: [".ts", ".mts", ".cts"],
|
|
20
|
+
supportLevel: "deep",
|
|
21
|
+
grammar: { moduleName: "tree-sitter-typescript", exportName: "typescript" },
|
|
22
|
+
hasTypes: true,
|
|
23
|
+
fieldDefinitionKind: "public_field_definition",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const TSX_DIALECT: Dialect = {
|
|
27
|
+
languageId: "tsx",
|
|
28
|
+
extensions: [".tsx"],
|
|
29
|
+
supportLevel: "deep",
|
|
30
|
+
grammar: { moduleName: "tree-sitter-typescript", exportName: "tsx" },
|
|
31
|
+
hasTypes: true,
|
|
32
|
+
fieldDefinitionKind: "public_field_definition",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const JAVASCRIPT_DIALECT: Dialect = {
|
|
36
|
+
languageId: "javascript",
|
|
37
|
+
extensions: [".js", ".mjs", ".cjs"],
|
|
38
|
+
supportLevel: "deep",
|
|
39
|
+
grammar: { moduleName: "tree-sitter-javascript" },
|
|
40
|
+
hasTypes: false,
|
|
41
|
+
fieldDefinitionKind: "field_definition",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const JSX_DIALECT: Dialect = {
|
|
45
|
+
languageId: "jsx",
|
|
46
|
+
extensions: [".jsx"],
|
|
47
|
+
supportLevel: "deep",
|
|
48
|
+
// tree-sitter-javascript's single grammar already parses JSX syntax
|
|
49
|
+
// (verified empirically — see README "Grammatik-Wahl"); JSX gets its own
|
|
50
|
+
// languageId/extension per spec.md §7.2's MVP table row ("TSX/JSX"), not
|
|
51
|
+
// its own grammar.
|
|
52
|
+
grammar: { moduleName: "tree-sitter-javascript" },
|
|
53
|
+
hasTypes: false,
|
|
54
|
+
fieldDefinitionKind: "field_definition",
|
|
55
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doc-comment binding (spec.md §8.3 step 2: "Doccomment, Annotationen und
|
|
3
|
+
* Dekoratoren an das folgende Symbol binden").
|
|
4
|
+
*
|
|
5
|
+
* Decorators are represented by the grammar as PRECEDING SIBLINGS of the
|
|
6
|
+
* member they decorate inside `class_body` (verified empirically — not as a
|
|
7
|
+
* nested field on the member node, despite `node-types.json` listing
|
|
8
|
+
* `decorator` as an optional field; that field shape applies to parameter
|
|
9
|
+
* decorators, e.g. `constructor(@Inject() dep: Dep)`, which nest inside
|
|
10
|
+
* `required_parameter` instead). A leading doc comment is, in turn, a
|
|
11
|
+
* preceding sibling of the (possibly decorator-preceded) member.
|
|
12
|
+
*
|
|
13
|
+
* For a symbol whose defining node is buried inside an expression (an arrow
|
|
14
|
+
* function assigned to a `const`, a function expression as an object
|
|
15
|
+
* property value, ...), the anchor for "preceding sibling" purposes is not
|
|
16
|
+
* the function node itself but its enclosing statement — see
|
|
17
|
+
* `resolveDocAnchor`.
|
|
18
|
+
*/
|
|
19
|
+
import type { SourceRange } from "@untangle-code/domain";
|
|
20
|
+
|
|
21
|
+
import { COMMENT_TYPE, DECORATOR_TYPE } from "./node-kinds.js";
|
|
22
|
+
import type { FileTextContext } from "./node-utils.js";
|
|
23
|
+
import { rangeOf, unionRange } from "./node-utils.js";
|
|
24
|
+
import type { SyntaxNode } from "./syntax.js";
|
|
25
|
+
|
|
26
|
+
/** Climbs from a (possibly deeply nested) scope-defining node to its statement-level anchor. */
|
|
27
|
+
export function resolveDocAnchor(node: SyntaxNode): SyntaxNode {
|
|
28
|
+
let anchor = node;
|
|
29
|
+
const parent = node.parent;
|
|
30
|
+
if (parent !== null) {
|
|
31
|
+
if (parent.type === "variable_declarator") {
|
|
32
|
+
const declarationList = parent.parent;
|
|
33
|
+
if (
|
|
34
|
+
declarationList !== null &&
|
|
35
|
+
(declarationList.type === "lexical_declaration" ||
|
|
36
|
+
declarationList.type === "variable_declaration")
|
|
37
|
+
) {
|
|
38
|
+
anchor = declarationList;
|
|
39
|
+
}
|
|
40
|
+
} else if (
|
|
41
|
+
parent.type === "assignment_expression" &&
|
|
42
|
+
parent.parent?.type === "expression_statement"
|
|
43
|
+
) {
|
|
44
|
+
anchor = parent.parent;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (anchor.parent !== null && anchor.parent.type === "export_statement") {
|
|
48
|
+
anchor = anchor.parent;
|
|
49
|
+
}
|
|
50
|
+
return anchor;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const MAX_BLANK_LINES_BETWEEN_DOC_AND_SYMBOL = 1;
|
|
54
|
+
|
|
55
|
+
/** Resolves the bound doc-comment range for a scope-defining node, if any (spec.md §8.3 step 2). */
|
|
56
|
+
export function resolveDocRange(node: SyntaxNode, ctx: FileTextContext): SourceRange | undefined {
|
|
57
|
+
const anchor = resolveDocAnchor(node);
|
|
58
|
+
|
|
59
|
+
let cursor = anchor.previousSibling;
|
|
60
|
+
let boundary = anchor;
|
|
61
|
+
// Skip immediately-preceding decorators (they travel with the symbol's own range, not the doc range,
|
|
62
|
+
// but a comment further back must still be considered "immediately preceding" through them).
|
|
63
|
+
while (cursor !== null && cursor.type === DECORATOR_TYPE) {
|
|
64
|
+
boundary = cursor;
|
|
65
|
+
cursor = cursor.previousSibling;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let docRange: SourceRange | undefined;
|
|
69
|
+
while (cursor !== null && cursor.type === COMMENT_TYPE) {
|
|
70
|
+
const gap = boundary.startPosition.row - cursor.endPosition.row;
|
|
71
|
+
if (gap > MAX_BLANK_LINES_BETWEEN_DOC_AND_SYMBOL) break;
|
|
72
|
+
const commentRange = rangeOf(cursor, ctx);
|
|
73
|
+
docRange = docRange === undefined ? commentRange : unionRange(commentRange, docRange);
|
|
74
|
+
boundary = cursor;
|
|
75
|
+
cursor = cursor.previousSibling;
|
|
76
|
+
}
|
|
77
|
+
return docRange;
|
|
78
|
+
}
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single unified AST walk. Every `LanguageAdapter` extraction method
|
|
3
|
+
* (`extractSymbols`, `extractImports`, `extractCalls`, `computeComplexity`,
|
|
4
|
+
* `tokenizeForHalstead`, `extractChunks`) is a thin projection over the ONE
|
|
5
|
+
* `AnalysisResult` this module computes — see `create-adapter.ts`, which
|
|
6
|
+
* memoizes it per `ParsedAst` (via `WeakMap`) so calling multiple extract
|
|
7
|
+
* methods on the same parse re-walks the tree only once.
|
|
8
|
+
*
|
|
9
|
+
* Building everything in one pass is not just a performance optimization:
|
|
10
|
+
* it is what GUARANTEES that a `symbolScopeId` produced for a
|
|
11
|
+
* `SymbolScopeFact` (from `computeComplexity`) is the exact same string as
|
|
12
|
+
* the `callerScopeId` on a `RawCall` (from `extractCalls`) for a call
|
|
13
|
+
* written inside that scope — both come from the same live scope-stack
|
|
14
|
+
* frame during the same walk, not from two independently-reimplemented
|
|
15
|
+
* scope-id algorithms that could drift apart.
|
|
16
|
+
*
|
|
17
|
+
* TRAVERSIERUNG (WP-95): der Walk laeuft ueber die CURSOR-API
|
|
18
|
+
* (`tree.walk()` / `gotoFirstChild` / `gotoNextSibling` / `gotoParent`),
|
|
19
|
+
* NICHT ueber `node.children`. Gemessen an diesem Repository (716 Dateien,
|
|
20
|
+
* 128.219 Zeilen) kostete der `.children`-Weg 25,6 s fuer den Walk gegen
|
|
21
|
+
* 3,6 s fuers Parsen: jeder `.children`-Zugriff baut ein JS-Array aus
|
|
22
|
+
* Knotenwrappern und ueberquert die Grenze zur nativen Bibliothek einmal je
|
|
23
|
+
* Knoten. Der Cursor haelt die Position nativ.
|
|
24
|
+
*
|
|
25
|
+
* WAS DER CURSOR NICHT HAT, und wie es hier ersetzt wird:
|
|
26
|
+
* - `node.parent` -> `parentTypeAt[depth]`, waehrend des Abstiegs gefuehrt.
|
|
27
|
+
* - `node.childCount === 0` -> ein probeweises `gotoFirstChild()`; schlaegt
|
|
28
|
+
* es fehl, ist der Knoten ein Blatt (sonst bringt `gotoParent()` zurueck).
|
|
29
|
+
* - `parent.childForFieldName(...)` fuer die Rolle eines Bezeichners ->
|
|
30
|
+
* `cursor.currentFieldName`, das denselben Feldnamen ohne Wrapper liefert.
|
|
31
|
+
*
|
|
32
|
+
* Ein `SyntaxNode`-Wrapper entsteht nur noch dort, wo ein Detektor ihn
|
|
33
|
+
* wirklich braucht (siehe `visitInnerNode`) — wer diese Vorsiebe aufweicht,
|
|
34
|
+
* baut die Grenzueberquerung je Knoten wieder ein.
|
|
35
|
+
*/
|
|
36
|
+
import type {
|
|
37
|
+
ComplexityFacts,
|
|
38
|
+
IdentifierFact,
|
|
39
|
+
LiteralFact,
|
|
40
|
+
NodeKindFact,
|
|
41
|
+
RawCall,
|
|
42
|
+
RawImport,
|
|
43
|
+
SourceRange,
|
|
44
|
+
SymbolScopeFact,
|
|
45
|
+
TokenFact,
|
|
46
|
+
} from "@untangle-code/domain";
|
|
47
|
+
|
|
48
|
+
import { lambdaNesting } from "./decisions.js";
|
|
49
|
+
import { computeAstHash, computeTokenFingerprint } from "./fingerprint.js";
|
|
50
|
+
import type { FileTextContext } from "./node-utils.js";
|
|
51
|
+
import { commentRangeOfCursor, rangeOf, rangeOfCursor } from "./node-utils.js";
|
|
52
|
+
import type { LanguageProfile, ModuleFactSink } from "./profile.js";
|
|
53
|
+
import { isExecutableScopeKind } from "./profile.js";
|
|
54
|
+
import type { ScopeNode } from "./scope-model.js";
|
|
55
|
+
import type { SyntaxCursor, SyntaxNode } from "./syntax.js";
|
|
56
|
+
|
|
57
|
+
export interface AnalysisResult {
|
|
58
|
+
scopeTree: ScopeNode;
|
|
59
|
+
facts: ComplexityFacts;
|
|
60
|
+
imports: RawImport[];
|
|
61
|
+
calls: RawCall[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface MutableFacts {
|
|
65
|
+
symbolScopes: SymbolScopeFact[];
|
|
66
|
+
decisions: ComplexityFacts["decisions"];
|
|
67
|
+
nestingEvents: ComplexityFacts["nestingEvents"];
|
|
68
|
+
operators: TokenFact[];
|
|
69
|
+
operands: TokenFact[];
|
|
70
|
+
nodeKinds: NodeKindFact[];
|
|
71
|
+
comments: SourceRange[];
|
|
72
|
+
identifiers: IdentifierFact[];
|
|
73
|
+
literals: LiteralFact[];
|
|
74
|
+
imports: RawImport[];
|
|
75
|
+
calls: RawCall[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Separates scope-id components (U+001F, unit separator) — avoids the classic "ab"+"c" == "a"+"bc" join ambiguity. */
|
|
79
|
+
const SCOPE_ID_SEPARATOR = "";
|
|
80
|
+
|
|
81
|
+
interface WorkingFrame {
|
|
82
|
+
scopeId: string;
|
|
83
|
+
qualifiedName: string;
|
|
84
|
+
executable: boolean;
|
|
85
|
+
scopeNode: ScopeNode;
|
|
86
|
+
childOrdinalCounters: Map<string, number>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function toSymbolScopeFact(
|
|
90
|
+
frame: WorkingFrame,
|
|
91
|
+
parentScopeId: string | undefined,
|
|
92
|
+
): SymbolScopeFact {
|
|
93
|
+
const { scopeNode } = frame;
|
|
94
|
+
return {
|
|
95
|
+
symbolScopeId: scopeNode.scopeId,
|
|
96
|
+
name: scopeNode.name,
|
|
97
|
+
qualifiedName: scopeNode.qualifiedName,
|
|
98
|
+
kind: scopeNode.kind,
|
|
99
|
+
range: scopeNode.range,
|
|
100
|
+
...(parentScopeId !== undefined ? { parentScopeId } : {}),
|
|
101
|
+
executable: scopeNode.executable,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function openScope(
|
|
106
|
+
cursor: SyntaxCursor,
|
|
107
|
+
node: SyntaxNode,
|
|
108
|
+
parent: WorkingFrame,
|
|
109
|
+
profile: LanguageProfile,
|
|
110
|
+
ctx: FileTextContext,
|
|
111
|
+
fileId: string,
|
|
112
|
+
out: MutableFacts,
|
|
113
|
+
): WorkingFrame | null {
|
|
114
|
+
if (profile.suppressesScope(node)) return null;
|
|
115
|
+
|
|
116
|
+
const kind = profile.scopeKindOf(node);
|
|
117
|
+
if (kind === null) return null;
|
|
118
|
+
|
|
119
|
+
const name = profile.scopeName(node);
|
|
120
|
+
// WP-237: Sprachen, die den Traeger als FELD statt als Elternknoten fuehren
|
|
121
|
+
// (Gos Methodenempfaenger), liefern ihn hier nach. Der SYMBOLNAME bleibt
|
|
122
|
+
// unveraendert `Run` — nur der qualifizierte Name wird `A.Run`, damit zwei
|
|
123
|
+
// gleichnamige Methoden auf verschiedenen Typen unterscheidbar bleiben.
|
|
124
|
+
const qualifier = profile.scopeQualifier?.(node);
|
|
125
|
+
const localName = qualifier === undefined ? name : `${qualifier}.${name}`;
|
|
126
|
+
const qualifiedName =
|
|
127
|
+
parent.qualifiedName.length > 0 ? `${parent.qualifiedName}.${localName}` : localName;
|
|
128
|
+
const counterKey = `${kind}:${qualifiedName}`;
|
|
129
|
+
const ordinal = parent.childOrdinalCounters.get(counterKey) ?? 0;
|
|
130
|
+
parent.childOrdinalCounters.set(counterKey, ordinal + 1);
|
|
131
|
+
const scopeId = [fileId, "scope", qualifiedName, kind, String(ordinal)].join(SCOPE_ID_SEPARATOR);
|
|
132
|
+
|
|
133
|
+
const signature = profile.scopeSignature(node, kind, name);
|
|
134
|
+
const docRange = profile.docRange(node, ctx);
|
|
135
|
+
const executable = isExecutableScopeKind(kind);
|
|
136
|
+
const visibility = profile.visibility(node, name);
|
|
137
|
+
const parentQualifiedName = parent.qualifiedName.length > 0 ? parent.qualifiedName : undefined;
|
|
138
|
+
|
|
139
|
+
const scopeNode: ScopeNode = {
|
|
140
|
+
scopeId,
|
|
141
|
+
kind,
|
|
142
|
+
name,
|
|
143
|
+
qualifiedName,
|
|
144
|
+
...(parentQualifiedName !== undefined ? { parentQualifiedName } : {}),
|
|
145
|
+
range: rangeOf(node, ctx),
|
|
146
|
+
...(docRange !== undefined ? { docRange } : {}),
|
|
147
|
+
...(signature.raw !== undefined ? { signature: signature.raw } : {}),
|
|
148
|
+
normalizedSignature: signature.normalized,
|
|
149
|
+
exportedNames: profile.exportedNames(node, name),
|
|
150
|
+
...(visibility !== undefined ? { visibility } : {}),
|
|
151
|
+
executable,
|
|
152
|
+
astHash: computeAstHash(cursor, profile),
|
|
153
|
+
tokenFingerprint: computeTokenFingerprint(cursor, profile),
|
|
154
|
+
node,
|
|
155
|
+
children: [],
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const frame: WorkingFrame = {
|
|
159
|
+
scopeId,
|
|
160
|
+
qualifiedName,
|
|
161
|
+
executable,
|
|
162
|
+
scopeNode,
|
|
163
|
+
childOrdinalCounters: new Map(),
|
|
164
|
+
};
|
|
165
|
+
out.symbolScopes.push(toSymbolScopeFact(frame, parent.scopeId));
|
|
166
|
+
parent.scopeNode.children.push(scopeNode);
|
|
167
|
+
return frame;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Ein Blattknoten (kein Kind) wird eingeordnet. Der Cursor steht auf ihm; ein
|
|
172
|
+
* `SyntaxNode`-Wrapper wird NICHT gebaut — `nodeText`, `nodeType` und
|
|
173
|
+
* `currentFieldName` liefern alles Noetige, `parentType` kommt aus dem Abstieg.
|
|
174
|
+
*
|
|
175
|
+
* Die frueher hier stehende `predefined_type`-Pruefung ist ENTFALLEN, nicht
|
|
176
|
+
* vergessen: der einzige Aufrufer (`walkWithCursor`) siebt diesen Fall bereits
|
|
177
|
+
* vor dem Blatt-Zweig aus (ueber `profile.typeKeywordParentKinds`), die
|
|
178
|
+
* Pruefung war an dieser Stelle unerreichbar.
|
|
179
|
+
*/
|
|
180
|
+
function classifyAndRecordLeaf(
|
|
181
|
+
cursor: SyntaxCursor,
|
|
182
|
+
nodeType: string,
|
|
183
|
+
parentType: string,
|
|
184
|
+
range: SourceRange,
|
|
185
|
+
frame: WorkingFrame,
|
|
186
|
+
profile: LanguageProfile,
|
|
187
|
+
out: MutableFacts,
|
|
188
|
+
): void {
|
|
189
|
+
const scopeId = frame.scopeId;
|
|
190
|
+
|
|
191
|
+
if (profile.identifierLeafKinds.has(nodeType)) {
|
|
192
|
+
const text = cursor.nodeText;
|
|
193
|
+
out.identifiers.push({
|
|
194
|
+
name: text,
|
|
195
|
+
range,
|
|
196
|
+
symbolScopeId: scopeId,
|
|
197
|
+
role: profile.identifierRole(cursor.currentFieldName, parentType),
|
|
198
|
+
});
|
|
199
|
+
out.operands.push({ text, range, symbolScopeId: scopeId });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (profile.simpleLiteralLeafKinds.has(nodeType)) {
|
|
204
|
+
const text = cursor.nodeText;
|
|
205
|
+
out.literals.push({
|
|
206
|
+
raw: text,
|
|
207
|
+
literalKind: profile.simpleLiteralKind(nodeType),
|
|
208
|
+
range,
|
|
209
|
+
symbolScopeId: scopeId,
|
|
210
|
+
});
|
|
211
|
+
out.operands.push({ text, range, symbolScopeId: scopeId });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (profile.templateTextLeafKinds.has(nodeType)) {
|
|
216
|
+
const text = cursor.nodeText;
|
|
217
|
+
out.literals.push({ raw: text, literalKind: "template", range, symbolScopeId: scopeId });
|
|
218
|
+
out.operands.push({ text, range, symbolScopeId: scopeId });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (profile.ignoredPunctuationKinds.has(nodeType)) return;
|
|
223
|
+
|
|
224
|
+
out.operators.push({ text: cursor.nodeText, range, symbolScopeId: scopeId });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Alles, was ein innerer Knoten (mindestens ein Kind) beitraegt: Entscheidung,
|
|
229
|
+
* Nesting, Import, Aufruf, eigener Scope. Gibt den neu geoeffneten Scope-Rahmen
|
|
230
|
+
* zurueck, sonst `null`.
|
|
231
|
+
*
|
|
232
|
+
* HIER und nur hier entsteht ein `SyntaxNode`-Wrapper, und nur wenn das Profil
|
|
233
|
+
* fuer diese Knotenart ueberhaupt einen Detektor auf den Plan ruft
|
|
234
|
+
* (`profile.needsNode`). Fuer die grosse Mehrheit der inneren Knoten faellt die
|
|
235
|
+
* Grenzueberquerung damit ganz weg — beim tree-sitter-Backend spart das den
|
|
236
|
+
* Wrapper, beim ast-grep-Backend den weit teureren `children()`-Aufbau.
|
|
237
|
+
*/
|
|
238
|
+
function visitInnerNode(
|
|
239
|
+
cursor: SyntaxCursor,
|
|
240
|
+
nodeType: string,
|
|
241
|
+
range: SourceRange,
|
|
242
|
+
frame: WorkingFrame,
|
|
243
|
+
profile: LanguageProfile,
|
|
244
|
+
ctx: FileTextContext,
|
|
245
|
+
fileId: string,
|
|
246
|
+
out: MutableFacts,
|
|
247
|
+
): WorkingFrame | null {
|
|
248
|
+
// Kein Detektor zustaendig: kein Wrapper, kein Scope. Das Lambda-Nesting
|
|
249
|
+
// unten kann hier nicht verloren gehen — ein funktionsartiger Knoten oeffnet
|
|
250
|
+
// immer auch einen Scope, also ist `needsNode` dort wahr (in
|
|
251
|
+
// `js-family-profile.ts` wie in `table-profile.ts` durch Konstruktion).
|
|
252
|
+
if (!profile.needsNode(nodeType)) return null;
|
|
253
|
+
|
|
254
|
+
const node = cursor.currentNode;
|
|
255
|
+
|
|
256
|
+
// Decision / nesting facts.
|
|
257
|
+
const detected = profile.detectDecisionAndNesting(node);
|
|
258
|
+
if (detected.decision !== undefined) {
|
|
259
|
+
const fact = {
|
|
260
|
+
kind: detected.decision.kind,
|
|
261
|
+
range,
|
|
262
|
+
symbolScopeId: frame.scopeId,
|
|
263
|
+
countsForClassic: detected.decision.countsForClassic,
|
|
264
|
+
countsForExtended: detected.decision.countsForExtended,
|
|
265
|
+
...(detected.decision.logicalGroupId !== undefined
|
|
266
|
+
? { logicalGroupId: detected.decision.logicalGroupId }
|
|
267
|
+
: {}),
|
|
268
|
+
};
|
|
269
|
+
// `repeat` (Vorgabe 1) ist die flache n-stellige Alternative — siehe
|
|
270
|
+
// `DetectedDecision.repeat`. Jede Wiederholung ist eine EIGENE Tatsache
|
|
271
|
+
// mit demselben Bereich, kein Zaehler auf einer.
|
|
272
|
+
for (let index = 0; index < (detected.decision.repeat ?? 1); index += 1) {
|
|
273
|
+
out.decisions.push({ ...fact });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (detected.nesting !== undefined) {
|
|
277
|
+
out.nestingEvents.push({
|
|
278
|
+
construct: detected.nesting.construct,
|
|
279
|
+
range,
|
|
280
|
+
symbolScopeId: frame.scopeId,
|
|
281
|
+
continuation: detected.nesting.continuation,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Importe und Aufrufe (Aufrufe dem AKTUELLEN Scope zugerechnet, also dem Rufer).
|
|
286
|
+
const sink: ModuleFactSink = { imports: out.imports, calls: out.calls };
|
|
287
|
+
profile.collectModuleFacts(node, nodeType, frame.scopeId, ctx, sink);
|
|
288
|
+
|
|
289
|
+
const openedScope = openScope(cursor, node, frame, profile, ctx, fileId, out);
|
|
290
|
+
|
|
291
|
+
// A directly-nested function-like node (lambda/local function) inside an
|
|
292
|
+
// already-executable scope gets an extra lambda nesting event (spec.md
|
|
293
|
+
// §16.4: "lokale Funktionen/Lambdas verwenden einen dokumentierten
|
|
294
|
+
// Nesting-Kontext") in addition to becoming its own scope below. A node kind
|
|
295
|
+
// can be function-like only in a particular syntactic context, so a rejected
|
|
296
|
+
// scope must not leave behind a phantom lambda event.
|
|
297
|
+
if (openedScope !== null && frame.executable && profile.functionLikeKinds.has(nodeType)) {
|
|
298
|
+
const lambda = lambdaNesting();
|
|
299
|
+
out.nestingEvents.push({
|
|
300
|
+
construct: lambda.construct,
|
|
301
|
+
range,
|
|
302
|
+
symbolScopeId: frame.scopeId,
|
|
303
|
+
continuation: lambda.continuation,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return openedScope;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Der vereinheitlichte Walk, iterativ ueber einen Baumcursor.
|
|
312
|
+
*
|
|
313
|
+
* Der Cursor beginnt auf der Wurzel und endet wieder dort. Besuchsreihenfolge,
|
|
314
|
+
* `depth`-Zaehlung und die Reihenfolge JEDER Faktenliste sind identisch mit
|
|
315
|
+
* der frueheren Rekursion ueber `node.children` — die Gegenprobe
|
|
316
|
+
* (`diff-walk.mjs`, siehe README) faehrt beide Wege ueber dieses Repository
|
|
317
|
+
* und vergleicht Symbole, Regionen, Chunk-IDs und Metriken Datei fuer Datei.
|
|
318
|
+
*
|
|
319
|
+
* `frameAt`/`parentTypeAt` sind nach Tiefe indiziert und ersetzen zusammen den
|
|
320
|
+
* Aufrufstapel der Rekursion samt `node.parent`. Eintraege unterhalb der
|
|
321
|
+
* aktuellen Tiefe sind veraltet, werden aber vor jedem Lesen ueberschrieben.
|
|
322
|
+
*/
|
|
323
|
+
function walkWithCursor(
|
|
324
|
+
cursor: SyntaxCursor,
|
|
325
|
+
rootType: string,
|
|
326
|
+
rootFrame: WorkingFrame,
|
|
327
|
+
profile: LanguageProfile,
|
|
328
|
+
ctx: FileTextContext,
|
|
329
|
+
fileId: string,
|
|
330
|
+
out: MutableFacts,
|
|
331
|
+
): void {
|
|
332
|
+
if (!cursor.gotoFirstChild()) return;
|
|
333
|
+
|
|
334
|
+
const frameAt: WorkingFrame[] = [rootFrame, rootFrame];
|
|
335
|
+
const parentTypeAt: string[] = [rootType, rootType];
|
|
336
|
+
let depth = 1;
|
|
337
|
+
|
|
338
|
+
for (;;) {
|
|
339
|
+
const frame = frameAt[depth] as WorkingFrame;
|
|
340
|
+
const parentType = parentTypeAt[depth] as string;
|
|
341
|
+
const nodeType = cursor.nodeType;
|
|
342
|
+
const range = rangeOfCursor(cursor, ctx);
|
|
343
|
+
out.nodeKinds.push({ kind: nodeType, depth, symbolScopeId: frame.scopeId });
|
|
344
|
+
|
|
345
|
+
let descended = false;
|
|
346
|
+
|
|
347
|
+
if (profile.commentKinds.has(nodeType)) {
|
|
348
|
+
out.comments.push(commentRangeOfCursor(cursor, ctx));
|
|
349
|
+
} else if (profile.typeKeywordParentKinds.has(parentType)) {
|
|
350
|
+
// Ein Typschluessselwort-Blatt (z. B. das `string`/`number`/`void`-Kind
|
|
351
|
+
// von `predefined_type`): dieselben Namen wie Literale, aber Typsyntax,
|
|
352
|
+
// kein Wert. Weiter in `nodeKinds` gezaehlt (oben), nie als
|
|
353
|
+
// Operator/Operand/Literal/Bezeichner. Muss VOR dem Literalcontainer
|
|
354
|
+
// unten stehen: das Kind fuer das Typschluesselwort `string` hat den
|
|
355
|
+
// Knotentyp "string" — genau denselben wie ein echtes Zeichenkettenliteral.
|
|
356
|
+
} else if (profile.literalContainerKinds.has(nodeType)) {
|
|
357
|
+
const text = cursor.nodeText;
|
|
358
|
+
out.operands.push({ text, range, symbolScopeId: frame.scopeId });
|
|
359
|
+
out.literals.push({
|
|
360
|
+
raw: text,
|
|
361
|
+
literalKind: profile.containerLiteralKind(nodeType),
|
|
362
|
+
range,
|
|
363
|
+
symbolScopeId: frame.scopeId,
|
|
364
|
+
});
|
|
365
|
+
} else if (!cursor.gotoFirstChild()) {
|
|
366
|
+
// Der Cursor kennt kein `childCount`: der fehlgeschlagene Abstieg IST
|
|
367
|
+
// die Blattpruefung, und er hat die Position nicht veraendert.
|
|
368
|
+
classifyAndRecordLeaf(cursor, nodeType, parentType, range, frame, profile, out);
|
|
369
|
+
} else {
|
|
370
|
+
cursor.gotoParent(); // zurueck auf den inneren Knoten selbst
|
|
371
|
+
const childFrame = visitInnerNode(cursor, nodeType, range, frame, profile, ctx, fileId, out);
|
|
372
|
+
cursor.gotoFirstChild();
|
|
373
|
+
depth += 1;
|
|
374
|
+
frameAt[depth] = childFrame ?? frame;
|
|
375
|
+
parentTypeAt[depth] = nodeType;
|
|
376
|
+
descended = true;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (descended) continue;
|
|
380
|
+
|
|
381
|
+
// Aufsteigen, bis ein Geschwisterknoten da ist. Tiefe 1 ohne Geschwister
|
|
382
|
+
// heisst: die Kinder der Wurzel sind abgearbeitet.
|
|
383
|
+
while (!cursor.gotoNextSibling()) {
|
|
384
|
+
if (depth === 1) return;
|
|
385
|
+
cursor.gotoParent();
|
|
386
|
+
depth -= 1;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Runs the single unified walk over a file's root node. */
|
|
392
|
+
export function analyzeTree(
|
|
393
|
+
root: SyntaxNode,
|
|
394
|
+
ctx: FileTextContext,
|
|
395
|
+
fileId: string,
|
|
396
|
+
profile: LanguageProfile,
|
|
397
|
+
): AnalysisResult {
|
|
398
|
+
const out: MutableFacts = {
|
|
399
|
+
symbolScopes: [],
|
|
400
|
+
decisions: [],
|
|
401
|
+
nestingEvents: [],
|
|
402
|
+
operators: [],
|
|
403
|
+
operands: [],
|
|
404
|
+
nodeKinds: [],
|
|
405
|
+
comments: [],
|
|
406
|
+
identifiers: [],
|
|
407
|
+
literals: [],
|
|
408
|
+
imports: [],
|
|
409
|
+
calls: [],
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// EIN Cursor fuer alles: er beginnt auf der Wurzel, und nur ein von der
|
|
413
|
+
// Wurzel her abgestiegener Cursor meldet Knotentypen verlaesslich (siehe
|
|
414
|
+
// `fingerprint.ts`, Punkt 2). Jede Hilfsfunktion, die ihn bewegt, gibt ihn
|
|
415
|
+
// an der Ausgangsposition zurueck.
|
|
416
|
+
const cursor = root.walk();
|
|
417
|
+
|
|
418
|
+
const fileScopeNode: ScopeNode = {
|
|
419
|
+
scopeId: fileId,
|
|
420
|
+
kind: "file",
|
|
421
|
+
name: "",
|
|
422
|
+
qualifiedName: "",
|
|
423
|
+
range: rangeOf(root, ctx),
|
|
424
|
+
normalizedSignature: "",
|
|
425
|
+
exportedNames: [],
|
|
426
|
+
executable: true,
|
|
427
|
+
astHash: computeAstHash(cursor, profile),
|
|
428
|
+
tokenFingerprint: computeTokenFingerprint(cursor, profile),
|
|
429
|
+
node: root,
|
|
430
|
+
children: [],
|
|
431
|
+
};
|
|
432
|
+
const rootFrame: WorkingFrame = {
|
|
433
|
+
scopeId: fileId,
|
|
434
|
+
qualifiedName: "",
|
|
435
|
+
executable: true,
|
|
436
|
+
scopeNode: fileScopeNode,
|
|
437
|
+
childOrdinalCounters: new Map(),
|
|
438
|
+
};
|
|
439
|
+
out.symbolScopes.push(toSymbolScopeFact(rootFrame, undefined));
|
|
440
|
+
|
|
441
|
+
walkWithCursor(cursor, root.type, rootFrame, profile, ctx, fileId, out);
|
|
442
|
+
|
|
443
|
+
const facts: ComplexityFacts = {
|
|
444
|
+
symbolScopes: out.symbolScopes,
|
|
445
|
+
decisions: out.decisions,
|
|
446
|
+
nestingEvents: out.nestingEvents,
|
|
447
|
+
operators: out.operators,
|
|
448
|
+
operands: out.operands,
|
|
449
|
+
nodeKinds: out.nodeKinds,
|
|
450
|
+
comments: out.comments,
|
|
451
|
+
identifiers: out.identifiers,
|
|
452
|
+
literals: out.literals,
|
|
453
|
+
// Leer AN DIESER STELLE mit Absicht: die Parse-Diagnosen entstehen in
|
|
454
|
+
// `parse()` und werden in `create-adapter.ts#getAnalysis` eingesetzt,
|
|
455
|
+
// bevor die Facts den Adapter verlassen. Wer diese Zeile als "sowieso
|
|
456
|
+
// immer leer" liest, hat den falschen Ausschnitt vor sich.
|
|
457
|
+
parseDiagnostics: [],
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
return { scopeTree: fileScopeNode, facts, imports: out.imports, calls: out.calls };
|
|
461
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ExtractedSymbol } from "@untangle-code/domain";
|
|
2
|
+
|
|
3
|
+
import type { ScopeNode } from "./scope-model.js";
|
|
4
|
+
|
|
5
|
+
function toExtractedSymbol(scope: ScopeNode): ExtractedSymbol {
|
|
6
|
+
return {
|
|
7
|
+
name: scope.name,
|
|
8
|
+
qualifiedName: scope.qualifiedName,
|
|
9
|
+
kind: scope.kind,
|
|
10
|
+
...(scope.signature !== undefined ? { signature: scope.signature } : {}),
|
|
11
|
+
normalizedSignature: scope.normalizedSignature,
|
|
12
|
+
range: scope.range,
|
|
13
|
+
...(scope.docRange !== undefined ? { docRange: scope.docRange } : {}),
|
|
14
|
+
...(scope.parentQualifiedName !== undefined
|
|
15
|
+
? { parentQualifiedName: scope.parentQualifiedName }
|
|
16
|
+
: {}),
|
|
17
|
+
exportedNames: scope.exportedNames,
|
|
18
|
+
...(scope.visibility !== undefined ? { visibility: scope.visibility } : {}),
|
|
19
|
+
astHash: scope.astHash,
|
|
20
|
+
tokenFingerprint: scope.tokenFingerprint,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Flattens the scope tree (excluding the synthetic file-level root) into `ExtractedSymbol[]`, document order. */
|
|
25
|
+
export function extractedSymbolsOf(fileScope: ScopeNode): ExtractedSymbol[] {
|
|
26
|
+
const symbols: ExtractedSymbol[] = [];
|
|
27
|
+
const visit = (scope: ScopeNode): void => {
|
|
28
|
+
for (const child of scope.children) {
|
|
29
|
+
symbols.push(toExtractedSymbol(child));
|
|
30
|
+
visit(child);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
visit(fileScope);
|
|
34
|
+
return symbols;
|
|
35
|
+
}
|