@defold-typescript/types 0.5.4 → 0.6.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/api-targets.json +1 -1
- package/generated/b2d.d.ts +3 -0
- package/generated/buffer.d.ts +44 -38
- package/generated/builtin-messages.d.ts +1 -1
- package/generated/camera.d.ts +3 -0
- package/generated/collectionfactory.d.ts +47 -40
- package/generated/collectionproxy.d.ts +23 -18
- package/generated/crash.d.ts +3 -0
- package/generated/factory.d.ts +32 -24
- package/generated/go.d.ts +293 -293
- package/generated/graphics.d.ts +3 -0
- package/generated/gui.d.ts +303 -283
- package/generated/http.d.ts +26 -16
- package/generated/iac.d.ts +3 -0
- package/generated/iap.d.ts +6 -3
- package/generated/image.d.ts +30 -26
- package/generated/json.d.ts +36 -32
- package/generated/kinds/gui-script.d.ts +7 -5
- package/generated/kinds/render-script.d.ts +7 -5
- package/generated/kinds/script.d.ts +7 -5
- package/generated/label.d.ts +16 -9
- package/generated/liveupdate.d.ts +29 -26
- package/generated/model.d.ts +57 -45
- package/generated/msg.d.ts +12 -9
- package/generated/particlefx.d.ts +50 -34
- package/generated/physics.d.ts +153 -133
- package/generated/profiler.d.ts +45 -41
- package/generated/push.d.ts +5 -2
- package/generated/render.d.ts +410 -349
- package/generated/resource.d.ts +619 -572
- package/generated/socket.d.ts +49 -33
- package/generated/sound.d.ts +83 -72
- package/generated/sprite.d.ts +36 -32
- package/generated/sys.d.ts +198 -189
- package/generated/tilemap.d.ts +43 -39
- package/generated/timer.d.ts +42 -36
- package/generated/vmath.d.ts +254 -229
- package/generated/webview.d.ts +3 -0
- package/generated/window.d.ts +23 -17
- package/generated/zlib.d.ts +15 -12
- package/index.d.ts +3 -1
- package/package.json +6 -2
- package/scripts/example-store-io.ts +18 -0
- package/scripts/fidelity-audit.ts +61 -1
- package/scripts/fidelity-baseline.json +10 -10
- package/scripts/ref-doc-delta.ts +143 -0
- package/scripts/regen.ts +23 -10
- package/src/core-types.ts +14 -0
- package/src/doc-comment.ts +2 -1
- package/src/emit-dts.ts +238 -18
- package/src/engine-globals.d.ts +2 -0
- package/src/example-store.ts +44 -0
- package/src/go-overloads.d.ts +73 -0
- package/src/index.ts +5 -0
- package/src/lifecycle.ts +157 -16
- package/src/message-dispatch.d.ts +21 -0
- package/src/message-guard.d.ts +19 -0
- package/src/msg-overloads.d.ts +20 -0
- package/src/publish-dts.ts +1 -1
package/generated/webview.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** @noSelfInFile */
|
|
2
2
|
declare global {
|
|
3
|
+
/**
|
|
4
|
+
* Functions and constants for interacting with webview APIs
|
|
5
|
+
*/
|
|
3
6
|
namespace webview {
|
|
4
7
|
/**
|
|
5
8
|
* Creates a webview instance. It can show HTML pages as well as evaluate Javascript. The view remains hidden until the first call. There can exist a maximum of 4 webviews at the same time.
|
package/generated/window.d.ts
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
import type { Opaque } from "../src/core-types";
|
|
3
3
|
|
|
4
4
|
declare global {
|
|
5
|
+
/**
|
|
6
|
+
* Functions and constants to access the window, window event listeners
|
|
7
|
+
* and screen dimming.
|
|
8
|
+
*/
|
|
5
9
|
namespace window {
|
|
6
10
|
/**
|
|
7
11
|
* Dimming mode is used to control whether or not a mobile device should dim the screen after a period without user interaction.
|
|
@@ -114,24 +118,26 @@ declare global {
|
|
|
114
118
|
* - number `width`: The width of a resize event. nil otherwise.
|
|
115
119
|
* - number `height`: The height of a resize event. nil otherwise.
|
|
116
120
|
* @example
|
|
117
|
-
* ```
|
|
118
|
-
* function window_callback(self, event, data)
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
121
|
+
* ```ts
|
|
122
|
+
* function window_callback(self, event, data) {
|
|
123
|
+
* if (event === window.WINDOW_EVENT_FOCUS_LOST) {
|
|
124
|
+
* print("window.WINDOW_EVENT_FOCUS_LOST");
|
|
125
|
+
* } else if (event === window.WINDOW_EVENT_FOCUS_GAINED) {
|
|
126
|
+
* print("window.WINDOW_EVENT_FOCUS_GAINED");
|
|
127
|
+
* } else if (event === window.WINDOW_EVENT_ICONFIED) {
|
|
128
|
+
* print("window.WINDOW_EVENT_ICONFIED");
|
|
129
|
+
* } else if (event === window.WINDOW_EVENT_DEICONIFIED) {
|
|
130
|
+
* print("window.WINDOW_EVENT_DEICONIFIED");
|
|
131
|
+
* } else if (event === window.WINDOW_EVENT_RESIZED) {
|
|
132
|
+
* print("Window resized: ", data.width, data.height);
|
|
133
|
+
* }
|
|
134
|
+
* }
|
|
131
135
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
136
|
+
* export default defineScript({
|
|
137
|
+
* init() {
|
|
138
|
+
* window.set_listener(window_callback);
|
|
139
|
+
* },
|
|
140
|
+
* });
|
|
135
141
|
* ```
|
|
136
142
|
*/
|
|
137
143
|
function set_listener(callback?: (self: unknown, event: unknown, data: unknown) => void): void;
|
package/generated/zlib.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** @noSelfInFile */
|
|
2
2
|
declare global {
|
|
3
|
+
/**
|
|
4
|
+
* Functions for compression and decompression of string buffers.
|
|
5
|
+
*/
|
|
3
6
|
namespace zlib {
|
|
4
7
|
/**
|
|
5
8
|
* A lua error is raised is on error
|
|
@@ -7,14 +10,14 @@ declare global {
|
|
|
7
10
|
* @param buf - buffer to deflate
|
|
8
11
|
* @returns deflated buffer
|
|
9
12
|
* @example
|
|
10
|
-
* ```
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* for c
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* print(s)
|
|
13
|
+
* ```ts
|
|
14
|
+
* const data = "This is a string with uncompressed data.";
|
|
15
|
+
* const compressed_data = zlib.deflate(data);
|
|
16
|
+
* let s = "";
|
|
17
|
+
* for (const c of compressed_data) {
|
|
18
|
+
* s = s + "\\" + c.charCodeAt(0);
|
|
19
|
+
* }
|
|
20
|
+
* print(s); //> \120\94\11\201\200\44\86\0\162\68\133\226\146\162 ...
|
|
18
21
|
* ```
|
|
19
22
|
*/
|
|
20
23
|
function deflate(buf: string): string;
|
|
@@ -24,10 +27,10 @@ declare global {
|
|
|
24
27
|
* @param buf - buffer to inflate
|
|
25
28
|
* @returns inflated buffer
|
|
26
29
|
* @example
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* print(uncompressed_data)
|
|
30
|
+
* ```ts
|
|
31
|
+
* const data = "\120\94\11\201\200\44\86\0\162\68\133\226\146\162\204\188\116\133\242\204\146\12\133\210\188\228\252\220\130\162\212\226\226\212\20\133\148\196\146\68\61\0\44\67\14\201";
|
|
32
|
+
* const uncompressed_data = zlib.inflate(data);
|
|
33
|
+
* print(uncompressed_data); //> This is a string with uncompressed data.
|
|
31
34
|
* ```
|
|
32
35
|
*/
|
|
33
36
|
function inflate(buf: string): string;
|
package/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import "./generated/builtin-messages";
|
|
|
2
2
|
import "./src/msg-overloads";
|
|
3
3
|
import "./src/message-guard";
|
|
4
4
|
import "./src/message-dispatch";
|
|
5
|
-
import "./src/go-overloads";
|
|
6
5
|
import "./src/engine-globals";
|
|
7
6
|
import "./generated/b2d";
|
|
8
7
|
import "./generated/buffer";
|
|
@@ -12,6 +11,7 @@ import "./generated/collectionproxy";
|
|
|
12
11
|
import "./generated/crash";
|
|
13
12
|
import "./generated/factory";
|
|
14
13
|
import "./generated/go";
|
|
14
|
+
import "./src/go-overloads";
|
|
15
15
|
import "./generated/graphics";
|
|
16
16
|
import "./generated/gui";
|
|
17
17
|
import "./generated/http";
|
|
@@ -64,5 +64,7 @@ export {
|
|
|
64
64
|
SCRIPT_HOOK_NAMES,
|
|
65
65
|
type ScriptHookName,
|
|
66
66
|
type ScriptHooks,
|
|
67
|
+
type ScriptProperties,
|
|
68
|
+
type ScriptProperty,
|
|
67
69
|
} from "./src/lifecycle";
|
|
68
70
|
export { type WrapOptions, wrapAsAmbientGlobal } from "./src/publish-dts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defold-typescript/types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "TypeScript types for the Defold engine's Lua APIs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
"./render-script": {
|
|
21
21
|
"types": "./generated/kinds/render-script.d.ts"
|
|
22
22
|
},
|
|
23
|
+
"./core-types": {
|
|
24
|
+
"types": "./src/core-types.ts"
|
|
25
|
+
},
|
|
23
26
|
"./package.json": "./package.json"
|
|
24
27
|
},
|
|
25
28
|
"files": [
|
|
@@ -39,7 +42,8 @@
|
|
|
39
42
|
"build": "tsc -p tsconfig.build.json",
|
|
40
43
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
44
|
"regen": "bun scripts/regen.ts",
|
|
42
|
-
"sync-api-docs": "bun scripts/sync-api-docs.ts"
|
|
45
|
+
"sync-api-docs": "bun scripts/sync-api-docs.ts",
|
|
46
|
+
"ref-doc-delta": "bun scripts/ref-doc-delta.ts --target defold-1.9.8 --namespace label --present label.get_text --absent label.set_text"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@typescript-to-lua/language-extensions": "1.19.0"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import type { TranslationStore } from "../src/example-store";
|
|
4
|
+
|
|
5
|
+
// Build-time only: lives under `scripts/` (never reachable from the shipped
|
|
6
|
+
// `src/index.ts` graph) so its `node:fs` import cannot leak into a consumer's
|
|
7
|
+
// typecheck. `src/example-store.ts` stays pure for exactly that reason.
|
|
8
|
+
const TRANSLATIONS_PATH = resolve(import.meta.dir, "..", "examples", "translations.json");
|
|
9
|
+
|
|
10
|
+
export function loadTranslations(path: string = TRANSLATIONS_PATH): TranslationStore {
|
|
11
|
+
let raw: string;
|
|
12
|
+
try {
|
|
13
|
+
raw = readFileSync(path, "utf8");
|
|
14
|
+
} catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
return JSON.parse(raw) as TranslationStore;
|
|
18
|
+
}
|
|
@@ -5,8 +5,11 @@ import {
|
|
|
5
5
|
buildTableDocResolver,
|
|
6
6
|
HOMOGENEOUS_ARRAY_SLOTS,
|
|
7
7
|
MAPPING_TABLE_SLOTS,
|
|
8
|
+
type NestedMapping,
|
|
8
9
|
parseTableFields,
|
|
9
10
|
recoverCallbackSignature,
|
|
11
|
+
TABLE_SLOT_CURATIONS,
|
|
12
|
+
type TableSlotCuration,
|
|
10
13
|
TS_IDENTIFIER,
|
|
11
14
|
} from "../src/emit-dts";
|
|
12
15
|
import { parseMessagesDoc } from "../src/emit-messages";
|
|
@@ -113,6 +116,7 @@ function auditEntry(
|
|
|
113
116
|
arbitraryTable = false,
|
|
114
117
|
mappingSlot?: { key: string; value: string },
|
|
115
118
|
homogeneousElement?: string | readonly string[],
|
|
119
|
+
tableSlotCuration?: TableSlotCuration,
|
|
116
120
|
) => {
|
|
117
121
|
for (const token of types) {
|
|
118
122
|
// A `table` slot whose doc carries a parseable `<dl>` field list is
|
|
@@ -127,6 +131,29 @@ function auditEntry(
|
|
|
127
131
|
// the curated key/value tokens — not a `Record`, so don't count it.
|
|
128
132
|
// Feed the curated tokens back through considerTypes so an unmapped one
|
|
129
133
|
// still surfaces under unknownTokens (none today: hash/node/vector3 map).
|
|
134
|
+
if (tableSlotCuration?.kind === "mapping") {
|
|
135
|
+
// A single-token value feeds straight back; an object-valued mapping
|
|
136
|
+
// (`LuaMap<K, { … }>`) feeds the key plus each curated field type, the
|
|
137
|
+
// same way the object branch does; a nested-mapping value
|
|
138
|
+
// (`LuaMap<K, LuaMap<K, V>>`) feeds the outer key plus the inner
|
|
139
|
+
// key/value tokens — so an unmapped token in any arm still surfaces.
|
|
140
|
+
if (typeof tableSlotCuration.value === "string") {
|
|
141
|
+
considerTypes([tableSlotCuration.key, tableSlotCuration.value]);
|
|
142
|
+
} else if (Array.isArray(tableSlotCuration.value)) {
|
|
143
|
+
considerTypes([tableSlotCuration.key]);
|
|
144
|
+
for (const field of tableSlotCuration.value) {
|
|
145
|
+
if (field.fields !== undefined) {
|
|
146
|
+
for (const nested of field.fields) considerTypes(nested.types);
|
|
147
|
+
} else if (field.numberList !== true) {
|
|
148
|
+
considerTypes(field.types);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
const nested = tableSlotCuration.value as NestedMapping;
|
|
153
|
+
considerTypes([tableSlotCuration.key, nested.key, nested.value]);
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
130
157
|
if (mappingSlot !== undefined) {
|
|
131
158
|
considerTypes([mappingSlot.key, mappingSlot.value]);
|
|
132
159
|
continue;
|
|
@@ -136,6 +163,24 @@ function auditEntry(
|
|
|
136
163
|
// `Record`, so don't count it. Feed the curated token(s) back through
|
|
137
164
|
// considerTypes so an unmapped one still surfaces under unknownTokens
|
|
138
165
|
// (none today: number/hash/string/url map).
|
|
166
|
+
if (tableSlotCuration?.kind === "array") {
|
|
167
|
+
considerTypes(
|
|
168
|
+
typeof tableSlotCuration.element === "string"
|
|
169
|
+
? [tableSlotCuration.element]
|
|
170
|
+
: tableSlotCuration.element,
|
|
171
|
+
);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (tableSlotCuration?.kind === "object" || tableSlotCuration?.kind === "array-object") {
|
|
175
|
+
for (const field of tableSlotCuration.fields) {
|
|
176
|
+
if (field.fields !== undefined) {
|
|
177
|
+
for (const nested of field.fields) considerTypes(nested.types);
|
|
178
|
+
} else if (field.numberList !== true) {
|
|
179
|
+
considerTypes(field.types);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
139
184
|
if (homogeneousElement !== undefined) {
|
|
140
185
|
considerTypes(
|
|
141
186
|
typeof homogeneousElement === "string" ? [homogeneousElement] : homogeneousElement,
|
|
@@ -236,26 +281,37 @@ function auditEntry(
|
|
|
236
281
|
const homogeneousElement =
|
|
237
282
|
typeof element.name === "string" ? HOMOGENEOUS_ARRAY_SLOTS.get(element.name) : undefined;
|
|
238
283
|
params.forEach((param, index) => {
|
|
284
|
+
const tableSlotCuration =
|
|
285
|
+
typeof element.name === "string" && typeof param.name === "string"
|
|
286
|
+
? TABLE_SLOT_CURATIONS.get(tableSlotKey(element.name, "param", param.name))
|
|
287
|
+
: undefined;
|
|
239
288
|
considerTypes(
|
|
240
289
|
stringArray(param.types),
|
|
241
290
|
docString(param.doc),
|
|
242
291
|
arbitraryTable,
|
|
243
292
|
mappingSlot,
|
|
244
293
|
homogeneousElement,
|
|
294
|
+
tableSlotCuration,
|
|
245
295
|
);
|
|
246
296
|
// Residual: a doc-optional param the emitter cannot mark `?` because a
|
|
247
297
|
// required param follows it. The trailing-run cutoff must match
|
|
248
298
|
// emit-dts so the gate and the emitted surface agree.
|
|
249
299
|
if (isDocOptional(param) && index < cutoff) optionalAsRequired += 1;
|
|
250
300
|
});
|
|
251
|
-
for (const ret of returns)
|
|
301
|
+
for (const ret of returns) {
|
|
302
|
+
const tableSlotCuration =
|
|
303
|
+
typeof element.name === "string" && typeof ret.name === "string"
|
|
304
|
+
? TABLE_SLOT_CURATIONS.get(tableSlotKey(element.name, "return", ret.name))
|
|
305
|
+
: undefined;
|
|
252
306
|
considerTypes(
|
|
253
307
|
stringArray(ret.types),
|
|
254
308
|
docString(ret.doc),
|
|
255
309
|
arbitraryTable,
|
|
256
310
|
mappingSlot,
|
|
257
311
|
homogeneousElement,
|
|
312
|
+
tableSlotCuration,
|
|
258
313
|
);
|
|
314
|
+
}
|
|
259
315
|
}
|
|
260
316
|
|
|
261
317
|
return {
|
|
@@ -274,6 +330,10 @@ function stripNamespace(name: string): string {
|
|
|
274
330
|
return index === -1 ? name : name.slice(index + 1);
|
|
275
331
|
}
|
|
276
332
|
|
|
333
|
+
function tableSlotKey(elementName: string, slotKind: "param" | "return", slotName: string): string {
|
|
334
|
+
return `${elementName}:${slotKind}:${slotName}`;
|
|
335
|
+
}
|
|
336
|
+
|
|
277
337
|
export function buildFidelityReport(
|
|
278
338
|
manifest: readonly ModuleManifestEntry[] = MODULE_MANIFEST,
|
|
279
339
|
): Record<string, FidelityEntry> {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"collectionfactory": {
|
|
27
27
|
"droppedElements": 0,
|
|
28
28
|
"unknownTokens": [],
|
|
29
|
-
"recordTables":
|
|
29
|
+
"recordTables": 1,
|
|
30
30
|
"multiReturn": 0,
|
|
31
31
|
"droppedMembers": 0,
|
|
32
32
|
"optionalAsRequired": 0
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"unknownTokens": [],
|
|
61
61
|
"recordTables": 2,
|
|
62
62
|
"multiReturn": 0,
|
|
63
|
-
"droppedMembers":
|
|
63
|
+
"droppedMembers": 3,
|
|
64
64
|
"optionalAsRequired": 0
|
|
65
65
|
},
|
|
66
66
|
"graphics": {
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"iac": {
|
|
91
91
|
"droppedElements": 0,
|
|
92
92
|
"unknownTokens": [],
|
|
93
|
-
"recordTables":
|
|
93
|
+
"recordTables": 0,
|
|
94
94
|
"multiReturn": 0,
|
|
95
95
|
"droppedMembers": 0,
|
|
96
96
|
"optionalAsRequired": 0
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"iap": {
|
|
99
99
|
"droppedElements": 0,
|
|
100
100
|
"unknownTokens": [],
|
|
101
|
-
"recordTables":
|
|
101
|
+
"recordTables": 0,
|
|
102
102
|
"multiReturn": 0,
|
|
103
103
|
"droppedMembers": 0,
|
|
104
104
|
"optionalAsRequired": 0
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"liveupdate": {
|
|
131
131
|
"droppedElements": 0,
|
|
132
132
|
"unknownTokens": [],
|
|
133
|
-
"recordTables":
|
|
133
|
+
"recordTables": 0,
|
|
134
134
|
"multiReturn": 0,
|
|
135
135
|
"droppedMembers": 0,
|
|
136
136
|
"optionalAsRequired": 0
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"model": {
|
|
139
139
|
"droppedElements": 0,
|
|
140
140
|
"unknownTokens": [],
|
|
141
|
-
"recordTables":
|
|
141
|
+
"recordTables": 0,
|
|
142
142
|
"multiReturn": 0,
|
|
143
143
|
"droppedMembers": 0,
|
|
144
144
|
"optionalAsRequired": 0
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"physics": {
|
|
163
163
|
"droppedElements": 0,
|
|
164
164
|
"unknownTokens": [],
|
|
165
|
-
"recordTables":
|
|
165
|
+
"recordTables": 3,
|
|
166
166
|
"multiReturn": 0,
|
|
167
167
|
"droppedMembers": 0,
|
|
168
168
|
"optionalAsRequired": 0
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"push": {
|
|
179
179
|
"droppedElements": 0,
|
|
180
180
|
"unknownTokens": [],
|
|
181
|
-
"recordTables":
|
|
181
|
+
"recordTables": 0,
|
|
182
182
|
"multiReturn": 0,
|
|
183
183
|
"droppedMembers": 0,
|
|
184
184
|
"optionalAsRequired": 0
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
"socket": {
|
|
203
203
|
"droppedElements": 0,
|
|
204
204
|
"unknownTokens": [],
|
|
205
|
-
"recordTables":
|
|
205
|
+
"recordTables": 4,
|
|
206
206
|
"multiReturn": 0,
|
|
207
207
|
"droppedMembers": 0,
|
|
208
208
|
"optionalAsRequired": 0
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
"tilemap": {
|
|
235
235
|
"droppedElements": 0,
|
|
236
236
|
"unknownTokens": [],
|
|
237
|
-
"recordTables":
|
|
237
|
+
"recordTables": 0,
|
|
238
238
|
"multiReturn": 0,
|
|
239
239
|
"droppedMembers": 0,
|
|
240
240
|
"optionalAsRequired": 0
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { parseDefoldApiDoc } from "../src/api-doc";
|
|
2
|
+
import {
|
|
3
|
+
type ApiTarget,
|
|
4
|
+
loadApiTargets,
|
|
5
|
+
type ResolveTargetOptions,
|
|
6
|
+
resolveTargetModules,
|
|
7
|
+
} from "./regen";
|
|
8
|
+
|
|
9
|
+
export interface RefDocDeltaArgs {
|
|
10
|
+
target: string;
|
|
11
|
+
namespace: string;
|
|
12
|
+
present: string[];
|
|
13
|
+
absent: string[];
|
|
14
|
+
json: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface RefDocDeltaReport {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
targetId: string;
|
|
20
|
+
version: string;
|
|
21
|
+
namespace: string;
|
|
22
|
+
provenance: string | null;
|
|
23
|
+
missingPresent: string[];
|
|
24
|
+
unexpectedPresent: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface VerifyRefDocDeltaInput {
|
|
28
|
+
target: ApiTarget;
|
|
29
|
+
namespace: string;
|
|
30
|
+
present: readonly string[];
|
|
31
|
+
absent: readonly string[];
|
|
32
|
+
resolveOpts?: ResolveTargetOptions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function collectElementNames(doc: unknown): Set<string> {
|
|
36
|
+
const module = parseDefoldApiDoc(doc);
|
|
37
|
+
const names = new Set<string>([module.namespace]);
|
|
38
|
+
for (const collection of [
|
|
39
|
+
module.functions,
|
|
40
|
+
module.constants,
|
|
41
|
+
module.variables,
|
|
42
|
+
module.properties,
|
|
43
|
+
]) {
|
|
44
|
+
for (const item of collection) {
|
|
45
|
+
if (item.name.length > 0) names.add(item.name);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return names;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function parseRefDocDeltaArgs(argv: readonly string[]): RefDocDeltaArgs {
|
|
52
|
+
const args: RefDocDeltaArgs = { target: "", namespace: "", present: [], absent: [], json: false };
|
|
53
|
+
for (let i = 0; i < argv.length; i++) {
|
|
54
|
+
const arg = argv[i];
|
|
55
|
+
if (arg === "--json") {
|
|
56
|
+
args.json = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (arg === "--target" || arg === "--namespace" || arg === "--present" || arg === "--absent") {
|
|
60
|
+
const value = argv[++i];
|
|
61
|
+
if (!value) throw new Error(`${arg} requires a value`);
|
|
62
|
+
if (arg === "--target") args.target = value;
|
|
63
|
+
else if (arg === "--namespace") args.namespace = value;
|
|
64
|
+
else if (arg === "--present") args.present.push(value);
|
|
65
|
+
else args.absent.push(value);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`unknown argument: ${arg}`);
|
|
69
|
+
}
|
|
70
|
+
if (!args.target) throw new Error("--target is required");
|
|
71
|
+
if (!args.namespace) throw new Error("--namespace is required");
|
|
72
|
+
if (args.present.length === 0 && args.absent.length === 0) {
|
|
73
|
+
throw new Error("at least one --present or --absent assertion is required");
|
|
74
|
+
}
|
|
75
|
+
return args;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function selectRefDocDeltaTarget(
|
|
79
|
+
targets: readonly ApiTarget[],
|
|
80
|
+
targetId: string,
|
|
81
|
+
): ApiTarget {
|
|
82
|
+
const target = targets.find((item) => item.id === targetId);
|
|
83
|
+
if (!target) throw new Error(`target "${targetId}" not found`);
|
|
84
|
+
if ((target.source ?? null)?.kind !== "ref-doc") {
|
|
85
|
+
throw new Error(`target "${targetId}" is not ref-doc sourced`);
|
|
86
|
+
}
|
|
87
|
+
return target;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function verifyRefDocDelta(input: VerifyRefDocDeltaInput): Promise<RefDocDeltaReport> {
|
|
91
|
+
const source = input.target.source ?? null;
|
|
92
|
+
if (source?.kind !== "ref-doc") {
|
|
93
|
+
throw new Error(`target "${input.target.id}" is not ref-doc sourced`);
|
|
94
|
+
}
|
|
95
|
+
const modules = await resolveTargetModules(input.target, input.resolveOpts);
|
|
96
|
+
const module = modules.find((entry) => entry.namespace === input.namespace);
|
|
97
|
+
if (!module) {
|
|
98
|
+
throw new Error(`target "${input.target.id}" has no namespace "${input.namespace}"`);
|
|
99
|
+
}
|
|
100
|
+
const names = collectElementNames(module.doc);
|
|
101
|
+
const missingPresent = input.present.filter((name) => !names.has(name));
|
|
102
|
+
const unexpectedPresent = input.absent.filter((name) => names.has(name));
|
|
103
|
+
return {
|
|
104
|
+
ok: missingPresent.length === 0 && unexpectedPresent.length === 0,
|
|
105
|
+
targetId: input.target.id,
|
|
106
|
+
version: source.version,
|
|
107
|
+
namespace: input.namespace,
|
|
108
|
+
provenance: module.sourceProvenance ?? null,
|
|
109
|
+
missingPresent,
|
|
110
|
+
unexpectedPresent,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function renderPlainReport(report: RefDocDeltaReport): string {
|
|
115
|
+
const lines = [
|
|
116
|
+
`${report.ok ? "ok" : "drift"}: ${report.targetId}/${report.namespace} (${report.version}, ${report.provenance ?? "unknown"})`,
|
|
117
|
+
];
|
|
118
|
+
if (report.missingPresent.length > 0) {
|
|
119
|
+
lines.push(`missing expected present: ${report.missingPresent.join(", ")}`);
|
|
120
|
+
}
|
|
121
|
+
if (report.unexpectedPresent.length > 0) {
|
|
122
|
+
lines.push(`unexpected expected absent: ${report.unexpectedPresent.join(", ")}`);
|
|
123
|
+
}
|
|
124
|
+
return lines.join("\n");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (import.meta.main) {
|
|
128
|
+
try {
|
|
129
|
+
const args = parseRefDocDeltaArgs(process.argv.slice(2));
|
|
130
|
+
const target = selectRefDocDeltaTarget(loadApiTargets(), args.target);
|
|
131
|
+
const report = await verifyRefDocDelta({
|
|
132
|
+
target,
|
|
133
|
+
namespace: args.namespace,
|
|
134
|
+
present: args.present,
|
|
135
|
+
absent: args.absent,
|
|
136
|
+
});
|
|
137
|
+
console.log(args.json ? JSON.stringify(report, null, 2) : renderPlainReport(report));
|
|
138
|
+
if (!report.ok) process.exitCode = 1;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
141
|
+
process.exitCode = 1;
|
|
142
|
+
}
|
|
143
|
+
}
|
package/scripts/regen.ts
CHANGED
|
@@ -4,8 +4,15 @@ import messagesDoc from "../fixtures/messages_doc.json" with { type: "json" };
|
|
|
4
4
|
import { parseDefoldApiDoc } from "../src/api-doc";
|
|
5
5
|
import { emitDeclarations } from "../src/emit-dts";
|
|
6
6
|
import { emitBuiltinMessages, parseMessagesDoc } from "../src/emit-messages";
|
|
7
|
+
import type { TranslationStore } from "../src/example-store";
|
|
7
8
|
import { wrapAsAmbientGlobal } from "../src/publish-dts";
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
type DocSourceProvenance,
|
|
11
|
+
type DownloadRefDoc,
|
|
12
|
+
refDocCacheDir,
|
|
13
|
+
resolveRefDoc,
|
|
14
|
+
} from "./doc-source";
|
|
15
|
+
import { loadTranslations } from "./example-store-io";
|
|
9
16
|
import { type readZip, SYNC_MANIFEST, type SyncManifestEntry } from "./sync-api-docs";
|
|
10
17
|
|
|
11
18
|
export interface ApiTargetModule {
|
|
@@ -73,6 +80,7 @@ export interface ModuleManifestEntry {
|
|
|
73
80
|
readonly outFile: string;
|
|
74
81
|
readonly skipFunctions?: readonly string[];
|
|
75
82
|
readonly importsFrom?: string;
|
|
83
|
+
readonly sourceProvenance?: DocSourceProvenance;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
export interface ResolveTargetOptions {
|
|
@@ -95,7 +103,7 @@ export async function resolveTargetModules(
|
|
|
95
103
|
if (source == null) {
|
|
96
104
|
return loadTargetModules(target, opts.packageRoot);
|
|
97
105
|
}
|
|
98
|
-
const { zip } = await resolveRefDoc({
|
|
106
|
+
const { zip, provenance } = await resolveRefDoc({
|
|
99
107
|
version: source.version,
|
|
100
108
|
cacheDir: opts.cacheDir ?? refDocCacheDir(),
|
|
101
109
|
...(opts.download ? { download: opts.download } : {}),
|
|
@@ -114,6 +122,7 @@ export async function resolveTargetModules(
|
|
|
114
122
|
doc: JSON.parse(zip.read(sync.zipEntry)),
|
|
115
123
|
outFile: module.outFile,
|
|
116
124
|
importsFrom: target.coreTypesImport,
|
|
125
|
+
sourceProvenance: provenance,
|
|
117
126
|
};
|
|
118
127
|
return module.skipFunctions ? { ...entry, skipFunctions: module.skipFunctions } : entry;
|
|
119
128
|
});
|
|
@@ -159,6 +168,7 @@ export function collectConstantFqns(
|
|
|
159
168
|
|
|
160
169
|
export interface GenerateOptions {
|
|
161
170
|
knownConstantFqns?: ReadonlySet<string>;
|
|
171
|
+
translations?: TranslationStore;
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
export function generateModuleDeclaration(
|
|
@@ -178,7 +188,8 @@ export function generateModuleDeclaration(
|
|
|
178
188
|
return true;
|
|
179
189
|
});
|
|
180
190
|
const knownConstantFqns = options?.knownConstantFqns ?? collectConstantFqns();
|
|
181
|
-
const
|
|
191
|
+
const translations = options?.translations ?? loadTranslations();
|
|
192
|
+
const emitted = emitDeclarations(module, { knownConstantFqns, translations });
|
|
182
193
|
const contents = wrapAsAmbientGlobal({
|
|
183
194
|
namespace: module.namespace,
|
|
184
195
|
emitted,
|
|
@@ -208,6 +219,7 @@ export const RESTRICTED_NAMESPACES: Readonly<Record<string, string>> = {
|
|
|
208
219
|
|
|
209
220
|
const UNIVERSAL_EXTRA_IMPORTS: readonly string[] = [
|
|
210
221
|
"../builtin-messages",
|
|
222
|
+
"../../src/engine-globals",
|
|
211
223
|
"../../src/msg-overloads",
|
|
212
224
|
"../../src/message-guard",
|
|
213
225
|
"../../src/go-overloads",
|
|
@@ -216,12 +228,13 @@ const UNIVERSAL_EXTRA_IMPORTS: readonly string[] = [
|
|
|
216
228
|
export interface KindManifestEntry {
|
|
217
229
|
readonly kind: string;
|
|
218
230
|
readonly restricted?: string;
|
|
231
|
+
readonly factory: string;
|
|
219
232
|
}
|
|
220
233
|
|
|
221
234
|
export const KIND_MODULE_MANIFEST: readonly KindManifestEntry[] = [
|
|
222
|
-
{ kind: "script" },
|
|
223
|
-
{ kind: "gui-script", restricted: "gui" },
|
|
224
|
-
{ kind: "render-script", restricted: "render" },
|
|
235
|
+
{ kind: "script", factory: "defineScript" },
|
|
236
|
+
{ kind: "gui-script", restricted: "gui", factory: "defineGuiScript" },
|
|
237
|
+
{ kind: "render-script", restricted: "render", factory: "defineRenderScript" },
|
|
225
238
|
];
|
|
226
239
|
|
|
227
240
|
export function generateKindIndex(kind: string): string {
|
|
@@ -230,11 +243,11 @@ export function generateKindIndex(kind: string): string {
|
|
|
230
243
|
const universalNamespaces = MODULE_MANIFEST.filter(
|
|
231
244
|
(m) => !Object.hasOwn(RESTRICTED_NAMESPACES, m.namespace),
|
|
232
245
|
).map((m) => `../${m.outFile.replace(/\.d\.ts$/, "")}`);
|
|
233
|
-
const lines = [
|
|
234
|
-
.sort()
|
|
235
|
-
|
|
246
|
+
const lines = [
|
|
247
|
+
...new Set([...universalNamespaces.sort(), ...[...UNIVERSAL_EXTRA_IMPORTS].sort()]),
|
|
248
|
+
].map((path) => `import "${path}";`);
|
|
236
249
|
if (entry.restricted) lines.push(`import "../${entry.restricted}";`);
|
|
237
|
-
return `${lines.join("\n")}\n\nexport {};\n`;
|
|
250
|
+
return `${lines.join("\n")}\n\nexport { ${entry.factory} } from "../../src/lifecycle";\nexport type { ScriptProperties, ScriptProperty } from "../../src/lifecycle";\n`;
|
|
238
251
|
}
|
|
239
252
|
|
|
240
253
|
export function generateVersionIndex(
|
package/src/core-types.ts
CHANGED
|
@@ -78,6 +78,20 @@ export interface Hash {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
declare const OpaqueBrand: unique symbol;
|
|
81
|
+
/**
|
|
82
|
+
* A nominal handle to an engine value you may hold and pass back to the API but
|
|
83
|
+
* must never inspect or construct — a Defold `node`, `texture`, `render_target`,
|
|
84
|
+
* `userdata`, etc. The `Name` parameter mints a distinct, mutually-incompatible
|
|
85
|
+
* brand per kind, so TypeScript's structural typing can't silently swap a
|
|
86
|
+
* `render_target` for a `constant`, and a plain object can't stand in for either.
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* The brand is a phantom `unique symbol` property: it exists only in the type
|
|
90
|
+
* system (erased at transpile, never present at runtime). Because the symbol is
|
|
91
|
+
* not exported, consumer code cannot fabricate an `Opaque` — the engine API is
|
|
92
|
+
* the only source. Contrast with a `LuaTable` alias, which says the opposite:
|
|
93
|
+
* "inspect freely, the shape just isn't modeled."
|
|
94
|
+
*/
|
|
81
95
|
export interface Opaque<Name extends string> {
|
|
82
96
|
readonly [OpaqueBrand]: Name;
|
|
83
97
|
}
|
package/src/doc-comment.ts
CHANGED
|
@@ -73,6 +73,7 @@ export interface DocCommentParts {
|
|
|
73
73
|
params?: { name: string; doc: string }[];
|
|
74
74
|
returns?: string;
|
|
75
75
|
example?: string;
|
|
76
|
+
exampleLang?: "lua" | "ts";
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
/**
|
|
@@ -115,7 +116,7 @@ export function renderDocComment(parts: DocCommentParts): string[] {
|
|
|
115
116
|
}
|
|
116
117
|
if (example !== "") {
|
|
117
118
|
lines.push(" * @example");
|
|
118
|
-
lines.push(
|
|
119
|
+
lines.push(` * \`\`\`${parts.exampleLang ?? "lua"}`);
|
|
119
120
|
for (const line of example.split("\n")) {
|
|
120
121
|
lines.push(line === "" ? " *" : ` * ${line}`);
|
|
121
122
|
}
|