@defold-typescript/cli 0.4.0 → 0.4.2

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/bin.js CHANGED
@@ -334,6 +334,13 @@ var BIOME_JSON_CONTENT = {
334
334
  }
335
335
  }
336
336
  };
337
+ var VSCODE_EXTENSIONS_CONTENT = {
338
+ recommendations: ["sumneko.lua", "astrochili.defold"],
339
+ unwantedRecommendations: ["johnnymorganz.luau-lsp"]
340
+ };
341
+ var VSCODE_SETTINGS_CONTENT = {
342
+ "Lua.workspace.ignoreDir": ["src"]
343
+ };
337
344
  var MAIN_TS_CONTENT = `export function init(): void {
338
345
  const start = vmath.vector3(0, 0, 0);
339
346
  msg.post("main:/hero", "spawn", { start });
@@ -367,9 +374,9 @@ var SCAFFOLD_DEV_DEPS = {
367
374
  "@defold-typescript/types": typesVersionSpec(),
368
375
  "@biomejs/biome": "^2.2.0"
369
376
  };
370
- function repairManagedDevDeps(devDeps) {
377
+ function repairManagedDevDeps(devDeps, force = false) {
371
378
  delete devDeps["@defold-typescript/transpiler"];
372
- if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
379
+ if (force || devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
373
380
  devDeps["@defold-typescript/types"] = typesVersionSpec();
374
381
  }
375
382
  }
@@ -407,7 +414,108 @@ function writeBiome(cwd, written) {
407
414
  writeJson(biomePath, BIOME_JSON_CONTENT);
408
415
  written.push("biome.json");
409
416
  }
410
- function writeTsSurface(cwd, written) {
417
+ function parseJsonc(text) {
418
+ let out = "";
419
+ let inString = false;
420
+ let inLineComment = false;
421
+ let inBlockComment = false;
422
+ for (let i = 0;i < text.length; i++) {
423
+ const ch = text[i];
424
+ const next = text[i + 1];
425
+ if (inLineComment) {
426
+ if (ch === `
427
+ `) {
428
+ inLineComment = false;
429
+ out += ch;
430
+ }
431
+ continue;
432
+ }
433
+ if (inBlockComment) {
434
+ if (ch === "*" && next === "/") {
435
+ inBlockComment = false;
436
+ i++;
437
+ }
438
+ continue;
439
+ }
440
+ if (inString) {
441
+ out += ch;
442
+ if (ch === "\\") {
443
+ out += next ?? "";
444
+ i++;
445
+ } else if (ch === '"') {
446
+ inString = false;
447
+ }
448
+ continue;
449
+ }
450
+ if (ch === '"') {
451
+ inString = true;
452
+ out += ch;
453
+ } else if (ch === "/" && next === "/") {
454
+ inLineComment = true;
455
+ i++;
456
+ } else if (ch === "/" && next === "*") {
457
+ inBlockComment = true;
458
+ i++;
459
+ } else {
460
+ out += ch;
461
+ }
462
+ }
463
+ return JSON.parse(out.replace(/,(\s*[}\]])/g, "$1"));
464
+ }
465
+ function isJsonObject(value) {
466
+ return typeof value === "object" && value !== null && !Array.isArray(value);
467
+ }
468
+ function unionStrings(existing, additions) {
469
+ const out = Array.isArray(existing) ? existing.filter((v) => typeof v === "string") : [];
470
+ for (const value of additions) {
471
+ if (!out.includes(value)) {
472
+ out.push(value);
473
+ }
474
+ }
475
+ return out;
476
+ }
477
+ function readVscodeJson(filePath) {
478
+ try {
479
+ const parsed = parseJsonc(readFileSync5(filePath, "utf8"));
480
+ return isJsonObject(parsed) ? parsed : null;
481
+ } catch {
482
+ return null;
483
+ }
484
+ }
485
+ function writeVscodeExtensions(cwd, written) {
486
+ const dir = path6.join(cwd, ".vscode");
487
+ const filePath = path6.join(dir, "extensions.json");
488
+ if (existsSync2(filePath)) {
489
+ const existing = readVscodeJson(filePath);
490
+ if (existing === null) {
491
+ return;
492
+ }
493
+ existing.recommendations = unionStrings(existing.recommendations, VSCODE_EXTENSIONS_CONTENT.recommendations);
494
+ existing.unwantedRecommendations = unionStrings(existing.unwantedRecommendations, VSCODE_EXTENSIONS_CONTENT.unwantedRecommendations);
495
+ writeJson(filePath, existing);
496
+ return;
497
+ }
498
+ mkdirSync2(dir, { recursive: true });
499
+ writeJson(filePath, VSCODE_EXTENSIONS_CONTENT);
500
+ written.push(".vscode/extensions.json");
501
+ }
502
+ function writeVscodeSettings(cwd, written) {
503
+ const dir = path6.join(cwd, ".vscode");
504
+ const filePath = path6.join(dir, "settings.json");
505
+ if (existsSync2(filePath)) {
506
+ const existing = readVscodeJson(filePath);
507
+ if (existing === null) {
508
+ return;
509
+ }
510
+ existing["Lua.workspace.ignoreDir"] = unionStrings(existing["Lua.workspace.ignoreDir"], VSCODE_SETTINGS_CONTENT["Lua.workspace.ignoreDir"]);
511
+ writeJson(filePath, existing);
512
+ return;
513
+ }
514
+ mkdirSync2(dir, { recursive: true });
515
+ writeJson(filePath, VSCODE_SETTINGS_CONTENT);
516
+ written.push(".vscode/settings.json");
517
+ }
518
+ function writeTsSurface(cwd, written, force = false) {
411
519
  mkdirSync2(path6.join(cwd, "src"), { recursive: true });
412
520
  writeFileSync2(path6.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
413
521
  written.push("src/main.ts");
@@ -430,7 +538,7 @@ function writeTsSurface(cwd, written) {
430
538
  devDeps[name] = version;
431
539
  }
432
540
  }
433
- repairManagedDevDeps(devDeps);
541
+ repairManagedDevDeps(devDeps, force);
434
542
  existing.devDependencies = devDeps;
435
543
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
436
544
  writeJson(pkgPath, existing);
@@ -448,6 +556,8 @@ function writeTsSurface(cwd, written) {
448
556
  writeGitignore(cwd);
449
557
  written.push(".gitignore");
450
558
  writeBiome(cwd, written);
559
+ writeVscodeExtensions(cwd, written);
560
+ writeVscodeSettings(cwd, written);
451
561
  return selectScriptKind(kinds);
452
562
  }
453
563
  function runNewProjectInit(cwd, force = false) {
@@ -467,7 +577,7 @@ main_collection = /main/main.collectionc
467
577
  written.push("main/main.collection");
468
578
  writeFileSync2(path6.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
469
579
  written.push("main/main.script");
470
- const scriptKind = writeTsSurface(cwd, written);
580
+ const scriptKind = writeTsSurface(cwd, written, force);
471
581
  return { written, scriptKind };
472
582
  }
473
583
  function runInit(opts) {
@@ -483,7 +593,7 @@ function runInit(opts) {
483
593
  }
484
594
  }
485
595
  const written = [];
486
- const scriptKind = writeTsSurface(cwd, written);
596
+ const scriptKind = writeTsSurface(cwd, written, force);
487
597
  return { written, scriptKind };
488
598
  }
489
599
 
package/dist/index.js CHANGED
@@ -398,6 +398,13 @@ var BIOME_JSON_CONTENT = {
398
398
  }
399
399
  }
400
400
  };
401
+ var VSCODE_EXTENSIONS_CONTENT = {
402
+ recommendations: ["sumneko.lua", "astrochili.defold"],
403
+ unwantedRecommendations: ["johnnymorganz.luau-lsp"]
404
+ };
405
+ var VSCODE_SETTINGS_CONTENT = {
406
+ "Lua.workspace.ignoreDir": ["src"]
407
+ };
401
408
  var MAIN_TS_CONTENT = `export function init(): void {
402
409
  const start = vmath.vector3(0, 0, 0);
403
410
  msg.post("main:/hero", "spawn", { start });
@@ -431,9 +438,9 @@ var SCAFFOLD_DEV_DEPS = {
431
438
  "@defold-typescript/types": typesVersionSpec(),
432
439
  "@biomejs/biome": "^2.2.0"
433
440
  };
434
- function repairManagedDevDeps(devDeps) {
441
+ function repairManagedDevDeps(devDeps, force = false) {
435
442
  delete devDeps["@defold-typescript/transpiler"];
436
- if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
443
+ if (force || devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
437
444
  devDeps["@defold-typescript/types"] = typesVersionSpec();
438
445
  }
439
446
  }
@@ -471,7 +478,108 @@ function writeBiome(cwd, written) {
471
478
  writeJson(biomePath, BIOME_JSON_CONTENT);
472
479
  written.push("biome.json");
473
480
  }
474
- function writeTsSurface(cwd, written) {
481
+ function parseJsonc(text) {
482
+ let out = "";
483
+ let inString = false;
484
+ let inLineComment = false;
485
+ let inBlockComment = false;
486
+ for (let i = 0;i < text.length; i++) {
487
+ const ch = text[i];
488
+ const next = text[i + 1];
489
+ if (inLineComment) {
490
+ if (ch === `
491
+ `) {
492
+ inLineComment = false;
493
+ out += ch;
494
+ }
495
+ continue;
496
+ }
497
+ if (inBlockComment) {
498
+ if (ch === "*" && next === "/") {
499
+ inBlockComment = false;
500
+ i++;
501
+ }
502
+ continue;
503
+ }
504
+ if (inString) {
505
+ out += ch;
506
+ if (ch === "\\") {
507
+ out += next ?? "";
508
+ i++;
509
+ } else if (ch === '"') {
510
+ inString = false;
511
+ }
512
+ continue;
513
+ }
514
+ if (ch === '"') {
515
+ inString = true;
516
+ out += ch;
517
+ } else if (ch === "/" && next === "/") {
518
+ inLineComment = true;
519
+ i++;
520
+ } else if (ch === "/" && next === "*") {
521
+ inBlockComment = true;
522
+ i++;
523
+ } else {
524
+ out += ch;
525
+ }
526
+ }
527
+ return JSON.parse(out.replace(/,(\s*[}\]])/g, "$1"));
528
+ }
529
+ function isJsonObject(value) {
530
+ return typeof value === "object" && value !== null && !Array.isArray(value);
531
+ }
532
+ function unionStrings(existing, additions) {
533
+ const out = Array.isArray(existing) ? existing.filter((v) => typeof v === "string") : [];
534
+ for (const value of additions) {
535
+ if (!out.includes(value)) {
536
+ out.push(value);
537
+ }
538
+ }
539
+ return out;
540
+ }
541
+ function readVscodeJson(filePath) {
542
+ try {
543
+ const parsed = parseJsonc(readFileSync6(filePath, "utf8"));
544
+ return isJsonObject(parsed) ? parsed : null;
545
+ } catch {
546
+ return null;
547
+ }
548
+ }
549
+ function writeVscodeExtensions(cwd, written) {
550
+ const dir = path7.join(cwd, ".vscode");
551
+ const filePath = path7.join(dir, "extensions.json");
552
+ if (existsSync2(filePath)) {
553
+ const existing = readVscodeJson(filePath);
554
+ if (existing === null) {
555
+ return;
556
+ }
557
+ existing.recommendations = unionStrings(existing.recommendations, VSCODE_EXTENSIONS_CONTENT.recommendations);
558
+ existing.unwantedRecommendations = unionStrings(existing.unwantedRecommendations, VSCODE_EXTENSIONS_CONTENT.unwantedRecommendations);
559
+ writeJson(filePath, existing);
560
+ return;
561
+ }
562
+ mkdirSync2(dir, { recursive: true });
563
+ writeJson(filePath, VSCODE_EXTENSIONS_CONTENT);
564
+ written.push(".vscode/extensions.json");
565
+ }
566
+ function writeVscodeSettings(cwd, written) {
567
+ const dir = path7.join(cwd, ".vscode");
568
+ const filePath = path7.join(dir, "settings.json");
569
+ if (existsSync2(filePath)) {
570
+ const existing = readVscodeJson(filePath);
571
+ if (existing === null) {
572
+ return;
573
+ }
574
+ existing["Lua.workspace.ignoreDir"] = unionStrings(existing["Lua.workspace.ignoreDir"], VSCODE_SETTINGS_CONTENT["Lua.workspace.ignoreDir"]);
575
+ writeJson(filePath, existing);
576
+ return;
577
+ }
578
+ mkdirSync2(dir, { recursive: true });
579
+ writeJson(filePath, VSCODE_SETTINGS_CONTENT);
580
+ written.push(".vscode/settings.json");
581
+ }
582
+ function writeTsSurface(cwd, written, force = false) {
475
583
  mkdirSync2(path7.join(cwd, "src"), { recursive: true });
476
584
  writeFileSync2(path7.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
477
585
  written.push("src/main.ts");
@@ -494,7 +602,7 @@ function writeTsSurface(cwd, written) {
494
602
  devDeps[name] = version;
495
603
  }
496
604
  }
497
- repairManagedDevDeps(devDeps);
605
+ repairManagedDevDeps(devDeps, force);
498
606
  existing.devDependencies = devDeps;
499
607
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
500
608
  writeJson(pkgPath, existing);
@@ -512,6 +620,8 @@ function writeTsSurface(cwd, written) {
512
620
  writeGitignore(cwd);
513
621
  written.push(".gitignore");
514
622
  writeBiome(cwd, written);
623
+ writeVscodeExtensions(cwd, written);
624
+ writeVscodeSettings(cwd, written);
515
625
  return selectScriptKind(kinds);
516
626
  }
517
627
  function runNewProjectInit(cwd, force = false) {
@@ -531,7 +641,7 @@ main_collection = /main/main.collectionc
531
641
  written.push("main/main.collection");
532
642
  writeFileSync2(path7.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
533
643
  written.push("main/main.script");
534
- const scriptKind = writeTsSurface(cwd, written);
644
+ const scriptKind = writeTsSurface(cwd, written, force);
535
645
  return { written, scriptKind };
536
646
  }
537
647
  function runInit(opts) {
@@ -547,7 +657,7 @@ function runInit(opts) {
547
657
  }
548
658
  }
549
659
  const written = [];
550
- const scriptKind = writeTsSurface(cwd, written);
660
+ const scriptKind = writeTsSurface(cwd, written, force);
551
661
  return { written, scriptKind };
552
662
  }
553
663
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defold-typescript/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "End-user CLI for scaffolding and building Defold projects written in TypeScript.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "test": "bun test"
32
32
  },
33
33
  "dependencies": {
34
- "@defold-typescript/transpiler": "0.4.0",
35
- "@defold-typescript/types": "0.4.0"
34
+ "@defold-typescript/transpiler": "0.4.2",
35
+ "@defold-typescript/types": "0.4.2"
36
36
  }
37
37
  }
package/src/init.ts CHANGED
@@ -72,6 +72,15 @@ const BIOME_JSON_CONTENT = {
72
72
  },
73
73
  };
74
74
 
75
+ const VSCODE_EXTENSIONS_CONTENT = {
76
+ recommendations: ["sumneko.lua", "astrochili.defold"],
77
+ unwantedRecommendations: ["johnnymorganz.luau-lsp"],
78
+ };
79
+
80
+ const VSCODE_SETTINGS_CONTENT = {
81
+ "Lua.workspace.ignoreDir": ["src"],
82
+ };
83
+
75
84
  const MAIN_TS_CONTENT = `export function init(): void {
76
85
  const start = vmath.vector3(0, 0, 0);
77
86
  msg.post("main:/hero", "spawn", { start });
@@ -134,10 +143,11 @@ const SCAFFOLD_DEV_DEPS: Record<string, string> = {
134
143
  // repairs an entry it didn't itself create, so repair them explicitly: the
135
144
  // transpiler is CLI-internal and must not be a consumer dep at all, and a
136
145
  // `workspace:` types pin must become a concrete published version. A concrete
137
- // user-chosen types pin is left alone.
138
- function repairManagedDevDeps(devDeps: Record<string, string>): void {
146
+ // user-chosen types pin is left alone unless `force` is set, the explicit
147
+ // opt-in to refresh the managed pin (and only that pin) to the CLI's version.
148
+ function repairManagedDevDeps(devDeps: Record<string, string>, force = false): void {
139
149
  delete devDeps["@defold-typescript/transpiler"];
140
- if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
150
+ if (force || devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
141
151
  devDeps["@defold-typescript/types"] = typesVersionSpec();
142
152
  }
143
153
  }
@@ -171,7 +181,127 @@ function writeBiome(cwd: string, written: string[]): void {
171
181
  written.push("biome.json");
172
182
  }
173
183
 
174
- function writeTsSurface(cwd: string, written: string[]): ScriptKind | null {
184
+ // Strip `//` line comments, `/* */` block comments, and trailing commas so a
185
+ // hand-edited JSONC `.vscode` file parses with `JSON.parse`. The walk tracks
186
+ // string state so a `//` or comma inside a value (e.g. a URL) is preserved.
187
+ function parseJsonc(text: string): unknown {
188
+ let out = "";
189
+ let inString = false;
190
+ let inLineComment = false;
191
+ let inBlockComment = false;
192
+ for (let i = 0; i < text.length; i++) {
193
+ const ch = text[i];
194
+ const next = text[i + 1];
195
+ if (inLineComment) {
196
+ if (ch === "\n") {
197
+ inLineComment = false;
198
+ out += ch;
199
+ }
200
+ continue;
201
+ }
202
+ if (inBlockComment) {
203
+ if (ch === "*" && next === "/") {
204
+ inBlockComment = false;
205
+ i++;
206
+ }
207
+ continue;
208
+ }
209
+ if (inString) {
210
+ out += ch;
211
+ if (ch === "\\") {
212
+ out += next ?? "";
213
+ i++;
214
+ } else if (ch === '"') {
215
+ inString = false;
216
+ }
217
+ continue;
218
+ }
219
+ if (ch === '"') {
220
+ inString = true;
221
+ out += ch;
222
+ } else if (ch === "/" && next === "/") {
223
+ inLineComment = true;
224
+ i++;
225
+ } else if (ch === "/" && next === "*") {
226
+ inBlockComment = true;
227
+ i++;
228
+ } else {
229
+ out += ch;
230
+ }
231
+ }
232
+ return JSON.parse(out.replace(/,(\s*[}\]])/g, "$1"));
233
+ }
234
+
235
+ function isJsonObject(value: unknown): value is Record<string, unknown> {
236
+ return typeof value === "object" && value !== null && !Array.isArray(value);
237
+ }
238
+
239
+ function unionStrings(existing: unknown, additions: readonly string[]): string[] {
240
+ const out = Array.isArray(existing)
241
+ ? existing.filter((v): v is string => typeof v === "string")
242
+ : [];
243
+ for (const value of additions) {
244
+ if (!out.includes(value)) {
245
+ out.push(value);
246
+ }
247
+ }
248
+ return out;
249
+ }
250
+
251
+ function readVscodeJson(filePath: string): Record<string, unknown> | null {
252
+ try {
253
+ const parsed = parseJsonc(readFileSync(filePath, "utf8"));
254
+ return isJsonObject(parsed) ? parsed : null;
255
+ } catch {
256
+ return null;
257
+ }
258
+ }
259
+
260
+ function writeVscodeExtensions(cwd: string, written: string[]): void {
261
+ const dir = path.join(cwd, ".vscode");
262
+ const filePath = path.join(dir, "extensions.json");
263
+ if (existsSync(filePath)) {
264
+ const existing = readVscodeJson(filePath);
265
+ if (existing === null) {
266
+ return;
267
+ }
268
+ existing.recommendations = unionStrings(
269
+ existing.recommendations,
270
+ VSCODE_EXTENSIONS_CONTENT.recommendations,
271
+ );
272
+ existing.unwantedRecommendations = unionStrings(
273
+ existing.unwantedRecommendations,
274
+ VSCODE_EXTENSIONS_CONTENT.unwantedRecommendations,
275
+ );
276
+ writeJson(filePath, existing);
277
+ return;
278
+ }
279
+ mkdirSync(dir, { recursive: true });
280
+ writeJson(filePath, VSCODE_EXTENSIONS_CONTENT);
281
+ written.push(".vscode/extensions.json");
282
+ }
283
+
284
+ function writeVscodeSettings(cwd: string, written: string[]): void {
285
+ const dir = path.join(cwd, ".vscode");
286
+ const filePath = path.join(dir, "settings.json");
287
+ if (existsSync(filePath)) {
288
+ const existing = readVscodeJson(filePath);
289
+ if (existing === null) {
290
+ return;
291
+ }
292
+ existing["Lua.workspace.ignoreDir"] = unionStrings(
293
+ existing["Lua.workspace.ignoreDir"],
294
+ VSCODE_SETTINGS_CONTENT["Lua.workspace.ignoreDir"],
295
+ );
296
+ writeJson(filePath, existing);
297
+ return;
298
+ }
299
+ mkdirSync(dir, { recursive: true });
300
+ writeJson(filePath, VSCODE_SETTINGS_CONTENT);
301
+ written.push(".vscode/settings.json");
302
+ }
303
+
304
+ function writeTsSurface(cwd: string, written: string[], force = false): ScriptKind | null {
175
305
  mkdirSync(path.join(cwd, "src"), { recursive: true });
176
306
  writeFileSync(path.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
177
307
  written.push("src/main.ts");
@@ -196,7 +326,7 @@ function writeTsSurface(cwd: string, written: string[]): ScriptKind | null {
196
326
  devDeps[name] = version;
197
327
  }
198
328
  }
199
- repairManagedDevDeps(devDeps);
329
+ repairManagedDevDeps(devDeps, force);
200
330
  existing.devDependencies = devDeps;
201
331
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
202
332
  writeJson(pkgPath, existing);
@@ -217,6 +347,9 @@ function writeTsSurface(cwd: string, written: string[]): ScriptKind | null {
217
347
 
218
348
  writeBiome(cwd, written);
219
349
 
350
+ writeVscodeExtensions(cwd, written);
351
+ writeVscodeSettings(cwd, written);
352
+
220
353
  return selectScriptKind(kinds);
221
354
  }
222
355
 
@@ -243,7 +376,7 @@ export function runNewProjectInit(cwd: string, force = false): RunInitResult {
243
376
  writeFileSync(path.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
244
377
  written.push("main/main.script");
245
378
 
246
- const scriptKind = writeTsSurface(cwd, written);
379
+ const scriptKind = writeTsSurface(cwd, written, force);
247
380
 
248
381
  return { written, scriptKind };
249
382
  }
@@ -266,6 +399,6 @@ export function runInit(opts: RunInitOptions): RunInitResult {
266
399
  }
267
400
 
268
401
  const written: string[] = [];
269
- const scriptKind = writeTsSurface(cwd, written);
402
+ const scriptKind = writeTsSurface(cwd, written, force);
270
403
  return { written, scriptKind };
271
404
  }