@vue-godot/cli 0.0.1
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 +112 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +188 -0
- package/dist/create.d.ts +5 -0
- package/dist/create.js +77 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +129 -0
- package/dist/integrate.d.ts +13 -0
- package/dist/integrate.js +153 -0
- package/package.json +37 -0
- package/templates/godot/.editorconfig +4 -0
- package/templates/godot/.gitattributes +2 -0
- package/templates/godot/app.tscn +12 -0
- package/templates/godot/icon.svg +1 -0
- package/templates/godot/project.godot +16 -0
- package/templates/typings/.gdignore +1 -0
- package/templates/typings/app.nodes.gen.d.ts +5 -0
- package/templates/typings/godot.minimal.d.ts +282 -0
- package/templates/typings/godot.mix.d.ts +257 -0
- package/templates/typings/godot.vue-components.gen.d.ts +216 -0
- package/templates/typings/godot.worker.d.ts +32 -0
- package/templates/typings/godot0.gen.d.ts +9973 -0
- package/templates/typings/godot1.gen.d.ts +9254 -0
- package/templates/typings/godot2.gen.d.ts +9279 -0
- package/templates/typings/godot3.gen.d.ts +9210 -0
- package/templates/typings/godot4.gen.d.ts +9253 -0
- package/templates/typings/godot5.gen.d.ts +9265 -0
- package/templates/typings/godot6.gen.d.ts +9508 -0
- package/templates/typings/godot7.gen.d.ts +9310 -0
- package/templates/typings/godot8.gen.d.ts +8552 -0
- package/templates/typings/jsb.editor.bundle.d.ts +73 -0
- package/templates/typings/jsb.runtime.bundle.d.ts +91 -0
- package/templates/vue/src/.gdignore +0 -0
- package/templates/vue/src/App.vue +5 -0
- package/templates/vue/src/env.d.ts +7 -0
- package/templates/vue/src/main.ts +10 -0
- package/templates/vue/tsconfig.json +17 -0
- package/templates/vue/vite.config.ts +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# @vue-godot/cli
|
|
2
|
+
|
|
3
|
+
CLI tool for vue-godot projects — scaffolds new projects, integrates Vue into existing Godot projects, and generates type declarations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @vue-godot/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly with `npx`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx vue-godot <command> [options]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
### `create`
|
|
20
|
+
|
|
21
|
+
Create a new Godot project with vue-godot set up and ready to go.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
vue-godot create [name] [options]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Argument | Description |
|
|
28
|
+
| -------- | ----------------------------------------------------- |
|
|
29
|
+
| `name` | Project name (used as dir name). Prompted if omitted. |
|
|
30
|
+
|
|
31
|
+
| Option | Description |
|
|
32
|
+
| ------ | ------------------------------------------- |
|
|
33
|
+
| `-f` | Force overwrite if directory already exists |
|
|
34
|
+
|
|
35
|
+
**Example:**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx vue-godot create my-game
|
|
39
|
+
cd my-game
|
|
40
|
+
npm install
|
|
41
|
+
npm run build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `integrate`
|
|
45
|
+
|
|
46
|
+
Scaffold a `vue/` folder with Vite + Vue configuration for an existing Godot project.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
vue-godot integrate [dir] [options]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Argument | Description |
|
|
53
|
+
| -------- | ---------------------------------- |
|
|
54
|
+
| `dir` | Target directory (defaults to `.`) |
|
|
55
|
+
|
|
56
|
+
| Option | Description |
|
|
57
|
+
| ------ | ---------------------------------------- |
|
|
58
|
+
| `-f` | Force overwrite if `vue/` already exists |
|
|
59
|
+
|
|
60
|
+
This command:
|
|
61
|
+
|
|
62
|
+
1. Copies a Vue + Vite template into `<dir>/vue/`
|
|
63
|
+
2. Creates or updates `package.json` with the necessary scripts and dependencies
|
|
64
|
+
3. Resolves `node_modules` paths for the generated `tsconfig.json`
|
|
65
|
+
|
|
66
|
+
**Example:**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd my-existing-godot-project
|
|
70
|
+
npx vue-godot integrate
|
|
71
|
+
npm install
|
|
72
|
+
npm run gen:types
|
|
73
|
+
npm run dev
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `gen-types`
|
|
77
|
+
|
|
78
|
+
Generate Vue `GlobalComponents` type augmentation from GodotJS typings. This gives Volar full autocomplete and type checking for Godot node tags (e.g. `<Button>`, `<Label>`) in `.vue` templates.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
vue-godot gen-types [options]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Option | Default | Description |
|
|
85
|
+
| ------------ | ----------------------------------------- | -------------------------------------------------- |
|
|
86
|
+
| `--typings` | `./typings` | Directory containing `godot*.gen.d.ts` files |
|
|
87
|
+
| `--out` | `<typings>/godot.vue-components.gen.d.ts` | Output file path for the generated `.d.ts` |
|
|
88
|
+
| `--ancestor` | `Control` | Base class — only descendants are included |
|
|
89
|
+
| `--vue-src` | `./vue/src` | Vue source dir — generates an `env.d.ts` shim here |
|
|
90
|
+
|
|
91
|
+
**Example:**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
cd apps/v-model
|
|
95
|
+
npx vue-godot gen-types
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Re-run whenever Godot typings are regenerated (e.g. after a Godot version upgrade).
|
|
99
|
+
|
|
100
|
+
## Development (monorepo)
|
|
101
|
+
|
|
102
|
+
From the repository root:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install
|
|
106
|
+
npm run build # builds all packages via Turborepo
|
|
107
|
+
npx vue-godot # runs the locally-built CLI
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as readline from 'node:readline/promises';
|
|
4
|
+
import { create } from './create.js';
|
|
5
|
+
import { generate } from './index.js';
|
|
6
|
+
import { integrate } from './integrate.js';
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const command = args[0];
|
|
9
|
+
function mainUsage() {
|
|
10
|
+
console.error(`Usage: vue-godot <command> [options]
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
create Create a new Godot project with vue-godot set up and ready to go
|
|
14
|
+
integrate Scaffold a vue/ folder with Vite + Vue configs for an existing Godot project
|
|
15
|
+
gen-types Generate Vue GlobalComponents type augmentation from Godot typings
|
|
16
|
+
|
|
17
|
+
Run \`vue-godot <command> --help\` for command-specific options.
|
|
18
|
+
`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
function genTypesUsage() {
|
|
22
|
+
console.error(`Usage: vue-godot gen-types [options]
|
|
23
|
+
|
|
24
|
+
Generate Vue GlobalComponents type augmentation from GodotJS typings.
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--typings Path to the typings directory containing godot*.gen.d.ts files.
|
|
28
|
+
Defaults to ./typings
|
|
29
|
+
--out Output file path for the generated .d.ts file.
|
|
30
|
+
Defaults to <typings>/godot.vue-components.gen.d.ts
|
|
31
|
+
--ancestor Base class to filter by inheritance. Only descendants are included.
|
|
32
|
+
Defaults to Control
|
|
33
|
+
--vue-src Path to the Vue source directory (e.g. vue/src).
|
|
34
|
+
When set, generates an env.d.ts shim for Vue SFC support.
|
|
35
|
+
Defaults to ./vue/src
|
|
36
|
+
`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
function parseGenTypesArgs(argv) {
|
|
40
|
+
let typingsDir;
|
|
41
|
+
let outFile;
|
|
42
|
+
let ancestor;
|
|
43
|
+
let vueSrcDir;
|
|
44
|
+
for (let i = 0; i < argv.length; i++) {
|
|
45
|
+
switch (argv[i]) {
|
|
46
|
+
case '--typings':
|
|
47
|
+
typingsDir = argv[++i];
|
|
48
|
+
break;
|
|
49
|
+
case '--out':
|
|
50
|
+
outFile = argv[++i];
|
|
51
|
+
break;
|
|
52
|
+
case '--ancestor':
|
|
53
|
+
ancestor = argv[++i];
|
|
54
|
+
break;
|
|
55
|
+
case '--vue-src':
|
|
56
|
+
vueSrcDir = argv[++i];
|
|
57
|
+
break;
|
|
58
|
+
case '--help':
|
|
59
|
+
case '-h':
|
|
60
|
+
genTypesUsage();
|
|
61
|
+
default:
|
|
62
|
+
console.error(`Unknown option: ${argv[i]}`);
|
|
63
|
+
genTypesUsage();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { typingsDir, outFile, ancestor, vueSrcDir };
|
|
67
|
+
}
|
|
68
|
+
function createUsage() {
|
|
69
|
+
console.error(`Usage: vue-godot create [name] [options]
|
|
70
|
+
|
|
71
|
+
Create a new Godot project with vue-godot set up and ready to go.
|
|
72
|
+
If no name is given you will be prompted for one.
|
|
73
|
+
|
|
74
|
+
Arguments:
|
|
75
|
+
name Project name (used as directory name)
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
-f Force overwrite if directory already exists
|
|
79
|
+
`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
function parseCreateArgs(argv) {
|
|
83
|
+
let projectName;
|
|
84
|
+
let force = false;
|
|
85
|
+
for (let i = 0; i < argv.length; i++) {
|
|
86
|
+
switch (argv[i]) {
|
|
87
|
+
case '-f':
|
|
88
|
+
force = true;
|
|
89
|
+
break;
|
|
90
|
+
case '--help':
|
|
91
|
+
case '-h':
|
|
92
|
+
createUsage();
|
|
93
|
+
default:
|
|
94
|
+
if (argv[i].startsWith('-')) {
|
|
95
|
+
console.error(`Unknown option: ${argv[i]}`);
|
|
96
|
+
createUsage();
|
|
97
|
+
}
|
|
98
|
+
if (!projectName) {
|
|
99
|
+
projectName = argv[i];
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(`Unexpected argument: ${argv[i]}`);
|
|
103
|
+
createUsage();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { projectName, force };
|
|
108
|
+
}
|
|
109
|
+
function integrateUsage() {
|
|
110
|
+
console.error(`Usage: vue-godot integrate [dir] [options]
|
|
111
|
+
|
|
112
|
+
Scaffold a vue/ folder with Vite + Vue configuration for a Godot project.
|
|
113
|
+
|
|
114
|
+
Arguments:
|
|
115
|
+
dir Target directory (defaults to the current directory)
|
|
116
|
+
|
|
117
|
+
Options:
|
|
118
|
+
-f Force overwrite if vue/ already exists (no prompt)
|
|
119
|
+
`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
function parseIntegrateArgs(argv) {
|
|
123
|
+
let targetDir;
|
|
124
|
+
let force = false;
|
|
125
|
+
for (let i = 0; i < argv.length; i++) {
|
|
126
|
+
switch (argv[i]) {
|
|
127
|
+
case '-f':
|
|
128
|
+
force = true;
|
|
129
|
+
break;
|
|
130
|
+
case '--help':
|
|
131
|
+
case '-h':
|
|
132
|
+
integrateUsage();
|
|
133
|
+
default:
|
|
134
|
+
if (argv[i].startsWith('-')) {
|
|
135
|
+
console.error(`Unknown option: ${argv[i]}`);
|
|
136
|
+
integrateUsage();
|
|
137
|
+
}
|
|
138
|
+
if (!targetDir) {
|
|
139
|
+
targetDir = argv[i];
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
console.error(`Unexpected argument: ${argv[i]}`);
|
|
143
|
+
integrateUsage();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { targetDir: targetDir ?? '.', force };
|
|
148
|
+
}
|
|
149
|
+
if (!command || command === '--help' || command === '-h') {
|
|
150
|
+
mainUsage();
|
|
151
|
+
}
|
|
152
|
+
switch (command) {
|
|
153
|
+
case 'create': {
|
|
154
|
+
const parsed = parseCreateArgs(args.slice(1));
|
|
155
|
+
let { projectName } = parsed;
|
|
156
|
+
if (!projectName) {
|
|
157
|
+
const rl = readline.createInterface({
|
|
158
|
+
input: process.stdin,
|
|
159
|
+
output: process.stdout,
|
|
160
|
+
});
|
|
161
|
+
projectName = (await rl.question('Project name: ')).trim();
|
|
162
|
+
rl.close();
|
|
163
|
+
if (!projectName) {
|
|
164
|
+
console.error('Project name is required.');
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
await create({ projectName, force: parsed.force });
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 'gen-types': {
|
|
172
|
+
const parsed = parseGenTypesArgs(args.slice(1));
|
|
173
|
+
const typingsDir = path.resolve(parsed.typingsDir ?? './typings');
|
|
174
|
+
const outFile = path.resolve(parsed.outFile ?? path.join(typingsDir, 'godot.vue-components.gen.d.ts'));
|
|
175
|
+
const ancestor = parsed.ancestor ?? 'Control';
|
|
176
|
+
const vueSrcDir = path.resolve(parsed.vueSrcDir ?? './vue/src');
|
|
177
|
+
generate({ typingsDir, outFile, ancestor, vueSrcDir });
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case 'integrate': {
|
|
181
|
+
const parsed = parseIntegrateArgs(args.slice(1));
|
|
182
|
+
await integrate(parsed);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
console.error(`Unknown command: ${command}`);
|
|
187
|
+
mainUsage();
|
|
188
|
+
}
|
package/dist/create.d.ts
ADDED
package/dist/create.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { copyTemplateDir, getTemplatesDir, newPackageJson } from './integrate.js';
|
|
5
|
+
function runCommand(command, args, cwd) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const child = spawn(command, args, {
|
|
8
|
+
cwd,
|
|
9
|
+
stdio: 'inherit',
|
|
10
|
+
shell: false,
|
|
11
|
+
});
|
|
12
|
+
child.on('error', reject);
|
|
13
|
+
child.on('close', (code) => {
|
|
14
|
+
if (code === 0) {
|
|
15
|
+
resolve();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
reject(new Error(`Command failed (${code ?? 'unknown'}): ${command} ${args.join(' ')}`));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export async function create(options) {
|
|
23
|
+
const { projectName, force } = options;
|
|
24
|
+
const absTarget = path.resolve(projectName);
|
|
25
|
+
const packageName = path.basename(absTarget);
|
|
26
|
+
/* --- guard: directory already exists --- */
|
|
27
|
+
if (fs.existsSync(absTarget)) {
|
|
28
|
+
if (!force) {
|
|
29
|
+
console.error(`Directory "${absTarget}" already exists. Use -f to overwrite.`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
fs.rmSync(absTarget, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
fs.mkdirSync(absTarget, { recursive: true });
|
|
35
|
+
const templatesDir = getTemplatesDir();
|
|
36
|
+
/* --- copy Godot project template --- */
|
|
37
|
+
const godotTplDir = path.join(templatesDir, 'godot');
|
|
38
|
+
if (!fs.existsSync(godotTplDir)) {
|
|
39
|
+
console.error(`Template directory not found: ${godotTplDir}\nThe CLI package may not be installed correctly.`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
copyTemplateDir(godotTplDir, absTarget, { '{{PROJECT_NAME}}': projectName }, process.cwd());
|
|
43
|
+
/* --- copy Vue template --- */
|
|
44
|
+
const vueTplDir = path.join(templatesDir, 'vue');
|
|
45
|
+
const vueDir = path.join(absTarget, 'vue');
|
|
46
|
+
if (!fs.existsSync(vueTplDir)) {
|
|
47
|
+
console.error(`Template directory not found: ${vueTplDir}\nThe CLI package may not be installed correctly.`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
// node_modules will live in the project root after npm install
|
|
51
|
+
const nodeModulesRelPath = '../node_modules';
|
|
52
|
+
copyTemplateDir(vueTplDir, vueDir, { '{{NODE_MODULES}}': nodeModulesRelPath }, process.cwd());
|
|
53
|
+
/* --- package.json --- */
|
|
54
|
+
const typingsTplDir = path.join(templatesDir, 'typings');
|
|
55
|
+
const typingsDir = path.join(absTarget, 'typings');
|
|
56
|
+
if (!fs.existsSync(typingsTplDir)) {
|
|
57
|
+
console.error(`Template directory not found: ${typingsTplDir}\nThe CLI package may not be installed correctly.`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
copyTemplateDir(typingsTplDir, typingsDir, {}, process.cwd());
|
|
61
|
+
const pkgJsonPath = path.join(absTarget, 'package.json');
|
|
62
|
+
fs.writeFileSync(pkgJsonPath, JSON.stringify(newPackageJson(packageName), null, 2) + '\n');
|
|
63
|
+
console.log(` created ${path.relative(process.cwd(), pkgJsonPath)}`);
|
|
64
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
65
|
+
console.log(`\nRunning project setup...`);
|
|
66
|
+
console.log(` npm install`);
|
|
67
|
+
await runCommand(npmCmd, ['install'], absTarget);
|
|
68
|
+
console.log(` npm run gen:types`);
|
|
69
|
+
await runCommand(npmCmd, ['run', 'gen:types'], absTarget);
|
|
70
|
+
console.log(`\n✔ Project "${packageName}" created at ${path.relative(process.cwd(), absTarget)}`);
|
|
71
|
+
console.log(`\nCompleted setup:`);
|
|
72
|
+
console.log(` cd ${projectName}`);
|
|
73
|
+
console.log(` npm install (executed)`);
|
|
74
|
+
console.log(` npm run gen:types (executed)`);
|
|
75
|
+
console.log(` npm run dev # rebuilds on change; Godot hot-reloads dist/app.js`);
|
|
76
|
+
console.log(` # Open the project in Godot and hit Play`);
|
|
77
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface GenerateOptions {
|
|
2
|
+
/** Directory containing godot*.gen.d.ts files */
|
|
3
|
+
typingsDir: string;
|
|
4
|
+
/** Output file path for the generated .d.ts */
|
|
5
|
+
outFile: string;
|
|
6
|
+
/**
|
|
7
|
+
* Base class name to filter by inheritance.
|
|
8
|
+
* Only classes derived from this ancestor will be included.
|
|
9
|
+
* @default 'Control'
|
|
10
|
+
*/
|
|
11
|
+
ancestor?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Directory containing Vue source files (e.g. `vue/src`).
|
|
14
|
+
* When set, an `env.d.ts` shim will be generated there.
|
|
15
|
+
*/
|
|
16
|
+
vueSrcDir?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generate the `declare module "@vue/runtime-core"` augmentation source text.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateSource(options: GenerateOptions): string;
|
|
22
|
+
/**
|
|
23
|
+
* Generate the Vue env.d.ts shim source text.
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateEnvDtsSource(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Generate and write the augmentation file (and optionally env.d.ts).
|
|
28
|
+
*/
|
|
29
|
+
export declare function generate(options: GenerateOptions): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Parse all `class Foo<…> extends Bar<…>` declarations from godot*.gen.d.ts
|
|
5
|
+
* and build a { className → parentClassName } map.
|
|
6
|
+
*/
|
|
7
|
+
function parseClassHierarchy(typingsDir) {
|
|
8
|
+
const classes = new Map();
|
|
9
|
+
const files = fs
|
|
10
|
+
.readdirSync(typingsDir)
|
|
11
|
+
.filter((f) => /^godot\d*\.gen\.d\.ts$/.test(f) || f === 'godot.mix.d.ts');
|
|
12
|
+
for (const file of files.sort()) {
|
|
13
|
+
const content = fs.readFileSync(path.join(typingsDir, file), 'utf-8');
|
|
14
|
+
const re = /class\s+(\w+)\s*<.*?>\s+extends\s+(\w+)/g;
|
|
15
|
+
let m;
|
|
16
|
+
while ((m = re.exec(content)) !== null) {
|
|
17
|
+
classes.set(m[1], m[2]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return classes;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Walk the inheritance chain of `cls` and return all ancestor class names.
|
|
24
|
+
*/
|
|
25
|
+
function getAncestors(cls, classes) {
|
|
26
|
+
const chain = [];
|
|
27
|
+
const visited = new Set();
|
|
28
|
+
let current = cls;
|
|
29
|
+
while (classes.has(current) && !visited.has(current)) {
|
|
30
|
+
visited.add(current);
|
|
31
|
+
const parent = classes.get(current);
|
|
32
|
+
chain.push(parent);
|
|
33
|
+
current = parent;
|
|
34
|
+
}
|
|
35
|
+
return chain;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Return all class names that inherit (directly or transitively) from `ancestor`,
|
|
39
|
+
* plus the ancestor itself.
|
|
40
|
+
*/
|
|
41
|
+
function getDescendants(classes, ancestor) {
|
|
42
|
+
const result = [];
|
|
43
|
+
for (const cls of classes.keys()) {
|
|
44
|
+
if (cls === ancestor || getAncestors(cls, classes).includes(ancestor)) {
|
|
45
|
+
result.push(cls);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result.sort();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Generate the `declare module "@vue/runtime-core"` augmentation source text.
|
|
52
|
+
*/
|
|
53
|
+
export function generateSource(options) {
|
|
54
|
+
const { typingsDir, ancestor = 'Control' } = options;
|
|
55
|
+
const classes = parseClassHierarchy(typingsDir);
|
|
56
|
+
const nodes = getDescendants(classes, ancestor);
|
|
57
|
+
const lines = [
|
|
58
|
+
'// AUTO-GENERATED by @vue-godot/cli — do not edit manually',
|
|
59
|
+
'// Augments @vue/runtime-core GlobalComponents so Volar provides',
|
|
60
|
+
'// typed props when using Godot nodes in Vue templates.',
|
|
61
|
+
'',
|
|
62
|
+
'import type { AllowedComponentProps, VNodeProps } from "@vue/runtime-core"',
|
|
63
|
+
'',
|
|
64
|
+
'/**',
|
|
65
|
+
' * Extracts settable (non-method) instance properties from a Godot node class.',
|
|
66
|
+
' * All keys become optional since props are optional in Vue templates.',
|
|
67
|
+
' */',
|
|
68
|
+
'type GodotProps<T> = {',
|
|
69
|
+
' [K in keyof T as T[K] extends (...args: any[]) => any ? never : K]?: T[K]',
|
|
70
|
+
'}',
|
|
71
|
+
'',
|
|
72
|
+
'type VueGodotComponentProps<T> = GodotProps<T> & AllowedComponentProps & VNodeProps',
|
|
73
|
+
'',
|
|
74
|
+
'declare module "@vue/runtime-core" {',
|
|
75
|
+
' interface GlobalComponents {',
|
|
76
|
+
];
|
|
77
|
+
for (const node of nodes) {
|
|
78
|
+
lines.push(` ${node}: new () => { $props: VueGodotComponentProps<import("godot").${node}> }`);
|
|
79
|
+
}
|
|
80
|
+
lines.push(' }', '}', '', 'declare module "vue" {', ' export interface GlobalComponents {');
|
|
81
|
+
for (const node of nodes) {
|
|
82
|
+
lines.push(` ${node}: new () => { $props: VueGodotComponentProps<import("godot").${node}> }`);
|
|
83
|
+
}
|
|
84
|
+
lines.push(' }', '}', '');
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Generate the Vue env.d.ts shim source text.
|
|
89
|
+
*/
|
|
90
|
+
export function generateEnvDtsSource() {
|
|
91
|
+
return [
|
|
92
|
+
'// AUTO-GENERATED by @vue-godot/cli — do not edit manually',
|
|
93
|
+
'/// <reference types="vite/client" />',
|
|
94
|
+
'',
|
|
95
|
+
"declare module '*.vue' {",
|
|
96
|
+
" import type { DefineComponent } from '@vue/runtime-core'",
|
|
97
|
+
' const component: DefineComponent<{}, {}, any>',
|
|
98
|
+
' export default component',
|
|
99
|
+
'}',
|
|
100
|
+
'',
|
|
101
|
+
].join('\n');
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generate and write the augmentation file (and optionally env.d.ts).
|
|
105
|
+
*/
|
|
106
|
+
export function generate(options) {
|
|
107
|
+
const source = generateSource(options);
|
|
108
|
+
const outDir = path.dirname(options.outFile);
|
|
109
|
+
if (!fs.existsSync(outDir)) {
|
|
110
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
fs.writeFileSync(options.outFile, source, 'utf-8');
|
|
113
|
+
// Count unique components (the source augments both "@vue/runtime-core" and "vue")
|
|
114
|
+
const count = new Set(source
|
|
115
|
+
.split('\n')
|
|
116
|
+
.map((l) => l.match(/^\s{4}(\w+):/))
|
|
117
|
+
.filter((m) => m !== null)
|
|
118
|
+
.map((m) => m[1])).size;
|
|
119
|
+
console.log(`@vue-godot/cli: wrote ${count} ${options.ancestor ?? 'Control'}-derived component types → ${options.outFile}`);
|
|
120
|
+
// Generate env.d.ts shim for Vue SFC support
|
|
121
|
+
if (options.vueSrcDir) {
|
|
122
|
+
const envFile = path.join(options.vueSrcDir, 'env.d.ts');
|
|
123
|
+
if (!fs.existsSync(options.vueSrcDir)) {
|
|
124
|
+
fs.mkdirSync(options.vueSrcDir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
fs.writeFileSync(envFile, generateEnvDtsSource(), 'utf-8');
|
|
127
|
+
console.log(`@vue-godot/cli: wrote env.d.ts → ${envFile}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface IntegrateOptions {
|
|
2
|
+
targetDir: string;
|
|
3
|
+
force: boolean;
|
|
4
|
+
}
|
|
5
|
+
/** Resolve the bundled templates/ directory (lives next to dist/). */
|
|
6
|
+
export declare function getTemplatesDir(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Recursively copy a directory, applying placeholder replacements to every
|
|
9
|
+
* text file. Binary files are copied as-is.
|
|
10
|
+
*/
|
|
11
|
+
export declare function copyTemplateDir(srcDir: string, destDir: string, replacements: Record<string, string>, cwd: string): void;
|
|
12
|
+
export declare function newPackageJson(name: string): Record<string, unknown>;
|
|
13
|
+
export declare function integrate(options: IntegrateOptions): Promise<void>;
|