@defold-typescript/types 0.34.0 → 0.35.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 (62) hide show
  1. package/api-signatures.json +156 -183
  2. package/api-targets.json +9 -66
  3. package/generated/buffer.d.ts +2 -2
  4. package/generated/collectionfactory.d.ts +2 -2
  5. package/generated/factory.d.ts +2 -2
  6. package/generated/gui.d.ts +23 -23
  7. package/generated/kinds/gui-script.d.ts +0 -4
  8. package/generated/kinds/render-script.d.ts +1 -4
  9. package/generated/kinds/script.d.ts +0 -4
  10. package/generated/model.d.ts +2 -2
  11. package/generated/profiler.d.ts +2 -4
  12. package/generated/render.d.ts +2 -150
  13. package/generated/sys.d.ts +1 -1
  14. package/generated/versions/defold-1.12.4/buffer.d.ts +2 -2
  15. package/generated/versions/defold-1.12.4/collectionfactory.d.ts +2 -2
  16. package/generated/versions/defold-1.12.4/factory.d.ts +2 -2
  17. package/generated/versions/defold-1.12.4/gui.d.ts +23 -23
  18. package/generated/versions/defold-1.12.4/index.d.ts +9 -4
  19. package/generated/versions/defold-1.12.4/model.d.ts +2 -2
  20. package/generated/versions/defold-1.12.4/profiler.d.ts +2 -4
  21. package/generated/versions/defold-1.12.4/render.d.ts +2 -150
  22. package/generated/versions/defold-1.12.4/sys.d.ts +1 -1
  23. package/generated/versions/defold-1.12.4/vmath.d.ts +0 -19
  24. package/generated/versions/defold-1.12.4/window.d.ts +2 -4
  25. package/generated/versions/defold-1.13.0/buffer.d.ts +2 -2
  26. package/generated/versions/defold-1.13.0/collectionfactory.d.ts +2 -2
  27. package/generated/versions/defold-1.13.0/factory.d.ts +2 -2
  28. package/generated/versions/defold-1.13.0/gui.d.ts +23 -23
  29. package/generated/versions/defold-1.13.0/index.d.ts +9 -4
  30. package/generated/versions/defold-1.13.0/model.d.ts +2 -2
  31. package/generated/versions/defold-1.13.0/profiler.d.ts +2 -4
  32. package/generated/versions/defold-1.13.0/render.d.ts +2 -150
  33. package/generated/versions/defold-1.13.0/sys.d.ts +1 -1
  34. package/generated/versions/defold-1.13.0/vmath.d.ts +0 -19
  35. package/generated/versions/defold-1.13.0/window.d.ts +2 -4
  36. package/generated/vmath.d.ts +0 -19
  37. package/generated/window.d.ts +2 -4
  38. package/index.d.ts +1 -4
  39. package/package.json +4 -2
  40. package/scripts/extension-goldens.ts +23 -0
  41. package/scripts/generate-api-signatures.ts +40 -1
  42. package/scripts/materialize-version.ts +15 -1
  43. package/scripts/regen.ts +109 -27
  44. package/scripts/signature-store-fs.ts +1 -0
  45. package/scripts/sync-api-docs.ts +5 -61
  46. package/src/emit-dts.ts +212 -21
  47. package/src/optional-correction-provenance.ts +13 -2
  48. package/src/render-overloads.d.ts +29 -0
  49. package/src/vmath-overloads.d.ts +19 -0
  50. package/generated/iac.d.ts +0 -18
  51. package/generated/iap.d.ts +0 -60
  52. package/generated/push.d.ts +0 -66
  53. package/generated/versions/defold-1.12.4/iac.d.ts +0 -18
  54. package/generated/versions/defold-1.12.4/iap.d.ts +0 -60
  55. package/generated/versions/defold-1.12.4/push.d.ts +0 -66
  56. package/generated/versions/defold-1.12.4/webview.d.ts +0 -71
  57. package/generated/versions/defold-1.13.0/iac.d.ts +0 -18
  58. package/generated/versions/defold-1.13.0/iap.d.ts +0 -60
  59. package/generated/versions/defold-1.13.0/push.d.ts +0 -66
  60. package/generated/versions/defold-1.13.0/webview.d.ts +0 -71
  61. package/generated/webview.d.ts +0 -71
  62. package/scripts/fidelity-audit.ts +0 -684
@@ -128,7 +128,7 @@ declare global {
128
128
  * render.draw(self.tile_pred);
129
129
  * ```
130
130
  */
131
- function disable_state(state: Opaque<"constant">): void;
131
+ function disable_state(state: number & { readonly __brand: "graphics.STATE_DEPTH_TEST" } | number & { readonly __brand: "graphics.STATE_STENCIL_TEST" } | number & { readonly __brand: "graphics.STATE_BLEND" } | number & { readonly __brand: "graphics.STATE_ALPHA_TEST" } | number & { readonly __brand: "graphics.STATE_CULL_FACE" } | number & { readonly __brand: "graphics.STATE_POLYGON_OFFSET_FILL" }): void;
132
132
  /**
133
133
  * Disables a texture that has previourly been enabled.
134
134
  *
@@ -307,7 +307,7 @@ declare global {
307
307
  * render.disable_state(graphics.STATE_STENCIL_TEST);
308
308
  * ```
309
309
  */
310
- function enable_state(state: Opaque<"constant">): void;
310
+ function enable_state(state: number & { readonly __brand: "graphics.STATE_DEPTH_TEST" } | number & { readonly __brand: "graphics.STATE_STENCIL_TEST" } | number & { readonly __brand: "graphics.STATE_BLEND" } | number & { readonly __brand: "graphics.STATE_ALPHA_TEST" } | number & { readonly __brand: "graphics.STATE_CULL_FACE" } | number & { readonly __brand: "graphics.STATE_POLYGON_OFFSET_FILL" }): void;
311
311
  /**
312
312
  * Sets the specified texture handle for a render target attachment or a regular texture
313
313
  * that should be used for rendering. The texture can be bound to either a texture unit
@@ -502,154 +502,6 @@ declare global {
502
502
  * ```
503
503
  */
504
504
  function predicate(tags: (string | Hash)[]): number;
505
- /**
506
- * Creates a new render target according to the supplied
507
- * specification table.
508
- * The table should contain keys specifying which buffers should be created
509
- * with what parameters. Each buffer key should have a table value consisting
510
- * of parameters. The following parameter keys are available:
511
- *
512
- * Key
513
- * Values
514
- *
515
- * `format`
516
- * `graphics.TEXTURE_FORMAT_LUMINANCE`
517
- * `graphics.TEXTURE_FORMAT_RGB`
518
- * `graphics.TEXTURE_FORMAT_RGBA`
519
- * `graphics.TEXTURE_FORMAT_DEPTH`
520
- * `graphics.TEXTURE_FORMAT_STENCIL`
521
- * `graphics.TEXTURE_FORMAT_RGBA32F`
522
- * `graphics.TEXTURE_FORMAT_RGBA16F`
523
- *
524
- * `width`
525
- * number
526
- *
527
- * `height`
528
- * number
529
- *
530
- * `min_filter` (optional)
531
- * `graphics.TEXTURE_FILTER_LINEAR`
532
- * `graphics.TEXTURE_FILTER_NEAREST`
533
- *
534
- * `mag_filter` (optional)
535
- * `graphics.TEXTURE_FILTER_LINEAR`
536
- * `graphics.TEXTURE_FILTER_NEAREST`
537
- *
538
- * `u_wrap` (optional)
539
- * `graphics.TEXTURE_WRAP_CLAMP_TO_BORDER`
540
- * `graphics.TEXTURE_WRAP_CLAMP_TO_EDGE`
541
- * `graphics.TEXTURE_WRAP_MIRRORED_REPEAT`
542
- * `graphics.TEXTURE_WRAP_REPEAT`
543
- *
544
- * `v_wrap` (optional)
545
- * `graphics.TEXTURE_WRAP_CLAMP_TO_BORDER`
546
- * `graphics.TEXTURE_WRAP_CLAMP_TO_EDGE`
547
- * `graphics.TEXTURE_WRAP_MIRRORED_REPEAT`
548
- * `graphics.TEXTURE_WRAP_REPEAT`
549
- *
550
- * `flags` (optional)
551
- * `render.TEXTURE_BIT` (only applicable to depth and stencil buffers)
552
- *
553
- * The render target can be created to support multiple color attachments. Each attachment can have different format settings and texture filters,
554
- * but attachments must be added in sequence, meaning you cannot create a render target at slot 0 and 3.
555
- * Instead it has to be created with all four buffer types ranging from [0..3] (as denoted by graphics.BUFFER_TYPE_COLORX_BIT where 'X' is the attachment you want to create).
556
- * It is not guaranteed that the device running the script can support creating render targets with multiple color attachments. To check if the device can support multiple attachments,
557
- * you can check if the `render` table contains any of the `BUFFER_TYPE_COLOR1_BIT`, `BUFFER_TYPE_COLOR2_BIT` or `BUFFER_TYPE_COLOR3_BIT` constants:
558
- *
559
- * `function init(self)
560
- * if graphics.BUFFER_TYPE_COLOR1_BIT == nil then
561
- * -- this devices does not support multiple color attachments
562
- * end
563
- * end
564
- * `
565
- *
566
- * @param name - render target name
567
- * @param parameters - table of buffer parameters, see the description for available keys and values
568
- * @returns new render target
569
- * @example
570
- * ```ts
571
- * // How to create a new render target and draw to it:
572
- * export default defineScript({
573
- * init() {
574
- * // render target buffer parameters
575
- * const color_params = {
576
- * format: graphics.TEXTURE_FORMAT_RGBA,
577
- * width: render.get_window_width(),
578
- * height: render.get_window_height(),
579
- * min_filter: graphics.TEXTURE_FILTER_LINEAR,
580
- * mag_filter: graphics.TEXTURE_FILTER_LINEAR,
581
- * u_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
582
- * v_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
583
- * };
584
- * const depth_params = {
585
- * format: graphics.TEXTURE_FORMAT_DEPTH,
586
- * width: render.get_window_width(),
587
- * height: render.get_window_height(),
588
- * u_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
589
- * v_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
590
- * };
591
- * return {
592
- * my_render_target: render.render_target({
593
- * [graphics.BUFFER_TYPE_COLOR0_BIT]: color_params,
594
- * [graphics.BUFFER_TYPE_DEPTH_BIT]: depth_params,
595
- * }),
596
- * };
597
- * },
598
- *
599
- * update(self, dt) {
600
- * // enable target so all drawing is done to it
601
- * render.set_render_target(self.my_render_target);
602
- *
603
- * // draw a predicate to the render target
604
- * render.draw(self.my_pred);
605
- * },
606
- * });
607
- *
608
- * // How to create a render target with multiple outputs:
609
- * export default defineScript({
610
- * init() {
611
- * // render target buffer parameters
612
- * const color_params_rgba = {
613
- * format: graphics.TEXTURE_FORMAT_RGBA,
614
- * width: render.get_window_width(),
615
- * height: render.get_window_height(),
616
- * min_filter: graphics.TEXTURE_FILTER_LINEAR,
617
- * mag_filter: graphics.TEXTURE_FILTER_LINEAR,
618
- * u_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
619
- * v_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
620
- * };
621
- * const color_params_float = {
622
- * format: graphics.TEXTURE_FORMAT_RG32F,
623
- * width: render.get_window_width(),
624
- * height: render.get_window_height(),
625
- * min_filter: graphics.TEXTURE_FILTER_LINEAR,
626
- * mag_filter: graphics.TEXTURE_FILTER_LINEAR,
627
- * u_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
628
- * v_wrap: graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
629
- * };
630
- *
631
- * // Create a render target with three color attachments
632
- * // Note: No depth buffer is attached here
633
- * return {
634
- * my_render_target: render.render_target({
635
- * [graphics.BUFFER_TYPE_COLOR0_BIT]: color_params_rgba,
636
- * [graphics.BUFFER_TYPE_COLOR1_BIT]: color_params_rgba,
637
- * [graphics.BUFFER_TYPE_COLOR2_BIT]: color_params_float,
638
- * }),
639
- * };
640
- * },
641
- *
642
- * update(self, dt) {
643
- * // enable target so all drawing is done to it
644
- * render.enable_render_target(self.my_render_target);
645
- *
646
- * // draw a predicate to the render target
647
- * render.draw(self.my_pred);
648
- * },
649
- * });
650
- * ```
651
- */
652
- function render_target(name: string, parameters: Record<string | number, unknown>): Opaque<"render_target">;
653
505
  /**
654
506
  * Sets the blend equation with separate equations for the color and alpha channels.
655
507
  *
@@ -228,7 +228,7 @@ declare global {
228
228
  * }
229
229
  * ```
230
230
  */
231
- function get_connectivity(): Opaque<"constant">;
231
+ function get_connectivity(): number & { readonly __brand: "sys.NETWORK_DISCONNECTED" } | number & { readonly __brand: "sys.NETWORK_CONNECTED_CELLULAR" } | number & { readonly __brand: "sys.NETWORK_CONNECTED" };
232
232
  /**
233
233
  * Returns a table with engine information.
234
234
  *
@@ -91,25 +91,6 @@ declare global {
91
91
  * ```
92
92
  */
93
93
  function dot(v1: Vector3 | Vector4, v2: Vector3 | Vector4): number;
94
- /**
95
- * Converts euler angles (x, y, z) in degrees into a quaternion
96
- * The error is guaranteed to be less than 0.001.
97
- * If the first argument is vector3, its values are used as x, y, z angles.
98
- *
99
- * @param x - rotation around x-axis in degrees or vector3 with euler angles in degrees
100
- * @param y - rotation around y-axis in degrees
101
- * @param z - rotation around z-axis in degrees
102
- * @returns quaternion describing an equivalent rotation (231 (YZX) rotation sequence)
103
- * @example
104
- * ```ts
105
- * const q = vmath.euler_to_quat(0, 45, 90);
106
- * print(q); // => vmath.quat(0.27059805393219, 0.27059805393219, 0.65328145027161, 0.65328145027161)
107
- *
108
- * const v = vmath.vector3(0, 0, 90);
109
- * print(vmath.euler_to_quat(v)); // => vmath.quat(0, 0, 0.70710676908493, 0.70710676908493)
110
- * ```
111
- */
112
- function euler_to_quat(x: number | Vector3, y: number, z: number): Quaternion;
113
94
  /**
114
95
  * The resulting matrix is the inverse of the supplied matrix.
115
96
  * For ortho-normal matrices, e.g. regular object transformation,
@@ -1,6 +1,4 @@
1
1
  /** @noSelfInFile */
2
- import type { Opaque } from "../../../src/core-types";
3
-
4
2
  declare global {
5
3
  /**
6
4
  * Functions and constants to access the window, window event listeners
@@ -58,7 +56,7 @@ declare global {
58
56
  *
59
57
  * - `window.DIMMING_OFF`
60
58
  */
61
- function get_dim_mode(): Opaque<"constant">;
59
+ function get_dim_mode(): number & { readonly __brand: "window.DIMMING_UNKNOWN" } | number & { readonly __brand: "window.DIMMING_ON" } | number & { readonly __brand: "window.DIMMING_OFF" };
62
60
  /**
63
61
  * This returns the content scale of the current display.
64
62
  *
@@ -113,7 +111,7 @@ declare global {
113
111
  *
114
112
  * - `window.DIMMING_OFF`
115
113
  */
116
- function set_dim_mode(mode: Opaque<"constant">): void;
114
+ function set_dim_mode(mode: number & { readonly __brand: "window.DIMMING_ON" } | number & { readonly __brand: "window.DIMMING_OFF" }): void;
117
115
  /**
118
116
  * Sets a window event listener. Only one window event listener can be set at a time.
119
117
  *
@@ -91,25 +91,6 @@ declare global {
91
91
  * ```
92
92
  */
93
93
  function dot(v1: Vector3 | Vector4, v2: Vector3 | Vector4): number;
94
- /**
95
- * Converts euler angles (x, y, z) in degrees into a quaternion
96
- * The error is guaranteed to be less than 0.001.
97
- * If the first argument is vector3, its values are used as x, y, z angles.
98
- *
99
- * @param x - rotation around x-axis in degrees or vector3 with euler angles in degrees
100
- * @param y - rotation around y-axis in degrees
101
- * @param z - rotation around z-axis in degrees
102
- * @returns quaternion describing an equivalent rotation (231 (YZX) rotation sequence)
103
- * @example
104
- * ```ts
105
- * const q = vmath.euler_to_quat(0, 45, 90);
106
- * print(q); // => vmath.quat(0.27059805393219, 0.27059805393219, 0.65328145027161, 0.65328145027161)
107
- *
108
- * const v = vmath.vector3(0, 0, 90);
109
- * print(vmath.euler_to_quat(v)); // => vmath.quat(0, 0, 0.70710676908493, 0.70710676908493)
110
- * ```
111
- */
112
- function euler_to_quat(x: number | Vector3, y: number, z: number): Quaternion;
113
94
  /**
114
95
  * The resulting matrix is the inverse of the supplied matrix.
115
96
  * For ortho-normal matrices, e.g. regular object transformation,
@@ -1,6 +1,4 @@
1
1
  /** @noSelfInFile */
2
- import type { Opaque } from "../src/core-types";
3
-
4
2
  declare global {
5
3
  /**
6
4
  * Functions and constants to access the window, window event listeners
@@ -58,7 +56,7 @@ declare global {
58
56
  *
59
57
  * - `window.DIMMING_OFF`
60
58
  */
61
- function get_dim_mode(): Opaque<"constant">;
59
+ function get_dim_mode(): number & { readonly __brand: "window.DIMMING_UNKNOWN" } | number & { readonly __brand: "window.DIMMING_ON" } | number & { readonly __brand: "window.DIMMING_OFF" };
62
60
  /**
63
61
  * This returns the content scale of the current display.
64
62
  *
@@ -113,7 +111,7 @@ declare global {
113
111
  *
114
112
  * - `window.DIMMING_OFF`
115
113
  */
116
- function set_dim_mode(mode: Opaque<"constant">): void;
114
+ function set_dim_mode(mode: number & { readonly __brand: "window.DIMMING_ON" } | number & { readonly __brand: "window.DIMMING_OFF" }): void;
117
115
  /**
118
116
  * Sets a window event listener. Only one window event listener can be set at a time.
119
117
  *
package/index.d.ts CHANGED
@@ -28,8 +28,6 @@ import "./generated/graphics";
28
28
  import "./generated/gui";
29
29
  import "./generated/html5";
30
30
  import "./generated/http";
31
- import "./generated/iac";
32
- import "./generated/iap";
33
31
  import "./generated/image";
34
32
  import "./generated/json";
35
33
  import "./generated/label";
@@ -40,8 +38,8 @@ import "./generated/msg";
40
38
  import "./generated/particlefx";
41
39
  import "./generated/physics";
42
40
  import "./generated/profiler";
43
- import "./generated/push";
44
41
  import "./generated/render";
42
+ import "./src/render-overloads";
45
43
  import "./generated/resource";
46
44
  import "./generated/socket";
47
45
  import "./src/socket-types";
@@ -53,7 +51,6 @@ import "./generated/timer";
53
51
  import "./generated/types";
54
52
  import "./generated/vmath";
55
53
  import "./src/vmath-overloads";
56
- import "./generated/webview";
57
54
  import "./generated/window";
58
55
  import "./generated/zlib";
59
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defold-typescript/types",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "TypeScript types for the Defold engine's Lua APIs.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -66,7 +66,9 @@
66
66
  "!src/**/*.test.ts",
67
67
  "!scripts/**/*.test.ts",
68
68
  "!src/**/__snapshots__",
69
- "!scripts/lua-types-signature-index.ts"
69
+ "!scripts/lua-types-signature-index.ts",
70
+ "!scripts/fidelity-audit.ts",
71
+ "!scripts/augmentation-namespaces.ts"
70
72
  ],
71
73
  "publishConfig": {
72
74
  "access": "public"
@@ -0,0 +1,23 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import type { ModuleManifestEntry } from "./regen";
4
+
5
+ // Committed declarations the `resolve` emitter must reproduce for the extensions
6
+ // whose ref-docs this repo carries. They are a golden lane, not a surface: no
7
+ // entrypoint, kind index or pinned version imports them. They live in their own
8
+ // module because `resolve` imports `regen.ts` from the published package, which
9
+ // does not ship these root fixtures, so reading them at `regen.ts` load time would
10
+ // break every installed `resolve`.
11
+ export const EXTENSION_GOLDENS_DIR = "extension-goldens";
12
+
13
+ const PACKAGE_ROOT = resolve(import.meta.dir, "..");
14
+ const EXTENSION_GOLDEN_NAMESPACES = ["iac", "iap", "push", "webview"] as const;
15
+
16
+ export const EXTENSION_GOLDEN_MANIFEST: readonly ModuleManifestEntry[] =
17
+ EXTENSION_GOLDEN_NAMESPACES.map((namespace) => ({
18
+ namespace,
19
+ doc: JSON.parse(
20
+ readFileSync(resolve(PACKAGE_ROOT, "fixtures", `${namespace}_doc.json`), "utf8"),
21
+ ),
22
+ outFile: `${namespace}.d.ts`,
23
+ }));
@@ -1,7 +1,13 @@
1
1
  import { resolve } from "node:path";
2
2
  import { symbolIdentityKey } from "../src/api-availability";
3
3
  import { selectCompleteVersionSurfaces, versionOf } from "./generate-api-availability";
4
- import { generateModuleSignatures, loadApiTargets, loadTargetModules } from "./regen";
4
+ import {
5
+ generateModuleSignatures,
6
+ loadApiTargets,
7
+ loadTargetModules,
8
+ type ModuleManifestEntry,
9
+ } from "./regen";
10
+ import { loadSignatureFile } from "./signature-store-fs";
5
11
 
6
12
  const PACKAGE_ROOT = resolve(import.meta.dir, "..");
7
13
  const SIGNATURES_PATH = resolve(PACKAGE_ROOT, "api-signatures.json");
@@ -16,6 +22,35 @@ export interface BuildSignaturesOptions {
16
22
  readonly registryPath?: string;
17
23
  }
18
24
 
25
+ // The authored replacement for a symbol the skip filter withheld, read from the
26
+ // same `signatures/<ns>.json` store the version-prefixed API pages render from.
27
+ // One seam keeps all three artifacts consistent: `overloads-signature-parity`
28
+ // pins the store to the `src/*-overloads.d.ts` declarations, so folding the
29
+ // store in cannot drift from the surface a consumer actually compiles against.
30
+ function authoredSignature(packageRoot: string, namespace: string, fqn: string): string | null {
31
+ const store = loadSignatureFile(resolve(packageRoot, "signatures", `${namespace}.json`));
32
+ const forms = store[fqn]?.signatures ?? [];
33
+ return forms.length > 0 ? forms.join("\n") : null;
34
+ }
35
+
36
+ // The symbols `skipFunctions` removed from this module, as the difference
37
+ // between the unfiltered and filtered signature emits. Derived rather than
38
+ // re-matched so the withholding rules stay owned by `prepareGeneratedModule`.
39
+ export function withheldSymbols(entry: ModuleManifestEntry): { key: string; fqn: string }[] {
40
+ if ((entry.skipFunctions ?? []).length === 0) return [];
41
+ const kept = new Set(
42
+ generateModuleSignatures(entry).map(({ identity }) => symbolIdentityKey(identity)),
43
+ );
44
+ const withheld: { key: string; fqn: string }[] = [];
45
+ for (const { identity } of generateModuleSignatures({ ...entry, skipFunctions: [] })) {
46
+ const key = symbolIdentityKey(identity);
47
+ if (kept.has(key)) continue;
48
+ const fqn = key.split("\0")[2] as string;
49
+ withheld.push({ key, fqn });
50
+ }
51
+ return withheld;
52
+ }
53
+
19
54
  function sortObjectKeys(record: Record<string, string>): Record<string, string> {
20
55
  const sorted: Record<string, string> = {};
21
56
  for (const key of Object.keys(record).sort()) sorted[key] = record[key] as string;
@@ -34,6 +69,10 @@ export function buildSignaturesArtifact(options: BuildSignaturesOptions = {}): S
34
69
  for (const { identity, tsSignature } of generateModuleSignatures(entry)) {
35
70
  perSymbol[symbolIdentityKey(identity)] = tsSignature;
36
71
  }
72
+ for (const { key, fqn } of withheldSymbols(entry)) {
73
+ const authored = authoredSignature(packageRoot, entry.namespace, fqn);
74
+ if (authored !== null) perSymbol[key] = authored;
75
+ }
37
76
  }
38
77
  versions[version] = sortObjectKeys(perSymbol);
39
78
  }
@@ -15,7 +15,12 @@ import {
15
15
  resolveTargetModules,
16
16
  } from "./regen";
17
17
 
18
- export { RUNTIME_KIND_MANIFEST, SRC_AUGMENTATION_MODULES, targetKindManifest } from "./regen";
18
+ export {
19
+ RESTRICTED_SRC_AUGMENTATIONS,
20
+ RUNTIME_KIND_MANIFEST,
21
+ SRC_AUGMENTATION_MODULES,
22
+ targetKindManifest,
23
+ } from "./regen";
19
24
 
20
25
  // The surface's own `core-types` module: a re-export of the installed package's,
21
26
  // so every declaration in the surface reaches the brand types through a
@@ -26,6 +31,10 @@ export interface RenderMaterializedKindIndexOptions {
26
31
  readonly kind: string;
27
32
  readonly universalModules: readonly string[];
28
33
  readonly restrictedModule: string | null;
34
+ // The `src/*` augmentations this kind earns because they re-open the very
35
+ // namespace the kind is restricted to. They sit outside `universalModules`
36
+ // precisely so no other kind imports them.
37
+ readonly restrictedAugmentations?: readonly string[];
29
38
  // Set for a kind built from the target's own editor documents. It replaces
30
39
  // the universal set outright — an editor kind is disjoint from the runtime
31
40
  // surface, not a narrowing of it.
@@ -54,6 +63,11 @@ export function renderMaterializedKindIndex(opts: RenderMaterializedKindIndexOpt
54
63
  if (entry.only === undefined && opts.restrictedModule) {
55
64
  lines.push(`import "../${opts.restrictedModule}";`);
56
65
  }
66
+ if (entry.only === undefined) {
67
+ for (const augmentation of opts.restrictedAugmentations ?? []) {
68
+ lines.push(`import "../${augmentation}";`);
69
+ }
70
+ }
57
71
  const from = installedFactoryModule(entry);
58
72
  const values = [entry.factory, ...(entry.extraExports ?? [])].join(", ");
59
73
  const typeExports = entry.extraTypeExports?.length
package/scripts/regen.ts CHANGED
@@ -191,15 +191,6 @@ const DEFAULT_TARGET = API_TARGETS.find((t) => t.default === true) as ApiTarget;
191
191
 
192
192
  export const MODULE_MANIFEST: readonly ModuleManifestEntry[] = loadTargetModules(DEFAULT_TARGET);
193
193
 
194
- // The fidelity audit runs over the promoted default surface (the `default: true`
195
- // target) so the 1.13-only modules (b2d.*, compute, material) and the 1.13 model
196
- // additions are audited too — auditing the older 1.12.4 target left them unseen,
197
- // which is how the promoted surface shipped opaque `Record` fallbacks while the
198
- // gate read `recordTables: 0`.
199
- const FIDELITY_BASELINE_TARGET = DEFAULT_TARGET;
200
- export const FIDELITY_BASELINE_MANIFEST: readonly ModuleManifestEntry[] =
201
- loadTargetModules(FIDELITY_BASELINE_TARGET);
202
-
203
194
  // Handle tokens the editor VM alone exposes. `transaction_step[` is what
204
195
  // upstream literally emits for `transaction_step[]` — the ref-doc's own type
205
196
  // string loses the closing bracket — so it is repaired here, per entry, rather
@@ -544,16 +535,29 @@ export function kindStdlibReferences(entry: KindManifestEntry): string {
544
535
  return `${LUA_51_REFERENCE}${entry.jit === false ? "" : LUA_JIT_ONLY_REFERENCE}`;
545
536
  }
546
537
 
547
- const UNIVERSAL_EXTRA_IMPORTS: readonly string[] = [
548
- "../builtin-messages",
549
- "../../src/custom-messages",
550
- "../../src/engine-globals",
551
- "../../src/msg-overloads",
552
- "../../src/message-guard",
553
- "../../src/window-event-guard",
554
- "../../src/scene-addresses",
555
- "../../src/go-overloads",
556
- "../../src/vmath-overloads",
538
+ // One augmentation a complete script surface imports. `restrictedTo` names the
539
+ // kind-restricted namespace the augmentation re-opens: such an entry belongs on
540
+ // that namespace's kind index alone, or it would re-open a wall the kind closes.
541
+ // The marker is declared rather than parsed out of the `.d.ts`, so
542
+ // `generateKindIndex` stays pure; `srcAugmentationScopingViolations` in
543
+ // `./augmentation-namespaces` is what catches a future restricted augmentation
544
+ // added without one, by reading the namespaces each file really re-opens.
545
+ interface UniversalExtraImport {
546
+ readonly specifier: string;
547
+ readonly restrictedTo?: string;
548
+ }
549
+
550
+ const UNIVERSAL_EXTRA_IMPORTS: readonly UniversalExtraImport[] = [
551
+ { specifier: "../builtin-messages" },
552
+ { specifier: "../../src/custom-messages" },
553
+ { specifier: "../../src/engine-globals" },
554
+ { specifier: "../../src/msg-overloads" },
555
+ { specifier: "../../src/message-guard" },
556
+ { specifier: "../../src/window-event-guard" },
557
+ { specifier: "../../src/scene-addresses" },
558
+ { specifier: "../../src/go-overloads" },
559
+ { specifier: "../../src/render-overloads", restrictedTo: "render" },
560
+ { specifier: "../../src/vmath-overloads" },
557
561
  ];
558
562
 
559
563
  const SRC_IMPORT_PREFIX = "../../src/";
@@ -561,9 +565,18 @@ const SRC_IMPORT_PREFIX = "../../src/";
561
565
  // The hand-authored `src/*` augmentations a complete script surface needs,
562
566
  // derived from the one declaration the generated kind index renders from so a
563
567
  // new augmentation reaches every materialization path with no second edit.
564
- export const SRC_AUGMENTATION_MODULES: readonly string[] = UNIVERSAL_EXTRA_IMPORTS.filter(
565
- (specifier) => specifier.startsWith(SRC_IMPORT_PREFIX),
566
- ).map((specifier) => specifier.slice(SRC_IMPORT_PREFIX.length));
568
+ export const SRC_AUGMENTATION_MODULES: readonly string[] = UNIVERSAL_EXTRA_IMPORTS.filter((entry) =>
569
+ entry.specifier.startsWith(SRC_IMPORT_PREFIX),
570
+ ).map((entry) => entry.specifier.slice(SRC_IMPORT_PREFIX.length));
571
+
572
+ // The `src/*` augmentations bound to a kind-restricted namespace, as
573
+ // `<module name> -> <namespace>`. Exported so the CLI's materialization scopes
574
+ // them the same way the in-repo kind indexes do, from one declaration.
575
+ export const RESTRICTED_SRC_AUGMENTATIONS: Readonly<Record<string, string>> = Object.fromEntries(
576
+ UNIVERSAL_EXTRA_IMPORTS.filter(
577
+ (entry) => entry.restrictedTo !== undefined && entry.specifier.startsWith(SRC_IMPORT_PREFIX),
578
+ ).map((entry) => [entry.specifier.slice(SRC_IMPORT_PREFIX.length), entry.restrictedTo as string]),
579
+ );
567
580
 
568
581
  // Read those augmentations as surface-root files. Mirrors
569
582
  // `loadTargetEditorModules`: a missing file throws with its path rather than
@@ -664,9 +677,14 @@ export function generateKindIndex(kind: string, target: ApiTarget = DEFAULT_TARG
664
677
  const universalNamespaces = MODULE_MANIFEST.filter(
665
678
  (m) => !Object.hasOwn(RESTRICTED_NAMESPACES, m.namespace),
666
679
  ).map((m) => `../${m.outFile.replace(/\.d\.ts$/, "")}`);
680
+ // An augmentation bound to a restricted namespace rides only that namespace's
681
+ // kind index; every unmarked entry stays universal.
682
+ const extraImports = UNIVERSAL_EXTRA_IMPORTS.filter(
683
+ (extra) => extra.restrictedTo === undefined || extra.restrictedTo === entry.restricted,
684
+ ).map((extra) => extra.specifier);
667
685
  const modules = (
668
686
  entry.only === undefined
669
- ? [...new Set([...universalNamespaces.sort(), ...[...UNIVERSAL_EXTRA_IMPORTS].sort()])]
687
+ ? [...new Set([...universalNamespaces.sort(), ...extraImports.sort()])]
670
688
  : [...editorKindModules(target), ...(entry.extraModules ?? [])]
671
689
  ).map((path) => retargetSrcPath(path, srcPrefix));
672
690
  const lines = modules.map((path) => `import "${path}";`);
@@ -687,8 +705,10 @@ export function generateKindIndex(kind: string, target: ApiTarget = DEFAULT_TARG
687
705
  export function generateVersionIndex(
688
706
  versionId: string,
689
707
  manifest: readonly VersionedModuleManifestEntry[] = VERSIONED_MODULE_MANIFEST,
690
- // Bare names appended after the module imports. A materialized surface carries
691
- // the `src/*` augmentations beside its modules; the in-repo emit does not.
708
+ // Names appended after the module imports. A materialized surface carries the
709
+ // `src/*` augmentations beside its modules and names them bare; the in-repo
710
+ // emit reaches back into the package and passes an already-relative specifier,
711
+ // which is kept verbatim rather than re-anchored to the surface directory.
692
712
  extraImports: readonly string[] = [],
693
713
  ): string {
694
714
  const imports = [
@@ -698,7 +718,7 @@ export function generateVersionIndex(
698
718
  .sort(),
699
719
  ...extraImports,
700
720
  ]
701
- .map((module) => `import "./${module}";`)
721
+ .map((module) => `import "${module.startsWith(".") ? module : `./${module}`}";`)
702
722
  .join("\n");
703
723
  // A pinned consumer names this surface in `types` and never loads the
704
724
  // package entrypoint, so the stdlib directives have to lead here too. A
@@ -706,6 +726,16 @@ export function generateVersionIndex(
706
726
  return `${LUA_STDLIB_REFERENCES}${imports}\n\nexport {};\n`;
707
727
  }
708
728
 
729
+ // The authored augmentations a committed per-version index imports, addressed
730
+ // back into the package's `src/`. The in-repo surface has no copies beside its
731
+ // modules, so a skipped symbol would otherwise be declared on no versioned
732
+ // surface at all. Derived from `SRC_AUGMENTATION_MODULES`, so a new augmentation
733
+ // reaches the pinned surfaces on the same edit that reaches the materialized ones.
734
+ export function versionSrcAugmentationImports(target: ApiTarget): string[] {
735
+ const srcPrefix = target.coreTypesImport.slice(0, -"core-types".length);
736
+ return SRC_AUGMENTATION_MODULES.map((name) => `${srcPrefix}${name}`);
737
+ }
738
+
709
739
  // The `src/`-relative prefix a kind index living in `<generatedDir>/kinds/` needs
710
740
  // to reach the package's hand-authored modules. The target's own
711
741
  // `coreTypesImport` already measures its generated dir's depth; the kind index
@@ -732,7 +762,37 @@ export function targetKindManifest(target: ApiTarget): readonly KindManifestEntr
732
762
  return [...RUNTIME_KIND_MANIFEST, ...KIND_MODULE_MANIFEST.filter((e) => e.only !== undefined)];
733
763
  }
734
764
 
765
+ // Every `src/*` augmentation bound to a kind-restricted namespace carries its
766
+ // `restrictedTo` marker, and every marker names a namespace its file re-opens.
767
+ // Exported so a test can reach the guard the entry point runs; never called on
768
+ // import, so the dynamic import below stays unreached from an installed package.
769
+ export async function assertSrcAugmentationScoping(
770
+ packageRoot: string = PACKAGE_ROOT,
771
+ ): Promise<number> {
772
+ // Imported here rather than at module scope: it imports the devDependency
773
+ // `typescript`, and `resolve` loads this module from an installed package.
774
+ const { srcAugmentationScopingViolations } = await import("./augmentation-namespaces");
775
+ const files = loadSrcAugmentations(packageRoot);
776
+ const violations = srcAugmentationScopingViolations(
777
+ files,
778
+ RESTRICTED_SRC_AUGMENTATIONS,
779
+ RESTRICTED_NAMESPACES,
780
+ );
781
+ if (violations.length > 0) {
782
+ throw new Error(`src augmentation scoping violations:\n${violations.join("\n")}`);
783
+ }
784
+ return files.length;
785
+ }
786
+
735
787
  if (import.meta.main) {
788
+ // Ordering contract: `regen-entrypoint.test.ts` reads this line's prefix to
789
+ // prove the guard runs before the first write. The count comes from the guard's
790
+ // own return value so the marker cannot be printed without a completed guard
791
+ // run — do not simplify it back to `SRC_AUGMENTATION_MODULES.length`, which
792
+ // would let the guard be deleted or reordered with the line still intact.
793
+ const checked = await assertSrcAugmentationScoping();
794
+ console.log(`src augmentation scoping checked: ${checked} file(s)`);
795
+
736
796
  const generated = resolve(import.meta.dir, "..", "generated");
737
797
  mkdirSync(resolve(generated, "editor-vm"), { recursive: true });
738
798
  for (const entry of [
@@ -752,6 +812,21 @@ if (import.meta.main) {
752
812
  writeFileSync(messagesOut, generateBuiltinMessagesDeclaration(MESSAGES_MANIFEST));
753
813
  console.log(`wrote ${messagesOut}`);
754
814
 
815
+ // Imported here rather than at module scope: its fixtures are not published,
816
+ // and `resolve` loads this module from an installed package.
817
+ const { EXTENSION_GOLDENS_DIR, EXTENSION_GOLDEN_MANIFEST } = await import("./extension-goldens");
818
+ const goldens = resolve(PACKAGE_ROOT, EXTENSION_GOLDENS_DIR);
819
+ mkdirSync(goldens, { recursive: true });
820
+ for (const entry of EXTENSION_GOLDEN_MANIFEST) {
821
+ const { contents, dropped } = generateModuleDeclaration(entry);
822
+ if (dropped.length > 0) {
823
+ console.log(`note: dropped skipped member(s) from ${entry.namespace}: ${dropped.join(", ")}`);
824
+ }
825
+ const out = resolve(goldens, entry.outFile);
826
+ writeFileSync(out, contents);
827
+ console.log(`wrote ${out}`);
828
+ }
829
+
755
830
  // The target's own `generatedDir` is where a version lands, so a declaring
756
831
  // target's editor surface (and its `editor-vm/` subdirectory) rides the same
757
832
  // destination rule as its runtime modules rather than a second convention.
@@ -778,7 +853,14 @@ if (import.meta.main) {
778
853
  for (const target of versionedTargets) {
779
854
  const indexOut = resolve(versionDirOf(target.id), "index.d.ts");
780
855
  mkdirSync(dirname(indexOut), { recursive: true });
781
- writeFileSync(indexOut, generateVersionIndex(target.id));
856
+ writeFileSync(
857
+ indexOut,
858
+ generateVersionIndex(
859
+ target.id,
860
+ VERSIONED_MODULE_MANIFEST,
861
+ versionSrcAugmentationImports(target),
862
+ ),
863
+ );
782
864
  console.log(`wrote ${indexOut}`);
783
865
 
784
866
  const editorKinds = targetKindManifest(target).filter((entry) => entry.only !== undefined);