@defold-typescript/types 0.40.0 → 0.41.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 +3963 -772
- package/api-migrations.json +27 -0
- package/api-signatures.json +18069 -10240
- package/api-targets.json +448 -11
- package/examples/translations.json +560 -89
- package/fixtures/messages_doc.json +96 -0
- package/generated/b2d.d.ts +680 -4
- package/generated/b2d_body.d.ts +29 -103
- package/generated/b2d_chain.d.ts +5 -6
- package/generated/b2d_fixture.d.ts +34 -38
- package/generated/b2d_joint.d.ts +503 -25
- package/generated/b2d_shape.d.ts +183 -20
- package/generated/b2d_world.d.ts +57 -63
- package/generated/buffer.d.ts +16 -15
- package/generated/builtin-messages.d.ts +7 -1
- package/generated/bullet3d.d.ts +91 -0
- package/generated/bullet3d_collision_object.d.ts +433 -0
- package/generated/bullet3d_constraint.d.ts +818 -0
- package/generated/bullet3d_rigid_body.d.ts +429 -0
- package/generated/bullet3d_shape.d.ts +123 -0
- package/generated/bullet3d_world.d.ts +492 -0
- package/generated/camera.d.ts +29 -32
- package/generated/collectionfactory.d.ts +15 -18
- package/generated/collectionproxy.d.ts +22 -6
- package/generated/compute.d.ts +12 -238
- package/generated/crash.d.ts +24 -10
- package/generated/editor-vm/http.d.ts +90 -7
- package/generated/editor-vm/image.d.ts +7 -7
- package/generated/editor-vm/json.d.ts +11 -0
- package/generated/editor-vm/localization.d.ts +7 -7
- package/generated/editor-vm/tilemap_tiles.d.ts +56 -10
- package/generated/editor-vm/zip.d.ts +28 -0
- package/generated/editor.d.ts +1496 -430
- package/generated/factory.d.ts +21 -25
- package/generated/font.d.ts +64 -22
- package/generated/go.d.ts +235 -182
- package/generated/graphics.d.ts +335 -97
- package/generated/gui.d.ts +240 -471
- package/generated/html5.d.ts +2 -2
- package/generated/http.d.ts +28 -35
- package/generated/image.d.ts +105 -72
- package/generated/json.d.ts +34 -16
- package/generated/kinds/gui-script.d.ts +7 -0
- package/generated/kinds/render-script.d.ts +7 -0
- package/generated/kinds/script.d.ts +7 -0
- package/generated/label.d.ts +77 -7
- package/generated/liveupdate.d.ts +13 -10
- package/generated/material.d.ts +312 -360
- package/generated/model.d.ts +40 -39
- package/generated/particlefx.d.ts +19 -28
- package/generated/physics.d.ts +365 -133
- package/generated/profiler.d.ts +13 -23
- package/generated/render.d.ts +237 -297
- package/generated/resource.d.ts +664 -583
- package/generated/socket.d.ts +120 -133
- package/generated/sound.d.ts +62 -31
- package/generated/sprite.d.ts +31 -17
- package/generated/sys.d.ts +234 -190
- package/generated/tilemap.d.ts +21 -16
- package/generated/timer.d.ts +34 -21
- package/generated/versions/defold-1.12.4/b2d_body.d.ts +0 -7
- package/generated/versions/defold-1.12.4/buffer.d.ts +1 -3
- package/generated/versions/defold-1.12.4/camera.d.ts +21 -21
- package/generated/versions/defold-1.12.4/collectionfactory.d.ts +9 -9
- package/generated/versions/defold-1.12.4/collectionproxy.d.ts +2 -2
- package/generated/versions/defold-1.12.4/crash.d.ts +2 -2
- package/generated/versions/defold-1.12.4/factory.d.ts +15 -16
- package/generated/versions/defold-1.12.4/go.d.ts +6 -12
- package/generated/versions/defold-1.12.4/gui.d.ts +77 -175
- package/generated/versions/defold-1.12.4/html5.d.ts +1 -1
- package/generated/versions/defold-1.12.4/http.d.ts +0 -13
- package/generated/versions/defold-1.12.4/image.d.ts +16 -33
- package/generated/versions/defold-1.12.4/index.d.ts +1 -0
- package/generated/versions/defold-1.12.4/json.d.ts +10 -6
- package/generated/versions/defold-1.12.4/label.d.ts +2 -3
- package/generated/versions/defold-1.12.4/liveupdate.d.ts +5 -3
- package/generated/versions/defold-1.12.4/model.d.ts +2 -10
- package/generated/versions/defold-1.12.4/particlefx.d.ts +2 -5
- package/generated/versions/defold-1.12.4/physics.d.ts +69 -67
- package/generated/versions/defold-1.12.4/profiler.d.ts +2 -5
- package/generated/versions/defold-1.12.4/render.d.ts +99 -128
- package/generated/versions/defold-1.12.4/resource.d.ts +120 -148
- package/generated/versions/defold-1.12.4/socket.d.ts +34 -60
- package/generated/versions/defold-1.12.4/sound.d.ts +8 -8
- package/generated/versions/defold-1.12.4/sprite.d.ts +15 -5
- package/generated/versions/defold-1.12.4/sys.d.ts +37 -71
- package/generated/versions/defold-1.12.4/tilemap.d.ts +18 -11
- package/generated/versions/defold-1.12.4/timer.d.ts +5 -3
- package/generated/versions/defold-1.12.4/vmath.d.ts +0 -21
- package/generated/versions/defold-1.12.4/window.d.ts +1 -16
- package/generated/versions/defold-1.13.0/b2d_body.d.ts +10 -55
- package/generated/versions/defold-1.13.0/b2d_fixture.d.ts +25 -25
- package/generated/versions/defold-1.13.0/b2d_shape.d.ts +169 -8
- package/generated/versions/defold-1.13.0/b2d_world.d.ts +16 -10
- package/generated/versions/defold-1.13.0/buffer.d.ts +1 -3
- package/generated/versions/defold-1.13.0/camera.d.ts +25 -25
- package/generated/versions/defold-1.13.0/collectionfactory.d.ts +9 -9
- package/generated/versions/defold-1.13.0/collectionproxy.d.ts +2 -2
- package/generated/versions/defold-1.13.0/compute.d.ts +0 -69
- package/generated/versions/defold-1.13.0/crash.d.ts +2 -2
- package/generated/versions/defold-1.13.0/editor-vm/tilemap_tiles.d.ts +3 -3
- package/generated/versions/defold-1.13.0/editor.d.ts +34 -24
- package/generated/versions/defold-1.13.0/factory.d.ts +15 -16
- package/generated/versions/defold-1.13.0/go.d.ts +6 -12
- package/generated/versions/defold-1.13.0/graphics.d.ts +73 -37
- package/generated/versions/defold-1.13.0/gui.d.ts +77 -175
- package/generated/versions/defold-1.13.0/html5.d.ts +1 -1
- package/generated/versions/defold-1.13.0/http.d.ts +0 -13
- package/generated/versions/defold-1.13.0/image.d.ts +16 -33
- package/generated/versions/defold-1.13.0/index.d.ts +1 -0
- package/generated/versions/defold-1.13.0/json.d.ts +10 -6
- package/generated/versions/defold-1.13.0/label.d.ts +2 -3
- package/generated/versions/defold-1.13.0/liveupdate.d.ts +7 -5
- package/generated/versions/defold-1.13.0/material.d.ts +68 -106
- package/generated/versions/defold-1.13.0/model.d.ts +2 -10
- package/generated/versions/defold-1.13.0/particlefx.d.ts +2 -5
- package/generated/versions/defold-1.13.0/physics.d.ts +69 -67
- package/generated/versions/defold-1.13.0/profiler.d.ts +2 -5
- package/generated/versions/defold-1.13.0/render.d.ts +99 -128
- package/generated/versions/defold-1.13.0/resource.d.ts +126 -150
- package/generated/versions/defold-1.13.0/socket.d.ts +34 -60
- package/generated/versions/defold-1.13.0/sound.d.ts +8 -8
- package/generated/versions/defold-1.13.0/sprite.d.ts +15 -5
- package/generated/versions/defold-1.13.0/sys.d.ts +37 -71
- package/generated/versions/defold-1.13.0/tilemap.d.ts +18 -11
- package/generated/versions/defold-1.13.0/timer.d.ts +5 -3
- package/generated/versions/defold-1.13.0/vmath.d.ts +0 -21
- package/generated/versions/defold-1.13.0/window.d.ts +1 -16
- package/generated/versions/defold-1.13.1/b2d.d.ts +33 -0
- package/generated/versions/defold-1.13.1/b2d_body.d.ts +636 -0
- package/generated/versions/defold-1.13.1/b2d_chain.d.ts +106 -0
- package/generated/versions/defold-1.13.1/b2d_fixture.d.ts +157 -0
- package/generated/versions/defold-1.13.1/b2d_joint.d.ts +823 -0
- package/generated/versions/defold-1.13.1/b2d_shape.d.ts +400 -0
- package/generated/versions/defold-1.13.1/b2d_world.d.ts +320 -0
- package/generated/versions/defold-1.13.1/buffer.d.ts +189 -0
- package/generated/versions/defold-1.13.1/camera.d.ts +303 -0
- package/generated/versions/defold-1.13.1/collectionfactory.d.ts +151 -0
- package/generated/versions/defold-1.13.1/collectionproxy.d.ts +93 -0
- package/generated/versions/defold-1.13.1/compute.d.ts +237 -0
- package/generated/versions/defold-1.13.1/crash.d.ts +143 -0
- package/generated/versions/defold-1.13.1/editor-vm/http.d.ts +56 -0
- package/generated/versions/defold-1.13.1/editor-vm/image.d.ts +48 -0
- package/generated/versions/defold-1.13.1/editor-vm/json.d.ts +10 -0
- package/generated/versions/defold-1.13.1/editor-vm/localization.d.ts +42 -0
- package/generated/versions/defold-1.13.1/editor-vm/tilemap_tiles.d.ts +80 -0
- package/generated/versions/defold-1.13.1/editor-vm/zip.d.ts +10 -0
- package/generated/versions/defold-1.13.1/editor-vm/zlib.d.ts +24 -0
- package/generated/versions/defold-1.13.1/editor.d.ts +1121 -0
- package/generated/versions/defold-1.13.1/factory.d.ts +124 -0
- package/generated/versions/defold-1.13.1/font.d.ts +81 -0
- package/generated/versions/defold-1.13.1/go.d.ts +1107 -0
- package/generated/versions/defold-1.13.1/graphics.d.ts +411 -0
- package/generated/versions/defold-1.13.1/gui.d.ts +2353 -0
- package/generated/versions/defold-1.13.1/html5.d.ts +55 -0
- package/generated/versions/defold-1.13.1/http.d.ts +77 -0
- package/generated/versions/defold-1.13.1/image.d.ts +131 -0
- package/generated/versions/defold-1.13.1/index.d.ts +57 -0
- package/generated/versions/defold-1.13.1/json.d.ts +80 -0
- package/generated/versions/defold-1.13.1/kinds/editor-script.d.ts +14 -0
- package/generated/versions/defold-1.13.1/label.d.ts +93 -0
- package/generated/versions/defold-1.13.1/liveupdate.d.ts +142 -0
- package/generated/versions/defold-1.13.1/material.d.ts +408 -0
- package/generated/versions/defold-1.13.1/model.d.ts +272 -0
- package/generated/versions/defold-1.13.1/msg.d.ts +10 -0
- package/generated/versions/defold-1.13.1/particlefx.d.ts +163 -0
- package/generated/versions/defold-1.13.1/physics.d.ts +559 -0
- package/generated/versions/defold-1.13.1/profiler.d.ts +235 -0
- package/generated/versions/defold-1.13.1/render.d.ts +1190 -0
- package/generated/versions/defold-1.13.1/resource.d.ts +1523 -0
- package/generated/versions/defold-1.13.1/socket.d.ts +784 -0
- package/generated/versions/defold-1.13.1/sound.d.ts +292 -0
- package/generated/versions/defold-1.13.1/sprite.d.ts +175 -0
- package/generated/versions/defold-1.13.1/sys.d.ts +678 -0
- package/generated/versions/defold-1.13.1/tilemap.d.ts +208 -0
- package/generated/versions/defold-1.13.1/timer.d.ts +125 -0
- package/generated/versions/defold-1.13.1/types.d.ts +61 -0
- package/generated/versions/defold-1.13.1/vmath.d.ts +774 -0
- package/generated/versions/defold-1.13.1/window.d.ts +183 -0
- package/generated/versions/defold-1.13.1/zlib.d.ts +41 -0
- package/generated/vmath.d.ts +1 -21
- package/generated/window.d.ts +71 -71
- package/identity-vocabulary.json +561 -0
- package/index.d.ts +7 -0
- package/package.json +13 -2
- package/scripts/example-store-io.ts +12 -1
- package/scripts/extension-goldens.ts +1 -0
- package/scripts/fidelity-baseline.json +146 -46
- package/scripts/generate-api-availability.ts +90 -12
- package/scripts/generate-api-signatures.ts +12 -2
- package/scripts/import-defold-release.ts +85 -24
- package/scripts/prose-constants.ts +77 -16
- package/scripts/regen.ts +391 -77
- package/scripts/shared-handle-methods.ts +53 -0
- package/scripts/signature-store-fs.ts +1 -0
- package/scripts/sync-api-docs.ts +16 -5
- package/src/api-availability.ts +0 -0
- package/src/api-doc.ts +201 -3
- package/src/api-identity.ts +252 -0
- package/src/core-types.ts +26 -3
- package/src/correction-pins.ts +49 -0
- package/src/doc-comment.ts +104 -11
- package/src/doc-corrections.ts +108 -0
- package/src/editor-vm-globals.d.ts +5 -2
- package/src/emit-dts.ts +2064 -281
- package/src/emit-messages.ts +52 -0
- package/src/example-store.ts +125 -14
- package/src/field-correction-coverage.ts +204 -0
- package/src/fnv1a.ts +16 -0
- package/src/go-overloads.d.ts +25 -6
- package/src/index-base-table.ts +145 -0
- package/src/index-slot-classifications.ts +588 -0
- package/src/index.ts +38 -5
- package/src/library-index-slot-classifications.ts +332 -0
- package/src/lifecycle.ts +61 -199
- package/src/luals-type-expr.ts +354 -0
- package/src/msg-overloads.d.ts +0 -1
- package/src/param-correction-provenance.ts +8 -11
- package/src/render-overloads.d.ts +0 -15
- package/src/return-correction-provenance.ts +58 -16
- package/src/sys-overloads.d.ts +48 -0
- package/src/vmath-overloads.d.ts +27 -1
- package/src/window-event-guard.d.ts +6 -9
- package/url-parameters.json +1 -2
package/src/emit-messages.ts
CHANGED
|
@@ -85,6 +85,58 @@ export function applyMessageDeprecations(
|
|
|
85
85
|
return { entries };
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
// A payload field whose documented type the engine refuses, with the type it
|
|
89
|
+
// takes instead. `upstream` is the documented type the correction replaces:
|
|
90
|
+
// once the catalog stops declaring it the entry throws and is deleted.
|
|
91
|
+
export interface MessageFieldCorrection {
|
|
92
|
+
readonly origin: string;
|
|
93
|
+
readonly name: string;
|
|
94
|
+
readonly field: string;
|
|
95
|
+
readonly types: readonly string[];
|
|
96
|
+
readonly upstream: readonly string[];
|
|
97
|
+
readonly reason: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Demonstrated by the engine probe only: each entry is a payload the running
|
|
101
|
+
// engine rejected when it held the documented type.
|
|
102
|
+
export const MESSAGE_FIELD_CORRECTIONS: readonly MessageFieldCorrection[] = [
|
|
103
|
+
{
|
|
104
|
+
origin: "camera",
|
|
105
|
+
name: "set_camera",
|
|
106
|
+
field: "orthographic_projection",
|
|
107
|
+
types: ["number"],
|
|
108
|
+
upstream: ["boolean"],
|
|
109
|
+
reason:
|
|
110
|
+
"the engine decodes the payload into a number field and raises `number expected, got boolean` for the documented boolean",
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
export function applyMessageFieldCorrections(
|
|
115
|
+
catalog: MessageCatalog,
|
|
116
|
+
overlay: readonly MessageFieldCorrection[] = MESSAGE_FIELD_CORRECTIONS,
|
|
117
|
+
): MessageCatalog {
|
|
118
|
+
const entries = catalog.entries.map((entry) => ({
|
|
119
|
+
...entry,
|
|
120
|
+
payload: entry.payload.map((field) => ({ ...field })),
|
|
121
|
+
}));
|
|
122
|
+
for (const correction of overlay) {
|
|
123
|
+
const field = entries
|
|
124
|
+
.find((entry) => entry.origin === correction.origin && entry.name === correction.name)
|
|
125
|
+
?.payload.find((candidate) => candidate.name === correction.field);
|
|
126
|
+
const identity = `(origin=${correction.origin}, name=${correction.name}, field=${correction.field})`;
|
|
127
|
+
if (field === undefined) {
|
|
128
|
+
throw new Error(`applyMessageFieldCorrections: no catalog field matches ${identity}`);
|
|
129
|
+
}
|
|
130
|
+
if (field.types.join("|") !== correction.upstream.join("|")) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`applyMessageFieldCorrections: upstream now declares ${field.types.join("|")} for ${identity}; delete the correction`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
field.types = [...correction.types];
|
|
136
|
+
}
|
|
137
|
+
return { entries };
|
|
138
|
+
}
|
|
139
|
+
|
|
88
140
|
const TS_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
89
141
|
const ENGINE_TYPES = [
|
|
90
142
|
"Hash",
|
package/src/example-store.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { ApiModule } from "./api-doc";
|
|
2
|
+
import { htmlToDocText, summaryFor } from "./doc-comment";
|
|
3
|
+
import { fnv1a64 } from "./fnv1a";
|
|
4
|
+
|
|
1
5
|
// A hand-authored TypeScript translation of one element's ref-doc `@example`,
|
|
2
6
|
// pinned by a hash of the exact source Lua it replaces. A ref-doc re-pin that
|
|
3
7
|
// changes the source Lua flips the hash, so a stale translation stops matching
|
|
@@ -5,6 +9,10 @@
|
|
|
5
9
|
export interface Translation {
|
|
6
10
|
sourceHash: string;
|
|
7
11
|
ts: string;
|
|
12
|
+
// The authored replacement for the upstream sentence that introduces this
|
|
13
|
+
// segment. Pinned by the same `sourceHash`, so an upstream rewrite of the
|
|
14
|
+
// example body drops the caption together with the body.
|
|
15
|
+
prose?: string;
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
// An FQN maps to one translation per distinct example body it carries: an
|
|
@@ -17,25 +25,20 @@ export interface Translation {
|
|
|
17
25
|
// replacing the entry silently regresses every demoted surface to raw Lua.
|
|
18
26
|
export type TranslationStore = Record<string, Translation[]>;
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
// A prose Lua fence deliberately left as Lua, pinned like a translation by the
|
|
29
|
+
// hash of the fence body, with the reason no TypeScript form fits. Keyed the
|
|
30
|
+
// way `proseLuaFences` keys the fence.
|
|
31
|
+
export type ProseLuaKeepStore = Record<string, { sourceHash: string; reason: string }[]>;
|
|
23
32
|
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// ambient-`Bun` reference here would fail type-checking in every downstream
|
|
28
|
-
// consumer that compiles the shipped `src/` graph.
|
|
33
|
+
// The `fnv1a64` hash of an example's source, which must stay node- and Bun-free
|
|
34
|
+
// for the reason given there: this module is reachable from `index.ts` (via
|
|
35
|
+
// `emit-dts`).
|
|
29
36
|
//
|
|
30
37
|
// The input is the already-normalized post-`htmlToCodeText` string (per-line
|
|
31
38
|
// trailing whitespace and surrounding blank lines stripped), so the hash is
|
|
32
39
|
// independent of trailing whitespace in the original ref-doc HTML.
|
|
33
40
|
export function hashExampleSource(source: string): string {
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < source.length; i++) {
|
|
36
|
-
hash = ((hash ^ BigInt(source.charCodeAt(i))) * FNV_PRIME) & U64_MASK;
|
|
37
|
-
}
|
|
38
|
-
return hash.toString(16).padStart(16, "0");
|
|
41
|
+
return fnv1a64(source);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
// Return the stored TypeScript body only when the FQN exists and one of its
|
|
@@ -60,7 +63,7 @@ export function lookupTranslation(
|
|
|
60
63
|
* emitted as several `@example` blocks only when every one of them has an
|
|
61
64
|
* authored body. A partial resolve would document some of the element's
|
|
62
65
|
* examples and silently drop the rest, so the caller falls back to the
|
|
63
|
-
*
|
|
66
|
+
* upstream Lua instead. An empty hash list is a miss for the same reason —
|
|
64
67
|
* it would otherwise report success while documenting nothing.
|
|
65
68
|
*/
|
|
66
69
|
export function lookupExampleTranslations(
|
|
@@ -77,3 +80,111 @@ export function lookupExampleTranslations(
|
|
|
77
80
|
}
|
|
78
81
|
return bodies;
|
|
79
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The stored body and caption for each of a blob's segments, in the order
|
|
86
|
+
* given, or `null` the moment one of them does not resolve.
|
|
87
|
+
*
|
|
88
|
+
* Same all-or-nothing and empty-list rules as `lookupExampleTranslations`. Each
|
|
89
|
+
* caption is the entry's authored `prose` when it carries one, else the
|
|
90
|
+
* segment's upstream prose.
|
|
91
|
+
*/
|
|
92
|
+
export function lookupExampleSegments(
|
|
93
|
+
store: TranslationStore,
|
|
94
|
+
fqn: string,
|
|
95
|
+
segments: readonly { code: string; prose: string }[],
|
|
96
|
+
): { ts: string; prose: string }[] | null {
|
|
97
|
+
const entries = store[fqn];
|
|
98
|
+
if (!entries || segments.length === 0) return null;
|
|
99
|
+
const resolved: { ts: string; prose: string }[] = [];
|
|
100
|
+
for (const segment of segments) {
|
|
101
|
+
const sourceHash = hashExampleSource(segment.code);
|
|
102
|
+
const entry = entries.find((candidate) => candidate.sourceHash === sourceHash);
|
|
103
|
+
if (!entry) return null;
|
|
104
|
+
resolved.push({ ts: entry.ts, prose: entry.prose ?? segment.prose });
|
|
105
|
+
}
|
|
106
|
+
return resolved;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// A fence `htmlToDocText` opened on a line of its own, located by line index:
|
|
110
|
+
// `open` is the opener, `close` the closing ``` line.
|
|
111
|
+
interface DocFence {
|
|
112
|
+
open: number;
|
|
113
|
+
close: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The one reader of prose fences, shared by the enumeration and the swap so the
|
|
117
|
+
// body one hashes is the body the other replaces. Every fence is walked, so a
|
|
118
|
+
// closing ``` of a `text` fence is never read as the opener of the next one.
|
|
119
|
+
function luaDocFences(lines: readonly string[]): DocFence[] {
|
|
120
|
+
const fences: DocFence[] = [];
|
|
121
|
+
for (let open = 0; open < lines.length; open += 1) {
|
|
122
|
+
if (!lines[open]?.startsWith("```")) continue;
|
|
123
|
+
let close = open + 1;
|
|
124
|
+
while (close < lines.length && !lines[close]?.startsWith("```")) close += 1;
|
|
125
|
+
if (close >= lines.length) break;
|
|
126
|
+
if (lines[open] === "```lua") fences.push({ open, close });
|
|
127
|
+
open = close;
|
|
128
|
+
}
|
|
129
|
+
return fences;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function fenceBody(lines: readonly string[], fence: DocFence): string {
|
|
133
|
+
return lines.slice(fence.open + 1, fence.close).join("\n");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Swap each ```lua fence in `htmlToDocText` output for the TypeScript pinned
|
|
138
|
+
* under `key` to its body's hash, leaving every other byte alone. A fence with
|
|
139
|
+
* no matching entry stays Lua, the same fallback the `@example` ladder keeps.
|
|
140
|
+
* With `keepSource`, each swapped fence is followed by a blank line and its
|
|
141
|
+
* untouched body as a ```lua original fence, the pairing the API reference
|
|
142
|
+
* renders as TypeScript and Lua tabs.
|
|
143
|
+
*/
|
|
144
|
+
export function translateProseFences(
|
|
145
|
+
markdown: string,
|
|
146
|
+
key: string,
|
|
147
|
+
store: TranslationStore,
|
|
148
|
+
options: { keepSource?: boolean } = {},
|
|
149
|
+
): string {
|
|
150
|
+
if (!store[key]) return markdown;
|
|
151
|
+
const lines = markdown.split("\n");
|
|
152
|
+
const fences = luaDocFences(lines);
|
|
153
|
+
for (const fence of fences.reverse()) {
|
|
154
|
+
const lua = fenceBody(lines, fence);
|
|
155
|
+
const ts = lookupTranslation(store, key, hashExampleSource(lua));
|
|
156
|
+
if (ts === null) continue;
|
|
157
|
+
const source = options.keepSource ? ["", "```lua original", ...lua.split("\n"), "```"] : [];
|
|
158
|
+
lines.splice(
|
|
159
|
+
fence.open,
|
|
160
|
+
fence.close - fence.open + 1,
|
|
161
|
+
"```ts",
|
|
162
|
+
...ts.split("\n"),
|
|
163
|
+
"```",
|
|
164
|
+
...source,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return lines.join("\n");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Every ```lua fence in the prose a module documents, keyed the way the emit
|
|
172
|
+
* and the API reference look its translation up: the namespace description
|
|
173
|
+
* under the namespace, and a function's summary, parameter and return docs
|
|
174
|
+
* under the function's name.
|
|
175
|
+
*/
|
|
176
|
+
export function proseLuaFences(module: ApiModule): { key: string; lua: string }[] {
|
|
177
|
+
const slots: [string, string][] = [
|
|
178
|
+
[module.namespace, summaryFor(module.brief, module.description)],
|
|
179
|
+
];
|
|
180
|
+
for (const fn of module.functions) {
|
|
181
|
+
slots.push([fn.name, summaryFor(fn.brief, fn.description)]);
|
|
182
|
+
for (const slot of [...fn.parameters, ...fn.returnValues]) slots.push([fn.name, slot.doc]);
|
|
183
|
+
}
|
|
184
|
+
const out: { key: string; lua: string }[] = [];
|
|
185
|
+
for (const [key, html] of slots) {
|
|
186
|
+
const lines = htmlToDocText(html).split("\n");
|
|
187
|
+
for (const fence of luaDocFences(lines)) out.push({ key, lua: fenceBody(lines, fence) });
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { ApiFunction, ApiModule, ApiParameter, ApiStruct } from "./api-doc";
|
|
2
|
+
import {
|
|
3
|
+
LIST_FIELD_CORRECTIONS,
|
|
4
|
+
memberCorrectionKey,
|
|
5
|
+
REQUIRED_FIELD_CORRECTIONS,
|
|
6
|
+
RETURN_FIELD_OPTIONALITY_CORRECTIONS,
|
|
7
|
+
} from "./emit-dts";
|
|
8
|
+
import { matchBracket, splitTopLevel } from "./luals-type-expr";
|
|
9
|
+
|
|
10
|
+
// The slot-keyed field corrections are applied to fields recovered from a prose
|
|
11
|
+
// `table` slot. A release that types the slot as a `STRUCT` or an inline record
|
|
12
|
+
// recovers no fields, so each such entry must be stated upstream already or be
|
|
13
|
+
// carried by a member-keyed entry on the struct; anything else would go inert.
|
|
14
|
+
export interface FieldCorrectionTables {
|
|
15
|
+
readonly required: ReadonlyMap<string, unknown>;
|
|
16
|
+
readonly list: ReadonlyMap<string, unknown>;
|
|
17
|
+
readonly optionality: ReadonlyMap<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const FIELD_CORRECTION_TABLES: FieldCorrectionTables = {
|
|
21
|
+
required: REQUIRED_FIELD_CORRECTIONS,
|
|
22
|
+
list: LIST_FIELD_CORRECTIONS,
|
|
23
|
+
optionality: RETURN_FIELD_OPTIONALITY_CORRECTIONS,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export interface FieldCorrectionGap {
|
|
27
|
+
readonly key: string;
|
|
28
|
+
// The struct whose member would carry the correction, when the path reached one.
|
|
29
|
+
readonly struct?: string;
|
|
30
|
+
readonly reason: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type Kind = keyof FieldCorrectionTables;
|
|
34
|
+
|
|
35
|
+
interface Member {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly type: string;
|
|
38
|
+
readonly optional: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// A slot or member type resolved to the members it declares: a `STRUCT` by name,
|
|
42
|
+
// or an inline `{ name:type, ... }` record.
|
|
43
|
+
interface Shape {
|
|
44
|
+
readonly struct?: string;
|
|
45
|
+
readonly members: readonly Member[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const PROSE_TABLE = "table";
|
|
49
|
+
|
|
50
|
+
function stripList(type: string): string {
|
|
51
|
+
let t = type.trim();
|
|
52
|
+
while (t.endsWith("[]")) t = t.slice(0, -2).trim();
|
|
53
|
+
while (t.startsWith("(") && matchBracket(t, 0) === t.length - 1) t = t.slice(1, -1).trim();
|
|
54
|
+
return t;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function recordMembers(record: string): Member[] {
|
|
58
|
+
return splitTopLevel(record.slice(1, -1), ",")
|
|
59
|
+
.map((part) => part.trim())
|
|
60
|
+
.filter((part) => part.length > 0)
|
|
61
|
+
.map((part) => {
|
|
62
|
+
const colon = part.indexOf(":");
|
|
63
|
+
const raw = colon === -1 ? part : part.slice(0, colon).trim();
|
|
64
|
+
const optional = raw.endsWith("?");
|
|
65
|
+
return {
|
|
66
|
+
name: optional ? raw.slice(0, -1) : raw,
|
|
67
|
+
type: colon === -1 ? "" : part.slice(colon + 1).trim(),
|
|
68
|
+
optional,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function shapeOf(type: string, structs: ReadonlyMap<string, ApiStruct>): Shape | null {
|
|
74
|
+
const t = stripList(type);
|
|
75
|
+
if (t.startsWith("{") && matchBracket(t, 0) === t.length - 1) {
|
|
76
|
+
return { members: recordMembers(t) };
|
|
77
|
+
}
|
|
78
|
+
const struct = structs.get(t);
|
|
79
|
+
if (struct === undefined) return null;
|
|
80
|
+
return {
|
|
81
|
+
struct: struct.name,
|
|
82
|
+
members: struct.members.map((member) => ({
|
|
83
|
+
name: member.name,
|
|
84
|
+
type: member.type,
|
|
85
|
+
optional: member.isOptional,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parseKey(key: string): {
|
|
91
|
+
element: string;
|
|
92
|
+
kind: "param" | "return";
|
|
93
|
+
slot: string;
|
|
94
|
+
segments: string[];
|
|
95
|
+
} | null {
|
|
96
|
+
const [element, kind, slot, path, ...rest] = key.split(":");
|
|
97
|
+
if (
|
|
98
|
+
element === undefined ||
|
|
99
|
+
slot === undefined ||
|
|
100
|
+
path === undefined ||
|
|
101
|
+
rest.length > 0 ||
|
|
102
|
+
(kind !== "param" && kind !== "return")
|
|
103
|
+
) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return { element, kind, slot, segments: path.split(".").map((s) => s.replace(/\[\]$/, "")) };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function slotsNamed(
|
|
110
|
+
overloads: readonly ApiFunction[],
|
|
111
|
+
kind: "param" | "return",
|
|
112
|
+
slot: string,
|
|
113
|
+
): ApiParameter[] {
|
|
114
|
+
return overloads.flatMap((fn) =>
|
|
115
|
+
(kind === "param" ? fn.parameters : fn.returnValues).filter((p) => p.name === slot),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function slotGap(
|
|
120
|
+
key: string,
|
|
121
|
+
table: Kind,
|
|
122
|
+
slotTypes: readonly string[],
|
|
123
|
+
segments: readonly string[],
|
|
124
|
+
structs: ReadonlyMap<string, ApiStruct>,
|
|
125
|
+
tables: FieldCorrectionTables,
|
|
126
|
+
): FieldCorrectionGap | null {
|
|
127
|
+
const shapes = slotTypes.map((type) => shapeOf(type, structs)).filter((s) => s !== null);
|
|
128
|
+
if (shapes.length === 0) {
|
|
129
|
+
return { key, reason: `slot is typed ${slotTypes.join("|")}, which declares no members` };
|
|
130
|
+
}
|
|
131
|
+
for (const initial of shapes) {
|
|
132
|
+
let shape: Shape = initial;
|
|
133
|
+
for (const [index, name] of segments.entries()) {
|
|
134
|
+
const member = shape.members.find((candidate) => candidate.name === name);
|
|
135
|
+
const struct = shape.struct === undefined ? {} : { struct: shape.struct };
|
|
136
|
+
if (member === undefined) return { key, ...struct, reason: `no member ${name}` };
|
|
137
|
+
if (index < segments.length - 1) {
|
|
138
|
+
const next = shapeOf(member.type, structs);
|
|
139
|
+
if (next === null) {
|
|
140
|
+
return { key, ...struct, reason: `member ${name} is typed ${member.type}` };
|
|
141
|
+
}
|
|
142
|
+
shape = next;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const carried =
|
|
146
|
+
shape.struct !== undefined && tables[table].has(memberCorrectionKey(shape.struct, name));
|
|
147
|
+
const upstream =
|
|
148
|
+
table === "required" ? !member.optional : table === "optionality" ? member.optional : false;
|
|
149
|
+
if (!carried && !upstream) {
|
|
150
|
+
return {
|
|
151
|
+
key,
|
|
152
|
+
...struct,
|
|
153
|
+
reason: `neither upstream nor a member-keyed ${table} correction states it`,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Every slot-keyed field correction that goes inert on these modules — one
|
|
163
|
+
* target's, after its skip rules, since a slot in `b2d.fixture` can name a struct
|
|
164
|
+
* `b2d` declares. An element the target does not declare, and a slot still typed
|
|
165
|
+
* as a prose `table`, are out of scope and report nothing.
|
|
166
|
+
*/
|
|
167
|
+
export function fieldCorrectionGaps(
|
|
168
|
+
modules: readonly ApiModule[],
|
|
169
|
+
tables: FieldCorrectionTables = FIELD_CORRECTION_TABLES,
|
|
170
|
+
): FieldCorrectionGap[] {
|
|
171
|
+
const structs = new Map(
|
|
172
|
+
modules.flatMap((module) => module.structs ?? []).map((struct) => [struct.name, struct]),
|
|
173
|
+
);
|
|
174
|
+
const functions = modules.flatMap((module) => module.functions);
|
|
175
|
+
const gaps: FieldCorrectionGap[] = [];
|
|
176
|
+
for (const table of ["required", "list", "optionality"] as const) {
|
|
177
|
+
for (const key of tables[table].keys()) {
|
|
178
|
+
const parsed = parseKey(key);
|
|
179
|
+
if (parsed === null) continue;
|
|
180
|
+
const overloads = functions.filter((fn) => fn.name === parsed.element);
|
|
181
|
+
if (overloads.length === 0) continue;
|
|
182
|
+
const slots = slotsNamed(overloads, parsed.kind, parsed.slot);
|
|
183
|
+
if (slots.length === 0) {
|
|
184
|
+
gaps.push({ key, reason: `${parsed.element} declares no ${parsed.kind} ${parsed.slot}` });
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
for (const slot of slots) {
|
|
188
|
+
if (slot.types.includes(PROSE_TABLE)) continue;
|
|
189
|
+
const gap = slotGap(key, table, slot.types, parsed.segments, structs, tables);
|
|
190
|
+
if (gap !== null) {
|
|
191
|
+
gaps.push(gap);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return gaps;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function formatFieldCorrectionGaps(gaps: readonly FieldCorrectionGap[]): string {
|
|
201
|
+
return gaps
|
|
202
|
+
.map((gap) => `${gap.key}${gap.struct === undefined ? "" : ` (${gap.struct})`}: ${gap.reason}`)
|
|
203
|
+
.join("\n");
|
|
204
|
+
}
|
package/src/fnv1a.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const FNV_OFFSET_BASIS = 0xcbf29ce484222325n;
|
|
2
|
+
const FNV_PRIME = 0x100000001b3n;
|
|
3
|
+
const U64_MASK = 0xffffffffffffffffn;
|
|
4
|
+
|
|
5
|
+
// A pure, dependency-free FNV-1a 64-bit hash over the text's UTF-16 code units,
|
|
6
|
+
// returned as zero-padded hex. Deliberately node- and Bun-free: this module is
|
|
7
|
+
// reachable from `index.ts`, so a `node:crypto` or ambient-`Bun` reference here
|
|
8
|
+
// would fail type-checking in every downstream consumer that compiles the
|
|
9
|
+
// shipped `src/` graph.
|
|
10
|
+
export function fnv1a64(text: string): string {
|
|
11
|
+
let hash = FNV_OFFSET_BASIS;
|
|
12
|
+
for (let i = 0; i < text.length; i++) {
|
|
13
|
+
hash = ((hash ^ BigInt(text.charCodeAt(i))) * FNV_PRIME) & U64_MASK;
|
|
14
|
+
}
|
|
15
|
+
return hash.toString(16).padStart(16, "0");
|
|
16
|
+
}
|
package/src/go-overloads.d.ts
CHANGED
|
@@ -6,10 +6,23 @@ interface ScriptProperty<TValue> {
|
|
|
6
6
|
readonly __defoldScriptProperty: TValue;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
// True when `A` and `B` are identical, `readonly` modifiers included, which
|
|
10
|
+
// plain assignability ignores.
|
|
11
|
+
type Identical<A, B> =
|
|
12
|
+
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
13
|
+
|
|
14
|
+
// The keys of `P` a write may name: every key but a `readonly` one, which the
|
|
15
|
+
// engine refuses to set.
|
|
16
|
+
type WritableKey<P> = {
|
|
17
|
+
[K in keyof P]-?: Identical<{ [Q in K]: P[K] }, { -readonly [Q in K]: P[K] }> extends true
|
|
18
|
+
? K
|
|
19
|
+
: never;
|
|
20
|
+
}[keyof P];
|
|
21
|
+
|
|
9
22
|
declare global {
|
|
10
23
|
namespace go {
|
|
11
24
|
interface GoPropertyOptions {
|
|
12
|
-
/**
|
|
25
|
+
/** **⚠️ 1-based index into an array property; passed to Defold unchanged.** */
|
|
13
26
|
index?: number;
|
|
14
27
|
key?: Hash | string;
|
|
15
28
|
keys?: (Hash | string)[];
|
|
@@ -21,7 +34,7 @@ declare global {
|
|
|
21
34
|
* @param url - url of the game object or component having the property
|
|
22
35
|
* @param property - id of the property to retrieve
|
|
23
36
|
* @param options - optional options table
|
|
24
|
-
* - index number
|
|
37
|
+
* - index number **⚠️ 1-based index into an array property; passed to Defold unchanged.**
|
|
25
38
|
* - key hash or string name of internal property
|
|
26
39
|
* - keys array of hashes or strings identifying internal component resources (e.g. a particle fx emitter, see examples below)
|
|
27
40
|
* @returns the value of the specified property
|
|
@@ -55,18 +68,19 @@ declare global {
|
|
|
55
68
|
* @param property - id of the property to set
|
|
56
69
|
* @param value - the value to set, or an array of vector4 to set a material property array
|
|
57
70
|
* @param options - optional options table
|
|
58
|
-
* - index integer
|
|
71
|
+
* - index integer **⚠️ 1-based index into an array property; passed to Defold unchanged.**
|
|
59
72
|
* - key hash or string name of internal property
|
|
60
73
|
* - keys array of hashes or strings identifying internal component resources (e.g. a particle fx emitter, see examples below)
|
|
61
74
|
* @example
|
|
62
75
|
* ```ts
|
|
63
76
|
* go.set("#sprite", "tint", vmath.vector4(1, 0, 0, 1));
|
|
64
77
|
* // Name the target component to gate the value to its property type. The
|
|
65
|
-
* // empty call applies the type argument, then the inner call infers the key
|
|
78
|
+
* // empty call applies the type argument, then the inner call infers the key.
|
|
79
|
+
* // A read-only property such as "animation" is not a key it accepts:
|
|
66
80
|
* go.set<sprite.properties>()("#sprite", "playback_rate", 2);
|
|
67
81
|
* ```
|
|
68
82
|
*/
|
|
69
|
-
function set<P>(): <K extends
|
|
83
|
+
function set<P>(): <K extends WritableKey<P>>(
|
|
70
84
|
url: SceneAddress | Hash | Url,
|
|
71
85
|
property: K,
|
|
72
86
|
value: P[K],
|
|
@@ -85,7 +99,10 @@ declare global {
|
|
|
85
99
|
options?: GoPropertyOptions,
|
|
86
100
|
): void;
|
|
87
101
|
/**
|
|
88
|
-
* Registers a Defold editor
|
|
102
|
+
* Registers a script property, which the Defold editor exposes on every game
|
|
103
|
+
* object and collection that uses the script. Defold accepts the call only at
|
|
104
|
+
* the top level of the script, outside callbacks such as `init` and `update`.
|
|
105
|
+
* A `string` default needs Defold 1.13.2 or later.
|
|
89
106
|
*
|
|
90
107
|
* @deprecated Don't call `go.property` yourself. Declare the property in
|
|
91
108
|
* `defineScript({ properties })` — that is the only form that types it onto
|
|
@@ -122,5 +139,7 @@ declare global {
|
|
|
122
139
|
function property(name: string, value: Vector4): ScriptProperty<Vector4>;
|
|
123
140
|
/** @deprecated Declare quaternions via the `defineScript({ properties })` field. */
|
|
124
141
|
function property(name: string, value: Quaternion): ScriptProperty<Quaternion>;
|
|
142
|
+
/** @deprecated Declare text via the `defineScript({ properties })` field; needs Defold 1.13.2. */
|
|
143
|
+
function property(name: string, value: string): ScriptProperty<string>;
|
|
125
144
|
}
|
|
126
145
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INDEX_BASE_MARKERS,
|
|
3
|
+
INDEX_SLOT_CLASSIFICATIONS,
|
|
4
|
+
type IndexSlotClassification,
|
|
5
|
+
} from "./index-slot-classifications";
|
|
6
|
+
|
|
7
|
+
type NativeBase = "native-1" | "native-0";
|
|
8
|
+
|
|
9
|
+
export interface EngineIndexBaseRow {
|
|
10
|
+
readonly base: NativeBase;
|
|
11
|
+
readonly elements: readonly string[];
|
|
12
|
+
// The slot, or the field path inside it, in plain words.
|
|
13
|
+
readonly position: string;
|
|
14
|
+
// The classification keys the row covers.
|
|
15
|
+
readonly keys: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Slot {
|
|
19
|
+
readonly key: string;
|
|
20
|
+
readonly element: string;
|
|
21
|
+
readonly kind: "param" | "return";
|
|
22
|
+
readonly path: readonly string[];
|
|
23
|
+
readonly base: NativeBase;
|
|
24
|
+
readonly fromEnd: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const KEY = /^(.+?):(param|return):(.+)$/;
|
|
28
|
+
const BASE_LABELS: Readonly<Record<NativeBase, string>> = {
|
|
29
|
+
"native-1": "**1-based**",
|
|
30
|
+
"native-0": "**0-based**",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function nativeSlot(key: string, classification: IndexSlotClassification): Slot | undefined {
|
|
34
|
+
if (classification.class === "not-a-position") return undefined;
|
|
35
|
+
const match = KEY.exec(key);
|
|
36
|
+
if (match?.[1] === undefined || match[3] === undefined) return undefined;
|
|
37
|
+
return {
|
|
38
|
+
key,
|
|
39
|
+
element: match[1],
|
|
40
|
+
kind: match[2] === "return" ? "return" : "param",
|
|
41
|
+
path: match[3].split(":"),
|
|
42
|
+
base: classification.class,
|
|
43
|
+
fromEnd: classification.fromEnd === true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// `b2d.fixture.get_density` -> `b2d.fixture`, `client:send` -> `client`.
|
|
48
|
+
function namespaceOf(element: string): string {
|
|
49
|
+
const end = Math.max(element.lastIndexOf("."), element.lastIndexOf(":"));
|
|
50
|
+
return end < 0 ? element : element.slice(0, end);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function groupBy<T>(items: readonly T[], keyOf: (item: T) => string): [T, ...T[]][] {
|
|
54
|
+
const groups = new Map<string, [T, ...T[]]>();
|
|
55
|
+
for (const item of items) {
|
|
56
|
+
const key = keyOf(item);
|
|
57
|
+
const group = groups.get(key);
|
|
58
|
+
if (group) group.push(item);
|
|
59
|
+
else groups.set(key, [item]);
|
|
60
|
+
}
|
|
61
|
+
return [...groups.values()];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function codeList(names: readonly string[]): string {
|
|
65
|
+
const code = names.map((name) => `\`${name}\``);
|
|
66
|
+
if (code.length < 2) return code.join("");
|
|
67
|
+
return `${code.slice(0, -1).join(", ")} and ${code[code.length - 1]}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function describePosition(
|
|
71
|
+
kind: "param" | "return",
|
|
72
|
+
parent: readonly string[],
|
|
73
|
+
leaves: readonly string[],
|
|
74
|
+
fromEnd: boolean,
|
|
75
|
+
): string {
|
|
76
|
+
const names = codeList(leaves);
|
|
77
|
+
const holder = parent.length === 0 ? "" : `\`${parent.join(".")}\``;
|
|
78
|
+
let position: string;
|
|
79
|
+
if (parent.length === 0) position = kind === "return" ? `returned ${names}` : names;
|
|
80
|
+
else {
|
|
81
|
+
const fields = leaves.length === 1 ? "field" : "fields";
|
|
82
|
+
position = `${names} ${fields} of ${kind === "return" ? "the returned " : ""}${holder}`;
|
|
83
|
+
}
|
|
84
|
+
return fromEnd ? `${position}; counts from the end when negative` : position;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Every engine position the classification table records, one row per slot of
|
|
89
|
+
* one base in one namespace. Slots that differ only in their last name and are
|
|
90
|
+
* taken by the same functions share a row (`x` and `y`), so each row states
|
|
91
|
+
* one fact about one set of calls. Rows come 1-based first, then 0-based, each
|
|
92
|
+
* in table order.
|
|
93
|
+
*/
|
|
94
|
+
export function engineIndexBaseRows(
|
|
95
|
+
classifications: ReadonlyMap<string, IndexSlotClassification> = INDEX_SLOT_CLASSIFICATIONS,
|
|
96
|
+
): EngineIndexBaseRow[] {
|
|
97
|
+
const slots = [...classifications].flatMap(([key, classification]) => {
|
|
98
|
+
const slot = nativeSlot(key, classification);
|
|
99
|
+
return slot === undefined ? [] : [slot];
|
|
100
|
+
});
|
|
101
|
+
const bySlot = groupBy(slots, (slot) =>
|
|
102
|
+
[slot.base, namespaceOf(slot.element), slot.kind, slot.path.join(":")].join("|"),
|
|
103
|
+
);
|
|
104
|
+
const merged = groupBy(bySlot, (group) =>
|
|
105
|
+
[
|
|
106
|
+
group[0].base,
|
|
107
|
+
group[0].kind,
|
|
108
|
+
group[0].path.slice(0, -1).join(":"),
|
|
109
|
+
group[0].fromEnd,
|
|
110
|
+
group.map((slot) => slot.element).join(","),
|
|
111
|
+
].join("|"),
|
|
112
|
+
);
|
|
113
|
+
const rows = merged.map((groups): EngineIndexBaseRow => {
|
|
114
|
+
const [first] = groups[0];
|
|
115
|
+
return {
|
|
116
|
+
base: first.base,
|
|
117
|
+
elements: groups[0].map((slot) => slot.element),
|
|
118
|
+
position: describePosition(
|
|
119
|
+
first.kind,
|
|
120
|
+
first.path.slice(0, -1),
|
|
121
|
+
groups.map(([slot]) => slot.path.at(-1) ?? ""),
|
|
122
|
+
first.fromEnd,
|
|
123
|
+
),
|
|
124
|
+
keys: groups.flatMap((group) => group.map((slot) => slot.key)),
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
return [
|
|
128
|
+
...rows.filter((row) => row.base === "native-1"),
|
|
129
|
+
...rows.filter((row) => row.base === "native-0"),
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The guide's table of engine positions by base, so the guide lists exactly
|
|
134
|
+
// the positions the hovers annotate.
|
|
135
|
+
export function engineIndexBaseTable(
|
|
136
|
+
classifications: ReadonlyMap<string, IndexSlotClassification> = INDEX_SLOT_CLASSIFICATIONS,
|
|
137
|
+
): string {
|
|
138
|
+
const lines = ["| Base | API | Position |", "| --- | --- | --- |"];
|
|
139
|
+
for (const row of engineIndexBaseRows(classifications)) {
|
|
140
|
+
const base = `${INDEX_BASE_MARKERS[row.base]} ${BASE_LABELS[row.base]}`;
|
|
141
|
+
const api = row.elements.map((element) => `\`${element}\``).join(", ");
|
|
142
|
+
lines.push(`| ${base} | ${api} | ${row.position} |`);
|
|
143
|
+
}
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
}
|