@defold-typescript/types 0.38.0 → 0.40.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-availability.json +117 -0
- package/api-signatures.json +586 -480
- package/examples/translations.json +356 -180
- package/generated/b2d_body.d.ts +7 -4
- package/generated/b2d_shape.d.ts +23 -1
- package/generated/buffer.d.ts +34 -19
- package/generated/camera.d.ts +3 -2
- package/generated/collectionfactory.d.ts +17 -12
- package/generated/collectionproxy.d.ts +2 -2
- package/generated/compute.d.ts +1 -1
- package/generated/factory.d.ts +2 -1
- package/generated/go.d.ts +150 -91
- package/generated/graphics.d.ts +54 -0
- package/generated/gui.d.ts +117 -71
- package/generated/html5.d.ts +4 -2
- package/generated/http.d.ts +8 -2
- package/generated/image.d.ts +24 -15
- package/generated/kinds/gui-script.d.ts +1 -0
- package/generated/kinds/render-script.d.ts +1 -0
- package/generated/kinds/script.d.ts +1 -0
- package/generated/material.d.ts +1 -1
- package/generated/model.d.ts +41 -7
- package/generated/particlefx.d.ts +1 -1
- package/generated/physics.d.ts +29 -20
- package/generated/profiler.d.ts +10 -3
- package/generated/render.d.ts +293 -111
- package/generated/resource.d.ts +243 -226
- package/generated/socket.d.ts +33 -18
- package/generated/sound.d.ts +6 -5
- package/generated/sprite.d.ts +9 -1
- package/generated/sys.d.ts +44 -27
- package/generated/tilemap.d.ts +25 -19
- package/generated/timer.d.ts +33 -24
- package/generated/versions/defold-1.12.4/buffer.d.ts +34 -19
- package/generated/versions/defold-1.12.4/camera.d.ts +3 -2
- package/generated/versions/defold-1.12.4/collectionfactory.d.ts +17 -12
- package/generated/versions/defold-1.12.4/collectionproxy.d.ts +1 -1
- package/generated/versions/defold-1.12.4/factory.d.ts +2 -1
- package/generated/versions/defold-1.12.4/go.d.ts +150 -91
- package/generated/versions/defold-1.12.4/graphics.d.ts +2 -0
- package/generated/versions/defold-1.12.4/gui.d.ts +109 -69
- package/generated/versions/defold-1.12.4/html5.d.ts +4 -2
- package/generated/versions/defold-1.12.4/http.d.ts +8 -2
- package/generated/versions/defold-1.12.4/image.d.ts +24 -15
- package/generated/versions/defold-1.12.4/index.d.ts +1 -0
- package/generated/versions/defold-1.12.4/model.d.ts +41 -7
- package/generated/versions/defold-1.12.4/particlefx.d.ts +1 -1
- package/generated/versions/defold-1.12.4/physics.d.ts +29 -20
- package/generated/versions/defold-1.12.4/profiler.d.ts +10 -3
- package/generated/versions/defold-1.12.4/render.d.ts +292 -110
- package/generated/versions/defold-1.12.4/resource.d.ts +243 -226
- package/generated/versions/defold-1.12.4/socket.d.ts +33 -18
- package/generated/versions/defold-1.12.4/sound.d.ts +6 -5
- package/generated/versions/defold-1.12.4/sprite.d.ts +9 -1
- package/generated/versions/defold-1.12.4/sys.d.ts +44 -27
- package/generated/versions/defold-1.12.4/tilemap.d.ts +25 -19
- package/generated/versions/defold-1.12.4/timer.d.ts +33 -24
- package/generated/versions/defold-1.12.4/vmath.d.ts +18 -10
- package/generated/versions/defold-1.12.4/window.d.ts +5 -3
- package/generated/versions/defold-1.13.0/b2d_body.d.ts +7 -4
- package/generated/versions/defold-1.13.0/b2d_shape.d.ts +23 -1
- package/generated/versions/defold-1.13.0/buffer.d.ts +34 -19
- package/generated/versions/defold-1.13.0/camera.d.ts +3 -2
- package/generated/versions/defold-1.13.0/collectionfactory.d.ts +17 -12
- package/generated/versions/defold-1.13.0/collectionproxy.d.ts +1 -1
- package/generated/versions/defold-1.13.0/compute.d.ts +1 -1
- package/generated/versions/defold-1.13.0/factory.d.ts +2 -1
- package/generated/versions/defold-1.13.0/go.d.ts +150 -91
- package/generated/versions/defold-1.13.0/graphics.d.ts +50 -0
- package/generated/versions/defold-1.13.0/gui.d.ts +109 -69
- package/generated/versions/defold-1.13.0/html5.d.ts +4 -2
- package/generated/versions/defold-1.13.0/http.d.ts +8 -2
- package/generated/versions/defold-1.13.0/image.d.ts +24 -15
- package/generated/versions/defold-1.13.0/index.d.ts +1 -0
- package/generated/versions/defold-1.13.0/material.d.ts +1 -1
- package/generated/versions/defold-1.13.0/model.d.ts +41 -7
- package/generated/versions/defold-1.13.0/particlefx.d.ts +1 -1
- package/generated/versions/defold-1.13.0/physics.d.ts +29 -20
- package/generated/versions/defold-1.13.0/profiler.d.ts +10 -3
- package/generated/versions/defold-1.13.0/render.d.ts +293 -111
- package/generated/versions/defold-1.13.0/resource.d.ts +243 -226
- package/generated/versions/defold-1.13.0/socket.d.ts +33 -18
- package/generated/versions/defold-1.13.0/sound.d.ts +6 -5
- package/generated/versions/defold-1.13.0/sprite.d.ts +9 -1
- package/generated/versions/defold-1.13.0/sys.d.ts +44 -27
- package/generated/versions/defold-1.13.0/tilemap.d.ts +25 -19
- package/generated/versions/defold-1.13.0/timer.d.ts +33 -24
- package/generated/versions/defold-1.13.0/vmath.d.ts +18 -10
- package/generated/versions/defold-1.13.0/window.d.ts +5 -3
- package/generated/vmath.d.ts +18 -10
- package/generated/window.d.ts +5 -3
- package/index.d.ts +1 -0
- package/package.json +2 -1
- package/scripts/generate-api-signatures.ts +2 -1
- package/scripts/prose-constants.ts +96 -0
- package/scripts/regen.ts +6 -2
- package/src/api-doc.ts +8 -0
- package/src/component-properties.d.ts +33 -0
- package/src/core-types.ts +4 -2
- package/src/custom-messages.d.ts +4 -3
- package/src/doc-comment.ts +247 -43
- package/src/emit-dts.ts +958 -57
- package/src/engine-globals.d.ts +2 -2
- package/src/example-store.ts +26 -0
- package/src/go-overloads.d.ts +11 -10
- package/src/index.ts +9 -0
- package/src/param-correction-provenance.ts +67 -0
- package/src/render-overloads.d.ts +15 -17
- package/src/script-api.ts +3 -1
package/src/emit-dts.ts
CHANGED
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
htmlToCodeText,
|
|
14
14
|
htmlToDocText,
|
|
15
15
|
renderDocComment,
|
|
16
|
+
splitExampleSources,
|
|
16
17
|
} from "./doc-comment";
|
|
17
18
|
import type { TranslationStore } from "./example-store";
|
|
18
|
-
import { hashExampleSource, lookupTranslation } from "./example-store";
|
|
19
|
+
import { hashExampleSource, lookupExampleTranslations, lookupTranslation } from "./example-store";
|
|
19
20
|
import { classifyUrlParameter, type UrlParameterTable } from "./url-parameters";
|
|
20
21
|
|
|
21
22
|
export interface EmitOptions {
|
|
@@ -130,6 +131,8 @@ export const ARBITRARY_TABLE_SLOTS = new Set([
|
|
|
130
131
|
// names; bare `on_message`'s receive `message` is the pre-hashed, user-routed
|
|
131
132
|
// payload (mitigated for authored code by isMessage/onMessage). No static shape
|
|
132
133
|
// exists, so `Record<string | number, unknown>` is faithful, not a loss.
|
|
134
|
+
// collectionfactory.create curates the instance-id layer of `properties` as a
|
|
135
|
+
// mapping; each per-instance property table stays that faithful `Record`.
|
|
133
136
|
"factory.create",
|
|
134
137
|
"collectionfactory.create",
|
|
135
138
|
"on_message",
|
|
@@ -253,6 +256,16 @@ export const RETURN_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
|
253
256
|
// ref-doc. Upstream adding `nil` to `types` hands the case to the top-level
|
|
254
257
|
// `nil` projection in `mapSlotUnion` and reds the entry, which is then deleted
|
|
255
258
|
// rather than re-pinned.
|
|
259
|
+
//
|
|
260
|
+
// The same table holds a `function` return whose prose documents the returned
|
|
261
|
+
// function's contract, which the bare token cannot carry: `socket.protect`'s
|
|
262
|
+
// safe function "returns nil followed by an error message", and
|
|
263
|
+
// `socket.newtry`'s try function returns its first argument when it is truthy
|
|
264
|
+
// and throws otherwise, the LuaSocket contract its example relies on to unwrap
|
|
265
|
+
// `socket.connect`'s `client, err` pair. The try function takes that pair
|
|
266
|
+
// destructured into separate arguments; a boxed `LuaMultiReturn` is rejected
|
|
267
|
+
// because TSTL passes it as one table, which is always truthy. `reason` quotes
|
|
268
|
+
// the slot prose the provenance test searches for, as for the `nil` entries.
|
|
256
269
|
export interface ReturnTypeCorrection {
|
|
257
270
|
readonly ts: string;
|
|
258
271
|
readonly upstream: readonly string[];
|
|
@@ -269,8 +282,193 @@ export const RETURN_TYPE_CORRECTIONS: ReadonlyMap<string, ReturnTypeCorrection>
|
|
|
269
282
|
reason: "the body if successful. Otherwise nil.",
|
|
270
283
|
},
|
|
271
284
|
],
|
|
285
|
+
[
|
|
286
|
+
"socket.protect",
|
|
287
|
+
{
|
|
288
|
+
ts: "(...args: unknown[]) => LuaMultiReturn<[unknown, string | undefined]>",
|
|
289
|
+
upstream: ["function(function())"],
|
|
290
|
+
reason: "returns nil followed by an error message.",
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
[
|
|
294
|
+
"socket.newtry",
|
|
295
|
+
{
|
|
296
|
+
ts: "<T>(value: T | undefined, ...rest: T extends { readonly __tstlMultiReturn: unknown } ? [boxedMultiReturn: never] : unknown[]) => T",
|
|
297
|
+
upstream: ["function"],
|
|
298
|
+
reason: "the customized try function.",
|
|
299
|
+
},
|
|
300
|
+
],
|
|
272
301
|
]);
|
|
273
302
|
|
|
303
|
+
// A parameter whose declared `types` reject what the same element's prose, or
|
|
304
|
+
// an upstream example, demonstrably passes — a render target by resource name,
|
|
305
|
+
// a texture unit, a Lua sequence where `table` is declared. Admission rule: only
|
|
306
|
+
// a slot upstream's own prose or example contradicts; a slot that is merely
|
|
307
|
+
// imprecise is not a candidate. Every such slot is too narrow, never wrong, so
|
|
308
|
+
// `adds` is appended to the mapped union rather than replacing it: the URL
|
|
309
|
+
// address alias, array curation and constant mapping stay live, and optionality
|
|
310
|
+
// stays with `isDocOptional`. Each entry records the upstream tokens it
|
|
311
|
+
// contradicts and `param-correction-provenance.test.ts` pins them against every
|
|
312
|
+
// retained vendored ref-doc. Once no retained target still declares those
|
|
313
|
+
// tokens the entry is deleted, never re-pinned.
|
|
314
|
+
export interface ParamTypeCorrection {
|
|
315
|
+
readonly adds: string;
|
|
316
|
+
readonly upstream: readonly string[];
|
|
317
|
+
readonly reason: string;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Keyed `<element>:param:<slot>` like OPTIONAL_SLOT_CORRECTIONS, so a
|
|
321
|
+
// same-named slot on another element is untouched.
|
|
322
|
+
export const PARAM_TYPE_CORRECTIONS: ReadonlyMap<string, ParamTypeCorrection> = new Map([
|
|
323
|
+
[
|
|
324
|
+
"render.set_render_target:param:render_target",
|
|
325
|
+
{
|
|
326
|
+
adds: "string | Hash | typeof render.RENDER_TARGET_DEFAULT",
|
|
327
|
+
upstream: ["render_target"],
|
|
328
|
+
reason:
|
|
329
|
+
"\"render.RENDER_TARGET_DEFAULT to set the default render target\"; example `render.set_render_target('my_rt_resource')`",
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
[
|
|
333
|
+
"render.get_render_target_width:param:render_target",
|
|
334
|
+
{
|
|
335
|
+
adds: "string | Hash",
|
|
336
|
+
upstream: ["render_target"],
|
|
337
|
+
reason:
|
|
338
|
+
"example `render.get_render_target_width('my_rt_resource', graphics.BUFFER_TYPE_COLOR0_BIT)`",
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
[
|
|
342
|
+
"render.get_render_target_height:param:render_target",
|
|
343
|
+
{
|
|
344
|
+
adds: "string | Hash",
|
|
345
|
+
upstream: ["render_target"],
|
|
346
|
+
reason:
|
|
347
|
+
"example `render.get_render_target_height('my_rt_resource', graphics.BUFFER_TYPE_COLOR0_BIT)`",
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
[
|
|
351
|
+
"render.set_render_target_size:param:render_target",
|
|
352
|
+
{
|
|
353
|
+
adds: "string | Hash",
|
|
354
|
+
upstream: ["render_target"],
|
|
355
|
+
reason:
|
|
356
|
+
"\"a render target created from either a render script, or from a render target resource\"; example `render.set_render_target_size('my_rt_resource', ...)`",
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
[
|
|
360
|
+
"render.enable_texture:param:handle_or_name",
|
|
361
|
+
{
|
|
362
|
+
adds: 'Opaque<"render_target"> | number',
|
|
363
|
+
upstream: ["texture", "string", "hash"],
|
|
364
|
+
reason:
|
|
365
|
+
"\"render target or texture handle that should be bound, or a named resource\"; examples `render.enable_texture(0, self.my_render_target, ...)` and `render.enable_texture(0, 'my_rt_resource', ...)`; `resource.get_texture_info` returns the handle as a number",
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
[
|
|
369
|
+
"render.disable_texture:param:binding",
|
|
370
|
+
{
|
|
371
|
+
adds: "number",
|
|
372
|
+
upstream: ["texture", "string", "hash"],
|
|
373
|
+
reason:
|
|
374
|
+
'"texture binding, either by texture unit, string or hash"; example `render.disable_texture(0)`',
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
[
|
|
378
|
+
"render.set_camera:param:camera",
|
|
379
|
+
{
|
|
380
|
+
adds: "string",
|
|
381
|
+
upstream: ["url", "number", "nil"],
|
|
382
|
+
reason: 'example `render.set_camera("main:/my_go#camera")`',
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
[
|
|
386
|
+
"go.delete:param:id",
|
|
387
|
+
{
|
|
388
|
+
adds: "boolean",
|
|
389
|
+
upstream: ["string", "hash", "url", "table"],
|
|
390
|
+
reason: "example `go.delete(true)` deletes the script game object and its children",
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
[
|
|
394
|
+
"buffer.get_bytes:param:stream_name",
|
|
395
|
+
{
|
|
396
|
+
adds: "string",
|
|
397
|
+
upstream: ["hash"],
|
|
398
|
+
reason: 'sys.load_buffer example `buffer.get_bytes(my_buffer, "data")`',
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
[
|
|
402
|
+
"gui.set:param:value",
|
|
403
|
+
{
|
|
404
|
+
adds: "Matrix4 | Hash",
|
|
405
|
+
upstream: ["number", "vector4", "vector3", "quaternion"],
|
|
406
|
+
reason:
|
|
407
|
+
'example `gui.set(node, "light_matrix", vmath.matrix4())` ("matrix4 is also supported"); example `gui.set(msg.url(), "textures", atlas_id, {key = "runtime_texture"})` passes the hash `resource.create_atlas` returns',
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
[
|
|
411
|
+
"gui.set_rotation:param:rotation",
|
|
412
|
+
{
|
|
413
|
+
adds: "Vector3",
|
|
414
|
+
upstream: ["quaternion", "vector4"],
|
|
415
|
+
reason: "gui.set example `gui.set_rotation(node, vmath.vector3(0,0,45))`",
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
[
|
|
419
|
+
"sys.save:param:table",
|
|
420
|
+
{
|
|
421
|
+
adds: "readonly unknown[]",
|
|
422
|
+
upstream: ["table"],
|
|
423
|
+
reason:
|
|
424
|
+
'example builds `my_table` with `table.insert(my_table, "my_value")` and passes it to `sys.save`',
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
[
|
|
428
|
+
"sys.serialize:param:table",
|
|
429
|
+
{
|
|
430
|
+
adds: "readonly unknown[]",
|
|
431
|
+
upstream: ["table"],
|
|
432
|
+
reason:
|
|
433
|
+
'example builds `my_table` with `table.insert(my_table, "my_value")` and passes it to `sys.serialize`',
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
]);
|
|
437
|
+
|
|
438
|
+
// Parameter doc text whose upstream wording describes Lua rather than the
|
|
439
|
+
// TypeScript a user writes. The transpiler adds one to a literal `options.index`
|
|
440
|
+
// at these calls, so the 1-based wording would tell the author to be off by one.
|
|
441
|
+
// The `.d.ts` emit and the API reference both apply it, and applying it throws
|
|
442
|
+
// when `from` is absent: an upstream rewording fails the build instead of
|
|
443
|
+
// shipping the stale text alongside the lowering.
|
|
444
|
+
export interface ParamDocRewrite {
|
|
445
|
+
readonly from: string;
|
|
446
|
+
readonly to: string;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const ZERO_BASED_INDEX_OPTION_DOC: ParamDocRewrite = {
|
|
450
|
+
from: "index into array property (1 based)",
|
|
451
|
+
to: "zero-based index into array property; the transpiler emits Defold's 1-based index",
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// Keyed `<element>:param:<slot>` like PARAM_TYPE_CORRECTIONS.
|
|
455
|
+
export const PARAM_DOC_REWRITES: ReadonlyMap<string, ParamDocRewrite> = new Map([
|
|
456
|
+
["go.get:param:options", ZERO_BASED_INDEX_OPTION_DOC],
|
|
457
|
+
["go.set:param:options", ZERO_BASED_INDEX_OPTION_DOC],
|
|
458
|
+
["gui.get:param:options", ZERO_BASED_INDEX_OPTION_DOC],
|
|
459
|
+
["gui.set:param:options", ZERO_BASED_INDEX_OPTION_DOC],
|
|
460
|
+
]);
|
|
461
|
+
|
|
462
|
+
export function rewriteParamDoc(elementName: string, slotName: string, doc: string): string {
|
|
463
|
+
const key = tableSlotKey(elementName, "param", slotName);
|
|
464
|
+
const rewrite = PARAM_DOC_REWRITES.get(key);
|
|
465
|
+
if (rewrite === undefined) return doc;
|
|
466
|
+
if (!doc.includes(rewrite.from)) {
|
|
467
|
+
throw new Error(`PARAM_DOC_REWRITES ${key}: upstream doc no longer contains "${rewrite.from}"`);
|
|
468
|
+
}
|
|
469
|
+
return doc.replaceAll(rewrite.from, rewrite.to);
|
|
470
|
+
}
|
|
471
|
+
|
|
274
472
|
// A property whose upstream `<span class="type">` states a type the engine does
|
|
275
473
|
// not use. Unlike every other override here, which fills a gap upstream left
|
|
276
474
|
// empty, these contradict a token upstream explicitly declares — so each entry
|
|
@@ -319,6 +517,26 @@ export const PROPERTY_TYPE_CORRECTIONS: ReadonlyMap<string, PropertyTypeCorrecti
|
|
|
319
517
|
],
|
|
320
518
|
]);
|
|
321
519
|
|
|
520
|
+
// A property upstream names with a placeholder standing for a numbered family of
|
|
521
|
+
// keys, so its literal name is not a key the engine accepts. The emitted members
|
|
522
|
+
// are one literal key per number in `first..last`, each typed like the
|
|
523
|
+
// placeholder. `evidence` is the brief phrase that defines the range;
|
|
524
|
+
// `property-correction-provenance.test.ts` reds when a vendored ref-doc stops
|
|
525
|
+
// saying it, or when the phrase stops stating `first-last`. Curated rather than
|
|
526
|
+
// matched on a trailing `N`, so each new upstream placeholder is a deliberate
|
|
527
|
+
// addition.
|
|
528
|
+
export interface PropertyKeyRange {
|
|
529
|
+
readonly prefix: string;
|
|
530
|
+
readonly first: number;
|
|
531
|
+
readonly last: number;
|
|
532
|
+
readonly evidence: string;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Keyed `<namespace>.<property>`, mirroring PROPERTY_TYPE_CORRECTIONS.
|
|
536
|
+
export const PROPERTY_KEY_RANGES: ReadonlyMap<string, PropertyKeyRange> = new Map([
|
|
537
|
+
["model.textureN", { prefix: "texture", first: 0, last: 7, evidence: "textureN where N is 0-7" }],
|
|
538
|
+
]);
|
|
539
|
+
|
|
322
540
|
// A parameter the ref-doc metadata marks required while the same element's prose
|
|
323
541
|
// or examples show it being omitted. `is_optional` is the only optionality
|
|
324
542
|
// signal the emitter has, and upstream leaves it `False` on slots its own
|
|
@@ -356,11 +574,16 @@ export const OPTIONAL_SLOT_CORRECTIONS: ReadonlyMap<string, string> = new Map([
|
|
|
356
574
|
"b2d.fixture.set_shape:param:update_mass",
|
|
357
575
|
'2 of 3 examples omit it; "The body mass is not updated unless update_mass is true"',
|
|
358
576
|
],
|
|
577
|
+
[
|
|
578
|
+
"b2d.shape.set_shape:param:update_mass",
|
|
579
|
+
'1 of 3 examples omits it; "The body mass is not updated unless update_mass is true"',
|
|
580
|
+
],
|
|
359
581
|
[
|
|
360
582
|
"b2d.shape.ray_cast:param:max_fraction",
|
|
361
583
|
'"optional maximum translation fraction, defaults to 1"',
|
|
362
584
|
],
|
|
363
585
|
["iap.buy:param:options", '"optional parameters as properties"'],
|
|
586
|
+
["socket.newtry:param:finalizer", "socket.protect's example `local try = socket.newtry()`"],
|
|
364
587
|
...(
|
|
365
588
|
[
|
|
366
589
|
"create_distance",
|
|
@@ -382,6 +605,69 @@ export const OPTIONAL_SLOT_CORRECTIONS: ReadonlyMap<string, string> = new Map([
|
|
|
382
605
|
),
|
|
383
606
|
]);
|
|
384
607
|
|
|
608
|
+
// A first slot upstream documents as standing in for a second argument list:
|
|
609
|
+
// every `b2d.shape` function takes a shape handle "or pass `body, shape_index`".
|
|
610
|
+
// The element keeps its declared signature and gains an overload with
|
|
611
|
+
// `parameters` in that slot's place. Keyed `<namespace>:param:<slot>`, so only a
|
|
612
|
+
// curated entry adds an overload: a reworded doc cannot add or drop one, and the
|
|
613
|
+
// same prose in another namespace adds nothing.
|
|
614
|
+
//
|
|
615
|
+
// `evidence` is the upstream slot-doc fragment that names the alternative. The
|
|
616
|
+
// emitter throws once a curated slot stops carrying it, so upstream dropping the
|
|
617
|
+
// alternative reds here rather than shipping an overload nothing documents.
|
|
618
|
+
export interface FirstSlotAlternative {
|
|
619
|
+
readonly parameters: readonly ApiParameter[];
|
|
620
|
+
readonly evidence: string;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export const FIRST_SLOT_ALTERNATIVES: ReadonlyMap<string, FirstSlotAlternative> = new Map([
|
|
624
|
+
[
|
|
625
|
+
"b2d.shape:param:shape_id",
|
|
626
|
+
{
|
|
627
|
+
parameters: [
|
|
628
|
+
{
|
|
629
|
+
name: "body",
|
|
630
|
+
doc: "The body that owns the shape.",
|
|
631
|
+
types: ["b2Body"],
|
|
632
|
+
isOptional: false,
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
name: "shape_index",
|
|
636
|
+
doc: "The shape's 1-based index on that body, as <code>b2d.body.get_shapes</code> lists them.",
|
|
637
|
+
types: ["number"],
|
|
638
|
+
isOptional: false,
|
|
639
|
+
},
|
|
640
|
+
],
|
|
641
|
+
evidence: "or pass <code>body, shape_index</code>",
|
|
642
|
+
},
|
|
643
|
+
],
|
|
644
|
+
]);
|
|
645
|
+
|
|
646
|
+
// The alternative signature FIRST_SLOT_ALTERNATIVES gives `fn`, or null when
|
|
647
|
+
// its first slot is not curated. Shared with the fidelity audit so the arity it
|
|
648
|
+
// measures is the arity the emitter declares.
|
|
649
|
+
export function firstSlotAlternativeOf(fn: ApiFunction, namespace: string): ApiFunction | null {
|
|
650
|
+
const [first, ...rest] = fn.parameters;
|
|
651
|
+
if (first === undefined) return null;
|
|
652
|
+
const key = `${namespace}:param:${first.name}`;
|
|
653
|
+
const alternative = FIRST_SLOT_ALTERNATIVES.get(key);
|
|
654
|
+
if (alternative === undefined) return null;
|
|
655
|
+
if (!first.doc.includes(alternative.evidence)) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
`first-slot alternative ${key}: ${fn.name} no longer documents "${alternative.evidence}"`,
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
return { ...fn, parameters: [...alternative.parameters, ...rest] };
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function firstSlotAlternative(
|
|
664
|
+
prepared: PreparedFunction,
|
|
665
|
+
namespace: string,
|
|
666
|
+
): PreparedFunction | null {
|
|
667
|
+
const original = firstSlotAlternativeOf(prepared.original, namespace);
|
|
668
|
+
return original === null ? null : { ...prepared, original };
|
|
669
|
+
}
|
|
670
|
+
|
|
385
671
|
export type ConstantSlotResolution =
|
|
386
672
|
| { readonly borrow: string }
|
|
387
673
|
| { readonly family: string; readonly evidence: string }
|
|
@@ -415,6 +701,377 @@ export const CONSTANT_SLOT_RESOLUTIONS: ReadonlyMap<string, ConstantSlotResoluti
|
|
|
415
701
|
],
|
|
416
702
|
]);
|
|
417
703
|
|
|
704
|
+
export interface ConstantUnionAlias {
|
|
705
|
+
// The namespace the alias is declared in. It is the namespace the union
|
|
706
|
+
// *means*, which is not always the one its constants live in: the three
|
|
707
|
+
// buffer keys `render.clear` accepts are `graphics.BUFFER_TYPE_*` constants,
|
|
708
|
+
// but the name that reads right at the call site is `render.ClearBufferKey`.
|
|
709
|
+
readonly home: string;
|
|
710
|
+
readonly name: string;
|
|
711
|
+
// In documentation order, which is the order the arms are emitted in today.
|
|
712
|
+
readonly members: readonly string[];
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// A documented constant union gets a public name so a caller can spell the type
|
|
716
|
+
// their own wrapper takes. Identity is the *member set*, never a name prefix:
|
|
717
|
+
// `gui.ANCHOR_*` splits into two rows because the x and y slots accept
|
|
718
|
+
// different thirds of it, and `graphics.BUFFER_TYPE_*` splits because
|
|
719
|
+
// `render.clear` accepts three of the six.
|
|
720
|
+
//
|
|
721
|
+
// The table is the only thing the emitter reads, and every name in it has been
|
|
722
|
+
// reviewed: a longest-common-prefix rule proposes, a human disposes. A union
|
|
723
|
+
// with no row keeps its inline spelling, which the coverage gate in
|
|
724
|
+
// `packages/types/test/constant-union-alias-coverage.test.ts` turns into a
|
|
725
|
+
// failure naming the row to review.
|
|
726
|
+
export const CONSTANT_UNION_ALIASES: readonly ConstantUnionAlias[] = [
|
|
727
|
+
{
|
|
728
|
+
home: "buffer",
|
|
729
|
+
name: "ValueType",
|
|
730
|
+
members: [
|
|
731
|
+
"buffer.VALUE_TYPE_FLOAT32",
|
|
732
|
+
"buffer.VALUE_TYPE_INT16",
|
|
733
|
+
"buffer.VALUE_TYPE_INT32",
|
|
734
|
+
"buffer.VALUE_TYPE_INT64",
|
|
735
|
+
"buffer.VALUE_TYPE_INT8",
|
|
736
|
+
"buffer.VALUE_TYPE_UINT16",
|
|
737
|
+
"buffer.VALUE_TYPE_UINT32",
|
|
738
|
+
"buffer.VALUE_TYPE_UINT64",
|
|
739
|
+
"buffer.VALUE_TYPE_UINT8",
|
|
740
|
+
],
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
home: "collectionfactory",
|
|
744
|
+
name: "Status",
|
|
745
|
+
members: [
|
|
746
|
+
"collectionfactory.STATUS_UNLOADED",
|
|
747
|
+
"collectionfactory.STATUS_LOADING",
|
|
748
|
+
"collectionfactory.STATUS_LOADED",
|
|
749
|
+
],
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
home: "factory",
|
|
753
|
+
name: "Status",
|
|
754
|
+
members: ["factory.STATUS_UNLOADED", "factory.STATUS_LOADING", "factory.STATUS_LOADED"],
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
home: "go",
|
|
758
|
+
name: "Easing",
|
|
759
|
+
members: [
|
|
760
|
+
"go.EASING_INBACK",
|
|
761
|
+
"go.EASING_INBOUNCE",
|
|
762
|
+
"go.EASING_INCIRC",
|
|
763
|
+
"go.EASING_INCUBIC",
|
|
764
|
+
"go.EASING_INELASTIC",
|
|
765
|
+
"go.EASING_INEXPO",
|
|
766
|
+
"go.EASING_INOUTBACK",
|
|
767
|
+
"go.EASING_INOUTBOUNCE",
|
|
768
|
+
"go.EASING_INOUTCIRC",
|
|
769
|
+
"go.EASING_INOUTCUBIC",
|
|
770
|
+
"go.EASING_INOUTELASTIC",
|
|
771
|
+
"go.EASING_INOUTEXPO",
|
|
772
|
+
"go.EASING_INOUTQUAD",
|
|
773
|
+
"go.EASING_INOUTQUART",
|
|
774
|
+
"go.EASING_INOUTQUINT",
|
|
775
|
+
"go.EASING_INOUTSINE",
|
|
776
|
+
"go.EASING_INQUAD",
|
|
777
|
+
"go.EASING_INQUART",
|
|
778
|
+
"go.EASING_INQUINT",
|
|
779
|
+
"go.EASING_INSINE",
|
|
780
|
+
"go.EASING_LINEAR",
|
|
781
|
+
"go.EASING_OUTBACK",
|
|
782
|
+
"go.EASING_OUTBOUNCE",
|
|
783
|
+
"go.EASING_OUTCIRC",
|
|
784
|
+
"go.EASING_OUTCUBIC",
|
|
785
|
+
"go.EASING_OUTELASTIC",
|
|
786
|
+
"go.EASING_OUTEXPO",
|
|
787
|
+
"go.EASING_OUTINBACK",
|
|
788
|
+
"go.EASING_OUTINBOUNCE",
|
|
789
|
+
"go.EASING_OUTINCIRC",
|
|
790
|
+
"go.EASING_OUTINCUBIC",
|
|
791
|
+
"go.EASING_OUTINELASTIC",
|
|
792
|
+
"go.EASING_OUTINEXPO",
|
|
793
|
+
"go.EASING_OUTINQUAD",
|
|
794
|
+
"go.EASING_OUTINQUART",
|
|
795
|
+
"go.EASING_OUTINQUINT",
|
|
796
|
+
"go.EASING_OUTINSINE",
|
|
797
|
+
"go.EASING_OUTQUAD",
|
|
798
|
+
"go.EASING_OUTQUART",
|
|
799
|
+
"go.EASING_OUTQUINT",
|
|
800
|
+
"go.EASING_OUTSINE",
|
|
801
|
+
],
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
home: "go",
|
|
805
|
+
name: "Playback",
|
|
806
|
+
members: [
|
|
807
|
+
"go.PLAYBACK_ONCE_FORWARD",
|
|
808
|
+
"go.PLAYBACK_ONCE_BACKWARD",
|
|
809
|
+
"go.PLAYBACK_ONCE_PINGPONG",
|
|
810
|
+
"go.PLAYBACK_LOOP_FORWARD",
|
|
811
|
+
"go.PLAYBACK_LOOP_BACKWARD",
|
|
812
|
+
"go.PLAYBACK_LOOP_PINGPONG",
|
|
813
|
+
],
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
home: "graphics",
|
|
817
|
+
name: "BufferType",
|
|
818
|
+
members: [
|
|
819
|
+
"graphics.BUFFER_TYPE_COLOR0_BIT",
|
|
820
|
+
"graphics.BUFFER_TYPE_COLOR1_BIT",
|
|
821
|
+
"graphics.BUFFER_TYPE_COLOR2_BIT",
|
|
822
|
+
"graphics.BUFFER_TYPE_COLOR3_BIT",
|
|
823
|
+
"graphics.BUFFER_TYPE_DEPTH_BIT",
|
|
824
|
+
"graphics.BUFFER_TYPE_STENCIL_BIT",
|
|
825
|
+
],
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
home: "graphics",
|
|
829
|
+
name: "State",
|
|
830
|
+
members: [
|
|
831
|
+
"graphics.STATE_DEPTH_TEST",
|
|
832
|
+
"graphics.STATE_STENCIL_TEST",
|
|
833
|
+
"graphics.STATE_BLEND",
|
|
834
|
+
"graphics.STATE_ALPHA_TEST",
|
|
835
|
+
"graphics.STATE_CULL_FACE",
|
|
836
|
+
"graphics.STATE_POLYGON_OFFSET_FILL",
|
|
837
|
+
],
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
home: "gui",
|
|
841
|
+
name: "AdjustMode",
|
|
842
|
+
members: ["gui.ADJUST_FIT", "gui.ADJUST_ZOOM", "gui.ADJUST_STRETCH"],
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
home: "gui",
|
|
846
|
+
name: "BlendMode",
|
|
847
|
+
members: [
|
|
848
|
+
"gui.BLEND_ALPHA",
|
|
849
|
+
"gui.BLEND_ADD",
|
|
850
|
+
"gui.BLEND_ADD_ALPHA",
|
|
851
|
+
"gui.BLEND_MULT",
|
|
852
|
+
"gui.BLEND_SCREEN",
|
|
853
|
+
],
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
home: "gui",
|
|
857
|
+
name: "ClippingMode",
|
|
858
|
+
members: ["gui.CLIPPING_MODE_NONE", "gui.CLIPPING_MODE_STENCIL"],
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
home: "gui",
|
|
862
|
+
name: "Easing",
|
|
863
|
+
members: [
|
|
864
|
+
"gui.EASING_INBACK",
|
|
865
|
+
"gui.EASING_INBOUNCE",
|
|
866
|
+
"gui.EASING_INCIRC",
|
|
867
|
+
"gui.EASING_INCUBIC",
|
|
868
|
+
"gui.EASING_INELASTIC",
|
|
869
|
+
"gui.EASING_INEXPO",
|
|
870
|
+
"gui.EASING_INOUTBACK",
|
|
871
|
+
"gui.EASING_INOUTBOUNCE",
|
|
872
|
+
"gui.EASING_INOUTCIRC",
|
|
873
|
+
"gui.EASING_INOUTCUBIC",
|
|
874
|
+
"gui.EASING_INOUTELASTIC",
|
|
875
|
+
"gui.EASING_INOUTEXPO",
|
|
876
|
+
"gui.EASING_INOUTQUAD",
|
|
877
|
+
"gui.EASING_INOUTQUART",
|
|
878
|
+
"gui.EASING_INOUTQUINT",
|
|
879
|
+
"gui.EASING_INOUTSINE",
|
|
880
|
+
"gui.EASING_INQUAD",
|
|
881
|
+
"gui.EASING_INQUART",
|
|
882
|
+
"gui.EASING_INQUINT",
|
|
883
|
+
"gui.EASING_INSINE",
|
|
884
|
+
"gui.EASING_LINEAR",
|
|
885
|
+
"gui.EASING_OUTBACK",
|
|
886
|
+
"gui.EASING_OUTBOUNCE",
|
|
887
|
+
"gui.EASING_OUTCIRC",
|
|
888
|
+
"gui.EASING_OUTCUBIC",
|
|
889
|
+
"gui.EASING_OUTELASTIC",
|
|
890
|
+
"gui.EASING_OUTEXPO",
|
|
891
|
+
"gui.EASING_OUTINBACK",
|
|
892
|
+
"gui.EASING_OUTINBOUNCE",
|
|
893
|
+
"gui.EASING_OUTINCIRC",
|
|
894
|
+
"gui.EASING_OUTINCUBIC",
|
|
895
|
+
"gui.EASING_OUTINELASTIC",
|
|
896
|
+
"gui.EASING_OUTINEXPO",
|
|
897
|
+
"gui.EASING_OUTINQUAD",
|
|
898
|
+
"gui.EASING_OUTINQUART",
|
|
899
|
+
"gui.EASING_OUTINQUINT",
|
|
900
|
+
"gui.EASING_OUTINSINE",
|
|
901
|
+
"gui.EASING_OUTQUAD",
|
|
902
|
+
"gui.EASING_OUTQUART",
|
|
903
|
+
"gui.EASING_OUTQUINT",
|
|
904
|
+
"gui.EASING_OUTSINE",
|
|
905
|
+
],
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
home: "gui",
|
|
909
|
+
name: "KeyboardType",
|
|
910
|
+
members: [
|
|
911
|
+
"gui.KEYBOARD_TYPE_DEFAULT",
|
|
912
|
+
"gui.KEYBOARD_TYPE_EMAIL",
|
|
913
|
+
"gui.KEYBOARD_TYPE_NUMBER_PAD",
|
|
914
|
+
"gui.KEYBOARD_TYPE_PASSWORD",
|
|
915
|
+
],
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
home: "gui",
|
|
919
|
+
name: "NodeType",
|
|
920
|
+
members: [
|
|
921
|
+
"gui.TYPE_BOX",
|
|
922
|
+
"gui.TYPE_TEXT",
|
|
923
|
+
"gui.TYPE_PIE",
|
|
924
|
+
"gui.TYPE_PARTICLEFX",
|
|
925
|
+
"gui.TYPE_CUSTOM",
|
|
926
|
+
],
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
home: "gui",
|
|
930
|
+
name: "PieBounds",
|
|
931
|
+
members: ["gui.PIEBOUNDS_RECTANGLE", "gui.PIEBOUNDS_ELLIPSE"],
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
home: "gui",
|
|
935
|
+
name: "Pivot",
|
|
936
|
+
members: [
|
|
937
|
+
"gui.PIVOT_CENTER",
|
|
938
|
+
"gui.PIVOT_N",
|
|
939
|
+
"gui.PIVOT_NE",
|
|
940
|
+
"gui.PIVOT_E",
|
|
941
|
+
"gui.PIVOT_SE",
|
|
942
|
+
"gui.PIVOT_S",
|
|
943
|
+
"gui.PIVOT_SW",
|
|
944
|
+
"gui.PIVOT_W",
|
|
945
|
+
"gui.PIVOT_NW",
|
|
946
|
+
],
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
home: "gui",
|
|
950
|
+
name: "Playback",
|
|
951
|
+
members: [
|
|
952
|
+
"gui.PLAYBACK_ONCE_FORWARD",
|
|
953
|
+
"gui.PLAYBACK_ONCE_BACKWARD",
|
|
954
|
+
"gui.PLAYBACK_ONCE_PINGPONG",
|
|
955
|
+
"gui.PLAYBACK_LOOP_FORWARD",
|
|
956
|
+
"gui.PLAYBACK_LOOP_BACKWARD",
|
|
957
|
+
"gui.PLAYBACK_LOOP_PINGPONG",
|
|
958
|
+
],
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
home: "gui",
|
|
962
|
+
name: "Property",
|
|
963
|
+
members: [
|
|
964
|
+
"gui.PROP_POSITION",
|
|
965
|
+
"gui.PROP_ROTATION",
|
|
966
|
+
"gui.PROP_EULER",
|
|
967
|
+
"gui.PROP_SCALE",
|
|
968
|
+
"gui.PROP_COLOR",
|
|
969
|
+
"gui.PROP_OUTLINE",
|
|
970
|
+
"gui.PROP_SHADOW",
|
|
971
|
+
"gui.PROP_SIZE",
|
|
972
|
+
"gui.PROP_FILL_ANGLE",
|
|
973
|
+
"gui.PROP_INNER_RADIUS",
|
|
974
|
+
"gui.PROP_LEADING",
|
|
975
|
+
"gui.PROP_TRACKING",
|
|
976
|
+
"gui.PROP_SLICE9",
|
|
977
|
+
],
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
home: "gui",
|
|
981
|
+
name: "SafeAreaMode",
|
|
982
|
+
members: [
|
|
983
|
+
"gui.SAFE_AREA_NONE",
|
|
984
|
+
"gui.SAFE_AREA_LONG",
|
|
985
|
+
"gui.SAFE_AREA_SHORT",
|
|
986
|
+
"gui.SAFE_AREA_BOTH",
|
|
987
|
+
],
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
home: "gui",
|
|
991
|
+
name: "SizeMode",
|
|
992
|
+
members: ["gui.SIZE_MODE_MANUAL", "gui.SIZE_MODE_AUTO"],
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
home: "gui",
|
|
996
|
+
name: "XAnchor",
|
|
997
|
+
members: ["gui.ANCHOR_NONE", "gui.ANCHOR_LEFT", "gui.ANCHOR_RIGHT"],
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
home: "gui",
|
|
1001
|
+
name: "YAnchor",
|
|
1002
|
+
members: ["gui.ANCHOR_NONE", "gui.ANCHOR_TOP", "gui.ANCHOR_BOTTOM"],
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
home: "profiler",
|
|
1006
|
+
name: "Mode",
|
|
1007
|
+
members: [
|
|
1008
|
+
"profiler.MODE_RUN",
|
|
1009
|
+
"profiler.MODE_PAUSE",
|
|
1010
|
+
"profiler.MODE_SHOW_PEAK_FRAME",
|
|
1011
|
+
"profiler.MODE_RECORD",
|
|
1012
|
+
],
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
home: "profiler",
|
|
1016
|
+
name: "ViewMode",
|
|
1017
|
+
members: ["profiler.VIEW_MODE_FULL", "profiler.VIEW_MODE_MINIMIZED"],
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
home: "render",
|
|
1021
|
+
name: "ClearBufferKey",
|
|
1022
|
+
members: [
|
|
1023
|
+
"graphics.BUFFER_TYPE_COLOR0_BIT",
|
|
1024
|
+
"graphics.BUFFER_TYPE_DEPTH_BIT",
|
|
1025
|
+
"graphics.BUFFER_TYPE_STENCIL_BIT",
|
|
1026
|
+
],
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
home: "sys",
|
|
1030
|
+
name: "NetworkConnectivity",
|
|
1031
|
+
members: [
|
|
1032
|
+
"sys.NETWORK_DISCONNECTED",
|
|
1033
|
+
"sys.NETWORK_CONNECTED_CELLULAR",
|
|
1034
|
+
"sys.NETWORK_CONNECTED",
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
home: "window",
|
|
1039
|
+
name: "DimModeState",
|
|
1040
|
+
members: ["window.DIMMING_UNKNOWN", "window.DIMMING_ON", "window.DIMMING_OFF"],
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
home: "window",
|
|
1044
|
+
name: "DimModeStateSettable",
|
|
1045
|
+
members: ["window.DIMMING_ON", "window.DIMMING_OFF"],
|
|
1046
|
+
},
|
|
1047
|
+
];
|
|
1048
|
+
|
|
1049
|
+
const CONSTANT_UNION_ALIAS_BY_MEMBERS: ReadonlyMap<string, ConstantUnionAlias> = new Map(
|
|
1050
|
+
CONSTANT_UNION_ALIASES.map((row) => [constantUnionAliasKey(row.members), row] as const),
|
|
1051
|
+
);
|
|
1052
|
+
|
|
1053
|
+
function constantUnionAliasKey(members: readonly string[]): string {
|
|
1054
|
+
return [...new Set(members)].sort().join("\u0000");
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// The alias naming exactly these constants, or undefined when no row does. A
|
|
1058
|
+
// single constant is never aliased: it already has a name.
|
|
1059
|
+
export function constantUnionAlias(fqns: readonly string[]): ConstantUnionAlias | undefined {
|
|
1060
|
+
if (fqns.length < 2) return undefined;
|
|
1061
|
+
return CONSTANT_UNION_ALIAS_BY_MEMBERS.get(constantUnionAliasKey(fqns));
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// The alias declarations a module owns, in name order. A row is declared in its
|
|
1065
|
+
// home whether or not that module references it, so a cross-namespace row is
|
|
1066
|
+
// reachable from the module whose signatures spell it.
|
|
1067
|
+
export function constantUnionAliasDeclarations(namespace: string): string[] {
|
|
1068
|
+
return CONSTANT_UNION_ALIASES.filter((row) => row.home === namespace)
|
|
1069
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
1070
|
+
.map(
|
|
1071
|
+
(row) => `type ${row.name} = ${row.members.map((member) => `typeof ${member}`).join(" | ")};`,
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
418
1075
|
const DOC_CONSTANT_TOKEN =
|
|
419
1076
|
/(?<![A-Za-z0-9_.])([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*\.[A-Z][A-Z0-9_]*)(\*)?/g;
|
|
420
1077
|
|
|
@@ -675,6 +1332,27 @@ const PHYSICS_SHAPE_TABLE_FIELDS: readonly TableField[] = [
|
|
|
675
1332
|
];
|
|
676
1333
|
|
|
677
1334
|
export const TABLE_SLOT_CURATIONS: ReadonlyMap<string, TableSlotCuration> = new Map([
|
|
1335
|
+
// buffer.create's `declaration` is "a table where each entry (table) describes
|
|
1336
|
+
// a stream", and upstream's example passes a list of stream records whose
|
|
1337
|
+
// `type` is a buffer.VALUE_TYPE_* constant.
|
|
1338
|
+
[
|
|
1339
|
+
"buffer.create:param:declaration",
|
|
1340
|
+
{
|
|
1341
|
+
kind: "array-object",
|
|
1342
|
+
fields: [
|
|
1343
|
+
{ name: "name", types: ["hash", "string"] },
|
|
1344
|
+
{ name: "type", types: ["constant"], tsType: "buffer.ValueType" },
|
|
1345
|
+
{ name: "count", types: ["number"] },
|
|
1346
|
+
],
|
|
1347
|
+
},
|
|
1348
|
+
],
|
|
1349
|
+
// collectionfactory.create's `properties` is keyed by "game object ids (hash)",
|
|
1350
|
+
// which upstream's example builds with `hash("/go")`. The `string` key keeps
|
|
1351
|
+
// the object-literal form this slot accepted as a bare `table`.
|
|
1352
|
+
[
|
|
1353
|
+
"collectionfactory.create:param:properties",
|
|
1354
|
+
{ kind: "mapping", key: "hash | string", value: "table" },
|
|
1355
|
+
],
|
|
678
1356
|
["collectionfactory.create:return:ids", { kind: "mapping", key: "hash", value: "hash" }],
|
|
679
1357
|
// font.get_info's `info` return is a `<dl>` with `path: hash` and a nested
|
|
680
1358
|
// `fonts` field whose `<dd>` is itself a `<dl>` (`path: string`, `path_hash:
|
|
@@ -906,8 +1584,8 @@ export const TABLE_SLOT_CURATIONS: ReadonlyMap<string, TableSlotCuration> = new
|
|
|
906
1584
|
// names as keys to their clear value: vector4 for the color buffer, number for
|
|
907
1585
|
// depth/stencil. Both sides are union tokens the mapping string branch splits,
|
|
908
1586
|
// so the key emits the three branded constants and the value `number | Vector4`.
|
|
909
|
-
// The key is
|
|
910
|
-
//
|
|
1587
|
+
// The key set is a CONSTANT_UNION_ALIASES row, so the signature carries the
|
|
1588
|
+
// `render.ClearBufferKey` alias rather than the three branded arms.
|
|
911
1589
|
[
|
|
912
1590
|
"render.clear:param:buffers",
|
|
913
1591
|
{
|
|
@@ -1380,11 +2058,33 @@ export const TABLE_SLOT_CURATIONS: ReadonlyMap<string, TableSlotCuration> = new
|
|
|
1380
2058
|
// its `data` is a bare record (only resize carries fields — `isWindowEvent` is the
|
|
1381
2059
|
// path to typed `data`), mirroring the `msg.post` (send, typed) / `isMessage`
|
|
1382
2060
|
// (receive, narrow) split.
|
|
2061
|
+
//
|
|
2062
|
+
// The other entries type what the slot's own prose lists and nothing more.
|
|
2063
|
+
// `http.request`'s response fields are the `<ul>` under "The response data.
|
|
2064
|
+
// Contains the fields:"; each is conditional ("if not saved on disc", "only if
|
|
2065
|
+
// option report_progress is true") except `status`, and `headers` is the same
|
|
2066
|
+
// string map the request sends. `sprite.play_flipbook`'s message is the
|
|
2067
|
+
// "Information about the completion" list. `collectionproxy.load` documents
|
|
2068
|
+
// only that the callback receives `proxy_loading`, `proxy_ready` or
|
|
2069
|
+
// `proxy_error` messages and lists no fields, so its message is the bare record
|
|
2070
|
+
// `window.set_listener`'s `data` is.
|
|
1383
2071
|
export const CALLBACK_SIGNATURE_CURATIONS: ReadonlyMap<string, string> = new Map([
|
|
1384
2072
|
[
|
|
1385
2073
|
"window.set_listener:param:callback",
|
|
1386
2074
|
"(self: unknown, event: typeof WINDOW_EVENT_FOCUS_LOST | typeof WINDOW_EVENT_FOCUS_GAINED | typeof WINDOW_EVENT_RESIZED | typeof WINDOW_EVENT_ICONFIED | typeof WINDOW_EVENT_DEICONIFIED, data: Record<string | number, unknown>) => void",
|
|
1387
2075
|
],
|
|
2076
|
+
[
|
|
2077
|
+
"http.request:param:callback",
|
|
2078
|
+
"(self: unknown, id: Hash, response: { status: number; response?: string; headers?: LuaMap<string, string>; path?: string; error?: string; bytes_received?: number; bytes_total?: number; range_start?: number; range_end?: number; document_size?: number }) => void",
|
|
2079
|
+
],
|
|
2080
|
+
[
|
|
2081
|
+
"sprite.play_flipbook:param:complete_function",
|
|
2082
|
+
"(self: unknown, message_id: Hash, message: { current_tile: number; id: Hash }, sender: Url) => void",
|
|
2083
|
+
],
|
|
2084
|
+
[
|
|
2085
|
+
"collectionproxy.load:param:callback",
|
|
2086
|
+
"(self: unknown, message_id: Hash, message: Record<string | number, unknown>, sender: Url) => void",
|
|
2087
|
+
],
|
|
1388
2088
|
]);
|
|
1389
2089
|
|
|
1390
2090
|
// resource.set_atlas's `table` param and resource.get_atlas's `data` return are
|
|
@@ -1417,7 +2117,19 @@ export const NESTED_FIELD_CURATIONS: ReadonlyMap<string, readonly TableField[]>
|
|
|
1417
2117
|
// parser recovers every other field faithfully but leaves that `table` token as
|
|
1418
2118
|
// a bare `Record`; this pins only the `value` field's TS type to the documented
|
|
1419
2119
|
// array union while every sibling field stays parser-authoritative. Keyed by
|
|
1420
|
-
// `<element>:<kind>:<slot>:<field>`, mirroring NESTED_FIELD_CURATIONS
|
|
2120
|
+
// `<element>:<kind>:<slot>:<field>`, mirroring NESTED_FIELD_CURATIONS; a field
|
|
2121
|
+
// one level down is `<field>.<member>`, or `<field>[].<member>` inside a list.
|
|
2122
|
+
//
|
|
2123
|
+
// The atlas animation `playback` field is documented as `constant` with the
|
|
2124
|
+
// prose "the default value is go.PLAYBACK_ONCE_FORWARD", which names the enum
|
|
2125
|
+
// the bare token cannot.
|
|
2126
|
+
//
|
|
2127
|
+
// `gui.set`'s `options.key` is documented as `hash`, while upstream's own
|
|
2128
|
+
// example sets a named font with `{ key = "my_font_name" }`.
|
|
2129
|
+
//
|
|
2130
|
+
// `render.set_render_target`'s `options.transient` is documented as `table`
|
|
2131
|
+
// with the prose "a list of buffer types", and upstream's example passes
|
|
2132
|
+
// graphics.BUFFER_TYPE_* constants.
|
|
1421
2133
|
const CONSTANT_VALUE_TS = "Vector4 | Vector3 | Matrix4 | number | (Vector4 | Matrix4)[]";
|
|
1422
2134
|
const ATTRIBUTE_VALUE_TS = "Vector4 | Vector3 | Matrix4 | number | number[]";
|
|
1423
2135
|
export const TABLE_FIELD_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
@@ -1425,6 +2137,40 @@ export const TABLE_FIELD_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
|
1425
2137
|
["material.set_constants:param:constants:value", CONSTANT_VALUE_TS],
|
|
1426
2138
|
["material.set_vertex_attributes:param:attributes:value", ATTRIBUTE_VALUE_TS],
|
|
1427
2139
|
["material.get_vertex_attributes:return:table:value", ATTRIBUTE_VALUE_TS],
|
|
2140
|
+
["resource.set_atlas:param:table:animations[].playback", "go.Playback"],
|
|
2141
|
+
["resource.create_atlas:param:table:animations[].playback", "go.Playback"],
|
|
2142
|
+
["resource.get_atlas:return:data:animations[].playback", "go.Playback"],
|
|
2143
|
+
["gui.set:param:options:key", "string | Hash"],
|
|
2144
|
+
["render.set_render_target:param:options:transient", "graphics.BufferType[]"],
|
|
2145
|
+
]);
|
|
2146
|
+
|
|
2147
|
+
// A field the engine accepts on an option bag whose `<dl>` upstream otherwise
|
|
2148
|
+
// documents in full. Every other authored table here retypes, marks optional or
|
|
2149
|
+
// suppresses a slot the parser already recovered; this one supplies a member
|
|
2150
|
+
// upstream omits, leaving the documented fields parser-authoritative so an
|
|
2151
|
+
// upstream edit to any of them lands without a hand-maintained restatement.
|
|
2152
|
+
//
|
|
2153
|
+
// `evidence` pins where upstream itself shows the field. applyFieldAdditions
|
|
2154
|
+
// throws once the parse recovers it, so upstream documenting the field reds
|
|
2155
|
+
// here and the entry is deleted rather than re-pinned.
|
|
2156
|
+
//
|
|
2157
|
+
// Keyed `<element>:<kind>:<slot>`, the TABLE_SLOT_CURATIONS shape.
|
|
2158
|
+
export interface TableFieldAddition {
|
|
2159
|
+
readonly field: TableField;
|
|
2160
|
+
readonly evidence: readonly string[];
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
export const TABLE_SLOT_FIELD_ADDITIONS: ReadonlyMap<string, TableFieldAddition> = new Map([
|
|
2164
|
+
[
|
|
2165
|
+
"resource.create_texture:param:table",
|
|
2166
|
+
{
|
|
2167
|
+
field: { name: "page_count", types: ["number"], optional: true },
|
|
2168
|
+
evidence: [
|
|
2169
|
+
"the array-texture example on this element creates with `page_count = 5`",
|
|
2170
|
+
"resource.get_texture_info documents `page_count` as the texture array's page count",
|
|
2171
|
+
],
|
|
2172
|
+
},
|
|
2173
|
+
],
|
|
1428
2174
|
]);
|
|
1429
2175
|
|
|
1430
2176
|
// A return-slot field upstream documents as platform-gated or nil-valued while
|
|
@@ -1516,6 +2262,26 @@ export function applyFieldOptionalityCorrections(
|
|
|
1516
2262
|
return corrected;
|
|
1517
2263
|
}
|
|
1518
2264
|
|
|
2265
|
+
// Append the member TABLE_SLOT_FIELD_ADDITIONS supplies for this slot, after
|
|
2266
|
+
// every field the parser recovered. Throws on an addition whose field the parse
|
|
2267
|
+
// already produced: upstream has documented it, and the entry is stale.
|
|
2268
|
+
// Returns a new array; never mutates the parser's result.
|
|
2269
|
+
export function applyFieldAdditions(
|
|
2270
|
+
elementName: string,
|
|
2271
|
+
slotKind: "param" | "return" | undefined,
|
|
2272
|
+
slotName: string | undefined,
|
|
2273
|
+
fields: readonly TableField[],
|
|
2274
|
+
): TableField[] {
|
|
2275
|
+
if (slotKind === undefined || slotName === undefined) return [...fields];
|
|
2276
|
+
const key = tableSlotKey(elementName, slotKind, slotName);
|
|
2277
|
+
const addition = TABLE_SLOT_FIELD_ADDITIONS.get(key);
|
|
2278
|
+
if (addition === undefined) return [...fields];
|
|
2279
|
+
if (fields.some((field) => field.name === addition.field.name)) {
|
|
2280
|
+
throw new Error(`field addition names a recovered field: ${key}:${addition.field.name}`);
|
|
2281
|
+
}
|
|
2282
|
+
return [...fields, addition.field];
|
|
2283
|
+
}
|
|
2284
|
+
|
|
1519
2285
|
// Pin a parser-recovered field's TS type from TABLE_FIELD_TYPE_OVERRIDES,
|
|
1520
2286
|
// leaving every other field parser-authoritative. A field the override does not
|
|
1521
2287
|
// name is returned unchanged; a field it names gains a `tsType` (emitted
|
|
@@ -1528,11 +2294,17 @@ export function applyFieldTypeOverrides(
|
|
|
1528
2294
|
fields: readonly TableField[],
|
|
1529
2295
|
): TableField[] {
|
|
1530
2296
|
if (slotKind === undefined || slotName === undefined) return [...fields];
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
);
|
|
2297
|
+
const prefix = `${tableSlotKey(elementName, slotKind, slotName)}:`;
|
|
2298
|
+
const typed = (field: TableField, path: string): TableField => {
|
|
2299
|
+
const override = TABLE_FIELD_TYPE_OVERRIDES.get(`${prefix}${path}`);
|
|
1535
2300
|
return override === undefined ? field : { ...field, tsType: override };
|
|
2301
|
+
};
|
|
2302
|
+
return fields.map((field) => {
|
|
2303
|
+
const own = typed(field, field.name);
|
|
2304
|
+
if (own.fields === undefined) return own;
|
|
2305
|
+
const parent = `${field.name}${field.isList === true ? "[]" : ""}`;
|
|
2306
|
+
const nested = own.fields.map((child) => typed(child, `${parent}.${child.name}`));
|
|
2307
|
+
return nested.every((child, i) => child === own.fields?.[i]) ? own : { ...own, fields: nested };
|
|
1536
2308
|
});
|
|
1537
2309
|
}
|
|
1538
2310
|
|
|
@@ -1864,6 +2636,15 @@ function groupFlattenedTableFields(fields: readonly TableField[]): TableField[]
|
|
|
1864
2636
|
return grouped;
|
|
1865
2637
|
}
|
|
1866
2638
|
|
|
2639
|
+
// A handle the type map widens (`constant_buffer` takes named constants) keeps
|
|
2640
|
+
// that shape, so annotating with the alias loses nothing the handle-returning
|
|
2641
|
+
// function yields.
|
|
2642
|
+
function typedefAlias(name: string, mapType: (token: string) => string): string {
|
|
2643
|
+
const brand = `Opaque<"${name}">`;
|
|
2644
|
+
const mapped = mapType(name);
|
|
2645
|
+
return `type ${name} = ${mapped.startsWith(brand) ? mapped : brand};`;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
1867
2648
|
export function emitDeclarations(module: ApiModule, options?: EmitOptions): string {
|
|
1868
2649
|
const prefix = `${module.namespace}.`;
|
|
1869
2650
|
|
|
@@ -1946,7 +2727,10 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1946
2727
|
// A typedef that also has colon methods is emitted as a method-bearing
|
|
1947
2728
|
// interface below, not an opaque brand alias.
|
|
1948
2729
|
if (handleGroups.has(t.name)) continue;
|
|
1949
|
-
lines.push(`${INDENT}${decl}
|
|
2730
|
+
lines.push(`${INDENT}${decl}${typedefAlias(t.name, baseMapType)}`);
|
|
2731
|
+
}
|
|
2732
|
+
for (const aliasDecl of constantUnionAliasDeclarations(module.namespace)) {
|
|
2733
|
+
lines.push(`${INDENT}${decl}${aliasDecl}`);
|
|
1950
2734
|
}
|
|
1951
2735
|
const handleIndent = `${INDENT}${INDENT}`;
|
|
1952
2736
|
for (const receiver of handleReceivers) {
|
|
@@ -1989,6 +2773,18 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1989
2773
|
for (const docLine of functionDocLines(fn.original, translations)) lines.push(docLine);
|
|
1990
2774
|
const line = emitFunction(fn, emitName, mapType, resolver, constantTokens, urlParameters);
|
|
1991
2775
|
lines.push(`${INDENT}${reserved ? "" : decl}${line}`);
|
|
2776
|
+
const alternative = firstSlotAlternative(fn, module.namespace);
|
|
2777
|
+
if (alternative !== null) {
|
|
2778
|
+
const overload = emitFunction(
|
|
2779
|
+
alternative,
|
|
2780
|
+
emitName,
|
|
2781
|
+
mapType,
|
|
2782
|
+
resolver,
|
|
2783
|
+
constantTokens,
|
|
2784
|
+
urlParameters,
|
|
2785
|
+
);
|
|
2786
|
+
lines.push(`${INDENT}${reserved ? "" : decl}${overload}`);
|
|
2787
|
+
}
|
|
1992
2788
|
}
|
|
1993
2789
|
|
|
1994
2790
|
for (const alias of [...aliases].sort((a, b) => a.public.localeCompare(b.public))) {
|
|
@@ -2051,10 +2847,12 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
2051
2847
|
const members = [...module.properties].sort((a, b) => a.name.localeCompare(b.name));
|
|
2052
2848
|
lines.push(`${INDENT}${decl}interface properties {`);
|
|
2053
2849
|
for (const p of members) {
|
|
2054
|
-
for (const
|
|
2055
|
-
|
|
2850
|
+
for (const member of emitPropertyMembers(p, mapType, module.namespace)) {
|
|
2851
|
+
for (const docLine of summaryDocLines(p.brief, p.description, `${INDENT}${INDENT}`)) {
|
|
2852
|
+
lines.push(docLine);
|
|
2853
|
+
}
|
|
2854
|
+
lines.push(`${INDENT}${INDENT}${member}`);
|
|
2056
2855
|
}
|
|
2057
|
-
lines.push(`${INDENT}${INDENT}${emitPropertyMember(p, mapType, module.namespace)}`);
|
|
2058
2856
|
}
|
|
2059
2857
|
lines.push(`${INDENT}}`);
|
|
2060
2858
|
}
|
|
@@ -2094,7 +2892,10 @@ export interface SymbolSignature {
|
|
|
2094
2892
|
* {@link collectNestedGroups} tree the declaration emitter walks, so neither
|
|
2095
2893
|
* surface can decide on its own which members are nested or how deep they go.
|
|
2096
2894
|
* The caller applies the same `skipFunctions` filter the `.d.ts` generation
|
|
2097
|
-
* does, so a dropped member never yields a signature.
|
|
2895
|
+
* does, so a dropped member never yields a signature. A top-level function the
|
|
2896
|
+
* declaration emits with a first-slot alternative overload carries one arm per
|
|
2897
|
+
* line, primary first, the same convention as the authored fold; its
|
|
2898
|
+
* `slotTypes` describe the primary arm only.
|
|
2098
2899
|
*/
|
|
2099
2900
|
export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions): SymbolSignature[] {
|
|
2100
2901
|
const prefix = `${module.namespace}.`;
|
|
@@ -2134,19 +2935,28 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
2134
2935
|
const prepared = prepareFunction(fn, prefix);
|
|
2135
2936
|
if (prepared === null) continue;
|
|
2136
2937
|
const slotTypes: Record<string, string> = {};
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
constantTokens,
|
|
2145
|
-
urlParameters,
|
|
2146
|
-
slotTypes,
|
|
2147
|
-
),
|
|
2938
|
+
const primary = emitFunction(
|
|
2939
|
+
prepared,
|
|
2940
|
+
emitName(prepared.name),
|
|
2941
|
+
mapType,
|
|
2942
|
+
resolver,
|
|
2943
|
+
constantTokens,
|
|
2944
|
+
urlParameters,
|
|
2148
2945
|
slotTypes,
|
|
2149
|
-
|
|
2946
|
+
);
|
|
2947
|
+
const alternative = firstSlotAlternative(prepared, module.namespace);
|
|
2948
|
+
const tsSignature =
|
|
2949
|
+
alternative === null
|
|
2950
|
+
? primary
|
|
2951
|
+
: `${primary}\n${emitFunction(
|
|
2952
|
+
alternative,
|
|
2953
|
+
emitName(prepared.name),
|
|
2954
|
+
mapType,
|
|
2955
|
+
resolver,
|
|
2956
|
+
constantTokens,
|
|
2957
|
+
urlParameters,
|
|
2958
|
+
)}`;
|
|
2959
|
+
out.push({ identity: fnIdentity(fn), tsSignature, slotTypes });
|
|
2150
2960
|
}
|
|
2151
2961
|
|
|
2152
2962
|
const nested = flattenNestedGroups(collectNestedGroups(module, prefix));
|
|
@@ -2218,10 +3028,14 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
2218
3028
|
});
|
|
2219
3029
|
}
|
|
2220
3030
|
|
|
3031
|
+
// A key-range property emits several members that share one type; its entry
|
|
3032
|
+
// carries the first, which is verbatim in the `.d.ts` and is what the `/api`
|
|
3033
|
+
// render layer reduces to `<placeholder>: <type>`.
|
|
2221
3034
|
for (const p of module.properties) {
|
|
3035
|
+
const [firstMember = ""] = emitPropertyMembers(p, mapType, module.namespace);
|
|
2222
3036
|
out.push({
|
|
2223
3037
|
identity: { namespace: module.namespace, kind: "PROPERTY", name: p.name, signature: "" },
|
|
2224
|
-
tsSignature:
|
|
3038
|
+
tsSignature: firstMember,
|
|
2225
3039
|
slotTypes: NO_SLOTS,
|
|
2226
3040
|
});
|
|
2227
3041
|
}
|
|
@@ -2230,7 +3044,20 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
2230
3044
|
if (!TS_IDENTIFIER.test(t.name) || handleGroups.has(t.name)) continue;
|
|
2231
3045
|
out.push({
|
|
2232
3046
|
identity: { namespace: module.namespace, kind: "TYPEDEF", name: t.name, signature: "" },
|
|
2233
|
-
tsSignature:
|
|
3047
|
+
tsSignature: typedefAlias(t.name, baseMapType),
|
|
3048
|
+
slotTypes: NO_SLOTS,
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// The module's constant-union aliases travel as typedefs too: a signature that
|
|
3053
|
+
// names one carries no member list of its own, so the docs read the members
|
|
3054
|
+
// from here rather than from the emitter's table.
|
|
3055
|
+
for (const row of CONSTANT_UNION_ALIASES.filter((r) => r.home === module.namespace)) {
|
|
3056
|
+
out.push({
|
|
3057
|
+
identity: { namespace: module.namespace, kind: "TYPEDEF", name: row.name, signature: "" },
|
|
3058
|
+
tsSignature: `type ${row.name} = ${row.members
|
|
3059
|
+
.map((member) => `typeof ${member}`)
|
|
3060
|
+
.join(" | ")};`,
|
|
2234
3061
|
slotTypes: NO_SLOTS,
|
|
2235
3062
|
});
|
|
2236
3063
|
}
|
|
@@ -2534,15 +3361,39 @@ function functionDocLines(
|
|
|
2534
3361
|
): string[] {
|
|
2535
3362
|
const params = fn.parameters.map((p, index) => ({
|
|
2536
3363
|
name: emittedParamName(p, index),
|
|
2537
|
-
doc: htmlToDocText(p.doc),
|
|
3364
|
+
doc: rewriteParamDoc(fn.name, p.name, htmlToDocText(p.doc)),
|
|
2538
3365
|
}));
|
|
2539
3366
|
const onlyReturn = fn.returnValues.length === 1 ? fn.returnValues[0] : undefined;
|
|
2540
3367
|
const lua = htmlToCodeText(fn.examples ?? "");
|
|
2541
|
-
// A
|
|
2542
|
-
//
|
|
3368
|
+
// A blob carrying several examples documents them as several, but only when
|
|
3369
|
+
// every segment has an authored body: a partial resolve would drop the rest.
|
|
3370
|
+
// Otherwise the whole-blob ladder stands — a hand-authored TS translation
|
|
3371
|
+
// pinned to this exact Lua flips the fence to ```ts; any hash mismatch (or
|
|
3372
|
+
// absent translation) keeps the Lua fallback.
|
|
3373
|
+
const segments = splitExampleSources(fn.examples ?? "");
|
|
3374
|
+
const perSegment =
|
|
3375
|
+
segments.length > 1
|
|
3376
|
+
? lookupExampleTranslations(
|
|
3377
|
+
translations,
|
|
3378
|
+
fn.name,
|
|
3379
|
+
segments.map((segment) => hashExampleSource(segment.code)),
|
|
3380
|
+
)
|
|
3381
|
+
: null;
|
|
2543
3382
|
const ts = lua === "" ? null : lookupTranslation(translations, fn.name, hashExampleSource(lua));
|
|
2544
|
-
const exampleParts: Pick<DocCommentParts, "
|
|
2545
|
-
|
|
3383
|
+
const exampleParts: Pick<DocCommentParts, "examples"> =
|
|
3384
|
+
perSegment !== null
|
|
3385
|
+
? {
|
|
3386
|
+
examples: perSegment.map((text, index) => ({
|
|
3387
|
+
text,
|
|
3388
|
+
lang: "ts" as const,
|
|
3389
|
+
...(segments[index]?.prose ? { prose: segments[index]?.prose } : {}),
|
|
3390
|
+
})),
|
|
3391
|
+
}
|
|
3392
|
+
: ts !== null
|
|
3393
|
+
? { examples: [{ text: ts, lang: "ts" }] }
|
|
3394
|
+
: lua !== ""
|
|
3395
|
+
? { examples: [{ text: lua, lang: "lua" }] }
|
|
3396
|
+
: {};
|
|
2546
3397
|
const parts: DocCommentParts = {
|
|
2547
3398
|
summary: htmlToDocText(summaryFor(fn.brief, fn.description)),
|
|
2548
3399
|
params,
|
|
@@ -2641,19 +3492,22 @@ function parameterType(
|
|
|
2641
3492
|
// `safeParamName` fallback.
|
|
2642
3493
|
const alias = SCENE_ADDRESS_ALIASES[classifyUrlParameter(urlParameters, elementName, p.name)];
|
|
2643
3494
|
const slotMapType = alias === undefined ? mapType : addressMapType(mapType, alias);
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
3495
|
+
const mapped =
|
|
3496
|
+
concrete.length > 0
|
|
3497
|
+
? mapSlotUnion(
|
|
3498
|
+
concrete,
|
|
3499
|
+
p.doc,
|
|
3500
|
+
slotMapType,
|
|
3501
|
+
true,
|
|
3502
|
+
resolver,
|
|
3503
|
+
constantTokens,
|
|
3504
|
+
elementName,
|
|
3505
|
+
"param",
|
|
3506
|
+
p.name,
|
|
3507
|
+
)
|
|
3508
|
+
: "unknown";
|
|
3509
|
+
const correction = PARAM_TYPE_CORRECTIONS.get(tableSlotKey(elementName, "param", p.name));
|
|
3510
|
+
return correction === undefined ? mapped : `${mapped} | ${correction.adds}`;
|
|
2657
3511
|
}
|
|
2658
3512
|
|
|
2659
3513
|
const VARARG_PREFIX = "...";
|
|
@@ -2802,12 +3656,19 @@ function emitReturn(
|
|
|
2802
3656
|
return { type: ts, trailing: "", slots: [{ position: 0, name: first.name, ts }] };
|
|
2803
3657
|
}
|
|
2804
3658
|
|
|
2805
|
-
function
|
|
3659
|
+
function emitPropertyMembers(
|
|
2806
3660
|
p: ApiProperty,
|
|
2807
3661
|
mapType: (t: string) => string,
|
|
2808
3662
|
namespace: string,
|
|
2809
|
-
): string {
|
|
2810
|
-
const
|
|
3663
|
+
): readonly string[] {
|
|
3664
|
+
const keyRange = PROPERTY_KEY_RANGES.get(`${namespace}.${p.name}`);
|
|
3665
|
+
const keys: string[] = [];
|
|
3666
|
+
if (keyRange !== undefined) {
|
|
3667
|
+
for (let unit = keyRange.first; unit <= keyRange.last; unit++)
|
|
3668
|
+
keys.push(`${keyRange.prefix}${unit}`);
|
|
3669
|
+
} else {
|
|
3670
|
+
keys.push(TS_IDENTIFIER.test(p.name) ? p.name : JSON.stringify(p.name));
|
|
3671
|
+
}
|
|
2811
3672
|
const correction = PROPERTY_TYPE_CORRECTIONS.get(`${namespace}.${p.name}`);
|
|
2812
3673
|
const ts =
|
|
2813
3674
|
correction !== undefined
|
|
@@ -2815,7 +3676,7 @@ function emitPropertyMember(
|
|
|
2815
3676
|
: p.types.length > 0
|
|
2816
3677
|
? unionFromTokens(p.types, mapType)
|
|
2817
3678
|
: "unknown";
|
|
2818
|
-
return `${key}: ${ts}
|
|
3679
|
+
return keys.map((key) => `${key}: ${ts};`);
|
|
2819
3680
|
}
|
|
2820
3681
|
|
|
2821
3682
|
// Like `unionFromTokens`, but a `table` token whose slot doc carries a parseable
|
|
@@ -2880,11 +3741,21 @@ function mapSlotUnion(
|
|
|
2880
3741
|
// A mapping key may be a `A | B` union token too (render.clear's three
|
|
2881
3742
|
// documented graphics.BUFFER_TYPE_* constants); split it the same way
|
|
2882
3743
|
// the value above is split. A single-token key (no `|`) is unaffected.
|
|
2883
|
-
const
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3744
|
+
const keyTokens = mapping.key.split("|").map((token) => token.trim());
|
|
3745
|
+
if (slotKind === "param" && keyTokens.includes("string")) {
|
|
3746
|
+
// A caller builds a string-keyed parameter table as an object literal,
|
|
3747
|
+
// which `LuaMap` rejects; the `Record` arm admits it and TSTL lowers
|
|
3748
|
+
// both to the same Lua table. The `Record` arm carries the string keys,
|
|
3749
|
+
// so `LuaMap` keeps only the other key tokens: `LuaMap`'s key is
|
|
3750
|
+
// invariant, and a `LuaMap<Hash | string, V>` would reject the
|
|
3751
|
+
// `LuaMap<Hash, V>` a caller builds. A string-only key keeps its
|
|
3752
|
+
// `LuaMap` arm so an existing `LuaMap` caller stays valid.
|
|
3753
|
+
const otherKeys = keyTokens.filter((token) => token !== "string");
|
|
3754
|
+
const key = unionFromTokens(otherKeys.length > 0 ? otherKeys : keyTokens, mapType);
|
|
3755
|
+
ts = `LuaMap<${key}, ${value}> | Record<string, ${value}>`;
|
|
3756
|
+
} else {
|
|
3757
|
+
ts = `LuaMap<${unionFromTokens(keyTokens, mapType)}, ${value}>`;
|
|
3758
|
+
}
|
|
2888
3759
|
} else if (element !== undefined) {
|
|
2889
3760
|
ts = arrayTypeFromTokens(element, mapType);
|
|
2890
3761
|
} else if (curation?.kind === "object" || curation?.kind === "array-object") {
|
|
@@ -2911,7 +3782,8 @@ function mapSlotUnion(
|
|
|
2911
3782
|
} else {
|
|
2912
3783
|
const parsed = parseTableFields(doc, resolver, slotName);
|
|
2913
3784
|
if (parsed !== null) {
|
|
2914
|
-
const
|
|
3785
|
+
const added = applyFieldAdditions(elementName, slotKind, slotName, parsed);
|
|
3786
|
+
const nested = applyNestedFieldCurations(elementName, slotKind, slotName, added);
|
|
2915
3787
|
const typed = applyFieldTypeOverrides(elementName, slotKind, slotName, nested);
|
|
2916
3788
|
const fields = applyFieldOptionalityCorrections(elementName, slotKind, slotName, typed);
|
|
2917
3789
|
const object = inlineTableType(fields, mapType, optionalFields);
|
|
@@ -2940,7 +3812,7 @@ function mapSlotUnion(
|
|
|
2940
3812
|
// every other union member, so collapse to exactly `unknown` rather than emit
|
|
2941
3813
|
// a redundant `T | unknown` or `unknown | undefined`.
|
|
2942
3814
|
if (mapped.includes("unknown")) return "unknown";
|
|
2943
|
-
return mapped
|
|
3815
|
+
return joinUnionArms(mapped);
|
|
2944
3816
|
}
|
|
2945
3817
|
|
|
2946
3818
|
function tableSlotKey(elementName: string, slotKind: "param" | "return", slotName: string): string {
|
|
@@ -3030,7 +3902,36 @@ function unionFromTokens(tokens: readonly string[], mapType: (t: string) => stri
|
|
|
3030
3902
|
seen.add(ts);
|
|
3031
3903
|
mapped.push(ts);
|
|
3032
3904
|
}
|
|
3033
|
-
return mapped
|
|
3905
|
+
return joinUnionArms(mapped);
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
const BRAND_ARM = /^number & \{ readonly __brand: "([^"]+)" \}$/;
|
|
3909
|
+
|
|
3910
|
+
// Joins already-mapped arms, collapsing the branded ones to their alias when
|
|
3911
|
+
// they are exactly a `CONSTANT_UNION_ALIASES` member set. The alias takes the
|
|
3912
|
+
// position of the first branded arm, so a mixed union keeps its reading order
|
|
3913
|
+
// (`gui.Easing | Vector`). Arms that are not constants are untouched, and a set
|
|
3914
|
+
// with no row keeps every arm inline.
|
|
3915
|
+
function joinUnionArms(mapped: readonly string[]): string {
|
|
3916
|
+
const branded: string[] = [];
|
|
3917
|
+
for (const arm of mapped) {
|
|
3918
|
+
const match = BRAND_ARM.exec(arm);
|
|
3919
|
+
if (match !== null) branded.push(match[1] as string);
|
|
3920
|
+
}
|
|
3921
|
+
const alias = constantUnionAlias(branded);
|
|
3922
|
+
if (alias === undefined) return mapped.join(" | ");
|
|
3923
|
+
const out: string[] = [];
|
|
3924
|
+
let placed = false;
|
|
3925
|
+
for (const arm of mapped) {
|
|
3926
|
+
if (BRAND_ARM.test(arm)) {
|
|
3927
|
+
if (placed) continue;
|
|
3928
|
+
out.push(`${alias.home}.${alias.name}`);
|
|
3929
|
+
placed = true;
|
|
3930
|
+
continue;
|
|
3931
|
+
}
|
|
3932
|
+
out.push(arm);
|
|
3933
|
+
}
|
|
3934
|
+
return out.join(" | ");
|
|
3034
3935
|
}
|
|
3035
3936
|
|
|
3036
3937
|
export function isKnownDefoldTypeToken(token: string): boolean {
|