Skip to content

Commit 04615f4

Browse files
feat: generate types using static-type.json
fix #8
1 parent d554166 commit 04615f4

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ dist
131131

132132
# ignore generated parser files
133133
packages/**/parser.so
134+
packages/**/type.d.ts
134135
# do not include copied directories
135136
packages/**/src
136137
# ignore generated ts files in scripts

packages/toml/nursery.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const toml = require('./index')
33
const assert = require('node:assert')
44

55
setup({
6+
dirname: __dirname,
67
name: 'toml',
78
languageRegistration: toml,
89
testRunner: (parse) => {

packages/toml/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"main": "index.js",
66
"scripts": {
77
"build": "tree-sitter build -o parser.so",
8+
"prepublishOnly": "node nursery.js source",
89
"postinstall": "node postinstall.js",
910
"test": "node nursery.js test"
1011
},

scripts/nursery/index.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1+
2+
import { readFileSync, writeFileSync } from 'node:fs'
3+
import path from 'node:path'
14
import { parse, registerDynamicLanguage, SgRoot, DynamicLangRegistrations } from '@ast-grep/napi'
25

36
/** Setup ast-grep/lang package's pre-release */
47
interface SetupConfig {
8+
/** the root directory of the package */
9+
dirname: string
510
/** Name of the language. e.g. toml */
611
name: string
712
/** Language registration object, usually the export of index.js */
813
languageRegistration: DynamicLangRegistrations[string]
9-
packageName: string
14+
/** Package name of tree-sitter package. e.g. tree-sitter-css */
15+
treeSitterPackage: string
1016
/** Test cases running in CI */
1117
testRunner: (parse: (c: string) => SgRoot) => void
1218
}
@@ -22,5 +28,79 @@ export function setup(setupConfig: SetupConfig) {
2228
const arg = process.argv[2]
2329
if (arg === 'test') {
2430
test(setupConfig)
31+
} else if (arg === 'source') {
32+
generateLangNodeTypes(setupConfig)
33+
}
34+
}
35+
36+
interface NodeBasicInfo {
37+
type: string
38+
named: boolean
39+
}
40+
41+
interface NodeFieldInfo {
42+
multiple: boolean
43+
required: boolean
44+
types: NodeBasicInfo[]
45+
}
46+
47+
interface NodeType extends NodeBasicInfo {
48+
root?: boolean
49+
fields?: {
50+
[fieldName: string]: NodeFieldInfo
51+
}
52+
children?: NodeFieldInfo
53+
subtypes?: NodeBasicInfo[]
54+
}
55+
56+
function filterOutUnNamedNode(node: NodeType): NodeType | null {
57+
if (!node.named) {
58+
return null
59+
}
60+
if (node.fields) {
61+
for (const field of Object.keys(node.fields)) {
62+
node.fields[field].types = node.fields[field].types.filter(n => n.named)
63+
}
64+
}
65+
if (node.children) {
66+
node.children.types = node.children.types.filter(n => n.named)
67+
}
68+
if (node.subtypes) {
69+
node.subtypes = node.subtypes.filter(n => n.named)
70+
}
71+
return node
72+
}
73+
74+
function processNodeTypes(nodeTypes: NodeType[]): Record<string, NodeType> {
75+
const filteredNodeTypes = nodeTypes
76+
.map(filterOutUnNamedNode)
77+
.filter(node => !!node)
78+
const nodeTypeMap = Object.fromEntries(
79+
filteredNodeTypes.map(node => [node.type, node]),
80+
)
81+
return nodeTypeMap
82+
}
83+
84+
function readLangNodeTypes(dirname: string): NodeType[] {
85+
const staticNodePath = path.join(dirname, 'src', 'node-types.json')
86+
const content = readFileSync(staticNodePath, 'utf-8')
87+
return JSON.parse(content)
88+
}
89+
90+
function generateLangNodeTypes(setupConfig: SetupConfig) {
91+
const { name: lang, treeSitterPackage, dirname } = setupConfig
92+
try {
93+
const nodeTypes = readLangNodeTypes(dirname)
94+
const nodeTypeMap = processNodeTypes(nodeTypes)
95+
const fileContent =
96+
`// Auto-generated from ${treeSitterPackage}` +
97+
'\n' +
98+
`type ${lang}Types = ${JSON.stringify(nodeTypeMap, null, 2)};` +
99+
'\n' +
100+
`export default ${lang}Types;`
101+
writeFileSync(path.join(dirname, `type.d.ts`), fileContent)
102+
} catch (e) {
103+
console.error(`Error while generating node types for ${lang}`)
104+
throw e
25105
}
26106
}

0 commit comments

Comments
 (0)