@defold-typescript/cli 0.2.0 → 0.3.0

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
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/dispatch.ts
4
- import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
5
- import * as path9 from "node:path";
4
+ import { existsSync as existsSync5, readFileSync as readFileSync8 } from "node:fs";
5
+ import * as path10 from "node:path";
6
6
 
7
7
  // src/api-registry.ts
8
8
  import { existsSync, readFileSync } from "node:fs";
@@ -209,10 +209,27 @@ function runBuild(opts) {
209
209
  return { written };
210
210
  }
211
211
 
212
- // src/init.ts
213
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
212
+ // src/cli-version.ts
213
+ import { readFileSync as readFileSync4 } from "node:fs";
214
214
  import * as path5 from "node:path";
215
215
  import { fileURLToPath } from "node:url";
216
+ var VERSION_FALLBACK = "0.0.0";
217
+ function defaultPackageRoot() {
218
+ return path5.join(path5.dirname(fileURLToPath(import.meta.url)), "..");
219
+ }
220
+ function readCliVersion(packageRoot = defaultPackageRoot()) {
221
+ try {
222
+ const pkg = JSON.parse(readFileSync4(path5.join(packageRoot, "package.json"), "utf8"));
223
+ return typeof pkg.version === "string" ? pkg.version : VERSION_FALLBACK;
224
+ } catch {
225
+ return VERSION_FALLBACK;
226
+ }
227
+ }
228
+
229
+ // src/init.ts
230
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "node:fs";
231
+ import * as path6 from "node:path";
232
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
216
233
 
217
234
  // src/script-kind.ts
218
235
  var DEFAULT_TYPES_ENTRYPOINT = "@defold-typescript/types";
@@ -339,8 +356,8 @@ embedded_instances {
339
356
  `;
340
357
  function typesVersionSpec() {
341
358
  try {
342
- const here = path5.dirname(fileURLToPath(import.meta.url));
343
- const pkg = JSON.parse(readFileSync4(path5.join(here, "..", "package.json"), "utf8"));
359
+ const here = path6.dirname(fileURLToPath2(import.meta.url));
360
+ const pkg = JSON.parse(readFileSync5(path6.join(here, "..", "package.json"), "utf8"));
344
361
  return pkg.version ? `^${pkg.version}` : "latest";
345
362
  } catch {
346
363
  return "latest";
@@ -350,14 +367,20 @@ var SCAFFOLD_DEV_DEPS = {
350
367
  "@defold-typescript/types": typesVersionSpec(),
351
368
  "@biomejs/biome": "^2.2.0"
352
369
  };
370
+ function repairManagedDevDeps(devDeps) {
371
+ delete devDeps["@defold-typescript/transpiler"];
372
+ if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
373
+ devDeps["@defold-typescript/types"] = typesVersionSpec();
374
+ }
375
+ }
353
376
  function writeJson(filePath, value) {
354
377
  writeFileSync2(filePath, `${JSON.stringify(value, null, 2)}
355
378
  `);
356
379
  }
357
380
  function writeGitignore(cwd) {
358
- const gitignorePath = path5.join(cwd, ".gitignore");
381
+ const gitignorePath = path6.join(cwd, ".gitignore");
359
382
  if (existsSync2(gitignorePath)) {
360
- const existing = readFileSync4(gitignorePath, "utf8");
383
+ const existing = readFileSync5(gitignorePath, "utf8");
361
384
  const present = new Set(existing.split(`
362
385
  `).map((line) => line.trim()));
363
386
  const missing = GITIGNORE_LINES.filter((line) => !present.has(line));
@@ -377,7 +400,7 @@ function writeGitignore(cwd) {
377
400
  }
378
401
  }
379
402
  function writeBiome(cwd, written) {
380
- const biomePath = path5.join(cwd, "biome.json");
403
+ const biomePath = path6.join(cwd, "biome.json");
381
404
  if (existsSync2(biomePath)) {
382
405
  return;
383
406
  }
@@ -385,8 +408,8 @@ function writeBiome(cwd, written) {
385
408
  written.push("biome.json");
386
409
  }
387
410
  function writeTsSurface(cwd, written) {
388
- mkdirSync2(path5.join(cwd, "src"), { recursive: true });
389
- writeFileSync2(path5.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
411
+ mkdirSync2(path6.join(cwd, "src"), { recursive: true });
412
+ writeFileSync2(path6.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
390
413
  written.push("src/main.ts");
391
414
  const kinds = detectScriptKinds(cwd);
392
415
  const tsconfig = {
@@ -396,23 +419,24 @@ function writeTsSurface(cwd, written) {
396
419
  },
397
420
  include: ["src/**/*.ts"]
398
421
  };
399
- writeJson(path5.join(cwd, "tsconfig.json"), tsconfig);
422
+ writeJson(path6.join(cwd, "tsconfig.json"), tsconfig);
400
423
  written.push("tsconfig.json");
401
- const pkgPath = path5.join(cwd, "package.json");
424
+ const pkgPath = path6.join(cwd, "package.json");
402
425
  if (existsSync2(pkgPath)) {
403
- const existing = JSON.parse(readFileSync4(pkgPath, "utf8"));
426
+ const existing = JSON.parse(readFileSync5(pkgPath, "utf8"));
404
427
  const devDeps = { ...existing.devDependencies ?? {} };
405
428
  for (const [name, version] of Object.entries(SCAFFOLD_DEV_DEPS)) {
406
429
  if (!(name in devDeps)) {
407
430
  devDeps[name] = version;
408
431
  }
409
432
  }
433
+ repairManagedDevDeps(devDeps);
410
434
  existing.devDependencies = devDeps;
411
435
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
412
436
  writeJson(pkgPath, existing);
413
437
  } else {
414
438
  const fresh = {
415
- name: path5.basename(cwd),
439
+ name: path6.basename(cwd),
416
440
  version: "0.0.0",
417
441
  type: "module",
418
442
  devDependencies: { ...SCAFFOLD_DEV_DEPS },
@@ -433,27 +457,27 @@ function runNewProjectInit(cwd, force = false) {
433
457
  throw new Error(`defold-typescript init: refusing to synthesize a new Defold project into non-empty directory ${cwd}. Pass --force to proceed.`);
434
458
  }
435
459
  const written = [];
436
- writeFileSync2(path5.join(cwd, "game.project"), `[project]
437
- title = ${path5.basename(cwd)}
460
+ writeFileSync2(path6.join(cwd, "game.project"), `[project]
461
+ title = ${path6.basename(cwd)}
438
462
  main_collection = /main/main.collectionc
439
463
  `);
440
464
  written.push("game.project");
441
- mkdirSync2(path5.join(cwd, "main"), { recursive: true });
442
- writeFileSync2(path5.join(cwd, "main", "main.collection"), MAIN_COLLECTION_CONTENT);
465
+ mkdirSync2(path6.join(cwd, "main"), { recursive: true });
466
+ writeFileSync2(path6.join(cwd, "main", "main.collection"), MAIN_COLLECTION_CONTENT);
443
467
  written.push("main/main.collection");
444
- writeFileSync2(path5.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
468
+ writeFileSync2(path6.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
445
469
  written.push("main/main.script");
446
470
  const scriptKind = writeTsSurface(cwd, written);
447
471
  return { written, scriptKind };
448
472
  }
449
473
  function runInit(opts) {
450
474
  const { cwd, force = false } = opts;
451
- if (!existsSync2(path5.join(cwd, "game.project"))) {
475
+ if (!existsSync2(path6.join(cwd, "game.project"))) {
452
476
  return runNewProjectInit(cwd, force);
453
477
  }
454
478
  if (!force) {
455
479
  for (const rel of CONFLICTING_TS_CONFIGS) {
456
- if (existsSync2(path5.join(cwd, rel))) {
480
+ if (existsSync2(path6.join(cwd, rel))) {
457
481
  throw new Error(`defold-typescript init: refusing to overwrite existing TS config: ${rel}. Pass --force to overwrite.`);
458
482
  }
459
483
  }
@@ -481,11 +505,11 @@ import {
481
505
  existsSync as existsSync3,
482
506
  mkdirSync as mkdirSync3,
483
507
  readdirSync as readdirSync2,
484
- readFileSync as readFileSync5,
508
+ readFileSync as readFileSync6,
485
509
  rmSync,
486
510
  writeFileSync as writeFileSync3
487
511
  } from "node:fs";
488
- import * as path6 from "node:path";
512
+ import * as path7 from "node:path";
489
513
  var MATERIALIZED_ROOT = ".defold-types";
490
514
  function writeJson2(filePath, value) {
491
515
  writeFileSync3(filePath, `${JSON.stringify(value, null, 2)}
@@ -500,14 +524,14 @@ function materializeApiSurface(opts) {
500
524
  return { materializedDir: null, active: null };
501
525
  }
502
526
  const { surfaceId } = surface;
503
- const relDir = path6.posix.join(MATERIALIZED_ROOT, surfaceId);
504
- const absDir = path6.join(cwd, MATERIALIZED_ROOT, surfaceId);
527
+ const relDir = path7.posix.join(MATERIALIZED_ROOT, surfaceId);
528
+ const absDir = path7.join(cwd, MATERIALIZED_ROOT, surfaceId);
505
529
  mkdirSync3(absDir, { recursive: true });
506
530
  const excluded = excludedModulesForKind(opts.scriptKind ?? null);
507
531
  const sources = listDts(sourceGeneratedDir).filter((file) => file !== "index.d.ts").filter((file) => !excluded.has(file.replace(/\.d\.ts$/, "")));
508
- const srcDir = path6.resolve(sourceGeneratedDir, "..", "src");
509
- const overloads = ["msg-overloads.d.ts", "go-overloads.d.ts"].filter((file) => existsSync3(path6.join(srcDir, file)));
510
- const coreTypesSrc = path6.join(srcDir, "core-types.ts");
532
+ const srcDir = path7.resolve(sourceGeneratedDir, "..", "src");
533
+ const overloads = ["msg-overloads.d.ts", "go-overloads.d.ts"].filter((file) => existsSync3(path7.join(srcDir, file)));
534
+ const coreTypesSrc = path7.join(srcDir, "core-types.ts");
511
535
  const includeCoreTypes = overloads.length > 0 && existsSync3(coreTypesSrc);
512
536
  const wanted = new Set(sources);
513
537
  for (const file of overloads) {
@@ -518,39 +542,39 @@ function materializeApiSurface(opts) {
518
542
  }
519
543
  for (const existing of readdirSync2(absDir)) {
520
544
  if (existing.endsWith(".d.ts") && existing !== "index.d.ts" && !wanted.has(existing)) {
521
- rmSync(path6.join(absDir, existing));
545
+ rmSync(path7.join(absDir, existing));
522
546
  }
523
547
  }
524
548
  for (const file of sources) {
525
- writeFileSync3(path6.join(absDir, file), readFileSync5(path6.join(sourceGeneratedDir, file), "utf8"));
549
+ writeFileSync3(path7.join(absDir, file), readFileSync6(path7.join(sourceGeneratedDir, file), "utf8"));
526
550
  }
527
551
  if (includeCoreTypes) {
528
- writeFileSync3(path6.join(absDir, "core-types.d.ts"), readFileSync5(coreTypesSrc, "utf8"));
552
+ writeFileSync3(path7.join(absDir, "core-types.d.ts"), readFileSync6(coreTypesSrc, "utf8"));
529
553
  }
530
554
  for (const file of overloads) {
531
- writeFileSync3(path6.join(absDir, file), readFileSync5(path6.join(srcDir, file), "utf8"));
555
+ writeFileSync3(path7.join(absDir, file), readFileSync6(path7.join(srcDir, file), "utf8"));
532
556
  }
533
557
  const modules = [...sources, ...overloads].map((file) => file.replace(/\.d\.ts$/, ""));
534
558
  const imports = modules.map((mod) => `import "./${mod}";`).join(`
535
559
  `);
536
- writeFileSync3(path6.join(absDir, "index.d.ts"), `${imports}
560
+ writeFileSync3(path7.join(absDir, "index.d.ts"), `${imports}
537
561
 
538
562
  export {};
539
563
  `);
540
- writeJson2(path6.join(absDir, "package.json"), {
564
+ writeJson2(path7.join(absDir, "package.json"), {
541
565
  name: `@defold-typescript/materialized-${surfaceId}`,
542
566
  types: "index.d.ts"
543
567
  });
544
568
  return { materializedDir: relDir, active: surfaceId };
545
569
  }
546
570
  function ensureGitignoreLine(cwd, line) {
547
- const gitignorePath = path6.join(cwd, ".gitignore");
571
+ const gitignorePath = path7.join(cwd, ".gitignore");
548
572
  if (!existsSync3(gitignorePath)) {
549
573
  writeFileSync3(gitignorePath, `${line}
550
574
  `);
551
575
  return;
552
576
  }
553
- const existing = readFileSync5(gitignorePath, "utf8");
577
+ const existing = readFileSync6(gitignorePath, "utf8");
554
578
  const present = new Set(existing.split(`
555
579
  `).map((entry) => entry.trim()));
556
580
  if (present.has(line)) {
@@ -566,10 +590,10 @@ function ensureMaterializedReference(cwd, materializedDir) {
566
590
  if (materializedDir === null) {
567
591
  return;
568
592
  }
569
- const surfaceId = path6.posix.basename(materializedDir);
570
- const tsconfigPath = path6.join(cwd, "tsconfig.json");
593
+ const surfaceId = path7.posix.basename(materializedDir);
594
+ const tsconfigPath = path7.join(cwd, "tsconfig.json");
571
595
  if (existsSync3(tsconfigPath)) {
572
- const tsconfig = JSON.parse(readFileSync5(tsconfigPath, "utf8"));
596
+ const tsconfig = JSON.parse(readFileSync6(tsconfigPath, "utf8"));
573
597
  tsconfig.compilerOptions = {
574
598
  ...tsconfig.compilerOptions ?? {},
575
599
  typeRoots: [MATERIALIZED_ROOT],
@@ -581,7 +605,7 @@ function ensureMaterializedReference(cwd, materializedDir) {
581
605
  }
582
606
  function resolveCurrentSurfaceGeneratedDir() {
583
607
  const root = resolveTypesPackageRoot();
584
- return root === null ? null : path6.join(root, "generated");
608
+ return root === null ? null : path7.join(root, "generated");
585
609
  }
586
610
  async function materializeRefDocSurface(opts) {
587
611
  const { cwd, surfaceId, resolveOpts } = opts;
@@ -595,17 +619,17 @@ async function materializeRefDocSurface(opts) {
595
619
  return { materializedDir: null, active: null };
596
620
  }
597
621
  const excludeModules = [...excludedModulesForKind(opts.scriptKind ?? null)];
598
- const relDir = path6.posix.join(MATERIALIZED_ROOT, surfaceId);
599
- const absDir = path6.join(cwd, MATERIALIZED_ROOT, surfaceId);
622
+ const relDir = path7.posix.join(MATERIALIZED_ROOT, surfaceId);
623
+ const absDir = path7.join(cwd, MATERIALIZED_ROOT, surfaceId);
600
624
  try {
601
- const mod = await import(path6.join(root, "scripts", "materialize-version.ts"));
625
+ const mod = await import(path7.join(root, "scripts", "materialize-version.ts"));
602
626
  const selfContained = { ...target, coreTypesImport: "./core-types" };
603
627
  await mod.materializeVersionedSurface(selfContained, {
604
628
  destDir: absDir,
605
629
  ...resolveOpts ? { resolveOpts } : {},
606
630
  ...excludeModules.length > 0 ? { excludeModules } : {}
607
631
  });
608
- copyFileSync(path6.join(root, "src", "core-types.ts"), path6.join(absDir, "core-types.d.ts"));
632
+ copyFileSync(path7.join(root, "src", "core-types.ts"), path7.join(absDir, "core-types.d.ts"));
609
633
  } catch {
610
634
  rmSync(absDir, { recursive: true, force: true });
611
635
  return { materializedDir: null, active: null };
@@ -615,11 +639,11 @@ async function materializeRefDocSurface(opts) {
615
639
 
616
640
  // src/watch.ts
617
641
  import { existsSync as existsSync4, watch as fsWatch } from "node:fs";
618
- import * as path8 from "node:path";
642
+ import * as path9 from "node:path";
619
643
 
620
644
  // src/build-session.ts
621
- import { readFileSync as readFileSync6, rmSync as rmSync2 } from "node:fs";
622
- import * as path7 from "node:path";
645
+ import { readFileSync as readFileSync7, rmSync as rmSync2 } from "node:fs";
646
+ import * as path8 from "node:path";
623
647
  import {
624
648
  createTranspileSession
625
649
  } from "@defold-typescript/transpiler";
@@ -658,7 +682,7 @@ function createBuildSession(opts) {
658
682
  }
659
683
  const files = {};
660
684
  for (const rel of sources) {
661
- files[rel] = readFileSync6(path7.join(cwd, rel), "utf8");
685
+ files[rel] = readFileSync7(path8.join(cwd, rel), "utf8");
662
686
  }
663
687
  const result = session.update(files);
664
688
  return writeOutputs(result, sources);
@@ -668,14 +692,14 @@ function createBuildSession(opts) {
668
692
  const sourceRemoved = removed.filter(isTranspilerSource);
669
693
  const changes = {};
670
694
  for (const rel of sourceChanged) {
671
- changes[rel] = readFileSync6(path7.join(cwd, rel), "utf8");
695
+ changes[rel] = readFileSync7(path8.join(cwd, rel), "utf8");
672
696
  }
673
697
  for (const rel of sourceRemoved) {
674
698
  changes[rel] = null;
675
699
  }
676
700
  const result = session.update(changes);
677
701
  for (const rel of sourceRemoved) {
678
- const luaAbs = path7.join(cwd, computeLuaRel(rel, config));
702
+ const luaAbs = path8.join(cwd, computeLuaRel(rel, config));
679
703
  rmSync2(luaAbs, { force: true });
680
704
  rmSync2(`${luaAbs}.map`, { force: true });
681
705
  }
@@ -727,7 +751,7 @@ function runWatch(opts) {
727
751
  waitForIdle: () => Promise.resolve()
728
752
  };
729
753
  }
730
- const srcDir = path8.join(cwd, "src");
754
+ const srcDir = path9.join(cwd, "src");
731
755
  let scheduled = null;
732
756
  let syncScheduled = null;
733
757
  let rebuildBusy = false;
@@ -751,7 +775,7 @@ function runWatch(opts) {
751
775
  const removed = [];
752
776
  for (const rel of drained) {
753
777
  const key = `src/${toPosix(rel)}`;
754
- if (existsSync4(path8.join(srcDir, rel))) {
778
+ if (existsSync4(path9.join(srcDir, rel))) {
755
779
  changed.push(key);
756
780
  } else {
757
781
  removed.push(key);
@@ -852,23 +876,30 @@ function parseDefoldVersionFlag(argv) {
852
876
  return { flag, rest };
853
877
  }
854
878
  function readProjectPin(cwd) {
855
- const pkgPath = path9.join(cwd, "package.json");
879
+ const pkgPath = path10.join(cwd, "package.json");
856
880
  if (!existsSync5(pkgPath)) {
857
881
  return;
858
882
  }
859
883
  try {
860
- return readDefoldVersionPin(JSON.parse(readFileSync7(pkgPath, "utf8")));
884
+ return readDefoldVersionPin(JSON.parse(readFileSync8(pkgPath, "utf8")));
861
885
  } catch {
862
886
  return;
863
887
  }
864
888
  }
865
889
  function dispatch(argv, io, internals) {
866
890
  const json = argv.includes("--json");
891
+ if (argv.includes("--version") || argv.includes("-v")) {
892
+ const version = internals?.cliVersion ?? readCliVersion();
893
+ io.stdout.write(json ? `{"command":"version","ok":true,"version":${JSON.stringify(version)}}
894
+ ` : `defold-typescript ${version}
895
+ `);
896
+ return 0;
897
+ }
867
898
  const force = argv.includes("--force");
868
899
  const { flag: defoldVersionFlag, rest: nonFlagArgs } = parseDefoldVersionFlag(argv);
869
900
  const positional = nonFlagArgs.filter((a) => a !== "--json" && a !== "--force");
870
901
  const [command, ...rest] = positional;
871
- const cwd = rest[0] ? path9.resolve(rest[0]) : process.cwd();
902
+ const cwd = rest[0] ? path10.resolve(rest[0]) : process.cwd();
872
903
  const pin = readProjectPin(cwd);
873
904
  const resolvedVersion = resolveDefoldVersion({
874
905
  ...defoldVersionFlag !== undefined ? { flag: defoldVersionFlag } : {},
@@ -0,0 +1 @@
1
+ export declare function readCliVersion(packageRoot?: string): string;
@@ -13,5 +13,6 @@ export interface DispatchInternals {
13
13
  readonly sourceGeneratedDir?: string;
14
14
  readonly resolveOpts?: RefDocResolveOptions;
15
15
  readonly refDocRegistry?: readonly RegistryTarget[];
16
+ readonly cliVersion?: string;
16
17
  }
17
18
  export declare function dispatch(argv: string[], io: DispatchIo, internals?: DispatchInternals): number | Promise<number>;
package/dist/index.js CHANGED
@@ -153,8 +153,8 @@ function createBuildSession(opts) {
153
153
  return { buildAll, applyEvents };
154
154
  }
155
155
  // src/dispatch.ts
156
- import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
157
- import * as path9 from "node:path";
156
+ import { existsSync as existsSync5, readFileSync as readFileSync8 } from "node:fs";
157
+ import * as path10 from "node:path";
158
158
 
159
159
  // src/api-registry.ts
160
160
  import { existsSync, readFileSync as readFileSync3 } from "node:fs";
@@ -273,10 +273,27 @@ function runBuild(opts) {
273
273
  return { written };
274
274
  }
275
275
 
276
- // src/init.ts
277
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "node:fs";
276
+ // src/cli-version.ts
277
+ import { readFileSync as readFileSync5 } from "node:fs";
278
278
  import * as path6 from "node:path";
279
279
  import { fileURLToPath } from "node:url";
280
+ var VERSION_FALLBACK = "0.0.0";
281
+ function defaultPackageRoot() {
282
+ return path6.join(path6.dirname(fileURLToPath(import.meta.url)), "..");
283
+ }
284
+ function readCliVersion(packageRoot = defaultPackageRoot()) {
285
+ try {
286
+ const pkg = JSON.parse(readFileSync5(path6.join(packageRoot, "package.json"), "utf8"));
287
+ return typeof pkg.version === "string" ? pkg.version : VERSION_FALLBACK;
288
+ } catch {
289
+ return VERSION_FALLBACK;
290
+ }
291
+ }
292
+
293
+ // src/init.ts
294
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
295
+ import * as path7 from "node:path";
296
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
280
297
 
281
298
  // src/script-kind.ts
282
299
  var DEFAULT_TYPES_ENTRYPOINT = "@defold-typescript/types";
@@ -403,8 +420,8 @@ embedded_instances {
403
420
  `;
404
421
  function typesVersionSpec() {
405
422
  try {
406
- const here = path6.dirname(fileURLToPath(import.meta.url));
407
- const pkg = JSON.parse(readFileSync5(path6.join(here, "..", "package.json"), "utf8"));
423
+ const here = path7.dirname(fileURLToPath2(import.meta.url));
424
+ const pkg = JSON.parse(readFileSync6(path7.join(here, "..", "package.json"), "utf8"));
408
425
  return pkg.version ? `^${pkg.version}` : "latest";
409
426
  } catch {
410
427
  return "latest";
@@ -414,14 +431,20 @@ var SCAFFOLD_DEV_DEPS = {
414
431
  "@defold-typescript/types": typesVersionSpec(),
415
432
  "@biomejs/biome": "^2.2.0"
416
433
  };
434
+ function repairManagedDevDeps(devDeps) {
435
+ delete devDeps["@defold-typescript/transpiler"];
436
+ if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
437
+ devDeps["@defold-typescript/types"] = typesVersionSpec();
438
+ }
439
+ }
417
440
  function writeJson(filePath, value) {
418
441
  writeFileSync2(filePath, `${JSON.stringify(value, null, 2)}
419
442
  `);
420
443
  }
421
444
  function writeGitignore(cwd) {
422
- const gitignorePath = path6.join(cwd, ".gitignore");
445
+ const gitignorePath = path7.join(cwd, ".gitignore");
423
446
  if (existsSync2(gitignorePath)) {
424
- const existing = readFileSync5(gitignorePath, "utf8");
447
+ const existing = readFileSync6(gitignorePath, "utf8");
425
448
  const present = new Set(existing.split(`
426
449
  `).map((line) => line.trim()));
427
450
  const missing = GITIGNORE_LINES.filter((line) => !present.has(line));
@@ -441,7 +464,7 @@ function writeGitignore(cwd) {
441
464
  }
442
465
  }
443
466
  function writeBiome(cwd, written) {
444
- const biomePath = path6.join(cwd, "biome.json");
467
+ const biomePath = path7.join(cwd, "biome.json");
445
468
  if (existsSync2(biomePath)) {
446
469
  return;
447
470
  }
@@ -449,8 +472,8 @@ function writeBiome(cwd, written) {
449
472
  written.push("biome.json");
450
473
  }
451
474
  function writeTsSurface(cwd, written) {
452
- mkdirSync2(path6.join(cwd, "src"), { recursive: true });
453
- writeFileSync2(path6.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
475
+ mkdirSync2(path7.join(cwd, "src"), { recursive: true });
476
+ writeFileSync2(path7.join(cwd, "src", "main.ts"), MAIN_TS_CONTENT);
454
477
  written.push("src/main.ts");
455
478
  const kinds = detectScriptKinds(cwd);
456
479
  const tsconfig = {
@@ -460,23 +483,24 @@ function writeTsSurface(cwd, written) {
460
483
  },
461
484
  include: ["src/**/*.ts"]
462
485
  };
463
- writeJson(path6.join(cwd, "tsconfig.json"), tsconfig);
486
+ writeJson(path7.join(cwd, "tsconfig.json"), tsconfig);
464
487
  written.push("tsconfig.json");
465
- const pkgPath = path6.join(cwd, "package.json");
488
+ const pkgPath = path7.join(cwd, "package.json");
466
489
  if (existsSync2(pkgPath)) {
467
- const existing = JSON.parse(readFileSync5(pkgPath, "utf8"));
490
+ const existing = JSON.parse(readFileSync6(pkgPath, "utf8"));
468
491
  const devDeps = { ...existing.devDependencies ?? {} };
469
492
  for (const [name, version] of Object.entries(SCAFFOLD_DEV_DEPS)) {
470
493
  if (!(name in devDeps)) {
471
494
  devDeps[name] = version;
472
495
  }
473
496
  }
497
+ repairManagedDevDeps(devDeps);
474
498
  existing.devDependencies = devDeps;
475
499
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
476
500
  writeJson(pkgPath, existing);
477
501
  } else {
478
502
  const fresh = {
479
- name: path6.basename(cwd),
503
+ name: path7.basename(cwd),
480
504
  version: "0.0.0",
481
505
  type: "module",
482
506
  devDependencies: { ...SCAFFOLD_DEV_DEPS },
@@ -497,27 +521,27 @@ function runNewProjectInit(cwd, force = false) {
497
521
  throw new Error(`defold-typescript init: refusing to synthesize a new Defold project into non-empty directory ${cwd}. Pass --force to proceed.`);
498
522
  }
499
523
  const written = [];
500
- writeFileSync2(path6.join(cwd, "game.project"), `[project]
501
- title = ${path6.basename(cwd)}
524
+ writeFileSync2(path7.join(cwd, "game.project"), `[project]
525
+ title = ${path7.basename(cwd)}
502
526
  main_collection = /main/main.collectionc
503
527
  `);
504
528
  written.push("game.project");
505
- mkdirSync2(path6.join(cwd, "main"), { recursive: true });
506
- writeFileSync2(path6.join(cwd, "main", "main.collection"), MAIN_COLLECTION_CONTENT);
529
+ mkdirSync2(path7.join(cwd, "main"), { recursive: true });
530
+ writeFileSync2(path7.join(cwd, "main", "main.collection"), MAIN_COLLECTION_CONTENT);
507
531
  written.push("main/main.collection");
508
- writeFileSync2(path6.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
532
+ writeFileSync2(path7.join(cwd, "main", "main.script"), MAIN_SCRIPT_CONTENT);
509
533
  written.push("main/main.script");
510
534
  const scriptKind = writeTsSurface(cwd, written);
511
535
  return { written, scriptKind };
512
536
  }
513
537
  function runInit(opts) {
514
538
  const { cwd, force = false } = opts;
515
- if (!existsSync2(path6.join(cwd, "game.project"))) {
539
+ if (!existsSync2(path7.join(cwd, "game.project"))) {
516
540
  return runNewProjectInit(cwd, force);
517
541
  }
518
542
  if (!force) {
519
543
  for (const rel of CONFLICTING_TS_CONFIGS) {
520
- if (existsSync2(path6.join(cwd, rel))) {
544
+ if (existsSync2(path7.join(cwd, rel))) {
521
545
  throw new Error(`defold-typescript init: refusing to overwrite existing TS config: ${rel}. Pass --force to overwrite.`);
522
546
  }
523
547
  }
@@ -545,11 +569,11 @@ import {
545
569
  existsSync as existsSync3,
546
570
  mkdirSync as mkdirSync3,
547
571
  readdirSync as readdirSync2,
548
- readFileSync as readFileSync6,
572
+ readFileSync as readFileSync7,
549
573
  rmSync as rmSync2,
550
574
  writeFileSync as writeFileSync3
551
575
  } from "node:fs";
552
- import * as path7 from "node:path";
576
+ import * as path8 from "node:path";
553
577
  var MATERIALIZED_ROOT = ".defold-types";
554
578
  function writeJson2(filePath, value) {
555
579
  writeFileSync3(filePath, `${JSON.stringify(value, null, 2)}
@@ -564,14 +588,14 @@ function materializeApiSurface(opts) {
564
588
  return { materializedDir: null, active: null };
565
589
  }
566
590
  const { surfaceId } = surface;
567
- const relDir = path7.posix.join(MATERIALIZED_ROOT, surfaceId);
568
- const absDir = path7.join(cwd, MATERIALIZED_ROOT, surfaceId);
591
+ const relDir = path8.posix.join(MATERIALIZED_ROOT, surfaceId);
592
+ const absDir = path8.join(cwd, MATERIALIZED_ROOT, surfaceId);
569
593
  mkdirSync3(absDir, { recursive: true });
570
594
  const excluded = excludedModulesForKind(opts.scriptKind ?? null);
571
595
  const sources = listDts(sourceGeneratedDir).filter((file) => file !== "index.d.ts").filter((file) => !excluded.has(file.replace(/\.d\.ts$/, "")));
572
- const srcDir = path7.resolve(sourceGeneratedDir, "..", "src");
573
- const overloads = ["msg-overloads.d.ts", "go-overloads.d.ts"].filter((file) => existsSync3(path7.join(srcDir, file)));
574
- const coreTypesSrc = path7.join(srcDir, "core-types.ts");
596
+ const srcDir = path8.resolve(sourceGeneratedDir, "..", "src");
597
+ const overloads = ["msg-overloads.d.ts", "go-overloads.d.ts"].filter((file) => existsSync3(path8.join(srcDir, file)));
598
+ const coreTypesSrc = path8.join(srcDir, "core-types.ts");
575
599
  const includeCoreTypes = overloads.length > 0 && existsSync3(coreTypesSrc);
576
600
  const wanted = new Set(sources);
577
601
  for (const file of overloads) {
@@ -582,39 +606,39 @@ function materializeApiSurface(opts) {
582
606
  }
583
607
  for (const existing of readdirSync2(absDir)) {
584
608
  if (existing.endsWith(".d.ts") && existing !== "index.d.ts" && !wanted.has(existing)) {
585
- rmSync2(path7.join(absDir, existing));
609
+ rmSync2(path8.join(absDir, existing));
586
610
  }
587
611
  }
588
612
  for (const file of sources) {
589
- writeFileSync3(path7.join(absDir, file), readFileSync6(path7.join(sourceGeneratedDir, file), "utf8"));
613
+ writeFileSync3(path8.join(absDir, file), readFileSync7(path8.join(sourceGeneratedDir, file), "utf8"));
590
614
  }
591
615
  if (includeCoreTypes) {
592
- writeFileSync3(path7.join(absDir, "core-types.d.ts"), readFileSync6(coreTypesSrc, "utf8"));
616
+ writeFileSync3(path8.join(absDir, "core-types.d.ts"), readFileSync7(coreTypesSrc, "utf8"));
593
617
  }
594
618
  for (const file of overloads) {
595
- writeFileSync3(path7.join(absDir, file), readFileSync6(path7.join(srcDir, file), "utf8"));
619
+ writeFileSync3(path8.join(absDir, file), readFileSync7(path8.join(srcDir, file), "utf8"));
596
620
  }
597
621
  const modules = [...sources, ...overloads].map((file) => file.replace(/\.d\.ts$/, ""));
598
622
  const imports = modules.map((mod) => `import "./${mod}";`).join(`
599
623
  `);
600
- writeFileSync3(path7.join(absDir, "index.d.ts"), `${imports}
624
+ writeFileSync3(path8.join(absDir, "index.d.ts"), `${imports}
601
625
 
602
626
  export {};
603
627
  `);
604
- writeJson2(path7.join(absDir, "package.json"), {
628
+ writeJson2(path8.join(absDir, "package.json"), {
605
629
  name: `@defold-typescript/materialized-${surfaceId}`,
606
630
  types: "index.d.ts"
607
631
  });
608
632
  return { materializedDir: relDir, active: surfaceId };
609
633
  }
610
634
  function ensureGitignoreLine(cwd, line) {
611
- const gitignorePath = path7.join(cwd, ".gitignore");
635
+ const gitignorePath = path8.join(cwd, ".gitignore");
612
636
  if (!existsSync3(gitignorePath)) {
613
637
  writeFileSync3(gitignorePath, `${line}
614
638
  `);
615
639
  return;
616
640
  }
617
- const existing = readFileSync6(gitignorePath, "utf8");
641
+ const existing = readFileSync7(gitignorePath, "utf8");
618
642
  const present = new Set(existing.split(`
619
643
  `).map((entry) => entry.trim()));
620
644
  if (present.has(line)) {
@@ -630,10 +654,10 @@ function ensureMaterializedReference(cwd, materializedDir) {
630
654
  if (materializedDir === null) {
631
655
  return;
632
656
  }
633
- const surfaceId = path7.posix.basename(materializedDir);
634
- const tsconfigPath = path7.join(cwd, "tsconfig.json");
657
+ const surfaceId = path8.posix.basename(materializedDir);
658
+ const tsconfigPath = path8.join(cwd, "tsconfig.json");
635
659
  if (existsSync3(tsconfigPath)) {
636
- const tsconfig = JSON.parse(readFileSync6(tsconfigPath, "utf8"));
660
+ const tsconfig = JSON.parse(readFileSync7(tsconfigPath, "utf8"));
637
661
  tsconfig.compilerOptions = {
638
662
  ...tsconfig.compilerOptions ?? {},
639
663
  typeRoots: [MATERIALIZED_ROOT],
@@ -645,7 +669,7 @@ function ensureMaterializedReference(cwd, materializedDir) {
645
669
  }
646
670
  function resolveCurrentSurfaceGeneratedDir() {
647
671
  const root = resolveTypesPackageRoot();
648
- return root === null ? null : path7.join(root, "generated");
672
+ return root === null ? null : path8.join(root, "generated");
649
673
  }
650
674
  async function materializeRefDocSurface(opts) {
651
675
  const { cwd, surfaceId, resolveOpts } = opts;
@@ -659,17 +683,17 @@ async function materializeRefDocSurface(opts) {
659
683
  return { materializedDir: null, active: null };
660
684
  }
661
685
  const excludeModules = [...excludedModulesForKind(opts.scriptKind ?? null)];
662
- const relDir = path7.posix.join(MATERIALIZED_ROOT, surfaceId);
663
- const absDir = path7.join(cwd, MATERIALIZED_ROOT, surfaceId);
686
+ const relDir = path8.posix.join(MATERIALIZED_ROOT, surfaceId);
687
+ const absDir = path8.join(cwd, MATERIALIZED_ROOT, surfaceId);
664
688
  try {
665
- const mod = await import(path7.join(root, "scripts", "materialize-version.ts"));
689
+ const mod = await import(path8.join(root, "scripts", "materialize-version.ts"));
666
690
  const selfContained = { ...target, coreTypesImport: "./core-types" };
667
691
  await mod.materializeVersionedSurface(selfContained, {
668
692
  destDir: absDir,
669
693
  ...resolveOpts ? { resolveOpts } : {},
670
694
  ...excludeModules.length > 0 ? { excludeModules } : {}
671
695
  });
672
- copyFileSync(path7.join(root, "src", "core-types.ts"), path7.join(absDir, "core-types.d.ts"));
696
+ copyFileSync(path8.join(root, "src", "core-types.ts"), path8.join(absDir, "core-types.d.ts"));
673
697
  } catch {
674
698
  rmSync2(absDir, { recursive: true, force: true });
675
699
  return { materializedDir: null, active: null };
@@ -679,7 +703,7 @@ async function materializeRefDocSurface(opts) {
679
703
 
680
704
  // src/watch.ts
681
705
  import { existsSync as existsSync4, watch as fsWatch } from "node:fs";
682
- import * as path8 from "node:path";
706
+ import * as path9 from "node:path";
683
707
  var DEFAULT_DEBOUNCE_MS = 50;
684
708
  var recursiveWatcherFactory = (srcDir, onEvent) => {
685
709
  const w = fsWatch(srcDir, { recursive: true }, (eventType, filename) => {
@@ -722,7 +746,7 @@ function runWatch(opts) {
722
746
  waitForIdle: () => Promise.resolve()
723
747
  };
724
748
  }
725
- const srcDir = path8.join(cwd, "src");
749
+ const srcDir = path9.join(cwd, "src");
726
750
  let scheduled = null;
727
751
  let syncScheduled = null;
728
752
  let rebuildBusy = false;
@@ -746,7 +770,7 @@ function runWatch(opts) {
746
770
  const removed = [];
747
771
  for (const rel of drained) {
748
772
  const key = `src/${toPosix(rel)}`;
749
- if (existsSync4(path8.join(srcDir, rel))) {
773
+ if (existsSync4(path9.join(srcDir, rel))) {
750
774
  changed.push(key);
751
775
  } else {
752
776
  removed.push(key);
@@ -847,23 +871,30 @@ function parseDefoldVersionFlag(argv) {
847
871
  return { flag, rest };
848
872
  }
849
873
  function readProjectPin(cwd) {
850
- const pkgPath = path9.join(cwd, "package.json");
874
+ const pkgPath = path10.join(cwd, "package.json");
851
875
  if (!existsSync5(pkgPath)) {
852
876
  return;
853
877
  }
854
878
  try {
855
- return readDefoldVersionPin(JSON.parse(readFileSync7(pkgPath, "utf8")));
879
+ return readDefoldVersionPin(JSON.parse(readFileSync8(pkgPath, "utf8")));
856
880
  } catch {
857
881
  return;
858
882
  }
859
883
  }
860
884
  function dispatch(argv, io, internals) {
861
885
  const json = argv.includes("--json");
886
+ if (argv.includes("--version") || argv.includes("-v")) {
887
+ const version = internals?.cliVersion ?? readCliVersion();
888
+ io.stdout.write(json ? `{"command":"version","ok":true,"version":${JSON.stringify(version)}}
889
+ ` : `defold-typescript ${version}
890
+ `);
891
+ return 0;
892
+ }
862
893
  const force = argv.includes("--force");
863
894
  const { flag: defoldVersionFlag, rest: nonFlagArgs } = parseDefoldVersionFlag(argv);
864
895
  const positional = nonFlagArgs.filter((a) => a !== "--json" && a !== "--force");
865
896
  const [command, ...rest] = positional;
866
- const cwd = rest[0] ? path9.resolve(rest[0]) : process.cwd();
897
+ const cwd = rest[0] ? path10.resolve(rest[0]) : process.cwd();
867
898
  const pin = readProjectPin(cwd);
868
899
  const resolvedVersion = resolveDefoldVersion({
869
900
  ...defoldVersionFlag !== undefined ? { flag: defoldVersionFlag } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defold-typescript/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
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.2.0",
35
- "@defold-typescript/types": "0.2.0"
34
+ "@defold-typescript/transpiler": "0.3.0",
35
+ "@defold-typescript/types": "0.3.0"
36
36
  }
37
37
  }
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const VERSION_FALLBACK = "0.0.0";
6
+
7
+ // Anchor on the module URL, not `import.meta.dir` — the latter is a Bun-only
8
+ // property and is undefined when the bundled CLI runs under node (the `npx`
9
+ // path), which would silently anchor at the cwd. The bundled bin (`dist/bin.js`)
10
+ // and the in-repo `src/` loop both sit one level below the package root, so
11
+ // `package.json` is always `../package.json` from this module's directory. A
12
+ // missing or malformed manifest reports the fallback rather than throwing.
13
+ function defaultPackageRoot(): string {
14
+ return path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
15
+ }
16
+
17
+ export function readCliVersion(packageRoot: string = defaultPackageRoot()): string {
18
+ try {
19
+ const pkg = JSON.parse(readFileSync(path.join(packageRoot, "package.json"), "utf8")) as {
20
+ version?: unknown;
21
+ };
22
+ return typeof pkg.version === "string" ? pkg.version : VERSION_FALLBACK;
23
+ } catch {
24
+ return VERSION_FALLBACK;
25
+ }
26
+ }
package/src/dispatch.ts CHANGED
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import type { RegistryTarget } from "./api-registry";
4
4
  import { CURRENT_STABLE_SURFACE_ID, selectApiSurface } from "./api-surface";
5
5
  import { runBuild } from "./build";
6
+ import { readCliVersion } from "./cli-version";
6
7
  import { readDefoldVersionPin, resolveDefoldVersion } from "./defold-version";
7
8
  import { runInit } from "./init";
8
9
  import { renderResult } from "./json-output";
@@ -35,6 +36,7 @@ export interface DispatchInternals {
35
36
  readonly sourceGeneratedDir?: string;
36
37
  readonly resolveOpts?: RefDocResolveOptions;
37
38
  readonly refDocRegistry?: readonly RegistryTarget[];
39
+ readonly cliVersion?: string;
38
40
  }
39
41
 
40
42
  const USAGE = "Usage: defold-typescript <init|build|watch> [path]\n";
@@ -74,6 +76,17 @@ export function dispatch(
74
76
  internals?: DispatchInternals,
75
77
  ): number | Promise<number> {
76
78
  const json = argv.includes("--json");
79
+
80
+ if (argv.includes("--version") || argv.includes("-v")) {
81
+ const version = internals?.cliVersion ?? readCliVersion();
82
+ io.stdout.write(
83
+ json
84
+ ? `{"command":"version","ok":true,"version":${JSON.stringify(version)}}\n`
85
+ : `defold-typescript ${version}\n`,
86
+ );
87
+ return 0;
88
+ }
89
+
77
90
  const force = argv.includes("--force");
78
91
  const { flag: defoldVersionFlag, rest: nonFlagArgs } = parseDefoldVersionFlag(argv);
79
92
  const positional = nonFlagArgs.filter((a) => a !== "--json" && a !== "--force");
package/src/init.ts CHANGED
@@ -128,6 +128,20 @@ const SCAFFOLD_DEV_DEPS: Record<string, string> = {
128
128
  "@biomejs/biome": "^2.2.0",
129
129
  };
130
130
 
131
+ // Older scaffolds wrote both managed `@defold-typescript/*` devDeps as
132
+ // `workspace:*`, which only resolves inside this monorepo and breaks
133
+ // `bun install` in consumers. The additive merge in `writeTsSurface` never
134
+ // repairs an entry it didn't itself create, so repair them explicitly: the
135
+ // transpiler is CLI-internal and must not be a consumer dep at all, and a
136
+ // `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 {
139
+ delete devDeps["@defold-typescript/transpiler"];
140
+ if (devDeps["@defold-typescript/types"]?.startsWith("workspace:")) {
141
+ devDeps["@defold-typescript/types"] = typesVersionSpec();
142
+ }
143
+ }
144
+
131
145
  function writeJson(filePath: string, value: unknown): void {
132
146
  writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
133
147
  }
@@ -182,6 +196,7 @@ function writeTsSurface(cwd: string, written: string[]): ScriptKind | null {
182
196
  devDeps[name] = version;
183
197
  }
184
198
  }
199
+ repairManagedDevDeps(devDeps);
185
200
  existing.devDependencies = devDeps;
186
201
  existing["defold-typescript"] ??= { "defold-version": CURRENT_STABLE_DEFOLD_VERSION };
187
202
  writeJson(pkgPath, existing);