kustom-mc 0.1.2 → 0.1.4
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/bundler.d.ts +33 -0
- package/dist/bundler.js +195 -0
- package/dist/commands/build.d.ts +16 -0
- package/dist/commands/build.js +14 -184
- package/dist/commands/bundle.js +22 -133
- package/dist/commands/init.js +10 -23
- package/dist/commands/login.js +27 -1
- package/dist/commands/new.js +29 -23
- package/dist/commands/push.d.ts +10 -3
- package/dist/commands/push.js +180 -101
- package/dist/commands/validate.js +1 -1
- package/dist/config.d.ts +6 -4
- package/dist/config.js +25 -6
- package/dist/runtime.d.ts +21 -3
- package/dist/runtime.js +2 -27
- package/dist/types/__tests__/debug-inference.d.ts +4 -0
- package/dist/types/__tests__/debug-inference.js +25 -0
- package/dist/types/__tests__/defineScript-methods-dx-test.d.ts +27 -0
- package/dist/types/__tests__/defineScript-methods-dx-test.js +76 -0
- package/dist/types/__tests__/defineScript-methods-negative-test.d.ts +16 -0
- package/dist/types/__tests__/defineScript-methods-negative-test.js +36 -0
- package/dist/types/__tests__/methods-type-test.d.ts +10 -0
- package/dist/types/__tests__/methods-type-test.js +39 -0
- package/dist/types/index.d.ts +91 -3
- package/dist/upload.d.ts +22 -0
- package/dist/upload.js +35 -0
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for creating a bundle.
|
|
3
|
+
*/
|
|
4
|
+
export interface BundleOptions {
|
|
5
|
+
/** Whether to generate and include the manifest (default: true) */
|
|
6
|
+
includeManifest?: boolean;
|
|
7
|
+
/** Whether to include TypeScript source files (default: false) */
|
|
8
|
+
includeSource?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Result of a bundle operation.
|
|
12
|
+
*/
|
|
13
|
+
export interface BundleResult {
|
|
14
|
+
packId: string;
|
|
15
|
+
version: string;
|
|
16
|
+
fileCount: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Result of bundling to a buffer.
|
|
20
|
+
*/
|
|
21
|
+
export interface BufferBundleResult extends BundleResult {
|
|
22
|
+
buffer: Buffer;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a zip bundle in memory and return as a Buffer.
|
|
26
|
+
* Used by the push command for HTTP upload.
|
|
27
|
+
*/
|
|
28
|
+
export declare function bundleToBuffer(projectDir: string, options?: BundleOptions): Promise<BufferBundleResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Create a zip bundle and write it to a file on disk.
|
|
31
|
+
* Used by the bundle command for distribution.
|
|
32
|
+
*/
|
|
33
|
+
export declare function bundleToFile(projectDir: string, outputPath: string, options?: BundleOptions): Promise<BundleResult>;
|
package/dist/bundler.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import archiver from 'archiver';
|
|
5
|
+
import { loadConfig, generateManifest, validateManifest } from './config.js';
|
|
6
|
+
/**
|
|
7
|
+
* Collect all files that should be included in the bundle.
|
|
8
|
+
* Returns a list of { absolutePath, archiveName } entries.
|
|
9
|
+
*/
|
|
10
|
+
async function collectBundleFiles(projectDir, config) {
|
|
11
|
+
const includePatterns = config.bundle?.include || [
|
|
12
|
+
'**/*.js',
|
|
13
|
+
'textures/**/*',
|
|
14
|
+
'gui/**/*',
|
|
15
|
+
'models/**/*',
|
|
16
|
+
'sounds/**/*'
|
|
17
|
+
];
|
|
18
|
+
const outDir = config.outDir || 'dist';
|
|
19
|
+
const outDirResolved = path.resolve(projectDir, outDir);
|
|
20
|
+
const addedFiles = new Set();
|
|
21
|
+
const files = [];
|
|
22
|
+
for (const pattern of includePatterns) {
|
|
23
|
+
const isJsPattern = pattern.includes('*.js');
|
|
24
|
+
if (isJsPattern) {
|
|
25
|
+
// JS files live in outDir (e.g. dist/)
|
|
26
|
+
// Exclude types/ directory (generated .d.ts files) and zip files
|
|
27
|
+
const matches = await glob(pattern, {
|
|
28
|
+
cwd: outDirResolved,
|
|
29
|
+
nodir: true,
|
|
30
|
+
ignore: ['types/**', '*.zip', 'kustompack.json']
|
|
31
|
+
});
|
|
32
|
+
for (const file of matches) {
|
|
33
|
+
if (addedFiles.has(file))
|
|
34
|
+
continue;
|
|
35
|
+
const absolutePath = path.resolve(outDirResolved, file);
|
|
36
|
+
if (fs.existsSync(absolutePath)) {
|
|
37
|
+
files.push({ absolutePath, archiveName: file });
|
|
38
|
+
addedFiles.add(file);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Asset files live in projectDir (source directory)
|
|
44
|
+
const matches = await glob(pattern, {
|
|
45
|
+
cwd: projectDir,
|
|
46
|
+
nodir: true,
|
|
47
|
+
ignore: ['node_modules/**', 'dist/**', '*.ts', 'kustompack.json']
|
|
48
|
+
});
|
|
49
|
+
for (const file of matches) {
|
|
50
|
+
if (addedFiles.has(file))
|
|
51
|
+
continue;
|
|
52
|
+
const absolutePath = path.resolve(projectDir, file);
|
|
53
|
+
if (fs.existsSync(absolutePath)) {
|
|
54
|
+
files.push({ absolutePath, archiveName: file });
|
|
55
|
+
addedFiles.add(file);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return files;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Collect TypeScript source files for optional inclusion.
|
|
64
|
+
*/
|
|
65
|
+
async function collectSourceFiles(projectDir, config) {
|
|
66
|
+
const sourcePatterns = config.include || ['scripts/**/*.ts', 'blocks/**/*.ts', 'items/**/*.ts'];
|
|
67
|
+
const addedFiles = new Set();
|
|
68
|
+
const files = [];
|
|
69
|
+
for (const pattern of sourcePatterns) {
|
|
70
|
+
const matches = await glob(pattern, {
|
|
71
|
+
cwd: projectDir,
|
|
72
|
+
nodir: true,
|
|
73
|
+
ignore: config.exclude
|
|
74
|
+
});
|
|
75
|
+
for (const file of matches) {
|
|
76
|
+
if (addedFiles.has(file))
|
|
77
|
+
continue;
|
|
78
|
+
const absolutePath = path.resolve(projectDir, file);
|
|
79
|
+
if (fs.existsSync(absolutePath)) {
|
|
80
|
+
files.push({ absolutePath, archiveName: file });
|
|
81
|
+
addedFiles.add(file);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return files;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Populate an archiver instance with all bundle files.
|
|
89
|
+
* Returns the file count.
|
|
90
|
+
*/
|
|
91
|
+
async function populateArchive(archive, projectDir, config, options = {}) {
|
|
92
|
+
let fileCount = 0;
|
|
93
|
+
// Add manifest
|
|
94
|
+
if (options.includeManifest !== false) {
|
|
95
|
+
const manifestContent = generateManifest(config);
|
|
96
|
+
archive.append(manifestContent, { name: 'kustompack.json' });
|
|
97
|
+
fileCount++;
|
|
98
|
+
}
|
|
99
|
+
// Add compiled JS + assets
|
|
100
|
+
const bundleFiles = await collectBundleFiles(projectDir, config);
|
|
101
|
+
for (const file of bundleFiles) {
|
|
102
|
+
archive.file(file.absolutePath, { name: file.archiveName });
|
|
103
|
+
fileCount++;
|
|
104
|
+
}
|
|
105
|
+
// Optionally add source files
|
|
106
|
+
if (options.includeSource) {
|
|
107
|
+
const sourceFiles = await collectSourceFiles(projectDir, config);
|
|
108
|
+
for (const file of sourceFiles) {
|
|
109
|
+
archive.file(file.absolutePath, { name: file.archiveName });
|
|
110
|
+
fileCount++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { fileCount };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate config and return pack metadata.
|
|
117
|
+
* Throws on validation errors.
|
|
118
|
+
*/
|
|
119
|
+
function validateConfig(config) {
|
|
120
|
+
const errors = validateManifest(config);
|
|
121
|
+
if (errors.length > 0) {
|
|
122
|
+
throw new Error(`Manifest validation failed:\n ${errors.join('\n ')}`);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
packId: config.manifest?.id || 'kustompack',
|
|
126
|
+
version: config.manifest?.version || '1.0.0'
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Create a zip bundle in memory and return as a Buffer.
|
|
131
|
+
* Used by the push command for HTTP upload.
|
|
132
|
+
*/
|
|
133
|
+
export async function bundleToBuffer(projectDir, options = {}) {
|
|
134
|
+
const config = loadConfig(projectDir);
|
|
135
|
+
const { packId, version } = validateConfig(config);
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
const chunks = [];
|
|
138
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
139
|
+
archive.on('data', (chunk) => chunks.push(chunk));
|
|
140
|
+
archive.on('error', reject);
|
|
141
|
+
archive.on('end', () => {
|
|
142
|
+
// fileCount is set by the async populate below before finalize
|
|
143
|
+
});
|
|
144
|
+
const run = async () => {
|
|
145
|
+
const { fileCount } = await populateArchive(archive, projectDir, config, options);
|
|
146
|
+
// Listen for end after we know fileCount
|
|
147
|
+
return new Promise((res) => {
|
|
148
|
+
archive.on('end', () => {
|
|
149
|
+
res({
|
|
150
|
+
buffer: Buffer.concat(chunks),
|
|
151
|
+
packId,
|
|
152
|
+
version,
|
|
153
|
+
fileCount
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
archive.finalize();
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
run().then(resolve).catch(reject);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Create a zip bundle and write it to a file on disk.
|
|
164
|
+
* Used by the bundle command for distribution.
|
|
165
|
+
*/
|
|
166
|
+
export async function bundleToFile(projectDir, outputPath, options = {}) {
|
|
167
|
+
const config = loadConfig(projectDir);
|
|
168
|
+
const { packId, version } = validateConfig(config);
|
|
169
|
+
// Ensure output directory exists
|
|
170
|
+
const outputDir = path.dirname(outputPath);
|
|
171
|
+
if (!fs.existsSync(outputDir)) {
|
|
172
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
173
|
+
}
|
|
174
|
+
return new Promise((resolve, reject) => {
|
|
175
|
+
const output = fs.createWriteStream(outputPath);
|
|
176
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
177
|
+
archive.on('warning', (err) => {
|
|
178
|
+
if (err.code !== 'ENOENT') {
|
|
179
|
+
reject(err);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
archive.on('error', reject);
|
|
183
|
+
archive.pipe(output);
|
|
184
|
+
const run = async () => {
|
|
185
|
+
const { fileCount } = await populateArchive(archive, projectDir, config, options);
|
|
186
|
+
return new Promise((res) => {
|
|
187
|
+
output.on('close', () => {
|
|
188
|
+
res({ packId, version, fileCount });
|
|
189
|
+
});
|
|
190
|
+
archive.finalize();
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
run().then(resolve).catch(reject);
|
|
194
|
+
});
|
|
195
|
+
}
|
package/dist/commands/build.d.ts
CHANGED
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { type KustomConfig } from '../config.js';
|
|
2
3
|
export declare const buildCommand: Command;
|
|
4
|
+
/**
|
|
5
|
+
* Build all TypeScript files in the project.
|
|
6
|
+
* Exported for use by push and bundle commands.
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildAll(config: KustomConfig, options: {
|
|
9
|
+
validate?: boolean;
|
|
10
|
+
verbose?: boolean;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Build a single TypeScript file to Rhino-compatible JavaScript.
|
|
14
|
+
* Exported for use by push --watch for incremental rebuilds.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildFile(file: string, config: KustomConfig, options: {
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
}): Promise<string>;
|
package/dist/commands/build.js
CHANGED
|
@@ -11,7 +11,6 @@ import { prepare } from './prepare.js';
|
|
|
11
11
|
export const buildCommand = new Command('build')
|
|
12
12
|
.description('Compile TypeScript scripts to Rhino-compatible JavaScript')
|
|
13
13
|
.option('-w, --watch', 'Watch for changes and rebuild')
|
|
14
|
-
.option('-d, --deploy', 'Copy compiled files to deploy target')
|
|
15
14
|
.option('--no-validate', 'Skip validation')
|
|
16
15
|
.option('-v, --verbose', 'Verbose output')
|
|
17
16
|
.option('--clean', 'Clean output directory before building')
|
|
@@ -47,7 +46,11 @@ function getOutputPath(sourceFile, config) {
|
|
|
47
46
|
function getOutDir(config) {
|
|
48
47
|
return path.resolve(process.cwd(), config.outDir || 'dist');
|
|
49
48
|
}
|
|
50
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Build all TypeScript files in the project.
|
|
51
|
+
* Exported for use by push and bundle commands.
|
|
52
|
+
*/
|
|
53
|
+
export async function buildAll(config, options) {
|
|
51
54
|
// Validate manifest configuration
|
|
52
55
|
const manifestErrors = validateManifest(config);
|
|
53
56
|
if (manifestErrors.length > 0) {
|
|
@@ -115,9 +118,6 @@ async function buildAll(config, options) {
|
|
|
115
118
|
}
|
|
116
119
|
const elapsed = Date.now() - startTime;
|
|
117
120
|
console.log(`\nBuild completed in ${elapsed}ms: ${successCount} succeeded, ${errorCount} failed`);
|
|
118
|
-
if (options.deploy && config.deploy?.target) {
|
|
119
|
-
await deployFiles(scriptFiles, config, options);
|
|
120
|
-
}
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* esbuild plugin to mark relative script imports and cross-pack imports as external.
|
|
@@ -173,7 +173,11 @@ function externalScriptImportsPlugin(config) {
|
|
|
173
173
|
}
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Build a single TypeScript file to Rhino-compatible JavaScript.
|
|
178
|
+
* Exported for use by push --watch for incremental rebuilds.
|
|
179
|
+
*/
|
|
180
|
+
export async function buildFile(file, config, options) {
|
|
177
181
|
const inputPath = path.resolve(process.cwd(), file);
|
|
178
182
|
const outputPath = getOutputPath(file, config);
|
|
179
183
|
// Ensure output directory exists
|
|
@@ -207,25 +211,8 @@ async function buildFile(file, config, options) {
|
|
|
207
211
|
}
|
|
208
212
|
async function watchMode(config, options) {
|
|
209
213
|
console.log('Starting watch mode...');
|
|
210
|
-
// Initial build
|
|
211
|
-
await buildAll(config,
|
|
212
|
-
// Initial deploy if requested (scripts + assets)
|
|
213
|
-
if (options.deploy && config.deploy?.target) {
|
|
214
|
-
const patterns = config.include || ['scripts/**/*.ts'];
|
|
215
|
-
const files = [];
|
|
216
|
-
for (const pattern of patterns) {
|
|
217
|
-
const matches = await glob(pattern, {
|
|
218
|
-
cwd: process.cwd(),
|
|
219
|
-
ignore: config.exclude || []
|
|
220
|
-
});
|
|
221
|
-
files.push(...matches);
|
|
222
|
-
}
|
|
223
|
-
const libDirs = config.lib || ['scripts/lib'];
|
|
224
|
-
const scriptFiles = files.filter(file => {
|
|
225
|
-
return !libDirs.some(lib => file.startsWith(lib + '/') || file.startsWith(lib + '\\'));
|
|
226
|
-
});
|
|
227
|
-
await deployFiles(scriptFiles, config, options);
|
|
228
|
-
}
|
|
214
|
+
// Initial build
|
|
215
|
+
await buildAll(config, options);
|
|
229
216
|
// Watch for changes
|
|
230
217
|
const patterns = config.include || ['scripts/**/*.ts'];
|
|
231
218
|
const libDirs = config.lib || ['scripts/lib'];
|
|
@@ -234,7 +221,7 @@ async function watchMode(config, options) {
|
|
|
234
221
|
ignoreInitial: true,
|
|
235
222
|
ignored: config.exclude
|
|
236
223
|
});
|
|
237
|
-
// Watch sounds folder for type regeneration
|
|
224
|
+
// Watch sounds folder for type regeneration
|
|
238
225
|
const soundsWatcher = chokidar.watch('sounds/**/*.ogg', {
|
|
239
226
|
cwd: process.cwd(),
|
|
240
227
|
ignoreInitial: true
|
|
@@ -243,56 +230,19 @@ async function watchMode(config, options) {
|
|
|
243
230
|
console.log(`\nSound added: ${file}`);
|
|
244
231
|
console.log('Regenerating types...');
|
|
245
232
|
await prepare(process.cwd());
|
|
246
|
-
if (options.deploy && config.deploy?.target) {
|
|
247
|
-
await deploySingleAsset(file, config);
|
|
248
|
-
console.log(` Deployed: ${file}`);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
soundsWatcher.on('change', async (file) => {
|
|
252
|
-
console.log(`\nSound changed: ${file}`);
|
|
253
|
-
if (options.deploy && config.deploy?.target) {
|
|
254
|
-
await deploySingleAsset(file, config);
|
|
255
|
-
console.log(` Deployed: ${file}`);
|
|
256
|
-
}
|
|
257
233
|
});
|
|
258
234
|
soundsWatcher.on('unlink', async (file) => {
|
|
259
235
|
console.log(`\nSound removed: ${file}`);
|
|
260
236
|
console.log('Regenerating types...');
|
|
261
237
|
await prepare(process.cwd());
|
|
262
238
|
});
|
|
263
|
-
// Watch other asset folders (textures, models, gui)
|
|
264
|
-
const assetPatterns = [
|
|
265
|
-
'textures/**/*',
|
|
266
|
-
'models/**/*',
|
|
267
|
-
'gui/**/*',
|
|
268
|
-
'items/**/*',
|
|
269
|
-
'blocks/**/*'
|
|
270
|
-
];
|
|
271
|
-
const assetsWatcher = chokidar.watch(assetPatterns, {
|
|
272
|
-
cwd: process.cwd(),
|
|
273
|
-
ignoreInitial: true
|
|
274
|
-
});
|
|
275
|
-
assetsWatcher.on('add', async (file) => {
|
|
276
|
-
if (options.deploy && config.deploy?.target) {
|
|
277
|
-
console.log(`\nAsset added: ${file}`);
|
|
278
|
-
await deploySingleAsset(file, config);
|
|
279
|
-
console.log(` Deployed: ${file}`);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
assetsWatcher.on('change', async (file) => {
|
|
283
|
-
if (options.deploy && config.deploy?.target) {
|
|
284
|
-
console.log(`\nAsset changed: ${file}`);
|
|
285
|
-
await deploySingleAsset(file, config);
|
|
286
|
-
console.log(` Deployed: ${file}`);
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
239
|
const rebuild = async (changedFile) => {
|
|
290
240
|
const isLibFile = libDirs.some(lib => changedFile.startsWith(lib + '/') || changedFile.startsWith(lib + '\\'));
|
|
291
241
|
if (isLibFile) {
|
|
292
242
|
// Rebuild all files if a lib file changed
|
|
293
243
|
console.log(`\nLib file changed: ${changedFile}`);
|
|
294
244
|
console.log('Rebuilding all scripts...');
|
|
295
|
-
await buildAll(config,
|
|
245
|
+
await buildAll(config, options);
|
|
296
246
|
}
|
|
297
247
|
else {
|
|
298
248
|
// Rebuild just the changed file
|
|
@@ -300,9 +250,6 @@ async function watchMode(config, options) {
|
|
|
300
250
|
try {
|
|
301
251
|
const outputPath = await buildFile(changedFile, config, options);
|
|
302
252
|
console.log(` [OK] ${changedFile} -> ${path.relative(process.cwd(), outputPath)}`);
|
|
303
|
-
if (options.deploy && config.deploy?.target) {
|
|
304
|
-
await deploySingleFile(changedFile, config);
|
|
305
|
-
}
|
|
306
253
|
}
|
|
307
254
|
catch (error) {
|
|
308
255
|
console.error(` [ERROR] ${changedFile}: ${error instanceof Error ? error.message : error}`);
|
|
@@ -325,123 +272,6 @@ async function watchMode(config, options) {
|
|
|
325
272
|
console.log('\nStopping watch mode...');
|
|
326
273
|
watcher.close();
|
|
327
274
|
soundsWatcher.close();
|
|
328
|
-
assetsWatcher.close();
|
|
329
275
|
process.exit(0);
|
|
330
276
|
});
|
|
331
277
|
}
|
|
332
|
-
async function deployFiles(sourceFiles, config, options = {}) {
|
|
333
|
-
if (!config.deploy?.target)
|
|
334
|
-
return;
|
|
335
|
-
const targetDir = path.resolve(process.cwd(), config.deploy.target);
|
|
336
|
-
console.log(`\nDeploying to ${targetDir}...`);
|
|
337
|
-
// Ensure target directory exists
|
|
338
|
-
if (!fs.existsSync(targetDir)) {
|
|
339
|
-
fs.mkdirSync(targetDir, { recursive: true });
|
|
340
|
-
}
|
|
341
|
-
// Deploy manifest
|
|
342
|
-
const outDir = getOutDir(config);
|
|
343
|
-
const manifestSource = path.resolve(outDir, 'kustompack.json');
|
|
344
|
-
const manifestTarget = path.join(targetDir, 'kustompack.json');
|
|
345
|
-
if (fs.existsSync(manifestSource)) {
|
|
346
|
-
fs.copyFileSync(manifestSource, manifestTarget);
|
|
347
|
-
console.log(` Deployed kustompack.json`);
|
|
348
|
-
}
|
|
349
|
-
// Deploy compiled scripts
|
|
350
|
-
let deployedScripts = 0;
|
|
351
|
-
for (const sourceFile of sourceFiles) {
|
|
352
|
-
await deploySingleFile(sourceFile, config);
|
|
353
|
-
deployedScripts++;
|
|
354
|
-
}
|
|
355
|
-
console.log(` Deployed ${deployedScripts} script(s)`);
|
|
356
|
-
// Deploy asset folders (sounds, textures, models, gui, etc.)
|
|
357
|
-
const deployedAssets = await deployAssets(config, options);
|
|
358
|
-
if (deployedAssets > 0) {
|
|
359
|
-
console.log(` Deployed ${deployedAssets} asset folder(s)`);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Deploy a single file from outDir to deploy target
|
|
364
|
-
*/
|
|
365
|
-
async function deploySingleFile(sourceFile, config) {
|
|
366
|
-
if (!config.deploy?.target)
|
|
367
|
-
return;
|
|
368
|
-
// Source is in outDir
|
|
369
|
-
const outputPath = getOutputPath(sourceFile, config);
|
|
370
|
-
// Target preserves relative path structure
|
|
371
|
-
const relativePath = sourceFile.replace(/\.ts$/, '.js');
|
|
372
|
-
const targetDir = path.resolve(process.cwd(), config.deploy.target);
|
|
373
|
-
const targetPath = path.join(targetDir, relativePath);
|
|
374
|
-
// Ensure target subdirectory exists
|
|
375
|
-
const targetSubDir = path.dirname(targetPath);
|
|
376
|
-
if (!fs.existsSync(targetSubDir)) {
|
|
377
|
-
fs.mkdirSync(targetSubDir, { recursive: true });
|
|
378
|
-
}
|
|
379
|
-
// Copy file from outDir to deploy target
|
|
380
|
-
if (fs.existsSync(outputPath)) {
|
|
381
|
-
fs.copyFileSync(outputPath, targetPath);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Asset folders that should be deployed alongside scripts
|
|
386
|
-
*/
|
|
387
|
-
const ASSET_FOLDERS = ['sounds', 'textures', 'models', 'gui', 'items', 'blocks'];
|
|
388
|
-
/**
|
|
389
|
-
* Copy a folder recursively
|
|
390
|
-
*/
|
|
391
|
-
function copyFolderRecursive(source, target) {
|
|
392
|
-
// Ensure target directory exists
|
|
393
|
-
if (!fs.existsSync(target)) {
|
|
394
|
-
fs.mkdirSync(target, { recursive: true });
|
|
395
|
-
}
|
|
396
|
-
const entries = fs.readdirSync(source, { withFileTypes: true });
|
|
397
|
-
for (const entry of entries) {
|
|
398
|
-
const sourcePath = path.join(source, entry.name);
|
|
399
|
-
const targetPath = path.join(target, entry.name);
|
|
400
|
-
if (entry.isDirectory()) {
|
|
401
|
-
copyFolderRecursive(sourcePath, targetPath);
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Deploy asset folders (sounds, textures, models, gui, etc.) to deploy target
|
|
410
|
-
*/
|
|
411
|
-
async function deployAssets(config, options) {
|
|
412
|
-
if (!config.deploy?.target)
|
|
413
|
-
return 0;
|
|
414
|
-
const targetDir = path.resolve(process.cwd(), config.deploy.target);
|
|
415
|
-
let deployedCount = 0;
|
|
416
|
-
for (const folder of ASSET_FOLDERS) {
|
|
417
|
-
const sourceDir = path.resolve(process.cwd(), folder);
|
|
418
|
-
if (fs.existsSync(sourceDir)) {
|
|
419
|
-
const targetSubDir = path.join(targetDir, folder);
|
|
420
|
-
copyFolderRecursive(sourceDir, targetSubDir);
|
|
421
|
-
deployedCount++;
|
|
422
|
-
if (options.verbose) {
|
|
423
|
-
console.log(` Deployed ${folder}/`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return deployedCount;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Deploy a single asset file to deploy target
|
|
431
|
-
*/
|
|
432
|
-
async function deploySingleAsset(assetFile, config) {
|
|
433
|
-
if (!config.deploy?.target)
|
|
434
|
-
return;
|
|
435
|
-
const sourcePath = path.resolve(process.cwd(), assetFile);
|
|
436
|
-
const targetDir = path.resolve(process.cwd(), config.deploy.target);
|
|
437
|
-
const targetPath = path.join(targetDir, assetFile);
|
|
438
|
-
// Ensure target subdirectory exists
|
|
439
|
-
const targetSubDir = path.dirname(targetPath);
|
|
440
|
-
if (!fs.existsSync(targetSubDir)) {
|
|
441
|
-
fs.mkdirSync(targetSubDir, { recursive: true });
|
|
442
|
-
}
|
|
443
|
-
// Copy file
|
|
444
|
-
if (fs.existsSync(sourcePath)) {
|
|
445
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
446
|
-
}
|
|
447
|
-
}
|
package/dist/commands/bundle.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { glob } from 'glob';
|
|
5
|
-
import archiver from 'archiver';
|
|
6
2
|
import chalk from 'chalk';
|
|
7
|
-
import { loadConfig,
|
|
3
|
+
import { loadConfig, validateManifest } from '../config.js';
|
|
4
|
+
import { bundleToFile } from '../bundler.js';
|
|
5
|
+
import { buildAll } from './build.js';
|
|
8
6
|
export const bundleCommand = new Command('bundle')
|
|
9
|
-
.description('
|
|
7
|
+
.description('Build and create a distributable zip file')
|
|
10
8
|
.option('-o, --output <file>', 'Output file name')
|
|
11
9
|
.option('--include-source', 'Include TypeScript source files')
|
|
12
|
-
.option('--no-manifest', 'Skip manifest generation
|
|
10
|
+
.option('--no-manifest', 'Skip manifest generation')
|
|
11
|
+
.option('-v, --verbose', 'Verbose output')
|
|
13
12
|
.action(async (options) => {
|
|
14
|
-
const
|
|
13
|
+
const projectDir = process.cwd();
|
|
14
|
+
const config = loadConfig(projectDir);
|
|
15
15
|
// Validate manifest configuration
|
|
16
16
|
const errors = validateManifest(config);
|
|
17
17
|
if (errors.length > 0) {
|
|
@@ -23,136 +23,25 @@ export const bundleCommand = new Command('bundle')
|
|
|
23
23
|
}
|
|
24
24
|
const packId = config.manifest?.id || 'kustompack';
|
|
25
25
|
const outputFile = options.output || config.bundle?.output || `dist/${packId}.zip`;
|
|
26
|
-
|
|
26
|
+
// Auto-build before bundling
|
|
27
|
+
console.log(chalk.blue('Building before bundle...\n'));
|
|
28
|
+
await buildAll(config, { verbose: options.verbose });
|
|
29
|
+
console.log();
|
|
30
|
+
// Create bundle
|
|
27
31
|
console.log(chalk.blue(`Creating bundle for pack: ${chalk.bold(packId)}`));
|
|
28
32
|
console.log(` Version: ${config.manifest?.version || '1.0.0'}`);
|
|
29
33
|
console.log(` Output: ${outputFile}`);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Generate manifest if enabled
|
|
36
|
-
let manifestContent = null;
|
|
37
|
-
if (options.manifest !== false) {
|
|
38
|
-
try {
|
|
39
|
-
manifestContent = generateManifest(config);
|
|
40
|
-
console.log(chalk.green(' Generated kustompack.json'));
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
console.error(chalk.red(`Failed to generate manifest: ${error}`));
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Create zip archive
|
|
48
|
-
const output = fs.createWriteStream(outputPath);
|
|
49
|
-
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
50
|
-
let fileCount = 0;
|
|
51
|
-
output.on('close', () => {
|
|
52
|
-
const sizeKB = (archive.pointer() / 1024).toFixed(2);
|
|
34
|
+
try {
|
|
35
|
+
const result = await bundleToFile(projectDir, outputFile, {
|
|
36
|
+
includeManifest: options.manifest !== false,
|
|
37
|
+
includeSource: options.includeSource
|
|
38
|
+
});
|
|
53
39
|
console.log(chalk.green(`\nBundle created successfully!`));
|
|
54
40
|
console.log(` File: ${outputFile}`);
|
|
55
|
-
console.log(`
|
|
56
|
-
console.log(` Files: ${fileCount}`);
|
|
57
|
-
});
|
|
58
|
-
archive.on('warning', (err) => {
|
|
59
|
-
if (err.code === 'ENOENT') {
|
|
60
|
-
console.warn(chalk.yellow('Warning:'), err.message);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
throw err;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
archive.on('error', (err) => {
|
|
67
|
-
throw err;
|
|
68
|
-
});
|
|
69
|
-
archive.pipe(output);
|
|
70
|
-
// Add manifest first
|
|
71
|
-
if (manifestContent) {
|
|
72
|
-
archive.append(manifestContent, { name: 'kustompack.json' });
|
|
73
|
-
fileCount++;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Check for existing manifest
|
|
77
|
-
const existingManifest = path.resolve(process.cwd(), 'kustompack.json');
|
|
78
|
-
if (fs.existsSync(existingManifest)) {
|
|
79
|
-
archive.file(existingManifest, { name: 'kustompack.json' });
|
|
80
|
-
fileCount++;
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
console.warn(chalk.yellow('Warning: No kustompack.json found. Pack may not load correctly.'));
|
|
84
|
-
}
|
|
41
|
+
console.log(` Files: ${result.fileCount}`);
|
|
85
42
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'textures/**/*',
|
|
90
|
-
'gui/**/*',
|
|
91
|
-
'models/**/*',
|
|
92
|
-
'sounds/**/*'
|
|
93
|
-
];
|
|
94
|
-
const outDir = config.outDir || 'dist';
|
|
95
|
-
const outDirResolved = path.resolve(process.cwd(), outDir);
|
|
96
|
-
const addedFiles = new Set();
|
|
97
|
-
for (const pattern of includePatterns) {
|
|
98
|
-
const isJsPattern = pattern.includes('*.js');
|
|
99
|
-
if (isJsPattern) {
|
|
100
|
-
// JS files live in outDir (e.g. dist/)
|
|
101
|
-
const files = await glob(pattern, {
|
|
102
|
-
cwd: outDirResolved,
|
|
103
|
-
nodir: true,
|
|
104
|
-
ignore: ['node_modules/**', '*.ts', 'kustompack.json']
|
|
105
|
-
});
|
|
106
|
-
for (const file of files) {
|
|
107
|
-
if (addedFiles.has(file))
|
|
108
|
-
continue;
|
|
109
|
-
const filePath = path.resolve(outDirResolved, file);
|
|
110
|
-
if (fs.existsSync(filePath)) {
|
|
111
|
-
archive.file(filePath, { name: file });
|
|
112
|
-
addedFiles.add(file);
|
|
113
|
-
fileCount++;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
// Asset files live in cwd (source directory)
|
|
119
|
-
const files = await glob(pattern, {
|
|
120
|
-
cwd: process.cwd(),
|
|
121
|
-
nodir: true,
|
|
122
|
-
ignore: ['node_modules/**', 'dist/**', '*.ts', 'kustompack.json']
|
|
123
|
-
});
|
|
124
|
-
for (const file of files) {
|
|
125
|
-
if (addedFiles.has(file))
|
|
126
|
-
continue;
|
|
127
|
-
const filePath = path.resolve(process.cwd(), file);
|
|
128
|
-
if (fs.existsSync(filePath)) {
|
|
129
|
-
archive.file(filePath, { name: file });
|
|
130
|
-
addedFiles.add(file);
|
|
131
|
-
fileCount++;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Optionally include source files
|
|
137
|
-
if (options.includeSource) {
|
|
138
|
-
const sourcePatterns = config.include || ['scripts/**/*.ts', 'blocks/**/*.ts', 'items/**/*.ts'];
|
|
139
|
-
for (const pattern of sourcePatterns) {
|
|
140
|
-
const files = await glob(pattern, {
|
|
141
|
-
cwd: process.cwd(),
|
|
142
|
-
nodir: true,
|
|
143
|
-
ignore: config.exclude
|
|
144
|
-
});
|
|
145
|
-
for (const file of files) {
|
|
146
|
-
if (addedFiles.has(file))
|
|
147
|
-
continue;
|
|
148
|
-
const filePath = path.resolve(process.cwd(), file);
|
|
149
|
-
if (fs.existsSync(filePath)) {
|
|
150
|
-
archive.file(filePath, { name: file });
|
|
151
|
-
addedFiles.add(file);
|
|
152
|
-
fileCount++;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(chalk.red(`\nFailed to create bundle: ${error instanceof Error ? error.message : error}`));
|
|
45
|
+
process.exit(1);
|
|
156
46
|
}
|
|
157
|
-
await archive.finalize();
|
|
158
47
|
});
|