@ast-grep/create-lang 0.0.0-prerelease-1 → 0.0.0-prerelease-3
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/README.md +28 -0
- package/package.json +8 -2
- package/template/.gitignore +30 -0
- package/template/.npmignore +0 -0
- package/template/package.json +2 -1
- package/index.d.ts +0 -1
- package/index.ts +0 -131
- package/tsconfig.json +0 -3
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @ast-grep/create-lang
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# create a new language package in current directory
|
|
7
|
+
pnpm create @ast-grep/lang
|
|
8
|
+
# create package in a specific directory
|
|
9
|
+
pnpm create @ast-grep/lang some-dir
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
You will be prompted to enter the language name, the language file extension, package name and tree-sitter grammar package.
|
|
13
|
+
|
|
14
|
+
Note the tree-sitter grammar package is different from the package name. package name is the repo you create, tree-sitter package should be a package already published on npm.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
After the package is created, you can use these commands:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm source # copy tree-sitter grammar files to the src folder
|
|
22
|
+
pnpm build # build the tree-sitter grammar files to dynamic lib
|
|
23
|
+
pnpm test # test the tree-sitter grammar files
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Test file
|
|
27
|
+
|
|
28
|
+
You can edit `nursery.js` to add test case for your language.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ast-grep/create-lang",
|
|
3
|
-
"version": "0.0.0-prerelease-
|
|
3
|
+
"version": "0.0.0-prerelease-3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "index.js",
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
"bin": {
|
|
13
13
|
"create-lang": "index.js"
|
|
14
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"index.js",
|
|
17
|
+
"template/.gitignore",
|
|
18
|
+
"template/.npmignore",
|
|
19
|
+
"template"
|
|
20
|
+
],
|
|
15
21
|
"dependencies": {
|
|
16
22
|
"prompts": "2.4.2"
|
|
17
23
|
},
|
|
@@ -20,7 +26,7 @@
|
|
|
20
26
|
"registry": "https://registry.npmjs.org/"
|
|
21
27
|
},
|
|
22
28
|
"devDependencies": {
|
|
23
|
-
"@types/node": "22.10.
|
|
29
|
+
"@types/node": "22.10.7",
|
|
24
30
|
"@types/prompts": "^2.4.9",
|
|
25
31
|
"typescript": "^5.7.3"
|
|
26
32
|
},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
25
|
+
|
|
26
|
+
# ignore generated parser files
|
|
27
|
+
parser.so
|
|
28
|
+
type.d.ts
|
|
29
|
+
# do not include copied directories
|
|
30
|
+
src
|
|
File without changes
|
package/template/package.json
CHANGED
package/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/index.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import prompts from 'prompts'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import fs from 'node:fs/promises'
|
|
4
|
-
import { execSync } from 'node:child_process'
|
|
5
|
-
|
|
6
|
-
function required(s: string): string | true {
|
|
7
|
-
if (s.length === 0) {
|
|
8
|
-
return 'This value is required'
|
|
9
|
-
}
|
|
10
|
-
return true
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// https://github.com/vitejs/vite/blob/76082e3d3033b09b02b6db64de6e36942593c753/packages/create-vite/src/index.ts#L557
|
|
14
|
-
function isValidPackageName(projectName: string) {
|
|
15
|
-
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(
|
|
16
|
-
projectName,
|
|
17
|
-
) || 'Invalid package name'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function askConfiguration() {
|
|
22
|
-
return prompts([
|
|
23
|
-
{
|
|
24
|
-
type: 'text',
|
|
25
|
-
name: 'name',
|
|
26
|
-
message: 'Language name',
|
|
27
|
-
validate: required,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
type: 'text',
|
|
31
|
-
name: 'packageName',
|
|
32
|
-
message: 'Package name',
|
|
33
|
-
validate: isValidPackageName,
|
|
34
|
-
initial: (_, answers) => `my-dynamic-lang-${answers.name}`,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
type: 'text',
|
|
38
|
-
name: 'treeSitterPackage',
|
|
39
|
-
message: 'Tree-sitter package to use',
|
|
40
|
-
validate: isValidPackageName,
|
|
41
|
-
initial: (_, answers) => `tree-sitter-${answers.name}`,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
type: 'list',
|
|
45
|
-
name: 'extensions',
|
|
46
|
-
message: 'File extensions used by the language, comma separated',
|
|
47
|
-
separator: ',',
|
|
48
|
-
validate: required,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
type: 'text',
|
|
52
|
-
name: 'expandoChar',
|
|
53
|
-
message: 'Expando char used in pattern',
|
|
54
|
-
initial: '$',
|
|
55
|
-
validate: (value) => {
|
|
56
|
-
return value.length === 1 ? true : 'Expando char must be a single character'
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
type: 'confirm',
|
|
61
|
-
name: 'includeDotFiles',
|
|
62
|
-
message: 'Include gitignore and npm publish files?',
|
|
63
|
-
initial: true,
|
|
64
|
-
}
|
|
65
|
-
], {
|
|
66
|
-
onCancel: () => {
|
|
67
|
-
process.exit(1)
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
type Answers = Awaited<ReturnType<typeof askConfiguration>>
|
|
73
|
-
|
|
74
|
-
function copyTemplate(targetDir: string, includeDotFiles: boolean) {
|
|
75
|
-
const templateDir = path.join(__dirname, 'template')
|
|
76
|
-
return fs.cp(templateDir, targetDir, {
|
|
77
|
-
recursive: true, // Copy all files and folders
|
|
78
|
-
// includes hidden files if `includeDotFiles` is true
|
|
79
|
-
filter: (src) => {
|
|
80
|
-
const basename = path.basename(src)
|
|
81
|
-
return includeDotFiles || !basename.startsWith('.')
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async function renameFiles(dir: string, answer: Answers) {
|
|
87
|
-
const name: Record<string, string> = {
|
|
88
|
-
$$PACKAGE_NAME$$: answer.packageName,
|
|
89
|
-
$$NAME$$: answer.name,
|
|
90
|
-
$$TREE_SITTER_PACKAGE$$: answer.treeSitterPackage,
|
|
91
|
-
$$EXTENSIONS$$: JSON.stringify(answer.extensions),
|
|
92
|
-
$$EXPANDO_CHAR$$: answer.expandoChar,
|
|
93
|
-
}
|
|
94
|
-
for (const file of await fs.readdir(dir)) {
|
|
95
|
-
const filePath = path.join(dir, file)
|
|
96
|
-
const stats = await fs.stat(filePath)
|
|
97
|
-
if (stats.isDirectory()) {
|
|
98
|
-
renameFiles(filePath, answer)
|
|
99
|
-
} else {
|
|
100
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
101
|
-
const newContent = content.replace(/(\$\$[A-Z_]+\$\$)/g, (match) => {
|
|
102
|
-
return name[match] || match
|
|
103
|
-
})
|
|
104
|
-
await fs.writeFile(filePath, newContent)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function installTreeSitterPackage(cwd: string, answer: Answers) {
|
|
109
|
-
console.log('Installing tree-sitter package...')
|
|
110
|
-
execSync(`pnpm install ${answer.treeSitterPackage} --save-dev --save-exact`, {
|
|
111
|
-
cwd,
|
|
112
|
-
})
|
|
113
|
-
console.log('Copying source code...')
|
|
114
|
-
execSync('pnpm run source', { cwd })
|
|
115
|
-
console.log('Compiling')
|
|
116
|
-
execSync('pnpm run build', { cwd })
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function main() {
|
|
120
|
-
let cwd = process.cwd()
|
|
121
|
-
if (process.argv.length > 2) {
|
|
122
|
-
const targetDir = process.argv[2]
|
|
123
|
-
cwd = path.join(cwd, targetDir)
|
|
124
|
-
}
|
|
125
|
-
const config = await askConfiguration()
|
|
126
|
-
await copyTemplate(cwd, config.includeDotFiles)
|
|
127
|
-
await renameFiles(cwd, config)
|
|
128
|
-
installTreeSitterPackage(cwd, config)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
main()
|
package/tsconfig.json
DELETED