@cr_docs_t/dts 0.26.0 → 0.27.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/dist/dts/FugueTree/FugueTree.d.ts +1 -1
- package/dist/dts/FugueTree/FugueTree.js +1 -1
- package/dist/treesitter/index.d.ts +3 -0
- package/dist/treesitter/index.d.ts.map +1 -0
- package/dist/treesitter/index.js +2 -0
- package/dist/treesitter/parser.d.ts +6 -0
- package/dist/treesitter/parser.d.ts.map +1 -0
- package/dist/treesitter/parser.js +32 -0
- package/dist/treesitter/types/AST.d.ts +1048 -0
- package/dist/treesitter/types/AST.d.ts.map +1 -0
- package/dist/treesitter/types/AST.js +2262 -0
- package/dist/treesitter/types/index.d.ts +2 -0
- package/dist/treesitter/types/index.d.ts.map +1 -0
- package/dist/treesitter/types/index.js +1 -0
- package/dist/treesitter.d.ts +2 -0
- package/dist/treesitter.d.ts.map +1 -0
- package/dist/treesitter.js +1 -0
- package/dist/type-gen.d.ts +2 -0
- package/dist/type-gen.d.ts.map +1 -0
- package/dist/type-gen.js +184 -0
- package/dist/types/index.js +1 -1
- package/package.json +13 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/treesitter/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./AST.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"treesitter.d.ts","sourceRoot":"","sources":["../src/treesitter.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./treesitter/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-gen.d.ts","sourceRoot":"","sources":["../src/type-gen.ts"],"names":[],"mappings":""}
|
package/dist/type-gen.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Inspired by https://github.com/github/semantic/tree/main/semantic-ast
|
|
2
|
+
import { writeFileSync, readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const dir = dirname(__filename);
|
|
7
|
+
const INPUT_PATH = join(dir, "node-types.json"); // Adjust as needed
|
|
8
|
+
const OUTPUT_PATH = join(dir, "treesitter", "types", "AST.ts");
|
|
9
|
+
const toPascalCase = (str) => {
|
|
10
|
+
return (str
|
|
11
|
+
.match(/[a-z_]+/gi)
|
|
12
|
+
?.map((word) => word
|
|
13
|
+
.split("_")
|
|
14
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
15
|
+
.join(""))
|
|
16
|
+
.join("") || str);
|
|
17
|
+
};
|
|
18
|
+
function generate() {
|
|
19
|
+
const rawData = readFileSync(INPUT_PATH, "utf8");
|
|
20
|
+
const nodes = JSON.parse(rawData);
|
|
21
|
+
let output = `// Auto-generated from node-types.json\n\n`;
|
|
22
|
+
output += `import { Node } from 'web-tree-sitter';
|
|
23
|
+
import { v4 } from 'uuid'
|
|
24
|
+
|
|
25
|
+
export type NodeId = string;
|
|
26
|
+
|
|
27
|
+
export interface ParserContext {
|
|
28
|
+
nodes: Map<NodeId, AstNode>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
`;
|
|
32
|
+
let interfacesOut = `// Interfaces
|
|
33
|
+
|
|
34
|
+
`;
|
|
35
|
+
let unmarshalersOut = `// Unmarshalers
|
|
36
|
+
|
|
37
|
+
`;
|
|
38
|
+
let switches = "";
|
|
39
|
+
const allNamedNodes = [];
|
|
40
|
+
for (const node of nodes) {
|
|
41
|
+
if (!node.named)
|
|
42
|
+
continue;
|
|
43
|
+
// Generate interfaces
|
|
44
|
+
const interfaceName = toPascalCase(node.type) + "Node";
|
|
45
|
+
// Handle Supertypes
|
|
46
|
+
if (node.subtypes && node.subtypes.length > 0) {
|
|
47
|
+
const subtypeNames = node.subtypes.filter((st) => st.named).map((st) => toPascalCase(st.type) + "Node");
|
|
48
|
+
if (subtypeNames.length > 0) {
|
|
49
|
+
interfacesOut += `export type ${interfaceName} = ${subtypeNames.join(" | ")};\n\n`;
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
allNamedNodes.push(interfaceName);
|
|
54
|
+
// Handle Standard Concrete Nodes
|
|
55
|
+
interfacesOut += `export interface ${interfaceName} {\n`;
|
|
56
|
+
// Use a Map to track properties so we can merge collisions
|
|
57
|
+
const props = new Map();
|
|
58
|
+
// Set default properties
|
|
59
|
+
props.set("id", { type: "NodeId", optional: false });
|
|
60
|
+
props.set("parentId", { type: "NodeId | null", optional: false });
|
|
61
|
+
props.set("type", { type: `'${node.type}'`, optional: false });
|
|
62
|
+
props.set("text", { type: "string", optional: false });
|
|
63
|
+
// Map Fields
|
|
64
|
+
if (node.fields) {
|
|
65
|
+
for (const [fieldName, fieldData] of Object.entries(node.fields)) {
|
|
66
|
+
let typeString = fieldData.multiple ? "NodeId[]" : "NodeId";
|
|
67
|
+
const isOptional = !fieldData.required;
|
|
68
|
+
if (props.has(fieldName)) {
|
|
69
|
+
// Merge types on collision
|
|
70
|
+
const existing = props.get(fieldName);
|
|
71
|
+
existing.type = `${existing.type} | ${typeString}`;
|
|
72
|
+
existing.optional = existing.optional && isOptional;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
props.set(fieldName, { type: typeString, optional: isOptional });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
props.set("childrenIds", { type: "NodeId[]", optional: false });
|
|
80
|
+
// Write all properties to the interface
|
|
81
|
+
for (const [propName, propData] of props.entries()) {
|
|
82
|
+
const optMod = propData.optional ? "?" : "";
|
|
83
|
+
interfacesOut += ` ${propName}${optMod}: ${propData.type};\n`;
|
|
84
|
+
}
|
|
85
|
+
interfacesOut += `}\n\n`;
|
|
86
|
+
// Generate Unmarshalers
|
|
87
|
+
const funcName = `unmarshaler${interfaceName}`;
|
|
88
|
+
switches += `case '${node.type}': return ${funcName}(node, ctx, parentId);\n`;
|
|
89
|
+
unmarshalersOut += `function ${funcName}(node: Node, ctx: ParserContext, parentId: NodeId | null): NodeId {
|
|
90
|
+
const id = v4();
|
|
91
|
+
const n: Partial<${interfaceName}> = {
|
|
92
|
+
id,
|
|
93
|
+
parentId,
|
|
94
|
+
type: '${node.type}',
|
|
95
|
+
text: node.text,
|
|
96
|
+
};
|
|
97
|
+
ctx.nodes.set(id, n as AstNode);
|
|
98
|
+
|
|
99
|
+
`;
|
|
100
|
+
let fieldExtractionNodes = "";
|
|
101
|
+
if (node.fields) {
|
|
102
|
+
for (const [fieldName, fieldData] of Object.entries(node.fields)) {
|
|
103
|
+
if (fieldData.multiple) {
|
|
104
|
+
unmarshalersOut += `n.${fieldName} = node.childrenForFieldName('${fieldName}').map(n => unmarshalNode(n, ctx, id));\n`;
|
|
105
|
+
fieldExtractionNodes += `...node.childrenForFieldName('${fieldName}').map(n => n.id), `;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
if (fieldData.required) {
|
|
109
|
+
unmarshalersOut += `n.${fieldName} = unmarshalNode(node.childForFieldName('${fieldName}')!, ctx, id);\n`;
|
|
110
|
+
fieldExtractionNodes += `node.childForFieldName('${fieldName}')!.id, `;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
unmarshalersOut += `const ${fieldName}Node = node.childForFieldName('${fieldName}');
|
|
114
|
+
n.${fieldName} = ${fieldName}Node ? unmarshalNode(${fieldName}Node, ctx, id) : undefined;
|
|
115
|
+
`;
|
|
116
|
+
fieldExtractionNodes += `${fieldName}Node ? ${fieldName}Node.id : undefined, `;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (fieldExtractionNodes.length > 0) {
|
|
122
|
+
unmarshalersOut += `
|
|
123
|
+
const fieldNodes = new Set([${fieldExtractionNodes}].filter(id => id !== undefined));
|
|
124
|
+
n.childrenIds = node.namedChildren.filter(n => !fieldNodes.has(n.id)).map(n => unmarshalNode(n, ctx, id));
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
unmarshalersOut += `n.childrenIds = node.namedChildren.map(n => unmarshalNode(n, ctx, id));\n`;
|
|
129
|
+
}
|
|
130
|
+
unmarshalersOut += `return id;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
const core = `// Parser core
|
|
136
|
+
|
|
137
|
+
export const unmarshalNode = (node: Node, ctx: ParserContext, parentId: NodeId | null): NodeId => {
|
|
138
|
+
switch(node.type) {
|
|
139
|
+
${switches}
|
|
140
|
+
default: {
|
|
141
|
+
const id = v4();
|
|
142
|
+
const n = {
|
|
143
|
+
id,
|
|
144
|
+
parentId,
|
|
145
|
+
type: node.type as any,
|
|
146
|
+
text: node.text,
|
|
147
|
+
childrenIds: [] as NodeId[],
|
|
148
|
+
};
|
|
149
|
+
ctx.nodes.set(id, n as AstNode);
|
|
150
|
+
n.childrenIds = node.namedChildren.map(n => unmarshalNode(n, ctx, id));
|
|
151
|
+
return id;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export type BragiAST = {rootId: NodeId, nodes: Map<NodeId, AstNode> };
|
|
157
|
+
|
|
158
|
+
// Parses a treesitter CST into a Bragi AST node map
|
|
159
|
+
export const parseCST = (root: Node | null) : BragiAST => {
|
|
160
|
+
if (!root) throw new Error ("No root node provided");
|
|
161
|
+
const ctx: ParserContext = { nodes: new Map() };
|
|
162
|
+
const rootId = unmarshalNode(root, ctx, null);
|
|
163
|
+
return {rootId, nodes: ctx.nodes};
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
// Create a generic ASTNode type
|
|
167
|
+
const concreteNodes = nodes
|
|
168
|
+
.filter((n) => n.named && (!n.subtypes || n.subtypes.length === 0))
|
|
169
|
+
.map((n) => toPascalCase(n.type) + "Node");
|
|
170
|
+
const genericType = `export type AstNode = ${concreteNodes.join(" | ")};\n`;
|
|
171
|
+
// Consolidate output
|
|
172
|
+
output += `
|
|
173
|
+
${interfacesOut}
|
|
174
|
+
|
|
175
|
+
${genericType}
|
|
176
|
+
|
|
177
|
+
${unmarshalersOut}
|
|
178
|
+
|
|
179
|
+
${core}
|
|
180
|
+
`;
|
|
181
|
+
writeFileSync(OUTPUT_PATH, output);
|
|
182
|
+
console.log(`Successfully generated AST types at ${OUTPUT_PATH}`);
|
|
183
|
+
}
|
|
184
|
+
generate();
|
package/dist/types/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cr_docs_t/dts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc",
|
|
10
|
+
"prebuild": "npm run gen-types",
|
|
10
11
|
"prepublishOnly": "npm run build",
|
|
11
12
|
"ci": "npm install && npm run build",
|
|
12
13
|
"pretest": "npm run build",
|
|
13
|
-
"
|
|
14
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
15
|
+
"gen-types": "tsx ./src/type-gen.ts && biome format --write ./src/treesitter/types/AST.ts"
|
|
14
16
|
},
|
|
15
17
|
"exports": {
|
|
16
18
|
".": {
|
|
17
19
|
"import": "./dist/index.js",
|
|
18
20
|
"require": "./dist/index.js",
|
|
19
21
|
"types": "./dist/index.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./treesitter": {
|
|
24
|
+
"import": "./dist/treesitter.js",
|
|
25
|
+
"require": "./dist/treesitter.js",
|
|
26
|
+
"types": "./dist/treesitter.d.ts"
|
|
20
27
|
}
|
|
21
28
|
},
|
|
22
29
|
"publishConfig": {
|
|
@@ -56,6 +63,7 @@
|
|
|
56
63
|
"license": "ISC",
|
|
57
64
|
"packageManager": "pnpm@10.20.0",
|
|
58
65
|
"devDependencies": {
|
|
66
|
+
"@biomejs/biome": "2.4.4",
|
|
59
67
|
"@semantic-release/changelog": "^6.0.3",
|
|
60
68
|
"@semantic-release/git": "^10.0.1",
|
|
61
69
|
"@types/jest": "^30.0.0",
|
|
@@ -64,6 +72,7 @@
|
|
|
64
72
|
"jest": "^30.2.0",
|
|
65
73
|
"semantic-release": "^25.0.2",
|
|
66
74
|
"ts-jest": "^29.4.6",
|
|
75
|
+
"tsx": "^4.21.0",
|
|
67
76
|
"typescript": "^5.9.3"
|
|
68
77
|
},
|
|
69
78
|
"files": [
|
|
@@ -72,6 +81,8 @@
|
|
|
72
81
|
"dependencies": {
|
|
73
82
|
"@msgpack/msgpack": "^3.1.3",
|
|
74
83
|
"lz4js": "^0.2.0",
|
|
84
|
+
"uuid": "^13.0.0",
|
|
85
|
+
"web-tree-sitter": "^0.26.5",
|
|
75
86
|
"zod": "^4.3.6"
|
|
76
87
|
}
|
|
77
88
|
}
|