@defold-typescript/types 0.24.0 → 0.26.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 +333 -306
- package/api-signatures.json +47 -46
- package/api-targets.json +66 -2
- package/generated/collectionproxy.d.ts +22 -0
- package/generated/editor-vm/http.d.ts +56 -0
- package/generated/editor-vm/image.d.ts +48 -0
- package/generated/editor-vm/json.d.ts +10 -0
- package/generated/editor-vm/localization.d.ts +42 -0
- package/generated/editor-vm/tilemap_tiles.d.ts +80 -0
- package/generated/editor-vm/zip.d.ts +10 -0
- package/generated/editor-vm/zlib.d.ts +24 -0
- package/generated/editor.d.ts +1111 -0
- package/generated/go.d.ts +22 -22
- package/generated/gui.d.ts +35 -6
- package/generated/kinds/editor-script.d.ts +14 -0
- package/generated/kinds/gui-script.d.ts +1 -0
- package/generated/kinds/render-script.d.ts +1 -0
- package/generated/kinds/script.d.ts +1 -0
- package/generated/material.d.ts +4 -0
- package/generated/versions/defold-1.12.4/go.d.ts +22 -22
- package/generated/versions/defold-1.12.4/gui.d.ts +43 -43
- package/index.d.ts +9 -0
- package/package.json +9 -1
- package/scripts/import-defold-release.ts +10 -0
- package/scripts/materialize-version.ts +54 -13
- package/scripts/regen.ts +425 -42
- package/scripts/sync-api-docs.ts +86 -9
- package/src/api-availability.ts +0 -0
- package/src/core-types.ts +15 -1
- package/src/editor-overloads.d.ts +33 -0
- package/src/editor-vm-globals.d.ts +200 -0
- package/src/editor-vm-types.ts +44 -0
- package/src/editor.ts +117 -16
- package/src/emit-dts.ts +298 -79
- package/src/engine-globals.d.ts +2 -2
- package/src/go-overloads.d.ts +6 -6
- package/src/index.ts +15 -0
- package/src/msg-overloads.d.ts +3 -3
- package/src/scene-addresses.d.ts +62 -0
- package/src/url-parameters.ts +174 -0
- package/url-parameters.json +285 -0
package/src/emit-dts.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./doc-comment";
|
|
17
17
|
import type { TranslationStore } from "./example-store";
|
|
18
18
|
import { hashExampleSource, lookupTranslation } from "./example-store";
|
|
19
|
+
import { classifyUrlParameter, type UrlParameterTable } from "./url-parameters";
|
|
19
20
|
|
|
20
21
|
export interface EmitOptions {
|
|
21
22
|
mapType?: (defoldType: string) => string;
|
|
@@ -30,6 +31,12 @@ export interface EmitOptions {
|
|
|
30
31
|
// `examples/translations.json`. Loading lives in `scripts/example-store-io.ts`
|
|
31
32
|
// so this module stays node-free for downstream consumers.
|
|
32
33
|
translations?: TranslationStore;
|
|
34
|
+
// Which parameters address the scene graph, so their `string` member emits a
|
|
35
|
+
// scene-derived address alias instead. Defaults to an empty table — every
|
|
36
|
+
// slot classifies `none` and the output is byte-identical to an un-retyped
|
|
37
|
+
// emit. `regen` supplies the committed `url-parameters.json`; the table
|
|
38
|
+
// arrives as data so this module stays free of `node:fs` (bug-88).
|
|
39
|
+
urlParameters?: UrlParameterTable;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
export const TS_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
@@ -81,6 +88,7 @@ export const TS_RESERVED_NAMES = new Set([
|
|
|
81
88
|
"with",
|
|
82
89
|
"debugger",
|
|
83
90
|
"extends",
|
|
91
|
+
"enum",
|
|
84
92
|
]);
|
|
85
93
|
|
|
86
94
|
// A parameter name that clears `TS_IDENTIFIER` but is a TS reserved word (e.g.
|
|
@@ -149,6 +157,12 @@ export const ARBITRARY_TABLE_SLOTS = new Set([
|
|
|
149
157
|
// is opaque to the field-list parser and the whole-slot `Record` is faithful.
|
|
150
158
|
"render.render_target",
|
|
151
159
|
"render.set_render_target",
|
|
160
|
+
// reserved-but-undocumented options bag: `collectionproxy.load`'s `options`
|
|
161
|
+
// slot is documented verbatim as "options table, currently unused" and accepts
|
|
162
|
+
// `nil`, so upstream defines no field list to emit. The whole-slot `Record` is
|
|
163
|
+
// faithful to what is documented today. If a later release fills the bag in,
|
|
164
|
+
// drop this entry so the missing fields resurface under `recordTables`.
|
|
165
|
+
"collectionproxy.load",
|
|
152
166
|
]);
|
|
153
167
|
|
|
154
168
|
// Per-slot companion to ARBITRARY_TABLE_SLOTS (`element:kind:name`), for a
|
|
@@ -218,7 +232,13 @@ export const MAPPING_TABLE_SLOTS: ReadonlyMap<string, { key: string; value: stri
|
|
|
218
232
|
// honest, ts-defold-matching shape. Per-FQN, not a blanket "empty returnvalues
|
|
219
233
|
// -> unknown" rule: `gui.set` also has empty returnvalues and `void` is correct
|
|
220
234
|
// there.
|
|
221
|
-
export const RETURN_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
235
|
+
export const RETURN_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
236
|
+
["gui.get", "unknown"],
|
|
237
|
+
// Upstream documents the returned transaction step in prose only — its
|
|
238
|
+
// `returnvalues` is empty while every sibling `editor.tx.*` builder declares
|
|
239
|
+
// one, and `editor.transact()` takes exactly that.
|
|
240
|
+
["editor.tx.add", 'Opaque<"transaction_step">'],
|
|
241
|
+
]);
|
|
222
242
|
|
|
223
243
|
// FQN-keyed allowlist of the `types.is_*` checks that genuinely narrow their
|
|
224
244
|
// argument, mapped to the `DEFOLD_TYPE_MAP` token whose interface they prove.
|
|
@@ -1426,6 +1446,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1426
1446
|
const constantFqns = new Set(module.constants.map((c) => c.name));
|
|
1427
1447
|
const knownConstantFqns = options?.knownConstantFqns;
|
|
1428
1448
|
const translations = options?.translations ?? {};
|
|
1449
|
+
const urlParameters = options?.urlParameters ?? [];
|
|
1429
1450
|
const baseMapType = options?.mapType ?? defaultMapType;
|
|
1430
1451
|
const mapType = (token: string): string =>
|
|
1431
1452
|
constantFqns.has(token) || knownConstantFqns?.has(token)
|
|
@@ -1451,32 +1472,14 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1451
1472
|
: a.name.localeCompare(b.name),
|
|
1452
1473
|
);
|
|
1453
1474
|
|
|
1454
|
-
//
|
|
1455
|
-
// in `prepareFunction` above (the
|
|
1456
|
-
//
|
|
1457
|
-
//
|
|
1458
|
-
//
|
|
1459
|
-
//
|
|
1460
|
-
|
|
1461
|
-
const
|
|
1462
|
-
for (const fn of module.functions) {
|
|
1463
|
-
const local = stripPrefix(fn.name, prefix);
|
|
1464
|
-
if (!nestedFunctionLocal.test(local)) continue;
|
|
1465
|
-
const segment = local.slice(0, local.indexOf("."));
|
|
1466
|
-
const prepared = prepareFunction(fn, `${module.namespace}.${segment}.`);
|
|
1467
|
-
if (prepared === null) continue;
|
|
1468
|
-
const group = nestedGroups.get(segment) ?? [];
|
|
1469
|
-
group.push(prepared);
|
|
1470
|
-
nestedGroups.set(segment, group);
|
|
1471
|
-
}
|
|
1472
|
-
for (const group of nestedGroups.values()) {
|
|
1473
|
-
group.sort((a, b) =>
|
|
1474
|
-
a.name === b.name
|
|
1475
|
-
? a.original.parameters.length - b.original.parameters.length
|
|
1476
|
-
: a.name.localeCompare(b.name),
|
|
1477
|
-
);
|
|
1478
|
-
}
|
|
1479
|
-
const nestedSegments = [...nestedGroups.keys()].sort((a, b) => a.localeCompare(b));
|
|
1475
|
+
// Nested members (`socket.dns.toip`, `editor.ui.COLOR.TEXT`) fail the
|
|
1476
|
+
// flat-identifier test in `prepareVariable`/`prepareFunction` above (the
|
|
1477
|
+
// stripped local has a dot), so they are absent from `variables`/`functions`.
|
|
1478
|
+
// Re-collect them into a tree keyed by their full leading path, re-stripping
|
|
1479
|
+
// against `<namespace>.<path>.` so the emitted identifier is the final
|
|
1480
|
+
// segment. One or two leading identifier segments qualify; anything deeper,
|
|
1481
|
+
// and any non-identifier segment, stays dropped.
|
|
1482
|
+
const nestedRoot = collectNestedGroups(module, prefix);
|
|
1480
1483
|
|
|
1481
1484
|
// Colon methods (`client:send`) are FUNCTION elements named `<receiver>:<method>`
|
|
1482
1485
|
// and are NOT namespace-prefixed, so they fail the flat-identifier test in
|
|
@@ -1525,7 +1528,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1525
1528
|
for (const docLine of functionDocLines(fn.original, translations, handleIndent)) {
|
|
1526
1529
|
lines.push(docLine);
|
|
1527
1530
|
}
|
|
1528
|
-
lines.push(`${handleIndent}${emitMethod(fn, mapType, resolver)}`);
|
|
1531
|
+
lines.push(`${handleIndent}${emitMethod(fn, mapType, resolver, urlParameters)}`);
|
|
1529
1532
|
}
|
|
1530
1533
|
lines.push(`${INDENT}}`);
|
|
1531
1534
|
}
|
|
@@ -1554,7 +1557,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1554
1557
|
const reserved = TS_RESERVED_NAMES.has(fn.name);
|
|
1555
1558
|
const emitName = aliasName(fn.name, aliases);
|
|
1556
1559
|
for (const docLine of functionDocLines(fn.original, translations)) lines.push(docLine);
|
|
1557
|
-
const line = emitFunction(fn, emitName, mapType, resolver);
|
|
1560
|
+
const line = emitFunction(fn, emitName, mapType, resolver, urlParameters);
|
|
1558
1561
|
lines.push(`${INDENT}${reserved ? "" : decl}${line}`);
|
|
1559
1562
|
}
|
|
1560
1563
|
|
|
@@ -1562,31 +1565,57 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1562
1565
|
lines.push(`${INDENT}export { ${alias.internal} as ${alias.public} };`);
|
|
1563
1566
|
}
|
|
1564
1567
|
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
|
|
1568
|
+
const emitNestedLevel = (
|
|
1569
|
+
level: ReadonlyMap<string, NestedGroup>,
|
|
1570
|
+
indent: string,
|
|
1571
|
+
outerDecl: string,
|
|
1572
|
+
): void => {
|
|
1573
|
+
for (const segment of [...level.keys()].sort((a, b) => a.localeCompare(b))) {
|
|
1574
|
+
const group = level.get(segment) as NestedGroup;
|
|
1575
|
+
const bodyIndent = `${indent}${INDENT}`;
|
|
1576
|
+
// A reserved-name member inside a nested namespace gets the same recovery as
|
|
1577
|
+
// a top-level one: emitted un-exported as `_<name>` and re-exported under the
|
|
1578
|
+
// reserved name. The alias switches this namespace out of implicit-export mode,
|
|
1579
|
+
// so its siblings then need an explicit `export` to stay reachable.
|
|
1580
|
+
const segmentAliases: { internal: string; public: string }[] = [];
|
|
1581
|
+
const segmentDecl =
|
|
1582
|
+
group.variables.some((v) => TS_RESERVED_NAMES.has(v.name)) ||
|
|
1583
|
+
group.functions.some((fn) => TS_RESERVED_NAMES.has(fn.name))
|
|
1584
|
+
? "export "
|
|
1585
|
+
: "";
|
|
1586
|
+
lines.push(`${indent}${outerDecl}namespace ${segment} {`);
|
|
1587
|
+
for (const v of group.variables) {
|
|
1588
|
+
const reserved = TS_RESERVED_NAMES.has(v.name);
|
|
1589
|
+
const emitName = aliasName(v.name, segmentAliases);
|
|
1590
|
+
for (const docLine of summaryDocLines(
|
|
1591
|
+
v.original.brief,
|
|
1592
|
+
v.original.description,
|
|
1593
|
+
bodyIndent,
|
|
1594
|
+
)) {
|
|
1595
|
+
lines.push(docLine);
|
|
1596
|
+
}
|
|
1597
|
+
lines.push(
|
|
1598
|
+
`${bodyIndent}${reserved ? "" : segmentDecl}${emitVariable(v, emitName, mapType)}`,
|
|
1599
|
+
);
|
|
1580
1600
|
}
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1601
|
+
for (const fn of group.functions) {
|
|
1602
|
+
const reserved = TS_RESERVED_NAMES.has(fn.name);
|
|
1603
|
+
const emitName = aliasName(fn.name, segmentAliases);
|
|
1604
|
+
for (const docLine of functionDocLines(fn.original, translations, bodyIndent)) {
|
|
1605
|
+
lines.push(docLine);
|
|
1606
|
+
}
|
|
1607
|
+
lines.push(
|
|
1608
|
+
`${bodyIndent}${reserved ? "" : segmentDecl}${emitFunction(fn, emitName, mapType, resolver, urlParameters)}`,
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
for (const alias of [...segmentAliases].sort((a, b) => a.public.localeCompare(b.public))) {
|
|
1612
|
+
lines.push(`${bodyIndent}export { ${alias.internal} as ${alias.public} };`);
|
|
1613
|
+
}
|
|
1614
|
+
emitNestedLevel(group.children, bodyIndent, segmentDecl);
|
|
1615
|
+
lines.push(`${indent}}`);
|
|
1587
1616
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1617
|
+
};
|
|
1618
|
+
emitNestedLevel(nestedRoot, INDENT, decl);
|
|
1590
1619
|
|
|
1591
1620
|
if (module.properties.length > 0) {
|
|
1592
1621
|
const members = [...module.properties].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -1616,13 +1645,17 @@ export interface SymbolSignature {
|
|
|
1616
1645
|
* availability matrix joins on. This is the single declaration-backed source for
|
|
1617
1646
|
* the shared `api-signatures.json` artifact: the same `mapType` (constant
|
|
1618
1647
|
* branding) and table-doc resolver produce text that appears verbatim in the
|
|
1619
|
-
* committed `.d.ts
|
|
1620
|
-
*
|
|
1648
|
+
* committed `.d.ts`, and nested members come from the same
|
|
1649
|
+
* {@link collectNestedGroups} tree the declaration emitter walks, so neither
|
|
1650
|
+
* surface can decide on its own which members are nested or how deep they go.
|
|
1651
|
+
* The caller applies the same `skipFunctions` filter the `.d.ts` generation
|
|
1652
|
+
* does, so a dropped member never yields a signature.
|
|
1621
1653
|
*/
|
|
1622
1654
|
export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions): SymbolSignature[] {
|
|
1623
1655
|
const prefix = `${module.namespace}.`;
|
|
1624
1656
|
const constantFqns = new Set(module.constants.map((c) => c.name));
|
|
1625
1657
|
const knownConstantFqns = options?.knownConstantFqns;
|
|
1658
|
+
const urlParameters = options?.urlParameters ?? [];
|
|
1626
1659
|
const baseMapType = options?.mapType ?? defaultMapType;
|
|
1627
1660
|
const mapType = (token: string): string =>
|
|
1628
1661
|
constantFqns.has(token) || knownConstantFqns?.has(token)
|
|
@@ -1649,20 +1682,32 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
1649
1682
|
if (prepared === null) continue;
|
|
1650
1683
|
out.push({
|
|
1651
1684
|
identity: fnIdentity(fn),
|
|
1652
|
-
tsSignature: emitFunction(
|
|
1685
|
+
tsSignature: emitFunction(
|
|
1686
|
+
prepared,
|
|
1687
|
+
emitName(prepared.name),
|
|
1688
|
+
mapType,
|
|
1689
|
+
resolver,
|
|
1690
|
+
urlParameters,
|
|
1691
|
+
),
|
|
1653
1692
|
});
|
|
1654
1693
|
}
|
|
1655
1694
|
|
|
1656
|
-
const
|
|
1657
|
-
for (const
|
|
1658
|
-
const local = stripPrefix(fn.name, prefix);
|
|
1659
|
-
if (!nestedFunctionLocal.test(local)) continue;
|
|
1660
|
-
const segment = local.slice(0, local.indexOf("."));
|
|
1661
|
-
const prepared = prepareFunction(fn, `${module.namespace}.${segment}.`);
|
|
1662
|
-
if (prepared === null) continue;
|
|
1695
|
+
const nested = flattenNestedGroups(collectNestedGroups(module, prefix));
|
|
1696
|
+
for (const v of nested.variables) {
|
|
1663
1697
|
out.push({
|
|
1664
|
-
identity:
|
|
1665
|
-
|
|
1698
|
+
identity: {
|
|
1699
|
+
namespace: module.namespace,
|
|
1700
|
+
kind: "VARIABLE",
|
|
1701
|
+
name: v.original.name,
|
|
1702
|
+
signature: "",
|
|
1703
|
+
},
|
|
1704
|
+
tsSignature: emitVariable(v, emitName(v.name), mapType),
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
for (const fn of nested.functions) {
|
|
1708
|
+
out.push({
|
|
1709
|
+
identity: fnIdentity(fn.original),
|
|
1710
|
+
tsSignature: emitFunction(fn, emitName(fn.name), mapType, resolver, urlParameters),
|
|
1666
1711
|
});
|
|
1667
1712
|
}
|
|
1668
1713
|
|
|
@@ -1671,7 +1716,7 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
1671
1716
|
for (const prepared of group) {
|
|
1672
1717
|
out.push({
|
|
1673
1718
|
identity: fnIdentity(prepared.original),
|
|
1674
|
-
tsSignature: emitMethod(prepared, mapType, resolver),
|
|
1719
|
+
tsSignature: emitMethod(prepared, mapType, resolver, urlParameters),
|
|
1675
1720
|
});
|
|
1676
1721
|
}
|
|
1677
1722
|
}
|
|
@@ -1728,6 +1773,92 @@ interface PreparedVariable {
|
|
|
1728
1773
|
original: ApiVariable;
|
|
1729
1774
|
}
|
|
1730
1775
|
|
|
1776
|
+
// One level of the nested-member tree: the members declared directly under a
|
|
1777
|
+
// segment, plus the segments declared beneath it.
|
|
1778
|
+
interface NestedGroup {
|
|
1779
|
+
variables: PreparedVariable[];
|
|
1780
|
+
functions: PreparedFunction[];
|
|
1781
|
+
children: Map<string, NestedGroup>;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// A stripped local carrying one or two leading identifier segments before the
|
|
1785
|
+
// member name (`dns.toip`, `COLOR.TEXT`, `schema.integer`). Three levels deep is
|
|
1786
|
+
// beyond anything the vendored documents describe, so it stays dropped rather
|
|
1787
|
+
// than half-emitted.
|
|
1788
|
+
const NESTED_MEMBER_LOCAL = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*){1,2}$/;
|
|
1789
|
+
|
|
1790
|
+
function collectNestedGroups(module: ApiModule, prefix: string): Map<string, NestedGroup> {
|
|
1791
|
+
const root = new Map<string, NestedGroup>();
|
|
1792
|
+
const groupAt = (segments: readonly string[]): NestedGroup => {
|
|
1793
|
+
let level = root;
|
|
1794
|
+
let group: NestedGroup | undefined;
|
|
1795
|
+
for (const segment of segments) {
|
|
1796
|
+
let next = level.get(segment);
|
|
1797
|
+
if (next === undefined) {
|
|
1798
|
+
next = { variables: [], functions: [], children: new Map() };
|
|
1799
|
+
level.set(segment, next);
|
|
1800
|
+
}
|
|
1801
|
+
group = next;
|
|
1802
|
+
level = next.children;
|
|
1803
|
+
}
|
|
1804
|
+
return group as NestedGroup;
|
|
1805
|
+
};
|
|
1806
|
+
const pathOf = (local: string): string[] => local.split(".").slice(0, -1);
|
|
1807
|
+
|
|
1808
|
+
for (const v of module.variables) {
|
|
1809
|
+
const local = stripPrefix(v.name, prefix);
|
|
1810
|
+
if (!NESTED_MEMBER_LOCAL.test(local)) continue;
|
|
1811
|
+
const segments = pathOf(local);
|
|
1812
|
+
const prepared = prepareVariable(v, `${module.namespace}.${segments.join(".")}.`);
|
|
1813
|
+
if (prepared === null) continue;
|
|
1814
|
+
groupAt(segments).variables.push(prepared);
|
|
1815
|
+
}
|
|
1816
|
+
for (const fn of module.functions) {
|
|
1817
|
+
const local = stripPrefix(fn.name, prefix);
|
|
1818
|
+
if (!NESTED_MEMBER_LOCAL.test(local)) continue;
|
|
1819
|
+
const segments = pathOf(local);
|
|
1820
|
+
const prepared = prepareFunction(fn, `${module.namespace}.${segments.join(".")}.`);
|
|
1821
|
+
if (prepared === null) continue;
|
|
1822
|
+
groupAt(segments).functions.push(prepared);
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
const sortLevel = (level: Map<string, NestedGroup>): void => {
|
|
1826
|
+
for (const group of level.values()) {
|
|
1827
|
+
group.variables.sort((a, b) => a.name.localeCompare(b.name));
|
|
1828
|
+
group.functions.sort((a, b) =>
|
|
1829
|
+
a.name === b.name
|
|
1830
|
+
? a.original.parameters.length - b.original.parameters.length
|
|
1831
|
+
: a.name.localeCompare(b.name),
|
|
1832
|
+
);
|
|
1833
|
+
sortLevel(group.children);
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
sortLevel(root);
|
|
1837
|
+
return root;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// Every member a nested tree holds, at any depth, in the order the declaration
|
|
1841
|
+
// emitter walks it (segments sorted, each group's own members before its
|
|
1842
|
+
// children). Callers that need no per-segment container read the tree through
|
|
1843
|
+
// this rather than re-deriving which members are nested and how deep.
|
|
1844
|
+
function flattenNestedGroups(level: ReadonlyMap<string, NestedGroup>): {
|
|
1845
|
+
variables: PreparedVariable[];
|
|
1846
|
+
functions: PreparedFunction[];
|
|
1847
|
+
} {
|
|
1848
|
+
const variables: PreparedVariable[] = [];
|
|
1849
|
+
const functions: PreparedFunction[] = [];
|
|
1850
|
+
const walk = (current: ReadonlyMap<string, NestedGroup>): void => {
|
|
1851
|
+
for (const segment of [...current.keys()].sort((a, b) => a.localeCompare(b))) {
|
|
1852
|
+
const group = current.get(segment) as NestedGroup;
|
|
1853
|
+
variables.push(...group.variables);
|
|
1854
|
+
functions.push(...group.functions);
|
|
1855
|
+
walk(group.children);
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
walk(level);
|
|
1859
|
+
return { variables, functions };
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1731
1862
|
function prepareFunction(fn: ApiFunction, prefix: string): PreparedFunction | null {
|
|
1732
1863
|
const stripped = stripPrefix(fn.name, prefix);
|
|
1733
1864
|
if (!TS_IDENTIFIER.test(stripped)) return null;
|
|
@@ -1813,13 +1944,23 @@ function memberSignature(
|
|
|
1813
1944
|
name: string,
|
|
1814
1945
|
mapType: (t: string) => string,
|
|
1815
1946
|
resolver: TableDocResolver,
|
|
1947
|
+
urlParameters: UrlParameterTable,
|
|
1816
1948
|
): string {
|
|
1817
1949
|
const original = prepared.original.parameters;
|
|
1818
1950
|
const elementName = prepared.original.name;
|
|
1819
1951
|
const cutoff = trailingOptionalCutoff(original);
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1822
|
-
|
|
1952
|
+
const varargIndex = original.findIndex(isVarargParameter);
|
|
1953
|
+
const positional = (varargIndex === -1 ? original : original.slice(0, varargIndex)).map((p, i) =>
|
|
1954
|
+
emitParameter(p, i, i >= cutoff, mapType, resolver, elementName, urlParameters),
|
|
1955
|
+
);
|
|
1956
|
+
const params = (
|
|
1957
|
+
varargIndex === -1
|
|
1958
|
+
? positional
|
|
1959
|
+
: [
|
|
1960
|
+
...positional,
|
|
1961
|
+
emitRestParameter(original, varargIndex, mapType, resolver, elementName, urlParameters),
|
|
1962
|
+
]
|
|
1963
|
+
).join(", ");
|
|
1823
1964
|
const ret = emitReturn(prepared.original.returnValues, mapType, resolver, elementName);
|
|
1824
1965
|
const predicateToken = TYPE_PREDICATES.get(elementName);
|
|
1825
1966
|
const soleParam = original[0];
|
|
@@ -1839,8 +1980,9 @@ function emitFunction(
|
|
|
1839
1980
|
name: string,
|
|
1840
1981
|
mapType: (t: string) => string,
|
|
1841
1982
|
resolver: TableDocResolver,
|
|
1983
|
+
urlParameters: UrlParameterTable,
|
|
1842
1984
|
): string {
|
|
1843
|
-
return `function ${memberSignature(prepared, name, mapType, resolver)}`;
|
|
1985
|
+
return `function ${memberSignature(prepared, name, mapType, resolver, urlParameters)}`;
|
|
1844
1986
|
}
|
|
1845
1987
|
|
|
1846
1988
|
// A colon-method member of a handle interface: identical signature machinery to a
|
|
@@ -1850,15 +1992,18 @@ function emitMethod(
|
|
|
1850
1992
|
prepared: PreparedFunction,
|
|
1851
1993
|
mapType: (t: string) => string,
|
|
1852
1994
|
resolver: TableDocResolver,
|
|
1995
|
+
urlParameters: UrlParameterTable,
|
|
1853
1996
|
): string {
|
|
1854
|
-
return memberSignature(prepared, prepared.name, mapType, resolver);
|
|
1997
|
+
return memberSignature(prepared, prepared.name, mapType, resolver, urlParameters);
|
|
1855
1998
|
}
|
|
1856
1999
|
|
|
1857
2000
|
// Build the indented JSDoc lines for a function from its ref-doc prose. The
|
|
1858
2001
|
// summary prefers the full `description`, falling back to the one-line `brief`;
|
|
1859
2002
|
// each `@param` name is the parameter's *emitted* name (the `arg<index>`
|
|
1860
|
-
// fallback applies to non-identifier names
|
|
1861
|
-
//
|
|
2003
|
+
// fallback applies to non-identifier names and a vararg drops its dots, matching
|
|
2004
|
+
// `emitParameter` and `emitRestParameter`) so the tag resolves on hover; a
|
|
2005
|
+
// parameter folded into a rest element union keeps its own tag, so the prose
|
|
2006
|
+
// documenting it survives. A single documented return becomes `@returns`. Returns `[]`
|
|
1862
2007
|
// for a fully-undocumented function, leaving its emission byte-identical.
|
|
1863
2008
|
function functionDocLines(
|
|
1864
2009
|
fn: ApiFunction,
|
|
@@ -1866,7 +2011,7 @@ function functionDocLines(
|
|
|
1866
2011
|
indent: string = INDENT,
|
|
1867
2012
|
): string[] {
|
|
1868
2013
|
const params = fn.parameters.map((p, index) => ({
|
|
1869
|
-
name:
|
|
2014
|
+
name: emittedParamName(p, index),
|
|
1870
2015
|
doc: htmlToDocText(p.doc),
|
|
1871
2016
|
}));
|
|
1872
2017
|
const onlyReturn = fn.returnValues.length === 1 ? fn.returnValues[0] : undefined;
|
|
@@ -1928,6 +2073,83 @@ function trailingOptionalCutoff(params: readonly ApiParameter[]): number {
|
|
|
1928
2073
|
return cutoff;
|
|
1929
2074
|
}
|
|
1930
2075
|
|
|
2076
|
+
const SCENE_ADDRESS_ALIASES: Readonly<Record<string, string>> = {
|
|
2077
|
+
"game-object": "SceneGameObjectAddress",
|
|
2078
|
+
component: "SceneComponentAddress",
|
|
2079
|
+
either: "SceneAddress",
|
|
2080
|
+
};
|
|
2081
|
+
|
|
2082
|
+
// A classified address slot keeps every mapped member except `string`, which
|
|
2083
|
+
// becomes the matching scene-derived alias. Wrapping `mapType` rather than
|
|
2084
|
+
// rewriting the finished union leaves `mapSlotUnion`'s member ordering and
|
|
2085
|
+
// de-duplication in charge, so only the one token moves.
|
|
2086
|
+
function addressMapType(mapType: (t: string) => string, alias: string): (t: string) => string {
|
|
2087
|
+
return (token) => (token === "string" ? alias : mapType(token));
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// The mapped slot type of a parameter, without the name, `?` or `| undefined`
|
|
2091
|
+
// decoration — so a parameter folded into a rest element union contributes its
|
|
2092
|
+
// type alone.
|
|
2093
|
+
function parameterType(
|
|
2094
|
+
p: ApiParameter,
|
|
2095
|
+
mapType: (t: string) => string,
|
|
2096
|
+
resolver: TableDocResolver,
|
|
2097
|
+
elementName: string,
|
|
2098
|
+
urlParameters: UrlParameterTable,
|
|
2099
|
+
): string {
|
|
2100
|
+
const concrete = p.types.filter((t) => t !== "nil");
|
|
2101
|
+
// The table is keyed by the *raw* ref-doc parameter name, not the emitted
|
|
2102
|
+
// `safeParamName` fallback.
|
|
2103
|
+
const alias = SCENE_ADDRESS_ALIASES[classifyUrlParameter(urlParameters, elementName, p.name)];
|
|
2104
|
+
const slotMapType = alias === undefined ? mapType : addressMapType(mapType, alias);
|
|
2105
|
+
return concrete.length > 0
|
|
2106
|
+
? mapSlotUnion(concrete, p.doc, slotMapType, true, resolver, elementName, "param", p.name)
|
|
2107
|
+
: "unknown";
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
const VARARG_PREFIX = "...";
|
|
2111
|
+
|
|
2112
|
+
function isVarargParameter(p: ApiParameter): boolean {
|
|
2113
|
+
return p.name.startsWith(VARARG_PREFIX);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// A vararg's emitted name is its documented name minus the dots (`...commands`
|
|
2117
|
+
// -> `commands`); a bare `...` carries none, so it becomes `args`.
|
|
2118
|
+
function varargParamName(rawName: string, index: number): string {
|
|
2119
|
+
const named = rawName.slice(VARARG_PREFIX.length);
|
|
2120
|
+
return named === "" ? "args" : safeParamName(named, index);
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
function emittedParamName(p: ApiParameter, index: number): string {
|
|
2124
|
+
return isVarargParameter(p) ? varargParamName(p.name, index) : safeParamName(p.name, index);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
// TS1266 forbids a positional parameter after a rest one, so every parameter
|
|
2128
|
+
// documented *after* the vararg folds into the rest's element union — which is
|
|
2129
|
+
// the only shape that types `editor.execute("git", "log", { out: "capture" })`,
|
|
2130
|
+
// where upstream documents a trailing options table behind the vararg.
|
|
2131
|
+
function emitRestParameter(
|
|
2132
|
+
params: readonly ApiParameter[],
|
|
2133
|
+
varargIndex: number,
|
|
2134
|
+
mapType: (t: string) => string,
|
|
2135
|
+
resolver: TableDocResolver,
|
|
2136
|
+
elementName: string,
|
|
2137
|
+
urlParameters: UrlParameterTable,
|
|
2138
|
+
): string {
|
|
2139
|
+
const vararg = params[varargIndex];
|
|
2140
|
+
if (vararg === undefined) return "";
|
|
2141
|
+
const members = [
|
|
2142
|
+
...new Set(
|
|
2143
|
+
params
|
|
2144
|
+
.slice(varargIndex)
|
|
2145
|
+
.map((p) => parameterType(p, mapType, resolver, elementName, urlParameters)),
|
|
2146
|
+
),
|
|
2147
|
+
];
|
|
2148
|
+
const first = members[0] ?? "unknown";
|
|
2149
|
+
const element = members.length > 1 ? `(${members.join(" | ")})` : first;
|
|
2150
|
+
return `...${varargParamName(vararg.name, varargIndex)}: ${element}[]`;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
1931
2153
|
function emitParameter(
|
|
1932
2154
|
p: ApiParameter,
|
|
1933
2155
|
index: number,
|
|
@@ -1935,13 +2157,10 @@ function emitParameter(
|
|
|
1935
2157
|
mapType: (t: string) => string,
|
|
1936
2158
|
resolver: TableDocResolver,
|
|
1937
2159
|
elementName: string,
|
|
2160
|
+
urlParameters: UrlParameterTable,
|
|
1938
2161
|
): string {
|
|
1939
2162
|
const name = safeParamName(p.name, index);
|
|
1940
|
-
const
|
|
1941
|
-
const ts =
|
|
1942
|
-
concrete.length > 0
|
|
1943
|
-
? mapSlotUnion(concrete, p.doc, mapType, true, resolver, elementName, "param", p.name)
|
|
1944
|
-
: "unknown";
|
|
2163
|
+
const ts = parameterType(p, mapType, resolver, elementName, urlParameters);
|
|
1945
2164
|
// An interior doc-optional param (a required param follows, so the trailing-`?`
|
|
1946
2165
|
// projection cannot mark it) keeps its optionality as `| undefined` — TSTL
|
|
1947
2166
|
// lowers `undefined` to `nil`, the faithful call. Trailing optionals keep the
|
|
@@ -2193,7 +2412,7 @@ export function isKnownDefoldTypeToken(token: string): boolean {
|
|
|
2193
2412
|
);
|
|
2194
2413
|
}
|
|
2195
2414
|
|
|
2196
|
-
function defaultMapType(token: string): string {
|
|
2415
|
+
export function defaultMapType(token: string): string {
|
|
2197
2416
|
if (Object.hasOwn(DEFOLD_TYPE_MAP, token)) {
|
|
2198
2417
|
const mapped = DEFOLD_TYPE_MAP[token];
|
|
2199
2418
|
if (typeof mapped === "string") return mapped;
|
package/src/engine-globals.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ import type * as Core from "./core-types";
|
|
|
7
7
|
// engine-globals test fails if the two fall out of sync.
|
|
8
8
|
declare global {
|
|
9
9
|
/** An opaque, branded handle to a hashed name; see {@link Core.Hash}. */
|
|
10
|
-
type Hash = Core.Hash
|
|
10
|
+
type Hash<S extends string = string> = Core.Hash<S>;
|
|
11
11
|
/** Hash a string into the engine's `Hash` handle. */
|
|
12
|
-
function hash(s:
|
|
12
|
+
function hash<S extends string>(s: S): Core.Hash<S>;
|
|
13
13
|
/** Render a `Hash` handle as its hexadecimal string. */
|
|
14
14
|
function hash_to_hex(h: Core.Hash): string;
|
|
15
15
|
/** Pretty-print any value to the console for debugging. */
|
package/src/go-overloads.d.ts
CHANGED
|
@@ -33,17 +33,17 @@ declare global {
|
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
function get<P>(): <K extends keyof P>(
|
|
36
|
-
url:
|
|
36
|
+
url: SceneAddress | Hash | Url,
|
|
37
37
|
property: K,
|
|
38
38
|
options?: GoPropertyOptions,
|
|
39
39
|
) => P[K];
|
|
40
40
|
function get<K extends keyof go.properties>(
|
|
41
|
-
url:
|
|
41
|
+
url: SceneAddress | Hash | Url,
|
|
42
42
|
property: K,
|
|
43
43
|
options?: GoPropertyOptions,
|
|
44
44
|
): go.properties[K];
|
|
45
45
|
function get(
|
|
46
|
-
url:
|
|
46
|
+
url: SceneAddress | Hash | Url,
|
|
47
47
|
property: string | Hash,
|
|
48
48
|
options?: GoPropertyOptions,
|
|
49
49
|
): number | boolean | Hash | Url | Vector3 | Vector4 | Quaternion | Opaque<"resource">;
|
|
@@ -66,19 +66,19 @@ declare global {
|
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
68
|
function set<P>(): <K extends keyof P>(
|
|
69
|
-
url:
|
|
69
|
+
url: SceneAddress | Hash | Url,
|
|
70
70
|
property: K,
|
|
71
71
|
value: P[K],
|
|
72
72
|
options?: GoPropertyOptions,
|
|
73
73
|
) => void;
|
|
74
74
|
function set<K extends keyof go.properties>(
|
|
75
|
-
url:
|
|
75
|
+
url: SceneAddress | Hash | Url,
|
|
76
76
|
property: K,
|
|
77
77
|
value: go.properties[K],
|
|
78
78
|
options?: GoPropertyOptions,
|
|
79
79
|
): void;
|
|
80
80
|
function set(
|
|
81
|
-
url:
|
|
81
|
+
url: SceneAddress | Hash | Url,
|
|
82
82
|
property: string | Hash,
|
|
83
83
|
value: number | boolean | Hash | Url | Vector3 | Vector4 | Quaternion | Opaque<"resource">,
|
|
84
84
|
options?: GoPropertyOptions,
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export {
|
|
|
5
5
|
type ApiSymbolIdentity,
|
|
6
6
|
type AvailabilityLabel,
|
|
7
7
|
type AvailabilityLabelKind,
|
|
8
|
+
type AvailabilityLabelOptions,
|
|
8
9
|
applyMigrationOverlay,
|
|
9
10
|
availabilityLabel,
|
|
10
11
|
type Box2dBackend,
|
|
@@ -14,7 +15,9 @@ export {
|
|
|
14
15
|
isSignatureTransition,
|
|
15
16
|
type LogicalNameGroup,
|
|
16
17
|
normalizedFunctionSignature,
|
|
18
|
+
signatureTransitionNames,
|
|
17
19
|
symbolIdentityKey,
|
|
20
|
+
symbolNameKey,
|
|
18
21
|
type VersionSurface,
|
|
19
22
|
validateAvailability,
|
|
20
23
|
} from "./api-availability";
|
|
@@ -91,3 +94,15 @@ export {
|
|
|
91
94
|
type SignatureOverride,
|
|
92
95
|
type SignatureStore,
|
|
93
96
|
} from "./signature-store";
|
|
97
|
+
export {
|
|
98
|
+
classifyUrlParameter,
|
|
99
|
+
collectParameterSlots,
|
|
100
|
+
collectUrlParameterSlots,
|
|
101
|
+
parameterTypesSatisfyClass,
|
|
102
|
+
REQUIRED_TYPES,
|
|
103
|
+
type UrlParameterClass,
|
|
104
|
+
type UrlParameterEntry,
|
|
105
|
+
type UrlParameterSlot,
|
|
106
|
+
type UrlParameterSource,
|
|
107
|
+
type UrlParameterTable,
|
|
108
|
+
} from "./url-parameters";
|
package/src/msg-overloads.d.ts
CHANGED
|
@@ -31,12 +31,12 @@ declare global {
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
function post<K extends string>(
|
|
34
|
-
receiver:
|
|
34
|
+
receiver: SceneAddress | Url | Hash,
|
|
35
35
|
message_id: K,
|
|
36
36
|
message?: MsgPostPayload<K>,
|
|
37
37
|
): void;
|
|
38
38
|
function post(
|
|
39
|
-
receiver:
|
|
39
|
+
receiver: SceneAddress | Url | Hash,
|
|
40
40
|
message_id: Hash,
|
|
41
41
|
message?: Record<string | number, unknown>,
|
|
42
42
|
): void;
|
|
@@ -76,7 +76,7 @@ declare global {
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
function url(): Url;
|
|
79
|
-
function url(urlstring:
|
|
79
|
+
function url(urlstring: SceneAddress): Url;
|
|
80
80
|
function url(socket: string | Hash, path: string | Hash, fragment: string | Hash): Url;
|
|
81
81
|
}
|
|
82
82
|
}
|