@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.
Files changed (224) hide show
  1. package/api-availability.json +3963 -772
  2. package/api-migrations.json +27 -0
  3. package/api-signatures.json +18069 -10240
  4. package/api-targets.json +448 -11
  5. package/examples/translations.json +560 -89
  6. package/fixtures/messages_doc.json +96 -0
  7. package/generated/b2d.d.ts +680 -4
  8. package/generated/b2d_body.d.ts +29 -103
  9. package/generated/b2d_chain.d.ts +5 -6
  10. package/generated/b2d_fixture.d.ts +34 -38
  11. package/generated/b2d_joint.d.ts +503 -25
  12. package/generated/b2d_shape.d.ts +183 -20
  13. package/generated/b2d_world.d.ts +57 -63
  14. package/generated/buffer.d.ts +16 -15
  15. package/generated/builtin-messages.d.ts +7 -1
  16. package/generated/bullet3d.d.ts +91 -0
  17. package/generated/bullet3d_collision_object.d.ts +433 -0
  18. package/generated/bullet3d_constraint.d.ts +818 -0
  19. package/generated/bullet3d_rigid_body.d.ts +429 -0
  20. package/generated/bullet3d_shape.d.ts +123 -0
  21. package/generated/bullet3d_world.d.ts +492 -0
  22. package/generated/camera.d.ts +29 -32
  23. package/generated/collectionfactory.d.ts +15 -18
  24. package/generated/collectionproxy.d.ts +22 -6
  25. package/generated/compute.d.ts +12 -238
  26. package/generated/crash.d.ts +24 -10
  27. package/generated/editor-vm/http.d.ts +90 -7
  28. package/generated/editor-vm/image.d.ts +7 -7
  29. package/generated/editor-vm/json.d.ts +11 -0
  30. package/generated/editor-vm/localization.d.ts +7 -7
  31. package/generated/editor-vm/tilemap_tiles.d.ts +56 -10
  32. package/generated/editor-vm/zip.d.ts +28 -0
  33. package/generated/editor.d.ts +1496 -430
  34. package/generated/factory.d.ts +21 -25
  35. package/generated/font.d.ts +64 -22
  36. package/generated/go.d.ts +235 -182
  37. package/generated/graphics.d.ts +335 -97
  38. package/generated/gui.d.ts +240 -471
  39. package/generated/html5.d.ts +2 -2
  40. package/generated/http.d.ts +28 -35
  41. package/generated/image.d.ts +105 -72
  42. package/generated/json.d.ts +34 -16
  43. package/generated/kinds/gui-script.d.ts +7 -0
  44. package/generated/kinds/render-script.d.ts +7 -0
  45. package/generated/kinds/script.d.ts +7 -0
  46. package/generated/label.d.ts +77 -7
  47. package/generated/liveupdate.d.ts +13 -10
  48. package/generated/material.d.ts +312 -360
  49. package/generated/model.d.ts +40 -39
  50. package/generated/particlefx.d.ts +19 -28
  51. package/generated/physics.d.ts +365 -133
  52. package/generated/profiler.d.ts +13 -23
  53. package/generated/render.d.ts +237 -297
  54. package/generated/resource.d.ts +664 -583
  55. package/generated/socket.d.ts +120 -133
  56. package/generated/sound.d.ts +62 -31
  57. package/generated/sprite.d.ts +31 -17
  58. package/generated/sys.d.ts +234 -190
  59. package/generated/tilemap.d.ts +21 -16
  60. package/generated/timer.d.ts +34 -21
  61. package/generated/versions/defold-1.12.4/b2d_body.d.ts +0 -7
  62. package/generated/versions/defold-1.12.4/buffer.d.ts +1 -3
  63. package/generated/versions/defold-1.12.4/camera.d.ts +21 -21
  64. package/generated/versions/defold-1.12.4/collectionfactory.d.ts +9 -9
  65. package/generated/versions/defold-1.12.4/collectionproxy.d.ts +2 -2
  66. package/generated/versions/defold-1.12.4/crash.d.ts +2 -2
  67. package/generated/versions/defold-1.12.4/factory.d.ts +15 -16
  68. package/generated/versions/defold-1.12.4/go.d.ts +6 -12
  69. package/generated/versions/defold-1.12.4/gui.d.ts +77 -175
  70. package/generated/versions/defold-1.12.4/html5.d.ts +1 -1
  71. package/generated/versions/defold-1.12.4/http.d.ts +0 -13
  72. package/generated/versions/defold-1.12.4/image.d.ts +16 -33
  73. package/generated/versions/defold-1.12.4/index.d.ts +1 -0
  74. package/generated/versions/defold-1.12.4/json.d.ts +10 -6
  75. package/generated/versions/defold-1.12.4/label.d.ts +2 -3
  76. package/generated/versions/defold-1.12.4/liveupdate.d.ts +5 -3
  77. package/generated/versions/defold-1.12.4/model.d.ts +2 -10
  78. package/generated/versions/defold-1.12.4/particlefx.d.ts +2 -5
  79. package/generated/versions/defold-1.12.4/physics.d.ts +69 -67
  80. package/generated/versions/defold-1.12.4/profiler.d.ts +2 -5
  81. package/generated/versions/defold-1.12.4/render.d.ts +99 -128
  82. package/generated/versions/defold-1.12.4/resource.d.ts +120 -148
  83. package/generated/versions/defold-1.12.4/socket.d.ts +34 -60
  84. package/generated/versions/defold-1.12.4/sound.d.ts +8 -8
  85. package/generated/versions/defold-1.12.4/sprite.d.ts +15 -5
  86. package/generated/versions/defold-1.12.4/sys.d.ts +37 -71
  87. package/generated/versions/defold-1.12.4/tilemap.d.ts +18 -11
  88. package/generated/versions/defold-1.12.4/timer.d.ts +5 -3
  89. package/generated/versions/defold-1.12.4/vmath.d.ts +0 -21
  90. package/generated/versions/defold-1.12.4/window.d.ts +1 -16
  91. package/generated/versions/defold-1.13.0/b2d_body.d.ts +10 -55
  92. package/generated/versions/defold-1.13.0/b2d_fixture.d.ts +25 -25
  93. package/generated/versions/defold-1.13.0/b2d_shape.d.ts +169 -8
  94. package/generated/versions/defold-1.13.0/b2d_world.d.ts +16 -10
  95. package/generated/versions/defold-1.13.0/buffer.d.ts +1 -3
  96. package/generated/versions/defold-1.13.0/camera.d.ts +25 -25
  97. package/generated/versions/defold-1.13.0/collectionfactory.d.ts +9 -9
  98. package/generated/versions/defold-1.13.0/collectionproxy.d.ts +2 -2
  99. package/generated/versions/defold-1.13.0/compute.d.ts +0 -69
  100. package/generated/versions/defold-1.13.0/crash.d.ts +2 -2
  101. package/generated/versions/defold-1.13.0/editor-vm/tilemap_tiles.d.ts +3 -3
  102. package/generated/versions/defold-1.13.0/editor.d.ts +34 -24
  103. package/generated/versions/defold-1.13.0/factory.d.ts +15 -16
  104. package/generated/versions/defold-1.13.0/go.d.ts +6 -12
  105. package/generated/versions/defold-1.13.0/graphics.d.ts +73 -37
  106. package/generated/versions/defold-1.13.0/gui.d.ts +77 -175
  107. package/generated/versions/defold-1.13.0/html5.d.ts +1 -1
  108. package/generated/versions/defold-1.13.0/http.d.ts +0 -13
  109. package/generated/versions/defold-1.13.0/image.d.ts +16 -33
  110. package/generated/versions/defold-1.13.0/index.d.ts +1 -0
  111. package/generated/versions/defold-1.13.0/json.d.ts +10 -6
  112. package/generated/versions/defold-1.13.0/label.d.ts +2 -3
  113. package/generated/versions/defold-1.13.0/liveupdate.d.ts +7 -5
  114. package/generated/versions/defold-1.13.0/material.d.ts +68 -106
  115. package/generated/versions/defold-1.13.0/model.d.ts +2 -10
  116. package/generated/versions/defold-1.13.0/particlefx.d.ts +2 -5
  117. package/generated/versions/defold-1.13.0/physics.d.ts +69 -67
  118. package/generated/versions/defold-1.13.0/profiler.d.ts +2 -5
  119. package/generated/versions/defold-1.13.0/render.d.ts +99 -128
  120. package/generated/versions/defold-1.13.0/resource.d.ts +126 -150
  121. package/generated/versions/defold-1.13.0/socket.d.ts +34 -60
  122. package/generated/versions/defold-1.13.0/sound.d.ts +8 -8
  123. package/generated/versions/defold-1.13.0/sprite.d.ts +15 -5
  124. package/generated/versions/defold-1.13.0/sys.d.ts +37 -71
  125. package/generated/versions/defold-1.13.0/tilemap.d.ts +18 -11
  126. package/generated/versions/defold-1.13.0/timer.d.ts +5 -3
  127. package/generated/versions/defold-1.13.0/vmath.d.ts +0 -21
  128. package/generated/versions/defold-1.13.0/window.d.ts +1 -16
  129. package/generated/versions/defold-1.13.1/b2d.d.ts +33 -0
  130. package/generated/versions/defold-1.13.1/b2d_body.d.ts +636 -0
  131. package/generated/versions/defold-1.13.1/b2d_chain.d.ts +106 -0
  132. package/generated/versions/defold-1.13.1/b2d_fixture.d.ts +157 -0
  133. package/generated/versions/defold-1.13.1/b2d_joint.d.ts +823 -0
  134. package/generated/versions/defold-1.13.1/b2d_shape.d.ts +400 -0
  135. package/generated/versions/defold-1.13.1/b2d_world.d.ts +320 -0
  136. package/generated/versions/defold-1.13.1/buffer.d.ts +189 -0
  137. package/generated/versions/defold-1.13.1/camera.d.ts +303 -0
  138. package/generated/versions/defold-1.13.1/collectionfactory.d.ts +151 -0
  139. package/generated/versions/defold-1.13.1/collectionproxy.d.ts +93 -0
  140. package/generated/versions/defold-1.13.1/compute.d.ts +237 -0
  141. package/generated/versions/defold-1.13.1/crash.d.ts +143 -0
  142. package/generated/versions/defold-1.13.1/editor-vm/http.d.ts +56 -0
  143. package/generated/versions/defold-1.13.1/editor-vm/image.d.ts +48 -0
  144. package/generated/versions/defold-1.13.1/editor-vm/json.d.ts +10 -0
  145. package/generated/versions/defold-1.13.1/editor-vm/localization.d.ts +42 -0
  146. package/generated/versions/defold-1.13.1/editor-vm/tilemap_tiles.d.ts +80 -0
  147. package/generated/versions/defold-1.13.1/editor-vm/zip.d.ts +10 -0
  148. package/generated/versions/defold-1.13.1/editor-vm/zlib.d.ts +24 -0
  149. package/generated/versions/defold-1.13.1/editor.d.ts +1121 -0
  150. package/generated/versions/defold-1.13.1/factory.d.ts +124 -0
  151. package/generated/versions/defold-1.13.1/font.d.ts +81 -0
  152. package/generated/versions/defold-1.13.1/go.d.ts +1107 -0
  153. package/generated/versions/defold-1.13.1/graphics.d.ts +411 -0
  154. package/generated/versions/defold-1.13.1/gui.d.ts +2353 -0
  155. package/generated/versions/defold-1.13.1/html5.d.ts +55 -0
  156. package/generated/versions/defold-1.13.1/http.d.ts +77 -0
  157. package/generated/versions/defold-1.13.1/image.d.ts +131 -0
  158. package/generated/versions/defold-1.13.1/index.d.ts +57 -0
  159. package/generated/versions/defold-1.13.1/json.d.ts +80 -0
  160. package/generated/versions/defold-1.13.1/kinds/editor-script.d.ts +14 -0
  161. package/generated/versions/defold-1.13.1/label.d.ts +93 -0
  162. package/generated/versions/defold-1.13.1/liveupdate.d.ts +142 -0
  163. package/generated/versions/defold-1.13.1/material.d.ts +408 -0
  164. package/generated/versions/defold-1.13.1/model.d.ts +272 -0
  165. package/generated/versions/defold-1.13.1/msg.d.ts +10 -0
  166. package/generated/versions/defold-1.13.1/particlefx.d.ts +163 -0
  167. package/generated/versions/defold-1.13.1/physics.d.ts +559 -0
  168. package/generated/versions/defold-1.13.1/profiler.d.ts +235 -0
  169. package/generated/versions/defold-1.13.1/render.d.ts +1190 -0
  170. package/generated/versions/defold-1.13.1/resource.d.ts +1523 -0
  171. package/generated/versions/defold-1.13.1/socket.d.ts +784 -0
  172. package/generated/versions/defold-1.13.1/sound.d.ts +292 -0
  173. package/generated/versions/defold-1.13.1/sprite.d.ts +175 -0
  174. package/generated/versions/defold-1.13.1/sys.d.ts +678 -0
  175. package/generated/versions/defold-1.13.1/tilemap.d.ts +208 -0
  176. package/generated/versions/defold-1.13.1/timer.d.ts +125 -0
  177. package/generated/versions/defold-1.13.1/types.d.ts +61 -0
  178. package/generated/versions/defold-1.13.1/vmath.d.ts +774 -0
  179. package/generated/versions/defold-1.13.1/window.d.ts +183 -0
  180. package/generated/versions/defold-1.13.1/zlib.d.ts +41 -0
  181. package/generated/vmath.d.ts +1 -21
  182. package/generated/window.d.ts +71 -71
  183. package/identity-vocabulary.json +561 -0
  184. package/index.d.ts +7 -0
  185. package/package.json +13 -2
  186. package/scripts/example-store-io.ts +12 -1
  187. package/scripts/extension-goldens.ts +1 -0
  188. package/scripts/fidelity-baseline.json +146 -46
  189. package/scripts/generate-api-availability.ts +90 -12
  190. package/scripts/generate-api-signatures.ts +12 -2
  191. package/scripts/import-defold-release.ts +85 -24
  192. package/scripts/prose-constants.ts +77 -16
  193. package/scripts/regen.ts +391 -77
  194. package/scripts/shared-handle-methods.ts +53 -0
  195. package/scripts/signature-store-fs.ts +1 -0
  196. package/scripts/sync-api-docs.ts +16 -5
  197. package/src/api-availability.ts +0 -0
  198. package/src/api-doc.ts +201 -3
  199. package/src/api-identity.ts +252 -0
  200. package/src/core-types.ts +26 -3
  201. package/src/correction-pins.ts +49 -0
  202. package/src/doc-comment.ts +104 -11
  203. package/src/doc-corrections.ts +108 -0
  204. package/src/editor-vm-globals.d.ts +5 -2
  205. package/src/emit-dts.ts +2064 -281
  206. package/src/emit-messages.ts +52 -0
  207. package/src/example-store.ts +125 -14
  208. package/src/field-correction-coverage.ts +204 -0
  209. package/src/fnv1a.ts +16 -0
  210. package/src/go-overloads.d.ts +25 -6
  211. package/src/index-base-table.ts +145 -0
  212. package/src/index-slot-classifications.ts +588 -0
  213. package/src/index.ts +38 -5
  214. package/src/library-index-slot-classifications.ts +332 -0
  215. package/src/lifecycle.ts +61 -199
  216. package/src/luals-type-expr.ts +354 -0
  217. package/src/msg-overloads.d.ts +0 -1
  218. package/src/param-correction-provenance.ts +8 -11
  219. package/src/render-overloads.d.ts +0 -15
  220. package/src/return-correction-provenance.ts +58 -16
  221. package/src/sys-overloads.d.ts +48 -0
  222. package/src/vmath-overloads.d.ts +27 -1
  223. package/src/window-event-guard.d.ts +6 -9
  224. package/url-parameters.json +1 -2
@@ -0,0 +1,53 @@
1
+ import type { ModuleManifestEntry } from "./regen";
2
+
3
+ // A method the engine shares across several handle classes where a release's
4
+ // ref-doc documents it on only some of them. The handles it omits are restored
5
+ // from the documented one, so a doc omission never drops a method the engine
6
+ // still binds. Applies only where the source handle documents it.
7
+ export interface SharedHandleMethod {
8
+ readonly namespace: string;
9
+ readonly method: string;
10
+ readonly source: string;
11
+ readonly handles: readonly string[];
12
+ readonly evidence: string;
13
+ }
14
+
15
+ const TCP_ANY =
16
+ 'LuaSocket tcp.c binds it in the one method table every tcp class shares, and checks its argument with auxiliar_checkgroup(L, "tcp{any}", 1)';
17
+
18
+ export const SHARED_HANDLE_METHODS: readonly SharedHandleMethod[] = (
19
+ ["getstats", "setstats"] as const
20
+ ).map((method) => ({
21
+ namespace: "socket",
22
+ method,
23
+ source: "client",
24
+ handles: ["master", "server"],
25
+ evidence: TCP_ANY,
26
+ }));
27
+
28
+ interface DocElement {
29
+ readonly name: string;
30
+ }
31
+
32
+ export function restoreSharedHandleMethods(
33
+ modules: readonly ModuleManifestEntry[],
34
+ ): ModuleManifestEntry[] {
35
+ return modules.map((entry) => {
36
+ const shared = SHARED_HANDLE_METHODS.filter((row) => row.namespace === entry.namespace);
37
+ if (shared.length === 0) return entry;
38
+ const doc = entry.doc as { elements: DocElement[] };
39
+ const declared = new Set(doc.elements.map((element) => element.name));
40
+ const restored: DocElement[] = [];
41
+ for (const { method, source, handles } of shared) {
42
+ const documented = doc.elements.find((element) => element.name === `${source}:${method}`);
43
+ if (documented === undefined) continue;
44
+ for (const handle of handles) {
45
+ const name = `${handle}:${method}`;
46
+ if (!declared.has(name)) restored.push({ ...documented, name });
47
+ }
48
+ }
49
+ return restored.length === 0
50
+ ? entry
51
+ : { ...entry, doc: { ...doc, elements: [...doc.elements, ...restored] } };
52
+ });
53
+ }
@@ -25,6 +25,7 @@ export const VMATH_SIGNATURES_PATH = resolve(import.meta.dir, "..", "signatures"
25
25
  export const GO_SIGNATURES_PATH = resolve(import.meta.dir, "..", "signatures", "go.json");
26
26
  export const MSG_SIGNATURES_PATH = resolve(import.meta.dir, "..", "signatures", "msg.json");
27
27
  export const RENDER_SIGNATURES_PATH = resolve(import.meta.dir, "..", "signatures", "render.json");
28
+ export const SYS_SIGNATURES_PATH = resolve(import.meta.dir, "..", "signatures", "sys.json");
28
29
 
29
30
  export function loadSignatureFile(path: string): SignatureStore {
30
31
  let raw: string;
@@ -11,7 +11,7 @@ import { MODULE_MANIFEST } from "./regen";
11
11
  // model because the per-package `rootDir` boundary forbids a types-package
12
12
  // module importing outside its own tree; `scripts/release-model.test.ts`
13
13
  // correspondence-guards these against the model so drift fails CI.
14
- export const DEFOLD_VERSION = "1.13.1";
14
+ export const DEFOLD_VERSION = "1.13.2";
15
15
  export const refDocUrl = (version = DEFOLD_VERSION): string =>
16
16
  `https://github.com/defold/defold/releases/download/${version}/ref-doc.zip`;
17
17
 
@@ -52,13 +52,24 @@ export const SYNC_MANIFEST: readonly SyncManifestEntry[] = [
52
52
  "doc/scripts-box2d-v3-script_box2d_world_v3.cpp_doc.json",
53
53
  ]),
54
54
  entry("buffer", "doc/scripts-script_buffer.cpp_doc.json"),
55
+ entry("bullet3d", "doc/scripts-bullet3d-script_bullet3d.cpp_doc.json"),
56
+ entry(
57
+ "bullet3d.collision_object",
58
+ "doc/scripts-bullet3d-script_bullet3d_collision_object.cpp_doc.json",
59
+ ),
60
+ entry("bullet3d.constraint", "doc/scripts-bullet3d-script_bullet3d_constraint.cpp_doc.json"),
61
+ entry("bullet3d.rigid_body", "doc/scripts-bullet3d-script_bullet3d_rigid_body.cpp_doc.json"),
62
+ entry("bullet3d.shape", "doc/scripts-bullet3d-script_bullet3d_shape.cpp_doc.json"),
63
+ entry("bullet3d.world", "doc/scripts-bullet3d-script_bullet3d_world.cpp_doc.json"),
55
64
  // Camera and component namespaces merge their DDF messages/properties into
56
65
  // the callable script API so release snapshots retain every declared symbol.
57
66
  entry("camera", "doc/gamesys-camera_ddf.proto_doc.json", undefined, [
58
67
  "doc/render-render_script_camera.cpp_doc.json",
59
68
  ]),
60
69
  entry("collectionfactory", "doc/scripts-script_collection_factory.cpp_doc.json"),
61
- entry("collectionproxy", "doc/scripts-script_collectionproxy.cpp_doc.json"),
70
+ entry("collectionproxy", "doc/scripts-script_collectionproxy.cpp_doc.json", undefined, [
71
+ "doc/gamesys-collectionproxy_ddf.proto_doc.json",
72
+ ]),
62
73
  entry("compute", "doc/scripts-script_compute.cpp_doc.json"),
63
74
  entry("crash", "doc/script_crash.cpp_doc.json"),
64
75
  entry("factory", "doc/scripts-script_factory.cpp_doc.json"),
@@ -115,11 +126,11 @@ export const SYNC_MANIFEST: readonly SyncManifestEntry[] = [
115
126
  export const UNMAPPED: ReadonlyMap<string, string> = new Map();
116
127
 
117
128
  // A Lua script namespace is a lowercase, dot-separated identifier (`sys`,
118
- // `b2d.body`). The native C/C++ SDK docs (`dmGraphics`, …), the C# bindings
129
+ // `b2d.body`, `bullet3d.rigid_body`). The native C/C++ SDK docs (`dmGraphics`, …), the C# bindings
119
130
  // (`cs-*`), and the struct-only docs (empty `info.namespace`) fail this shape,
120
131
  // so the upstream-coverage guard skips them structurally rather than listing
121
132
  // each by hand — that keeps the guard self-maintaining as the SDK grows.
122
- const LUA_NAMESPACE = /^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$/;
133
+ const LUA_NAMESPACE = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/;
123
134
 
124
135
  // Lowercase-identifier namespaces that pass LUA_NAMESPACE but are intentionally
125
136
  // not wired through SYNC_MANIFEST, each with a sourced reason (mirrors the
@@ -205,7 +216,7 @@ function editorVm(namespace: string): SyncManifestEntry {
205
216
  function entry(
206
217
  namespace: string,
207
218
  zipEntry: string,
208
- fixture: string = `fixtures/defold-1.13.1/${namespace.replace(/\./g, "_")}_doc.json`,
219
+ fixture: string = `fixtures/defold-1.13.2/${namespace.replace(/\./g, "_")}_doc.json`,
209
220
  mergeEntries?: readonly string[],
210
221
  ): SyncManifestEntry {
211
222
  return { namespace, zipEntry, fixture, ...(mergeEntries ? { mergeEntries } : {}) };
Binary file
package/src/api-doc.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { correctedDoc, docCorrectionKey } from "./doc-corrections";
2
+
1
3
  export interface ApiModule {
2
4
  namespace: string;
3
5
  brief: string;
@@ -7,6 +9,39 @@ export interface ApiModule {
7
9
  constants: ApiConstant[];
8
10
  properties: ApiProperty[];
9
11
  typedefs: ApiTypedef[];
12
+ /**
13
+ * Each ref-doc `ENUM`, whose members are also lowered into `constants`. Absent
14
+ * on a hand-built module, which reads the same as an empty list.
15
+ */
16
+ enums?: ApiEnum[];
17
+ /** Each ref-doc `STRUCT`. Absent on a hand-built module, read as an empty list. */
18
+ structs?: ApiStruct[];
19
+ }
20
+
21
+ /** A ref-doc `STRUCT`: a named table shape. */
22
+ export interface ApiStruct {
23
+ name: string;
24
+ brief: string;
25
+ description: string;
26
+ members: ApiStructMember[];
27
+ }
28
+
29
+ /** One `STRUCT` member; upstream marks an optional one with a `name?` suffix. */
30
+ export interface ApiStructMember {
31
+ name: string;
32
+ doc: string;
33
+ /** One LuaLS type expression. */
34
+ type: string;
35
+ isOptional: boolean;
36
+ }
37
+
38
+ /** A ref-doc `ENUM`: a named set of constants, each lowered into `constants`. */
39
+ export interface ApiEnum {
40
+ name: string;
41
+ brief: string;
42
+ description: string;
43
+ /** The member FQNs, in documentation order. */
44
+ members: string[];
10
45
  }
11
46
 
12
47
  export interface ApiProperty {
@@ -24,6 +59,11 @@ export interface ApiTypedef {
24
59
  types?: string[];
25
60
  /** The type text of each parent an interface-backed typedef extends. */
26
61
  extends?: string[];
62
+ /**
63
+ * The type an engine ref-doc `TYPEDEF` aliases (`parameters[0].types`): a
64
+ * handle's `userdata`/`number`, or the arms of a union, literal or record alias.
65
+ */
66
+ aliasOf?: string[];
27
67
  /** See {@link ApiFunction.global}. */
28
68
  global?: true;
29
69
  }
@@ -32,6 +72,16 @@ export interface ApiConstant {
32
72
  name: string;
33
73
  brief: string;
34
74
  description: string;
75
+ /**
76
+ * Present when the constant is a member of an `ENUM` whose value type is
77
+ * `string` (`parameters[0].types`); absence means a number, as every
78
+ * pre-`ENUM` constant is.
79
+ */
80
+ valueType?: "string";
81
+ /** Present when an `ENUM` member is typed `<ENUM>|nil`: some platforms leave it unset. */
82
+ nilable?: true;
83
+ /** The documented constant a back-filled one shares its value, and so its type, with. */
84
+ aliasOf?: string;
35
85
  /** See {@link ApiFunction.global}. */
36
86
  global?: true;
37
87
  }
@@ -122,6 +172,27 @@ function docSourceKey(element: Record<string, unknown>): { docSource?: "upstream
122
172
  return element.docSource === "upstream" ? { docSource: "upstream" } : {};
123
173
  }
124
174
 
175
+ // A function the ref-doc names differently from the name its engine binding
176
+ // registers, so the documented call raises "attempt to call a nil value". Keyed
177
+ // by the ref-doc FQN; `name` is the registered FQN and `evidence` the
178
+ // registration. The parse renames the element, so the declaration, the signature
179
+ // store, the example translations and every audit read the bound name. An entry
180
+ // is deleted once no retained target documents the old name.
181
+ export interface FunctionNameCorrection {
182
+ readonly name: string;
183
+ readonly evidence: string;
184
+ }
185
+
186
+ export const FUNCTION_NAME_CORRECTIONS: ReadonlyMap<string, FunctionNameCorrection> = new Map([
187
+ [
188
+ "sys.set_render_enable",
189
+ {
190
+ name: "sys.set_render_enabled",
191
+ evidence: 'script_engine.cpp registers {"set_render_enabled", EngineSys_SetRenderEnabled}',
192
+ },
193
+ ],
194
+ ]);
195
+
125
196
  export function parseDefoldApiDoc(input: unknown): ApiModule {
126
197
  if (!isRecord(input)) {
127
198
  throw new Error(`parseDefoldApiDoc: expected object, got ${describeKind(input)}`);
@@ -145,24 +216,99 @@ export function parseDefoldApiDoc(input: unknown): ApiModule {
145
216
  const constants: ApiConstant[] = [];
146
217
  const properties: ApiProperty[] = [];
147
218
  const typedefs: ApiTypedef[] = [];
219
+ const enums: ApiEnum[] = [];
220
+ const structs: ApiStruct[] = [];
148
221
 
149
222
  for (const element of elements) {
150
223
  if (!isRecord(element)) continue;
151
224
  const type = element.type;
152
225
  if (type === "FUNCTION") {
153
- functions.push(parseFunction(element));
226
+ const fn = withDocCorrections(parseFunction(element));
227
+ const corrected = FUNCTION_NAME_CORRECTIONS.get(fn.name);
228
+ functions.push(corrected === undefined ? fn : { ...fn, name: corrected.name });
154
229
  } else if (type === "VARIABLE") {
155
230
  variables.push(parseVariable(element));
156
231
  } else if (type === "CONSTANT") {
157
232
  constants.push(parseConstant(element));
158
233
  } else if (type === "PROPERTY") {
159
- properties.push(parseProperty(element));
234
+ const property = parseProperty(element);
235
+ const doc = correctedDoc(
236
+ docCorrectionKey(namespace, "property", property.name),
237
+ property.description,
238
+ );
239
+ properties.push(doc === property.description ? property : { ...property, description: doc });
160
240
  } else if (type === "TYPEDEF") {
161
241
  typedefs.push(parseTypedef(element));
242
+ } else if (type === "ENUM") {
243
+ const members = parseEnumMembers(element);
244
+ constants.push(...members);
245
+ enums.push({
246
+ name: stringOr(element.name, ""),
247
+ brief: stringOr(element.brief, ""),
248
+ description: stringOr(element.description, ""),
249
+ members: members.map((m) => m.name),
250
+ });
251
+ } else if (type === "STRUCT") {
252
+ structs.push(parseStruct(element));
253
+ }
254
+ }
255
+
256
+ return {
257
+ namespace,
258
+ brief,
259
+ description,
260
+ functions,
261
+ variables,
262
+ constants,
263
+ properties,
264
+ typedefs,
265
+ enums,
266
+ structs,
267
+ };
268
+ }
269
+
270
+ // Withholds one overload of a documented function — the one whose `param` has
271
+ // exactly the upstream type `type` — while its same-named siblings still emit.
272
+ // `name` is the local name, like a `skipFunctions` rule.
273
+ export interface SkipOverloadRule {
274
+ readonly name: string;
275
+ readonly param: string;
276
+ readonly type: string;
277
+ }
278
+
279
+ export function withholdOverloads(
280
+ module: ApiModule,
281
+ rules: readonly SkipOverloadRule[],
282
+ ): ApiModule {
283
+ let functions = module.functions;
284
+ for (const rule of rules) {
285
+ const fqn = `${module.namespace}.${rule.name}`;
286
+ const kept = functions.filter(
287
+ (fn) =>
288
+ fn.name !== fqn ||
289
+ !fn.parameters.some(
290
+ (p) => p.name === rule.param && p.types.length === 1 && p.types[0] === rule.type,
291
+ ),
292
+ );
293
+ if (kept.length === functions.length) {
294
+ throw new Error(`skipOverloads: ${fqn} has no overload whose ${rule.param} is ${rule.type}`);
162
295
  }
296
+ functions = kept;
163
297
  }
298
+ return functions === module.functions ? module : { ...module, functions };
299
+ }
164
300
 
165
- return { namespace, brief, description, functions, variables, constants, properties, typedefs };
301
+ // Keyed by the ref-doc FQN, before any `FUNCTION_NAME_CORRECTIONS` rename.
302
+ function withDocCorrections(fn: ApiFunction): ApiFunction {
303
+ const correct = (slot: "param" | "return") => (p: ApiParameter) => {
304
+ const doc = correctedDoc(docCorrectionKey(fn.name, slot, p.name), p.doc);
305
+ return doc === p.doc ? p : { ...p, doc };
306
+ };
307
+ return {
308
+ ...fn,
309
+ parameters: fn.parameters.map(correct("param")),
310
+ returnValues: fn.returnValues.map(correct("return")),
311
+ };
166
312
  }
167
313
 
168
314
  function parseTypedef(element: Record<string, unknown>): ApiTypedef {
@@ -170,16 +316,41 @@ function parseTypedef(element: Record<string, unknown>): ApiTypedef {
170
316
  const properties = parseVariableList(element.properties);
171
317
  const types = parseStringArray(element.types);
172
318
  const parents = parseStringArray(element.extends);
319
+ const [aliased] = parseParameterList(element.parameters);
320
+ const aliasOf = aliased?.types ?? [];
173
321
  return {
174
322
  name: stringOr(element.name, ""),
175
323
  ...(functions.length > 0 ? { functions } : {}),
176
324
  ...(properties.length > 0 ? { properties } : {}),
177
325
  ...(types.length > 0 ? { types } : {}),
178
326
  ...(parents.length > 0 ? { extends: parents } : {}),
327
+ ...(aliasOf.length > 0 ? { aliasOf } : {}),
179
328
  ...globalKey(element),
180
329
  };
181
330
  }
182
331
 
332
+ function parseStruct(element: Record<string, unknown>): ApiStruct {
333
+ const raw = Array.isArray(element.members) ? element.members : [];
334
+ const members: ApiStructMember[] = [];
335
+ for (const member of raw) {
336
+ if (!isRecord(member)) continue;
337
+ const name = stringOr(member.name, "");
338
+ const isOptional = name.endsWith("?");
339
+ members.push({
340
+ name: isOptional ? name.slice(0, -1) : name,
341
+ doc: stringOr(member.doc, ""),
342
+ type: stringOr(member.type, ""),
343
+ isOptional,
344
+ });
345
+ }
346
+ return {
347
+ name: stringOr(element.name, ""),
348
+ brief: stringOr(element.brief, ""),
349
+ description: stringOr(element.description, ""),
350
+ members,
351
+ };
352
+ }
353
+
183
354
  function parseProperty(element: Record<string, unknown>): ApiProperty {
184
355
  const brief = stringOr(element.brief, "");
185
356
  const span = /<span class="type">([^<]+)<\/span>/.exec(brief);
@@ -207,6 +378,33 @@ function parseConstant(element: Record<string, unknown>): ApiConstant {
207
378
  };
208
379
  }
209
380
 
381
+ // A member carries one `doc` string where a constant carried `brief` and
382
+ // `description`; both take it.
383
+ function parseEnumMembers(element: Record<string, unknown>): ApiConstant[] {
384
+ // A member named bare (1.13.2's bullet3d enums) is registered on the enum's
385
+ // own namespace, so it takes that prefix.
386
+ const enumName = stringOr(element.name, "");
387
+ const owner = enumName.includes(".") ? enumName.slice(0, enumName.lastIndexOf(".")) : "";
388
+ const qualify = (name: string): string =>
389
+ name.includes(".") || owner === "" ? name : `${owner}.${name}`;
390
+ const [value] = parseParameterList(element.parameters);
391
+ const valueType = value?.types.length === 1 && value.types[0] === "string" ? "string" : null;
392
+ const raw = Array.isArray(element.members) ? element.members : [];
393
+ const out: ApiConstant[] = [];
394
+ for (const member of raw) {
395
+ if (!isRecord(member)) continue;
396
+ const doc = stringOr(member.doc, "");
397
+ out.push({
398
+ name: qualify(stringOr(member.name, "")),
399
+ brief: doc,
400
+ description: doc,
401
+ ...(valueType === null ? {} : { valueType }),
402
+ ...(stringOr(member.type, "").endsWith("|nil") ? { nilable: true } : {}),
403
+ });
404
+ }
405
+ return out;
406
+ }
407
+
210
408
  function parseFunction(element: Record<string, unknown>): ApiFunction {
211
409
  return {
212
410
  name: stringOr(element.name, ""),
@@ -0,0 +1,252 @@
1
+ import type { ApiFunction, ApiModule, ApiParameter } from "./api-doc";
2
+ import { DEFOLD_TYPE_MAP } from "./core-types";
3
+ import { pinMatches } from "./correction-pins";
4
+ import { splitTopLevel } from "./luals-type-expr";
5
+
6
+ /**
7
+ * A type correction as identity applies it: where the slot still declares one of
8
+ * `pins`, its values are the declared ones less `removes` plus `adds`, or
9
+ * `replaces` outright. Every list is written in ref-doc or TypeScript spelling;
10
+ * both canonicalize to the same values.
11
+ */
12
+ export interface IdentityCorrection {
13
+ readonly pins: readonly (readonly string[])[];
14
+ readonly adds?: readonly string[];
15
+ readonly removes?: readonly string[];
16
+ readonly replaces?: readonly string[];
17
+ /** A return correction's slot name, when it rewrites one of several returns. */
18
+ readonly slot?: string;
19
+ }
20
+
21
+ /**
22
+ * The corrections this repo records from verified engine behavior. Identity
23
+ * follows them rather than each release's markup, so a release whose ref-doc
24
+ * starts stating what a correction already did is not a change.
25
+ */
26
+ export interface IdentityCorrections {
27
+ /** `<element>:param:<slot>` keys a correction makes optional. */
28
+ readonly optionalSlots: readonly string[];
29
+ /** `<element>:param:<slot>` keys a correction keeps required. */
30
+ readonly requiredSlots: readonly string[];
31
+ /** Keyed `<element>:param:<slot>`. */
32
+ readonly parameterCorrections: Readonly<Record<string, IdentityCorrection>>;
33
+ /** Keyed by element. */
34
+ readonly returnCorrections: Readonly<Record<string, IdentityCorrection>>;
35
+ /** Constant-family aliases a correction may name (`window.DimModeStateSettable`), with members. */
36
+ readonly constantFamilies: Readonly<Record<string, readonly string[]>>;
37
+ }
38
+
39
+ /**
40
+ * The names a ref-doc type token may refer to, gathered across every committed
41
+ * target so each release's spelling resolves the same way, plus the corrections.
42
+ * A name keeps its kind across releases: a 1.13.2 `STRUCT` is a table wherever
43
+ * it appears.
44
+ */
45
+ export interface IdentityVocabulary extends Omit<IdentityCorrections, "constantFamilies"> {
46
+ /** `STRUCT` names: a table at runtime. */
47
+ readonly tables: readonly string[];
48
+ /** `ENUM` names and constant families, with the runtime type of their members. */
49
+ readonly enums: Readonly<Record<string, "number" | "string">>;
50
+ /** Constants whose value is a string; every other constant is a number. */
51
+ readonly stringConstants: readonly string[];
52
+ /** Non-handle `TYPEDEF` names and the tokens they alias. */
53
+ readonly aliases: Readonly<Record<string, readonly string[]>>;
54
+ }
55
+
56
+ export const NO_IDENTITY_CORRECTIONS: IdentityCorrections = {
57
+ optionalSlots: [],
58
+ requiredSlots: [],
59
+ parameterCorrections: {},
60
+ returnCorrections: {},
61
+ constantFamilies: {},
62
+ };
63
+
64
+ const sortedRecord = <T>(entries: Iterable<[string, T]>): Record<string, T> =>
65
+ Object.fromEntries([...entries].sort(([a], [b]) => a.localeCompare(b)));
66
+
67
+ export function buildIdentityVocabulary(
68
+ modules: readonly ApiModule[],
69
+ corrections: IdentityCorrections = NO_IDENTITY_CORRECTIONS,
70
+ ): IdentityVocabulary {
71
+ const tables = new Set<string>();
72
+ const stringConstants = new Set<string>();
73
+ const aliases = new Map<string, readonly string[]>();
74
+ const enumMembers = new Map<string, readonly string[]>(
75
+ Object.entries(corrections.constantFamilies),
76
+ );
77
+ for (const module of modules) {
78
+ for (const struct of module.structs ?? []) tables.add(struct.name);
79
+ for (const constant of module.constants) {
80
+ if (constant.valueType === "string") stringConstants.add(constant.name);
81
+ }
82
+ for (const enumeration of module.enums ?? []) {
83
+ enumMembers.set(enumeration.name, enumeration.members);
84
+ }
85
+ for (const typedef of module.typedefs) {
86
+ const aliasOf = typedef.aliasOf;
87
+ if (aliasOf === undefined || (aliasOf.length === 1 && aliasOf[0] === "userdata")) continue;
88
+ aliases.set(typedef.name, aliasOf);
89
+ }
90
+ }
91
+ const enums = [...enumMembers].map(([name, members]): [string, "number" | "string"] => [
92
+ name,
93
+ members.length > 0 && members.every((member) => stringConstants.has(member))
94
+ ? "string"
95
+ : "number",
96
+ ]);
97
+ return {
98
+ tables: [...tables].sort(),
99
+ enums: sortedRecord(enums),
100
+ stringConstants: [...stringConstants].sort(),
101
+ aliases: sortedRecord(aliases),
102
+ optionalSlots: [...corrections.optionalSlots].sort(),
103
+ requiredSlots: [...corrections.requiredSlots].sort(),
104
+ parameterCorrections: sortedRecord(Object.entries(corrections.parameterCorrections)),
105
+ returnCorrections: sortedRecord(Object.entries(corrections.returnCorrections)),
106
+ };
107
+ }
108
+
109
+ // Tokens a later release renamed without changing what they denote.
110
+ const RENAMED_TOKENS: Readonly<Record<string, string>> = {
111
+ // 1.13.2 names the lifecycle callbacks' `self` after what it is.
112
+ script_instance: "userdata",
113
+ };
114
+
115
+ const CONSTANT_FQN = /^[a-z_][\w.]*\.[A-Z][A-Z0-9_]*$/;
116
+ const NUMERIC_LITERAL = /^-?\d+(\.\d+)?$/;
117
+ const STRING_LITERAL = /^(".*"|'.*')$/;
118
+ // The TypeScript table types a correction writes.
119
+ const TS_TABLE = /^(Record|LuaMap|ReadonlyLuaMap|LuaTable)\b/;
120
+
121
+ function canonicalLeaves(
122
+ token: string,
123
+ vocabulary: IdentityVocabulary,
124
+ expanding: ReadonlySet<string>,
125
+ ): string[] {
126
+ const trimmed = token.trim();
127
+ const arms = splitTopLevel(trimmed, "|");
128
+ if (arms.length > 1) return arms.flatMap((arm) => canonicalLeaves(arm, vocabulary, expanding));
129
+ if (trimmed.endsWith("?")) {
130
+ return [...canonicalLeaves(trimmed.slice(0, -1), vocabulary, expanding), "nil"];
131
+ }
132
+ if (/^(fun|function)\b/.test(trimmed) || trimmed.includes("=>")) return ["function"];
133
+ if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
134
+ return canonicalLeaves(trimmed.slice(1, -1), vocabulary, expanding);
135
+ }
136
+ if (trimmed.startsWith("typeof ")) {
137
+ return canonicalLeaves(trimmed.slice("typeof ".length), vocabulary, expanding);
138
+ }
139
+ if (trimmed === "nil" || trimmed === "undefined") return ["nil"];
140
+ // Every table shape — a bare or typed `table`, a list, an inline record, a
141
+ // struct, a built-in message payload — is one Lua table at runtime; its
142
+ // documented fields are not part of what identifies the call.
143
+ if (
144
+ trimmed === "table" ||
145
+ trimmed.startsWith("table<") ||
146
+ trimmed.startsWith("{") ||
147
+ trimmed.endsWith("[]") ||
148
+ trimmed.startsWith("message.") ||
149
+ TS_TABLE.test(trimmed) ||
150
+ vocabulary.tables.includes(trimmed)
151
+ ) {
152
+ return ["table"];
153
+ }
154
+ if (STRING_LITERAL.test(trimmed)) return ["string"];
155
+ if (NUMERIC_LITERAL.test(trimmed)) return ["number"];
156
+ if (trimmed === "true" || trimmed === "false") return ["boolean"];
157
+ // An enum, one of its constants, or the untyped `constant` older releases
158
+ // wrote are all the value the engine registered: a number unless declared a
159
+ // string.
160
+ const enumType = vocabulary.enums[trimmed];
161
+ if (enumType !== undefined) return [enumType];
162
+ if (vocabulary.stringConstants.includes(trimmed)) return ["string"];
163
+ if (trimmed === "constant" || CONSTANT_FQN.test(trimmed)) return ["number"];
164
+ const aliasOf = vocabulary.aliases[trimmed];
165
+ if (aliasOf !== undefined && !expanding.has(trimmed)) {
166
+ const next = new Set(expanding).add(trimmed);
167
+ return aliasOf.flatMap((aliased) => canonicalLeaves(aliased, vocabulary, next));
168
+ }
169
+ const renamed = RENAMED_TOKENS[trimmed] ?? trimmed;
170
+ // Primitive synonyms (`integer` and `number`, `buffer_data` and `buffer`) are
171
+ // the tokens the engine vocabulary maps to one TypeScript type.
172
+ return [
173
+ Object.hasOwn(DEFOLD_TYPE_MAP, renamed)
174
+ ? ((DEFOLD_TYPE_MAP as Readonly<Record<string, string>>)[renamed] as string)
175
+ : renamed,
176
+ ];
177
+ }
178
+
179
+ /**
180
+ * A slot's ref-doc tokens in a vocabulary-neutral form: the runtime values the
181
+ * slot takes, sorted and without duplicates, so a release that only respells a
182
+ * slot keeps its identity while one that changes what it takes does not.
183
+ */
184
+ export function canonicalIdentityTypes(
185
+ types: readonly string[],
186
+ vocabulary: IdentityVocabulary,
187
+ ): string[] {
188
+ return [
189
+ ...new Set(types.flatMap((token) => canonicalLeaves(token, vocabulary, new Set()))),
190
+ ].sort();
191
+ }
192
+
193
+ function correctedTypes(
194
+ types: readonly string[],
195
+ correction: IdentityCorrection | undefined,
196
+ vocabulary: IdentityVocabulary,
197
+ ): string[] {
198
+ if (correction === undefined || !pinMatches(types, correction.pins)) {
199
+ return canonicalIdentityTypes(types, vocabulary);
200
+ }
201
+ if (correction.replaces !== undefined) {
202
+ return canonicalIdentityTypes(correction.replaces, vocabulary);
203
+ }
204
+ const removed = new Set(canonicalIdentityTypes(correction.removes ?? [], vocabulary));
205
+ return [
206
+ ...new Set([
207
+ ...canonicalIdentityTypes(types, vocabulary).filter((value) => !removed.has(value)),
208
+ ...canonicalIdentityTypes(correction.adds ?? [], vocabulary),
209
+ ]),
210
+ ].sort();
211
+ }
212
+
213
+ export interface IdentitySlot {
214
+ readonly types: readonly string[];
215
+ readonly isOptional: boolean;
216
+ }
217
+
218
+ /** A parameter as identity reads it: its corrected values and effective optionality. */
219
+ export function identityParameter(
220
+ fn: ApiFunction,
221
+ parameter: ApiParameter,
222
+ vocabulary: IdentityVocabulary,
223
+ ): IdentitySlot {
224
+ const key = `${fn.name}:param:${parameter.name}`;
225
+ const types = correctedTypes(parameter.types, vocabulary.parameterCorrections[key], vocabulary);
226
+ // A slot a correction keeps required may still take an explicit nil, which
227
+ // stays part of what it takes; anywhere else, taking nil is being omissible.
228
+ if (vocabulary.requiredSlots.includes(key)) return { types, isOptional: false };
229
+ return {
230
+ types: types.filter((value) => value !== "nil"),
231
+ isOptional:
232
+ parameter.isOptional || types.includes("nil") || vocabulary.optionalSlots.includes(key),
233
+ };
234
+ }
235
+
236
+ /** A return value as identity reads it, with a return correction applied where it holds. */
237
+ export function identityReturn(
238
+ fn: ApiFunction,
239
+ returned: ApiParameter,
240
+ vocabulary: IdentityVocabulary,
241
+ ): IdentitySlot {
242
+ const correction = vocabulary.returnCorrections[fn.name];
243
+ const applies =
244
+ correction !== undefined &&
245
+ (correction.slot === undefined
246
+ ? fn.returnValues.length === 1
247
+ : correction.slot === returned.name);
248
+ return {
249
+ types: correctedTypes(returned.types, applies ? correction : undefined, vocabulary),
250
+ isOptional: returned.isOptional,
251
+ };
252
+ }