@defold-typescript/cli 0.1.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/api-registry.d.ts +14 -0
- package/dist/api-surface.d.ts +6 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +1023 -0
- package/dist/build-output.d.ts +11 -0
- package/dist/build-session.d.ts +11 -0
- package/dist/build.d.ts +7 -0
- package/dist/defold-version.d.ts +11 -0
- package/dist/dispatch.d.ts +17 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1017 -0
- package/dist/init.d.ts +11 -0
- package/dist/json-output.d.ts +11 -0
- package/dist/materialize.d.ts +29 -0
- package/dist/ref-doc-test-fixture.d.ts +18 -0
- package/dist/scan.d.ts +1 -0
- package/dist/script-kind.d.ts +8 -0
- package/dist/watch.d.ts +24 -0
- package/package.json +36 -0
- package/src/api-registry.ts +65 -0
- package/src/api-surface.ts +18 -0
- package/src/bin.ts +8 -0
- package/src/build-output.ts +106 -0
- package/src/build-session.ts +98 -0
- package/src/build.ts +62 -0
- package/src/defold-version.ts +30 -0
- package/src/dispatch.ts +273 -0
- package/src/index.ts +17 -0
- package/src/init.ts +237 -0
- package/src/json-output.ts +29 -0
- package/src/materialize.ts +224 -0
- package/src/ref-doc-test-fixture.ts +92 -0
- package/src/scan.ts +10 -0
- package/src/script-kind.ts +68 -0
- package/src/watch.ts +185 -0
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ScriptKind } from "./script-kind";
|
|
2
|
+
export interface RunInitOptions {
|
|
3
|
+
readonly cwd: string;
|
|
4
|
+
readonly force?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface RunInitResult {
|
|
7
|
+
readonly written: string[];
|
|
8
|
+
readonly scriptKind: ScriptKind | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function runNewProjectInit(cwd: string, force?: boolean): RunInitResult;
|
|
11
|
+
export declare function runInit(opts: RunInitOptions): RunInitResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type CliCommand = "init" | "build";
|
|
2
|
+
export interface RenderResultInput {
|
|
3
|
+
readonly command: CliCommand;
|
|
4
|
+
readonly written?: readonly string[];
|
|
5
|
+
readonly error?: string;
|
|
6
|
+
readonly defoldVersion?: string;
|
|
7
|
+
readonly apiSurface?: string | null;
|
|
8
|
+
readonly scriptKind?: string | null;
|
|
9
|
+
readonly materializedSurface?: string | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function renderResult(input: RenderResultInput): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type RegistryTarget } from "./api-registry";
|
|
2
|
+
import type { SelectedApiSurface } from "./api-surface";
|
|
3
|
+
import { type ScriptKind } from "./script-kind";
|
|
4
|
+
export interface MaterializeApiSurfaceOptions {
|
|
5
|
+
readonly cwd: string;
|
|
6
|
+
readonly surface: SelectedApiSurface;
|
|
7
|
+
readonly sourceGeneratedDir: string | null;
|
|
8
|
+
readonly scriptKind?: ScriptKind | null;
|
|
9
|
+
}
|
|
10
|
+
export interface MaterializeApiSurfaceResult {
|
|
11
|
+
readonly materializedDir: string | null;
|
|
12
|
+
readonly active: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function materializeApiSurface(opts: MaterializeApiSurfaceOptions): MaterializeApiSurfaceResult;
|
|
15
|
+
export declare function ensureMaterializedReference(cwd: string, materializedDir: string | null): void;
|
|
16
|
+
export declare function resolveCurrentSurfaceGeneratedDir(): string | null;
|
|
17
|
+
export interface RefDocResolveOptions {
|
|
18
|
+
readonly cacheDir?: string;
|
|
19
|
+
readonly download?: (version: string) => Promise<Uint8Array>;
|
|
20
|
+
readonly readZip?: (zipPath: string) => unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface MaterializeRefDocSurfaceOptions {
|
|
23
|
+
readonly cwd: string;
|
|
24
|
+
readonly surfaceId: string;
|
|
25
|
+
readonly resolveOpts?: RefDocResolveOptions;
|
|
26
|
+
readonly scriptKind?: ScriptKind | null;
|
|
27
|
+
readonly registry?: readonly RegistryTarget[];
|
|
28
|
+
}
|
|
29
|
+
export declare function materializeRefDocSurface(opts: MaterializeRefDocSurfaceOptions): Promise<MaterializeApiSurfaceResult>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RegistryTarget } from "./api-registry";
|
|
2
|
+
interface FakeZip {
|
|
3
|
+
has: (entry: string) => boolean;
|
|
4
|
+
read: (entry: string) => string;
|
|
5
|
+
}
|
|
6
|
+
export declare const noDownload: () => Promise<Uint8Array>;
|
|
7
|
+
export declare function labelRefDocResolveOpts(): {
|
|
8
|
+
cacheDir: string;
|
|
9
|
+
readZip: () => FakeZip;
|
|
10
|
+
download: typeof noDownload;
|
|
11
|
+
};
|
|
12
|
+
export declare function multiKindRefDocResolveOpts(): {
|
|
13
|
+
cacheDir: string;
|
|
14
|
+
readZip: () => FakeZip;
|
|
15
|
+
download: typeof noDownload;
|
|
16
|
+
};
|
|
17
|
+
export declare function multiKindRefDocTarget(): RegistryTarget;
|
|
18
|
+
export {};
|
package/dist/scan.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function scanFilesSync(cwd: string, pattern: string): string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ScriptKind = "script" | "gui-script" | "render-script";
|
|
2
|
+
export declare const DEFAULT_TYPES_ENTRYPOINT = "@defold-typescript/types";
|
|
3
|
+
export declare function isSkipped(relPath: string): boolean;
|
|
4
|
+
export declare function isComponentPath(relPath: string): boolean;
|
|
5
|
+
export declare function detectScriptKinds(cwd: string): Set<ScriptKind>;
|
|
6
|
+
export declare function selectScriptKind(kinds: Set<ScriptKind>): ScriptKind | null;
|
|
7
|
+
export declare function selectScriptKindEntrypoint(kinds: Set<ScriptKind>): string;
|
|
8
|
+
export declare function excludedModulesForKind(kind: ScriptKind | null): Set<string>;
|
package/dist/watch.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface WatchEvent {
|
|
2
|
+
readonly kind: "change" | "rename";
|
|
3
|
+
readonly path: string;
|
|
4
|
+
}
|
|
5
|
+
export interface Watcher {
|
|
6
|
+
close(): void;
|
|
7
|
+
}
|
|
8
|
+
export type WatcherFactory = (srcDir: string, onEvent: (e: WatchEvent) => void) => Watcher;
|
|
9
|
+
export interface RunWatchOptions {
|
|
10
|
+
readonly cwd: string;
|
|
11
|
+
readonly stdout: NodeJS.WritableStream;
|
|
12
|
+
readonly stderr: NodeJS.WritableStream;
|
|
13
|
+
readonly debounceMs?: number;
|
|
14
|
+
readonly watcherFactory?: WatcherFactory;
|
|
15
|
+
readonly syncSurface?: () => void;
|
|
16
|
+
readonly componentWatcherFactory?: WatcherFactory;
|
|
17
|
+
}
|
|
18
|
+
export interface RunWatchHandle {
|
|
19
|
+
readonly stop: () => void;
|
|
20
|
+
readonly done: Promise<number>;
|
|
21
|
+
readonly waitForIdle: () => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare const recursiveWatcherFactory: WatcherFactory;
|
|
24
|
+
export declare function runWatch(opts: RunWatchOptions): RunWatchHandle;
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@defold-typescript/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "End-user CLI for scaffolding and building Defold projects written in TypeScript.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"bun": "./src/index.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"defold-typescript": "./dist/bin.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src",
|
|
21
|
+
"!src/**/*.test.ts",
|
|
22
|
+
"!src/**/__snapshots__"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rm -rf dist && bun build src/index.ts src/bin.ts --target=node --format=esm --packages=external --outdir=dist && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
29
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
30
|
+
"test": "bun test"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@defold-typescript/transpiler": "0.1.0",
|
|
34
|
+
"@defold-typescript/types": "0.1.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
|
|
5
|
+
export interface RegistryTargetSource {
|
|
6
|
+
readonly kind: string;
|
|
7
|
+
readonly version: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface RegistryTarget {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly default?: boolean;
|
|
13
|
+
readonly coreTypesImport?: string;
|
|
14
|
+
readonly source?: RegistryTargetSource | null;
|
|
15
|
+
readonly [key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function findPackageRoot(start: string): string | null {
|
|
19
|
+
let dir = start;
|
|
20
|
+
for (;;) {
|
|
21
|
+
if (existsSync(path.join(dir, "package.json"))) {
|
|
22
|
+
return dir;
|
|
23
|
+
}
|
|
24
|
+
const parent = path.dirname(dir);
|
|
25
|
+
if (parent === dir) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveTypesPackageRoot(): string | null {
|
|
33
|
+
try {
|
|
34
|
+
const require = createRequire(import.meta.url);
|
|
35
|
+
const entry = require.resolve("@defold-typescript/types");
|
|
36
|
+
return findPackageRoot(path.dirname(entry));
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function loadApiTargetsRegistry(): RegistryTarget[] {
|
|
43
|
+
const root = resolveTypesPackageRoot();
|
|
44
|
+
if (root === null) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const registryPath = path.join(root, "api-targets.json");
|
|
48
|
+
if (!existsSync(registryPath)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const { targets } = JSON.parse(readFileSync(registryPath, "utf8")) as {
|
|
53
|
+
targets: RegistryTarget[];
|
|
54
|
+
};
|
|
55
|
+
return targets;
|
|
56
|
+
} catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function findRefDocTarget(version: string): RegistryTarget | undefined {
|
|
62
|
+
return loadApiTargetsRegistry().find(
|
|
63
|
+
(target) => target.source?.kind === "ref-doc" && target.source.version === version,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { loadApiTargetsRegistry } from "./api-registry";
|
|
2
|
+
import { CURRENT_STABLE_DEFOLD_VERSION } from "./defold-version";
|
|
3
|
+
|
|
4
|
+
export const CURRENT_STABLE_SURFACE_ID = `defold-${CURRENT_STABLE_DEFOLD_VERSION}`;
|
|
5
|
+
|
|
6
|
+
export interface SelectedApiSurface {
|
|
7
|
+
readonly surfaceId: string | null;
|
|
8
|
+
readonly available: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function selectApiSurface(resolvedVersion: string): SelectedApiSurface {
|
|
12
|
+
const id = `defold-${resolvedVersion}`;
|
|
13
|
+
const target = loadApiTargetsRegistry().find((t) => t.id === id);
|
|
14
|
+
if (target) {
|
|
15
|
+
return { surfaceId: target.id, available: true };
|
|
16
|
+
}
|
|
17
|
+
return { surfaceId: null, available: false };
|
|
18
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import type { TranspileDiagnostic } from "@defold-typescript/transpiler";
|
|
4
|
+
|
|
5
|
+
export interface BuildConfig {
|
|
6
|
+
readonly outDir: string | undefined;
|
|
7
|
+
readonly include: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface TsConfig {
|
|
11
|
+
compilerOptions?: {
|
|
12
|
+
outDir?: string;
|
|
13
|
+
};
|
|
14
|
+
include?: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DEFAULT_INCLUDE = ["src/**/*.ts"];
|
|
18
|
+
const PROJECT_BUCKET = "<project>";
|
|
19
|
+
|
|
20
|
+
export function toPosix(p: string, sep: string = path.sep): string {
|
|
21
|
+
return p.split(sep).join("/");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function readBuildConfig(cwd: string): BuildConfig {
|
|
25
|
+
const tsconfigPath = path.join(cwd, "tsconfig.json");
|
|
26
|
+
let raw: string;
|
|
27
|
+
try {
|
|
28
|
+
raw = readFileSync(tsconfigPath, "utf8");
|
|
29
|
+
} catch {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`defold-typescript build: no tsconfig.json at ${cwd}; run 'defold-typescript init' first.`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const tsconfig = JSON.parse(raw) as TsConfig;
|
|
36
|
+
const outDir = tsconfig.compilerOptions?.outDir;
|
|
37
|
+
const include = tsconfig.include?.length ? tsconfig.include : DEFAULT_INCLUDE;
|
|
38
|
+
return { outDir, include };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function stripIncludeBase(pattern: string): string {
|
|
42
|
+
const firstWildcard = pattern.search(/[*?[]/);
|
|
43
|
+
if (firstWildcard === -1) {
|
|
44
|
+
return pattern.endsWith("/") ? pattern : `${path.posix.dirname(pattern)}/`;
|
|
45
|
+
}
|
|
46
|
+
const upToWildcard = pattern.slice(0, firstWildcard);
|
|
47
|
+
const lastSlash = upToWildcard.lastIndexOf("/");
|
|
48
|
+
return lastSlash === -1 ? "" : upToWildcard.slice(0, lastSlash + 1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function computeLuaRel(rel: string, config: BuildConfig): string {
|
|
52
|
+
const { outDir, include } = config;
|
|
53
|
+
if (outDir === undefined || outDir === "" || outDir === ".") {
|
|
54
|
+
return rel.replace(/\.ts$/, ".lua");
|
|
55
|
+
}
|
|
56
|
+
const includeBase =
|
|
57
|
+
include
|
|
58
|
+
.map(stripIncludeBase)
|
|
59
|
+
.filter((base) => rel.startsWith(base))
|
|
60
|
+
.sort((a, b) => b.length - a.length)[0] ?? "";
|
|
61
|
+
const relUnderBase = rel.slice(includeBase.length);
|
|
62
|
+
return path.posix.join(outDir, relUnderBase.replace(/\.ts$/, ".lua"));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function collectFailures(
|
|
66
|
+
diagnostics: readonly TranspileDiagnostic[],
|
|
67
|
+
): Map<string, string[]> {
|
|
68
|
+
const failures = new Map<string, string[]>();
|
|
69
|
+
for (const diag of diagnostics) {
|
|
70
|
+
const bucket = diag.file ?? PROJECT_BUCKET;
|
|
71
|
+
const list = failures.get(bucket);
|
|
72
|
+
if (list) {
|
|
73
|
+
list.push(diag.message);
|
|
74
|
+
} else {
|
|
75
|
+
failures.set(bucket, [diag.message]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return failures;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function throwIfFailures(failures: ReadonlyMap<string, string[]>): void {
|
|
82
|
+
if (failures.size === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const formatted = [...failures.entries()]
|
|
86
|
+
.map(([file, messages]) => ` ${file}: ${messages.join("; ")}`)
|
|
87
|
+
.join("\n");
|
|
88
|
+
throw new Error(`defold-typescript build: ${failures.size} file(s) failed:\n${formatted}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function writeLuaFile(
|
|
92
|
+
cwd: string,
|
|
93
|
+
luaRel: string,
|
|
94
|
+
lua: string,
|
|
95
|
+
map: string | undefined,
|
|
96
|
+
): void {
|
|
97
|
+
const luaAbs = path.join(cwd, luaRel);
|
|
98
|
+
mkdirSync(path.dirname(luaAbs), { recursive: true });
|
|
99
|
+
if (map) {
|
|
100
|
+
const mapBasename = `${path.posix.basename(luaRel)}.map`;
|
|
101
|
+
writeFileSync(`${luaAbs}.map`, map);
|
|
102
|
+
writeFileSync(luaAbs, `${lua}\n--# sourceMappingURL=${mapBasename}\n`);
|
|
103
|
+
} else {
|
|
104
|
+
writeFileSync(luaAbs, lua);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
createTranspileSession,
|
|
5
|
+
type TranspileProjectResult,
|
|
6
|
+
type TranspileSession,
|
|
7
|
+
} from "@defold-typescript/transpiler";
|
|
8
|
+
import {
|
|
9
|
+
type BuildConfig,
|
|
10
|
+
collectFailures,
|
|
11
|
+
computeLuaRel,
|
|
12
|
+
readBuildConfig,
|
|
13
|
+
throwIfFailures,
|
|
14
|
+
toPosix,
|
|
15
|
+
writeLuaFile,
|
|
16
|
+
} from "./build-output";
|
|
17
|
+
import { scanFilesSync } from "./scan";
|
|
18
|
+
|
|
19
|
+
export interface CreateBuildSessionOptions {
|
|
20
|
+
readonly cwd: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface BuildResult {
|
|
24
|
+
readonly written: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BuildSession {
|
|
28
|
+
buildAll(): BuildResult;
|
|
29
|
+
applyEvents(changed: string[], removed: string[]): BuildResult;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createBuildSession(opts: CreateBuildSessionOptions): BuildSession {
|
|
33
|
+
const { cwd } = opts;
|
|
34
|
+
const config: BuildConfig = readBuildConfig(cwd);
|
|
35
|
+
const session: TranspileSession = createTranspileSession();
|
|
36
|
+
|
|
37
|
+
function writeOutputs(result: TranspileProjectResult, keys: readonly string[]): BuildResult {
|
|
38
|
+
const failures = collectFailures(result.diagnostics);
|
|
39
|
+
const written: string[] = [];
|
|
40
|
+
for (const rel of keys) {
|
|
41
|
+
if (failures.has(rel)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const lua = result.lua[rel];
|
|
45
|
+
if (lua === undefined) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const luaRel = computeLuaRel(rel, config);
|
|
49
|
+
writeLuaFile(cwd, luaRel, lua, result.sourceMaps[rel]);
|
|
50
|
+
written.push(luaRel);
|
|
51
|
+
}
|
|
52
|
+
throwIfFailures(failures);
|
|
53
|
+
return { written };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildAll(): BuildResult {
|
|
57
|
+
const seen = new Set<string>();
|
|
58
|
+
for (const pattern of config.include) {
|
|
59
|
+
for (const match of scanFilesSync(cwd, pattern)) {
|
|
60
|
+
seen.add(toPosix(match));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const sources = [...seen].sort();
|
|
64
|
+
if (sources.length === 0) {
|
|
65
|
+
return { written: [] };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const files: Record<string, string> = {};
|
|
69
|
+
for (const rel of sources) {
|
|
70
|
+
files[rel] = readFileSync(path.join(cwd, rel), "utf8");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const result = session.update(files);
|
|
74
|
+
return writeOutputs(result, sources);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function applyEvents(changed: string[], removed: string[]): BuildResult {
|
|
78
|
+
const changes: Record<string, string | null> = {};
|
|
79
|
+
for (const rel of changed) {
|
|
80
|
+
changes[rel] = readFileSync(path.join(cwd, rel), "utf8");
|
|
81
|
+
}
|
|
82
|
+
for (const rel of removed) {
|
|
83
|
+
changes[rel] = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const result = session.update(changes);
|
|
87
|
+
|
|
88
|
+
for (const rel of removed) {
|
|
89
|
+
const luaAbs = path.join(cwd, computeLuaRel(rel, config));
|
|
90
|
+
rmSync(luaAbs, { force: true });
|
|
91
|
+
rmSync(`${luaAbs}.map`, { force: true });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return writeOutputs(result, changed);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { buildAll, applyEvents };
|
|
98
|
+
}
|
package/src/build.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { transpileProject } from "@defold-typescript/transpiler";
|
|
4
|
+
import {
|
|
5
|
+
collectFailures,
|
|
6
|
+
computeLuaRel,
|
|
7
|
+
readBuildConfig,
|
|
8
|
+
throwIfFailures,
|
|
9
|
+
toPosix,
|
|
10
|
+
writeLuaFile,
|
|
11
|
+
} from "./build-output";
|
|
12
|
+
import { scanFilesSync } from "./scan";
|
|
13
|
+
|
|
14
|
+
export interface RunBuildOptions {
|
|
15
|
+
readonly cwd: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RunBuildResult {
|
|
19
|
+
readonly written: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function runBuild(opts: RunBuildOptions): RunBuildResult {
|
|
23
|
+
const { cwd } = opts;
|
|
24
|
+
const config = readBuildConfig(cwd);
|
|
25
|
+
|
|
26
|
+
const seen = new Set<string>();
|
|
27
|
+
for (const pattern of config.include) {
|
|
28
|
+
for (const match of scanFilesSync(cwd, pattern)) {
|
|
29
|
+
seen.add(toPosix(match));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const sources = [...seen].sort();
|
|
33
|
+
|
|
34
|
+
if (sources.length === 0) {
|
|
35
|
+
return { written: [] };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const files: Record<string, string> = {};
|
|
39
|
+
for (const rel of sources) {
|
|
40
|
+
files[rel] = readFileSync(path.join(cwd, rel), "utf8");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = transpileProject({ files });
|
|
44
|
+
const failures = collectFailures(result.diagnostics);
|
|
45
|
+
|
|
46
|
+
const written: string[] = [];
|
|
47
|
+
for (const rel of sources) {
|
|
48
|
+
if (failures.has(rel)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const lua = result.lua[rel];
|
|
52
|
+
if (!lua) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const luaRel = computeLuaRel(rel, config);
|
|
56
|
+
writeLuaFile(cwd, luaRel, lua, result.sourceMaps[rel]);
|
|
57
|
+
written.push(luaRel);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throwIfFailures(failures);
|
|
61
|
+
return { written };
|
|
62
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const CURRENT_STABLE_DEFOLD_VERSION = "1.12.4";
|
|
2
|
+
|
|
3
|
+
export type DefoldVersionSource = "flag" | "pin" | "default";
|
|
4
|
+
|
|
5
|
+
export interface ResolvedDefoldVersion {
|
|
6
|
+
readonly version: string;
|
|
7
|
+
readonly source: DefoldVersionSource;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function readDefoldVersionPin(pkg: unknown): string | undefined {
|
|
11
|
+
if (typeof pkg !== "object" || pkg === null) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const namespace = (pkg as Record<string, unknown>)["defold-typescript"];
|
|
15
|
+
if (typeof namespace !== "object" || namespace === null) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const version = (namespace as Record<string, unknown>)["defold-version"];
|
|
19
|
+
return typeof version === "string" ? version : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveDefoldVersion(opts: { flag?: string; pin?: string }): ResolvedDefoldVersion {
|
|
23
|
+
if (opts.flag !== undefined) {
|
|
24
|
+
return { version: opts.flag, source: "flag" };
|
|
25
|
+
}
|
|
26
|
+
if (opts.pin !== undefined) {
|
|
27
|
+
return { version: opts.pin, source: "pin" };
|
|
28
|
+
}
|
|
29
|
+
return { version: CURRENT_STABLE_DEFOLD_VERSION, source: "default" };
|
|
30
|
+
}
|