@lowgular/code-graph 0.1.1 → 0.1.2
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/bin/cli.js +2458 -5
- package/lib.js +2430 -0
- package/package.json +3 -2
- package/code-graph-v2/code.graph.js +0 -37
- package/code-graph-v2/config-from-query.js +0 -131
- package/code-graph-v2/extractors/extractor.js +0 -27
- package/code-graph-v2/extractors/index.js +0 -1
- package/code-graph-v2/graph-builder/code-graph.builder.js +0 -49
- package/code-graph-v2/graph-builder/index.js +0 -1
- package/code-graph-v2/graph-builder/node.processor.js +0 -22
- package/code-graph-v2/graph-builder/relationship.processor.js +0 -55
- package/code-graph-v2/graph-builder/type.processor.js +0 -21
- package/code-graph-v2/index.js +0 -4
- package/code-graph-v2/tools/build-code-graph.tool.js +0 -19
- package/code-graph-v2/utils.js +0 -34
- package/codegular/index.js +0 -5
- package/codegular/node.js +0 -71
- package/codegular/program.js +0 -100
- package/codegular/string.js +0 -121
- package/codegular/type-checker.js +0 -133
- package/codegular/type.js +0 -356
- package/codegular/utils.js +0 -335
- package/cypher/index.js +0 -1
- package/cypher/lib/executor/condition-evaluator.js +0 -135
- package/cypher/lib/executor/executor.js +0 -60
- package/cypher/lib/executor/graph.js +0 -0
- package/cypher/lib/executor/match-engine.js +0 -130
- package/cypher/lib/executor/pattern-matcher.js +0 -86
- package/cypher/lib/executor/relationship-navigator.js +0 -41
- package/cypher/lib/executor/result-formatter.js +0 -149
- package/cypher/lib/executor/traverse-engine.js +0 -141
- package/cypher/lib/executor/utils.js +0 -14
- package/cypher/lib/graph.stub.js +0 -38
- package/cypher/lib/index.js +0 -32
- package/cypher/lib/lexer.js +0 -376
- package/cypher/lib/parser.js +0 -586
- package/cypher/lib/validator/query-validator.js +0 -75
- package/cypher/lib/validator/supported-features.config.js +0 -83
- package/cypher/lib/validator/unsupported-features.config.js +0 -124
- package/cypher-cli.js +0 -41
- package/infra/code-graph.js +0 -147
- package/main.js +0 -0
- package/resources-cli.js +0 -75
- package/run-cli.js +0 -43
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
const NODE_CONSTRAINTS = [
|
|
2
|
-
{
|
|
3
|
-
description: "Nodes can have multiple labels (:A:B means must have A AND B and :A|B means must have A OR B)"
|
|
4
|
-
},
|
|
5
|
-
{
|
|
6
|
-
description: "Properties are flat (no nested objects)"
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
description: "Property values are primitive types only (no temporal types, points, or complex objects)"
|
|
10
|
-
}
|
|
11
|
-
];
|
|
12
|
-
const RELATIONSHIP_CONSTRAINTS = [
|
|
13
|
-
{
|
|
14
|
-
description: "Variable-length paths only support `*` (unlimited, zero or more)"
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
description: "Path range syntax not supported: `*1..3`, `*2..`, `*..3` are invalid"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
description: "Edge properties not supported - cannot filter edges by properties"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
description: "Edges only have: source, target, type (no custom properties)"
|
|
24
|
-
}
|
|
25
|
-
];
|
|
26
|
-
const QUERY_CONSTRAINTS = [
|
|
27
|
-
{
|
|
28
|
-
description: "RETURN clause cannot be omitted (make sure to always add at least the clause: RETURN * - all matched variables are returned)"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
description: "The IN operator matches the EXACT array."
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
description: "WHERE conditions must use same logic operator (all AND or all OR, cannot mix)"
|
|
35
|
-
}
|
|
36
|
-
];
|
|
37
|
-
const PATTERN_CONSTRAINTS = [
|
|
38
|
-
{
|
|
39
|
-
description: "Label AND syntax: `(n:Label1:Label2)` requires both labels (AND semantics)"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
description: "Label OR syntax: `(n:Label1|Label2)` requires either label (OR semantics)"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
description: "Anonymous variables are auto-generated and filtered from results"
|
|
46
|
-
}
|
|
47
|
-
];
|
|
48
|
-
const RESULT_FORMAT_ITEMS = [
|
|
49
|
-
{
|
|
50
|
-
description: "Results are arrays of objects"
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
description: "Each object maps variable names to matched nodes/edges"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
description: "Nodes include: id, labels, filePath, range and name."
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
description: "Edges include: source, target, type"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
description: "Null values preserved for unmatched optional variables"
|
|
63
|
-
}
|
|
64
|
-
];
|
|
65
|
-
const ERROR_HANDLING_ITEMS = [
|
|
66
|
-
{
|
|
67
|
-
description: "Standard parser errors for invalid syntax"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
description: "Undefined variables in WHERE or RETURN will cause errors"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
description: "Using FORBIDDEN features will cause errors"
|
|
74
|
-
}
|
|
75
|
-
];
|
|
76
|
-
export {
|
|
77
|
-
ERROR_HANDLING_ITEMS,
|
|
78
|
-
NODE_CONSTRAINTS,
|
|
79
|
-
PATTERN_CONSTRAINTS,
|
|
80
|
-
QUERY_CONSTRAINTS,
|
|
81
|
-
RELATIONSHIP_CONSTRAINTS,
|
|
82
|
-
RESULT_FORMAT_ITEMS
|
|
83
|
-
};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
const FORBIDDEN_KEYWORDS = [
|
|
2
|
-
{
|
|
3
|
-
pattern: /\bWITH\b/i,
|
|
4
|
-
name: "WITH clause",
|
|
5
|
-
errorMessage: "WITH clause is not supported. Cannot use WITH for intermediate results or variable passing.",
|
|
6
|
-
alternative: "Use multiple MATCH statements or inline variables directly in WHERE/RETURN clauses."
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
pattern: /\bUNWIND\b/i,
|
|
10
|
-
name: "UNWIND clause",
|
|
11
|
-
errorMessage: "UNWIND clause is not supported. Cannot use UNWIND to expand arrays."
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
pattern: /\bUNION\b/i,
|
|
15
|
-
name: "UNION clause",
|
|
16
|
-
errorMessage: "UNION clause is not supported. Cannot combine result sets with UNION."
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
pattern: /\bCREATE\b/i,
|
|
20
|
-
name: "CREATE clause",
|
|
21
|
-
errorMessage: "CREATE clause is not supported. This is a read-only query engine (no mutations)."
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
pattern: /\bMERGE\b/i,
|
|
25
|
-
name: "MERGE clause",
|
|
26
|
-
errorMessage: "MERGE clause is not supported. This is a read-only query engine (no mutations)."
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
pattern: /\bDELETE\b/i,
|
|
30
|
-
name: "DELETE clause",
|
|
31
|
-
errorMessage: "DELETE clause is not supported. This is a read-only query engine (no mutations)."
|
|
32
|
-
}
|
|
33
|
-
// {
|
|
34
|
-
// pattern: /\bSET\b/i,
|
|
35
|
-
// name: 'SET clause',
|
|
36
|
-
// errorMessage:
|
|
37
|
-
// 'SET clause is not supported. This is a read-only query engine (no mutations).',
|
|
38
|
-
// },
|
|
39
|
-
];
|
|
40
|
-
const FORBIDDEN_AGGREGATIONS = [
|
|
41
|
-
{
|
|
42
|
-
pattern: /\bCOUNT\s*\(/i,
|
|
43
|
-
name: "COUNT() function",
|
|
44
|
-
errorMessage: "COUNT() aggregation function is not supported. Aggregation functions are not available.",
|
|
45
|
-
alternative: "Use manual counting patterns or return all results and count in application code."
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
pattern: /\bSUM\s*\(/i,
|
|
49
|
-
name: "SUM() function",
|
|
50
|
-
errorMessage: "SUM() aggregation function is not supported. Aggregation functions are not available."
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
pattern: /\bcollect\s*\(/i,
|
|
54
|
-
name: "collect() function",
|
|
55
|
-
errorMessage: "collect() aggregation function is not supported. Aggregation functions are not available."
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
pattern: /\bMIN\s*\(/i,
|
|
59
|
-
name: "MIN() function",
|
|
60
|
-
errorMessage: "MIN() aggregation function is not supported. Aggregation functions are not available."
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
pattern: /\bMAX\s*\(/i,
|
|
64
|
-
name: "MAX() function",
|
|
65
|
-
errorMessage: "MAX() aggregation function is not supported. Aggregation functions are not available."
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
pattern: /\bAVG\s*\(/i,
|
|
69
|
-
name: "AVG() function",
|
|
70
|
-
errorMessage: "AVG() aggregation function is not supported. Aggregation functions are not available."
|
|
71
|
-
}
|
|
72
|
-
];
|
|
73
|
-
const FORBIDDEN_MODIFIERS = [
|
|
74
|
-
{
|
|
75
|
-
pattern: /\bSKIP\b/i,
|
|
76
|
-
name: "SKIP clause",
|
|
77
|
-
errorMessage: "SKIP clause is not supported. Pagination is not available."
|
|
78
|
-
}
|
|
79
|
-
];
|
|
80
|
-
const FORBIDDEN_PATTERNS = [
|
|
81
|
-
{
|
|
82
|
-
pattern: /\[.*:\w+\*\d+\.\.\d+.*\]/,
|
|
83
|
-
name: "Path range syntax",
|
|
84
|
-
errorMessage: "Path range syntax is not supported. Patterns like `*1..3`, `*2..`, `*..3` are invalid.",
|
|
85
|
-
alternative: "Use `*` (unlimited, zero or more) for variable-length paths."
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
pattern: /\[.*:\w+\*\d+\.\..*\]/,
|
|
89
|
-
name: "Path range syntax (lower bound)",
|
|
90
|
-
errorMessage: "Path range syntax is not supported. Patterns like `*2..` are invalid.",
|
|
91
|
-
alternative: "Use `*` (unlimited, zero or more) for variable-length paths."
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
pattern: /\[.*:\w+\*\.\.\d+.*\]/,
|
|
95
|
-
name: "Path range syntax (upper bound)",
|
|
96
|
-
errorMessage: "Path range syntax is not supported. Patterns like `*..3` are invalid.",
|
|
97
|
-
alternative: "Use `*` (unlimited, zero or more) for variable-length paths."
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
pattern: /WHERE\s+NOT\s*\(/i,
|
|
101
|
-
name: "WHERE NOT (pattern)",
|
|
102
|
-
errorMessage: "WHERE NOT (pattern) is not supported. Cannot use pattern negation in WHERE clause.",
|
|
103
|
-
alternative: "Use `OPTIONAL MATCH` + `WHERE IS NULL` instead. Example: `OPTIONAL MATCH (m)-[:HAS_PARAMETER]->(:ParameterDeclaration) WHERE ... IS NULL`."
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
pattern: /MATCH\s*\(:\w+[^)]*\)(?:\s*,\s*\(:\w+[^)]*\))*(?:\s*WHERE[^R]*)?/i,
|
|
107
|
-
name: "Anonymous-only queries",
|
|
108
|
-
errorMessage: "Queries with only anonymous nodes (no variable bindings) are not useful.",
|
|
109
|
-
alternative: "Use bound variables in the pattern. Example: `MATCH (a:A)` instead of `MATCH (:A)`."
|
|
110
|
-
}
|
|
111
|
-
];
|
|
112
|
-
const FORBIDDEN_FEATURES = [
|
|
113
|
-
{
|
|
114
|
-
name: "Subqueries",
|
|
115
|
-
description: "Nested queries not supported"
|
|
116
|
-
}
|
|
117
|
-
];
|
|
118
|
-
export {
|
|
119
|
-
FORBIDDEN_AGGREGATIONS,
|
|
120
|
-
FORBIDDEN_FEATURES,
|
|
121
|
-
FORBIDDEN_KEYWORDS,
|
|
122
|
-
FORBIDDEN_MODIFIERS,
|
|
123
|
-
FORBIDDEN_PATTERNS
|
|
124
|
-
};
|
package/cypher-cli.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const command = "cypher";
|
|
2
|
-
const describe = "Print supported Cypher syntax and constraints (MATCH, WHERE, RETURN, etc.).";
|
|
3
|
-
const builder = (yargs) => yargs;
|
|
4
|
-
function handler() {
|
|
5
|
-
console.log(CYPHER_REFERENCE);
|
|
6
|
-
}
|
|
7
|
-
const CYPHER_REFERENCE = `# Cypher reference (code-graph dialect)
|
|
8
|
-
|
|
9
|
-
Unsupported features (e.g. CREATE, MERGE, path ranges like *1..3) will error \u2014 see validator if needed.
|
|
10
|
-
|
|
11
|
-
MATCH, WHERE, RETURN, ORDER BY, LIMIT, OPTIONAL MATCH, and variable-length paths are supported.
|
|
12
|
-
|
|
13
|
-
## MATCH
|
|
14
|
-
(n:Label), (n:Label { prop: 'value' }), (a)-[:REL]->(b), (a)<-[:REL]-(b)
|
|
15
|
-
Variable-length: (a)-[*]->(b)
|
|
16
|
-
Multiple labels: (n:A:B) AND, (n:A|B) OR. Multiple rel types: [:R1|R2]
|
|
17
|
-
OPTIONAL MATCH for left outer joins.
|
|
18
|
-
|
|
19
|
-
## WHERE
|
|
20
|
-
=, !=, >, <, >=, <=
|
|
21
|
-
IN [...], NOT IN [...]
|
|
22
|
-
IS NULL, IS NOT NULL
|
|
23
|
-
STARTS WITH, ENDS WITH, CONTAINS, =~ 'regex'
|
|
24
|
-
Same logic for whole clause: all AND or all OR (no mixing).
|
|
25
|
-
|
|
26
|
-
## RETURN
|
|
27
|
-
RETURN n, m | RETURN * | RETURN n AS alias
|
|
28
|
-
RETURN DISTINCT n | RETURN n LIMIT 10
|
|
29
|
-
|
|
30
|
-
## ORDER BY
|
|
31
|
-
ORDER BY n.name ASC | DESC, multiple fields supported.
|
|
32
|
-
|
|
33
|
-
## Constraints
|
|
34
|
-
RETURN required. Node properties flat, primitives only. Edges: source, target, type (no edge properties). Variable-length only * (no *1..3 etc).
|
|
35
|
-
`;
|
|
36
|
-
export {
|
|
37
|
-
builder,
|
|
38
|
-
command,
|
|
39
|
-
describe,
|
|
40
|
-
handler
|
|
41
|
-
};
|
package/infra/code-graph.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildCodeGraph,
|
|
3
|
-
buildConfigFromQuery
|
|
4
|
-
} from "../code-graph-v2/index.js";
|
|
5
|
-
import {
|
|
6
|
-
createProgramFromFileSystem,
|
|
7
|
-
createProgramFromTsConfig
|
|
8
|
-
} from "../codegular/index.js";
|
|
9
|
-
import { buildQueryObject, query } from "../cypher/index.js";
|
|
10
|
-
const matchFromGeneratedFiles = (cypherQuery, config, generatedFiles) => {
|
|
11
|
-
const fileSystem = generatedFiles.reduce((acc, file) => {
|
|
12
|
-
if (file.filePath.endsWith(".ts")) {
|
|
13
|
-
acc[file.filePath] = file.code;
|
|
14
|
-
}
|
|
15
|
-
return acc;
|
|
16
|
-
}, {});
|
|
17
|
-
return matchFromFileSystem(cypherQuery, config, fileSystem);
|
|
18
|
-
};
|
|
19
|
-
const matchFromFileSystem = (cypherQuery, config, fileSystem) => {
|
|
20
|
-
const program = createProgramFromFileSystem(fileSystem);
|
|
21
|
-
const codeGraph = buildCodeGraph(program, config);
|
|
22
|
-
const results = query(cypherQuery, codeGraph);
|
|
23
|
-
return results;
|
|
24
|
-
};
|
|
25
|
-
const mapGeneratedFilesToFileSystem = (generatedFiles) => {
|
|
26
|
-
return generatedFiles.reduce(
|
|
27
|
-
(acc, file) => {
|
|
28
|
-
acc[file.filePath] = file.code;
|
|
29
|
-
return acc;
|
|
30
|
-
},
|
|
31
|
-
{}
|
|
32
|
-
);
|
|
33
|
-
};
|
|
34
|
-
const resolveProgramFromConfig = (env) => {
|
|
35
|
-
return env.tsConfig ? createProgramFromTsConfig(env.tsConfig) : createProgramFromFileSystem(
|
|
36
|
-
mapGeneratedFilesToFileSystem(env.generatedFiles)
|
|
37
|
-
);
|
|
38
|
-
};
|
|
39
|
-
const autoMatch = (cypherQuery, program, options) => {
|
|
40
|
-
const queryObject = buildQueryObject(cypherQuery);
|
|
41
|
-
const config = buildConfigFromQuery(queryObject);
|
|
42
|
-
const codeGraph = buildCodeGraph(program, config);
|
|
43
|
-
const results = query(cypherQuery, codeGraph);
|
|
44
|
-
return options?.skipRewrite ? results : rewriteOccurenceOf(results);
|
|
45
|
-
};
|
|
46
|
-
const PATH_ANCHOR_SRC_APP = "src/app";
|
|
47
|
-
const rewriteUntilPath = (pathOrNodeId, pathAnchor) => {
|
|
48
|
-
const searchSegment = pathAnchor.startsWith("/") && pathAnchor.endsWith("/") ? pathAnchor : `/${pathAnchor.replace(/^\/|\/$/g, "")}/`;
|
|
49
|
-
const idx = pathOrNodeId.lastIndexOf(searchSegment);
|
|
50
|
-
if (idx < 0)
|
|
51
|
-
return pathOrNodeId;
|
|
52
|
-
const sliced = pathOrNodeId.slice(idx);
|
|
53
|
-
return sliced.startsWith("/") ? sliced.slice(1) : sliced;
|
|
54
|
-
};
|
|
55
|
-
const rewriteOccurenceOf = (result) => {
|
|
56
|
-
return result.map((result2) => {
|
|
57
|
-
return Object.keys(result2).reduce((acc, key) => {
|
|
58
|
-
if (!result2[key]) {
|
|
59
|
-
return acc;
|
|
60
|
-
}
|
|
61
|
-
const id = result2[key]["id"];
|
|
62
|
-
if (!id) {
|
|
63
|
-
return acc;
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
...acc,
|
|
67
|
-
[key]: {
|
|
68
|
-
...result2[key],
|
|
69
|
-
id: rewriteUntilPath(id, PATH_ANCHOR_SRC_APP)
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}, {});
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
const filterResultsByGeneratedFiles = (results, generatedFiles) => {
|
|
76
|
-
const filePaths = generatedFiles.map((file) => file.filePath);
|
|
77
|
-
return results.filter(
|
|
78
|
-
(result) => Object.values(result).find(
|
|
79
|
-
(n) => filePaths.includes(n["id"].split(".")[0] + ".ts")
|
|
80
|
-
)
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
const autoMatchFromGeneratedFiles = (cypherQuery, generatedFiles) => {
|
|
84
|
-
const queryObject = buildQueryObject(cypherQuery);
|
|
85
|
-
const config = buildConfigFromQuery(queryObject);
|
|
86
|
-
return matchFromGeneratedFiles(cypherQuery, config, generatedFiles);
|
|
87
|
-
};
|
|
88
|
-
const NODE_PROPERTIES_PRESET = {
|
|
89
|
-
NAMEABLE: {
|
|
90
|
-
name: `helpers.getDescendantsBy(args.current, (node) => node.kind === args.ts.SyntaxKind.Identifier)[0]?.getText();`,
|
|
91
|
-
filePath: "args.sourceFile.fileName;"
|
|
92
|
-
},
|
|
93
|
-
/**
|
|
94
|
-
* Creates a preset that extracts a property value from an ObjectLiteralExpression
|
|
95
|
-
* @param key - The property name to look for in the object literal
|
|
96
|
-
* @returns An extractor code string that finds the property and returns its initializer text
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```typescript
|
|
100
|
-
* properties: {
|
|
101
|
-
* selector: NODE_PROPERTIES_PRESET.OBJECT_PROPERTY('selector'),
|
|
102
|
-
* template: NODE_PROPERTIES_PRESET.OBJECT_PROPERTY('template'),
|
|
103
|
-
* }
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
OBJECT_LITERAL_PROPERTY: (key, valueFns = []) => {
|
|
107
|
-
return `(function() {
|
|
108
|
-
const objectLiterals = helpers.getDescendantsBy(
|
|
109
|
-
args.current,
|
|
110
|
-
(node) => node.kind === args.ts.SyntaxKind.ObjectLiteralExpression
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
for (const objLiteral of objectLiterals) {
|
|
114
|
-
if (args.ts.isObjectLiteralExpression(objLiteral)) {
|
|
115
|
-
for (const property of objLiteral.properties) {
|
|
116
|
-
if (args.ts.isPropertyAssignment(property)) {
|
|
117
|
-
const propName = property.name;
|
|
118
|
-
let propNameText = '';
|
|
119
|
-
|
|
120
|
-
if (args.ts.isIdentifier(propName)) {
|
|
121
|
-
propNameText = propName.text;
|
|
122
|
-
} else if (args.ts.isStringLiteral(propName)) {
|
|
123
|
-
propNameText = propName.text;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (propNameText === '${key}') {
|
|
127
|
-
const value = property.initializer?.getText() || null;
|
|
128
|
-
return [${valueFns.join(", ")}].reduce((acc, valueFn) => valueFn(acc), value);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return null;
|
|
135
|
-
})();`;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
export {
|
|
139
|
-
NODE_PROPERTIES_PRESET,
|
|
140
|
-
autoMatch,
|
|
141
|
-
autoMatchFromGeneratedFiles,
|
|
142
|
-
filterResultsByGeneratedFiles,
|
|
143
|
-
matchFromFileSystem,
|
|
144
|
-
matchFromGeneratedFiles,
|
|
145
|
-
resolveProgramFromConfig,
|
|
146
|
-
rewriteUntilPath
|
|
147
|
-
};
|
package/main.js
DELETED
|
File without changes
|
package/resources-cli.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
const command = "resources";
|
|
2
|
-
const describe = "Print code graph schema and Cypher reference (for agents and tooling).";
|
|
3
|
-
const builder = (yargs) => yargs;
|
|
4
|
-
function handler() {
|
|
5
|
-
console.log(RESOURCES_TEXT);
|
|
6
|
-
}
|
|
7
|
-
const RESOURCES_TEXT = `# Code Graph \u2014 Cypher over TypeScript
|
|
8
|
-
|
|
9
|
-
The graph database is your **TypeScript code**. Nodes are AST nodes; relationships follow the structure of the program. You run Cypher queries against a project built from a tsconfig; the engine builds the graph on the fly from the query (no separate schema).
|
|
10
|
-
|
|
11
|
-
## Node labels = TypeScript SyntaxKind
|
|
12
|
-
|
|
13
|
-
Labels are **TypeScript AST node kinds** (SyntaxKind names). Examples:
|
|
14
|
-
|
|
15
|
-
ClassDeclaration, MethodDeclaration, PropertyDeclaration, Constructor,
|
|
16
|
-
FunctionDeclaration, VariableStatement, CallExpression, Identifier,
|
|
17
|
-
ObjectLiteralExpression, Decorator, SourceFile, ImportDeclaration, ...
|
|
18
|
-
|
|
19
|
-
Use them in patterns: \`(n:ClassDeclaration)\`, \`(d:Decorator)\`, \`(p:PropertyDeclaration)\`.
|
|
20
|
-
|
|
21
|
-
## Node shape (every node)
|
|
22
|
-
|
|
23
|
-
Each node in the result has:
|
|
24
|
-
|
|
25
|
-
- **id** \u2014 unique node id (file path + position)
|
|
26
|
-
- **labels** \u2014 array of one label (the SyntaxKind name)
|
|
27
|
-
- **name** \u2014 \`node.name?.getText()\` (e.g. class/method/prop name)
|
|
28
|
-
- **filePath** \u2014 source file path
|
|
29
|
-
- **text** \u2014 full text of the AST node
|
|
30
|
-
- **type** \u2014 resolved type from TypeChecker when available
|
|
31
|
-
- **firstIdentifier** \u2014 first descendant Identifier text
|
|
32
|
-
- **initializer** \u2014 initializer text when present (e.g. variable, property)
|
|
33
|
-
|
|
34
|
-
So you can filter or return \`n.name\`, \`n.filePath\`, \`n.text\`, \`n.type\`, etc.
|
|
35
|
-
|
|
36
|
-
## Relationships (most common)
|
|
37
|
-
|
|
38
|
-
**Traversal (AST structure)**
|
|
39
|
-
- **HAS_DESCENDANTS** \u2014 recursive descent into child nodes (optionally by kind)
|
|
40
|
-
- **HAS_ANCESTORS** \u2014 recursive ascent to parent nodes
|
|
41
|
-
|
|
42
|
-
**Direct AST properties**
|
|
43
|
-
- **HAS_INITIALIZER** \u2014 \`node.initializer\` (VariableDeclaration, PropertyDeclaration, \u2026)
|
|
44
|
-
- **HAS_PARAMETERS** \u2014 \`node.parameters\` (functions, constructors, \u2026)
|
|
45
|
-
- **HAS_EXPRESSION** \u2014 \`node.expression\` (CallExpression, Decorator, \u2026)
|
|
46
|
-
- **HAS_TYPE_ANNOTATION** \u2014 \`node.type\` (explicit type on params, properties, return)
|
|
47
|
-
- **HAS_BODY** \u2014 \`node.body\` (functions, methods, arrow functions, \u2026)
|
|
48
|
-
- **HAS_MEMBERS** \u2014 \`node.members\` (class/interface/enum members)
|
|
49
|
-
- **HAS_PROPERTIES** \u2014 \`node.properties\` (ObjectLiteralExpression)
|
|
50
|
-
- **HAS_ARGUMENTS** \u2014 \`node.arguments\` (CallExpression, NewExpression)
|
|
51
|
-
- **HAS_DECORATORS** \u2014 decorators on the node
|
|
52
|
-
- **HAS_TYPE** \u2014 resolved type (TypeChecker)
|
|
53
|
-
- **HAS_NAME** \u2014 \`node.name\` (Identifier)
|
|
54
|
-
|
|
55
|
-
**Heritage**
|
|
56
|
-
- **EXTENDS** \u2014 \`extends\` clause (classes, interfaces)
|
|
57
|
-
- **IMPLEMENTS** \u2014 \`implements\` clause (classes)
|
|
58
|
-
|
|
59
|
-
Example: find classes with a \`Component\` decorator:
|
|
60
|
-
|
|
61
|
-
MATCH (c:ClassDeclaration)-[:HAS_DECORATORS]->(d:Decorator)
|
|
62
|
-
WHERE d.name = 'Component'
|
|
63
|
-
RETURN c
|
|
64
|
-
|
|
65
|
-
Example: find method and its parameters:
|
|
66
|
-
|
|
67
|
-
MATCH (m:MethodDeclaration)-[:HAS_PARAMETERS]->(p:ParameterDeclaration)
|
|
68
|
-
RETURN m, p
|
|
69
|
-
`;
|
|
70
|
-
export {
|
|
71
|
-
builder,
|
|
72
|
-
command,
|
|
73
|
-
describe,
|
|
74
|
-
handler
|
|
75
|
-
};
|
package/run-cli.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import { createProgramFromTsConfig } from "./codegular/index.js";
|
|
4
|
-
import { autoMatch } from "./infra/code-graph.js";
|
|
5
|
-
const command = "query <cypher>";
|
|
6
|
-
const describe = "Run Cypher and print match results as JSON. Builds the code graph from the project tsconfig; node/relationship config is inferred from the query.";
|
|
7
|
-
const builder = (yargs) => yargs.option("tsconfig", {
|
|
8
|
-
type: "string",
|
|
9
|
-
default: "tsconfig.json",
|
|
10
|
-
description: "Path to tsconfig.json (default: tsconfig.json in cwd)"
|
|
11
|
-
}).positional("cypher", {
|
|
12
|
-
type: "string",
|
|
13
|
-
demandOption: true,
|
|
14
|
-
description: 'Cypher query (quote in shell: "MATCH (n:ClassDeclaration) RETURN n")'
|
|
15
|
-
});
|
|
16
|
-
async function handler(argv) {
|
|
17
|
-
const cypherQuery = argv.cypher.trim();
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
const tsconfigPath = path.isAbsolute(argv.tsconfig) ? argv.tsconfig : path.join(cwd, argv.tsconfig);
|
|
20
|
-
if (!fs.existsSync(tsconfigPath)) {
|
|
21
|
-
console.error(`Error: tsconfig not found at ${tsconfigPath}`);
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
const program = createProgramFromTsConfig(tsconfigPath);
|
|
26
|
-
const results = autoMatch(cypherQuery, program);
|
|
27
|
-
console.log(JSON.stringify(results, null, 2));
|
|
28
|
-
} catch (err) {
|
|
29
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
-
const stack = err instanceof Error ? err.stack : void 0;
|
|
31
|
-
console.error(`Error: ${message}`);
|
|
32
|
-
if (stack && process.env.DEBUG) {
|
|
33
|
-
console.error(stack);
|
|
34
|
-
}
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export {
|
|
39
|
-
builder,
|
|
40
|
-
command,
|
|
41
|
-
describe,
|
|
42
|
-
handler
|
|
43
|
-
};
|