@defold-typescript/types 0.24.0 → 0.25.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-signatures.json +44 -44
- package/api-targets.json +57 -0
- package/generated/editor-vm/http.d.ts +56 -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 +1092 -0
- package/generated/go.d.ts +22 -22
- package/generated/kinds/editor-script.d.ts +13 -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/versions/defold-1.12.4/go.d.ts +22 -22
- package/index.d.ts +6 -0
- package/package.json +9 -1
- package/scripts/materialize-version.ts +54 -13
- package/scripts/regen.ts +425 -42
- package/scripts/sync-api-docs.ts +82 -6
- 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 +292 -79
- package/src/engine-globals.d.ts +2 -2
- package/src/go-overloads.d.ts +6 -6
- package/src/index.ts +12 -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.
|
|
@@ -218,7 +226,13 @@ export const MAPPING_TABLE_SLOTS: ReadonlyMap<string, { key: string; value: stri
|
|
|
218
226
|
// honest, ts-defold-matching shape. Per-FQN, not a blanket "empty returnvalues
|
|
219
227
|
// -> unknown" rule: `gui.set` also has empty returnvalues and `void` is correct
|
|
220
228
|
// there.
|
|
221
|
-
export const RETURN_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
229
|
+
export const RETURN_TYPE_OVERRIDES: ReadonlyMap<string, string> = new Map([
|
|
230
|
+
["gui.get", "unknown"],
|
|
231
|
+
// Upstream documents the returned transaction step in prose only — its
|
|
232
|
+
// `returnvalues` is empty while every sibling `editor.tx.*` builder declares
|
|
233
|
+
// one, and `editor.transact()` takes exactly that.
|
|
234
|
+
["editor.tx.add", 'Opaque<"transaction_step">'],
|
|
235
|
+
]);
|
|
222
236
|
|
|
223
237
|
// FQN-keyed allowlist of the `types.is_*` checks that genuinely narrow their
|
|
224
238
|
// argument, mapped to the `DEFOLD_TYPE_MAP` token whose interface they prove.
|
|
@@ -1426,6 +1440,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1426
1440
|
const constantFqns = new Set(module.constants.map((c) => c.name));
|
|
1427
1441
|
const knownConstantFqns = options?.knownConstantFqns;
|
|
1428
1442
|
const translations = options?.translations ?? {};
|
|
1443
|
+
const urlParameters = options?.urlParameters ?? [];
|
|
1429
1444
|
const baseMapType = options?.mapType ?? defaultMapType;
|
|
1430
1445
|
const mapType = (token: string): string =>
|
|
1431
1446
|
constantFqns.has(token) || knownConstantFqns?.has(token)
|
|
@@ -1451,32 +1466,14 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1451
1466
|
: a.name.localeCompare(b.name),
|
|
1452
1467
|
);
|
|
1453
1468
|
|
|
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));
|
|
1469
|
+
// Nested members (`socket.dns.toip`, `editor.ui.COLOR.TEXT`) fail the
|
|
1470
|
+
// flat-identifier test in `prepareVariable`/`prepareFunction` above (the
|
|
1471
|
+
// stripped local has a dot), so they are absent from `variables`/`functions`.
|
|
1472
|
+
// Re-collect them into a tree keyed by their full leading path, re-stripping
|
|
1473
|
+
// against `<namespace>.<path>.` so the emitted identifier is the final
|
|
1474
|
+
// segment. One or two leading identifier segments qualify; anything deeper,
|
|
1475
|
+
// and any non-identifier segment, stays dropped.
|
|
1476
|
+
const nestedRoot = collectNestedGroups(module, prefix);
|
|
1480
1477
|
|
|
1481
1478
|
// Colon methods (`client:send`) are FUNCTION elements named `<receiver>:<method>`
|
|
1482
1479
|
// and are NOT namespace-prefixed, so they fail the flat-identifier test in
|
|
@@ -1525,7 +1522,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1525
1522
|
for (const docLine of functionDocLines(fn.original, translations, handleIndent)) {
|
|
1526
1523
|
lines.push(docLine);
|
|
1527
1524
|
}
|
|
1528
|
-
lines.push(`${handleIndent}${emitMethod(fn, mapType, resolver)}`);
|
|
1525
|
+
lines.push(`${handleIndent}${emitMethod(fn, mapType, resolver, urlParameters)}`);
|
|
1529
1526
|
}
|
|
1530
1527
|
lines.push(`${INDENT}}`);
|
|
1531
1528
|
}
|
|
@@ -1554,7 +1551,7 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1554
1551
|
const reserved = TS_RESERVED_NAMES.has(fn.name);
|
|
1555
1552
|
const emitName = aliasName(fn.name, aliases);
|
|
1556
1553
|
for (const docLine of functionDocLines(fn.original, translations)) lines.push(docLine);
|
|
1557
|
-
const line = emitFunction(fn, emitName, mapType, resolver);
|
|
1554
|
+
const line = emitFunction(fn, emitName, mapType, resolver, urlParameters);
|
|
1558
1555
|
lines.push(`${INDENT}${reserved ? "" : decl}${line}`);
|
|
1559
1556
|
}
|
|
1560
1557
|
|
|
@@ -1562,31 +1559,57 @@ export function emitDeclarations(module: ApiModule, options?: EmitOptions): stri
|
|
|
1562
1559
|
lines.push(`${INDENT}export { ${alias.internal} as ${alias.public} };`);
|
|
1563
1560
|
}
|
|
1564
1561
|
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
|
|
1562
|
+
const emitNestedLevel = (
|
|
1563
|
+
level: ReadonlyMap<string, NestedGroup>,
|
|
1564
|
+
indent: string,
|
|
1565
|
+
outerDecl: string,
|
|
1566
|
+
): void => {
|
|
1567
|
+
for (const segment of [...level.keys()].sort((a, b) => a.localeCompare(b))) {
|
|
1568
|
+
const group = level.get(segment) as NestedGroup;
|
|
1569
|
+
const bodyIndent = `${indent}${INDENT}`;
|
|
1570
|
+
// A reserved-name member inside a nested namespace gets the same recovery as
|
|
1571
|
+
// a top-level one: emitted un-exported as `_<name>` and re-exported under the
|
|
1572
|
+
// reserved name. The alias switches this namespace out of implicit-export mode,
|
|
1573
|
+
// so its siblings then need an explicit `export` to stay reachable.
|
|
1574
|
+
const segmentAliases: { internal: string; public: string }[] = [];
|
|
1575
|
+
const segmentDecl =
|
|
1576
|
+
group.variables.some((v) => TS_RESERVED_NAMES.has(v.name)) ||
|
|
1577
|
+
group.functions.some((fn) => TS_RESERVED_NAMES.has(fn.name))
|
|
1578
|
+
? "export "
|
|
1579
|
+
: "";
|
|
1580
|
+
lines.push(`${indent}${outerDecl}namespace ${segment} {`);
|
|
1581
|
+
for (const v of group.variables) {
|
|
1582
|
+
const reserved = TS_RESERVED_NAMES.has(v.name);
|
|
1583
|
+
const emitName = aliasName(v.name, segmentAliases);
|
|
1584
|
+
for (const docLine of summaryDocLines(
|
|
1585
|
+
v.original.brief,
|
|
1586
|
+
v.original.description,
|
|
1587
|
+
bodyIndent,
|
|
1588
|
+
)) {
|
|
1589
|
+
lines.push(docLine);
|
|
1590
|
+
}
|
|
1591
|
+
lines.push(
|
|
1592
|
+
`${bodyIndent}${reserved ? "" : segmentDecl}${emitVariable(v, emitName, mapType)}`,
|
|
1593
|
+
);
|
|
1580
1594
|
}
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1595
|
+
for (const fn of group.functions) {
|
|
1596
|
+
const reserved = TS_RESERVED_NAMES.has(fn.name);
|
|
1597
|
+
const emitName = aliasName(fn.name, segmentAliases);
|
|
1598
|
+
for (const docLine of functionDocLines(fn.original, translations, bodyIndent)) {
|
|
1599
|
+
lines.push(docLine);
|
|
1600
|
+
}
|
|
1601
|
+
lines.push(
|
|
1602
|
+
`${bodyIndent}${reserved ? "" : segmentDecl}${emitFunction(fn, emitName, mapType, resolver, urlParameters)}`,
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
for (const alias of [...segmentAliases].sort((a, b) => a.public.localeCompare(b.public))) {
|
|
1606
|
+
lines.push(`${bodyIndent}export { ${alias.internal} as ${alias.public} };`);
|
|
1607
|
+
}
|
|
1608
|
+
emitNestedLevel(group.children, bodyIndent, segmentDecl);
|
|
1609
|
+
lines.push(`${indent}}`);
|
|
1587
1610
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1611
|
+
};
|
|
1612
|
+
emitNestedLevel(nestedRoot, INDENT, decl);
|
|
1590
1613
|
|
|
1591
1614
|
if (module.properties.length > 0) {
|
|
1592
1615
|
const members = [...module.properties].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -1616,13 +1639,17 @@ export interface SymbolSignature {
|
|
|
1616
1639
|
* availability matrix joins on. This is the single declaration-backed source for
|
|
1617
1640
|
* the shared `api-signatures.json` artifact: the same `mapType` (constant
|
|
1618
1641
|
* branding) and table-doc resolver produce text that appears verbatim in the
|
|
1619
|
-
* committed `.d.ts
|
|
1620
|
-
*
|
|
1642
|
+
* committed `.d.ts`, and nested members come from the same
|
|
1643
|
+
* {@link collectNestedGroups} tree the declaration emitter walks, so neither
|
|
1644
|
+
* surface can decide on its own which members are nested or how deep they go.
|
|
1645
|
+
* The caller applies the same `skipFunctions` filter the `.d.ts` generation
|
|
1646
|
+
* does, so a dropped member never yields a signature.
|
|
1621
1647
|
*/
|
|
1622
1648
|
export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions): SymbolSignature[] {
|
|
1623
1649
|
const prefix = `${module.namespace}.`;
|
|
1624
1650
|
const constantFqns = new Set(module.constants.map((c) => c.name));
|
|
1625
1651
|
const knownConstantFqns = options?.knownConstantFqns;
|
|
1652
|
+
const urlParameters = options?.urlParameters ?? [];
|
|
1626
1653
|
const baseMapType = options?.mapType ?? defaultMapType;
|
|
1627
1654
|
const mapType = (token: string): string =>
|
|
1628
1655
|
constantFqns.has(token) || knownConstantFqns?.has(token)
|
|
@@ -1649,20 +1676,32 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
1649
1676
|
if (prepared === null) continue;
|
|
1650
1677
|
out.push({
|
|
1651
1678
|
identity: fnIdentity(fn),
|
|
1652
|
-
tsSignature: emitFunction(
|
|
1679
|
+
tsSignature: emitFunction(
|
|
1680
|
+
prepared,
|
|
1681
|
+
emitName(prepared.name),
|
|
1682
|
+
mapType,
|
|
1683
|
+
resolver,
|
|
1684
|
+
urlParameters,
|
|
1685
|
+
),
|
|
1653
1686
|
});
|
|
1654
1687
|
}
|
|
1655
1688
|
|
|
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;
|
|
1689
|
+
const nested = flattenNestedGroups(collectNestedGroups(module, prefix));
|
|
1690
|
+
for (const v of nested.variables) {
|
|
1663
1691
|
out.push({
|
|
1664
|
-
identity:
|
|
1665
|
-
|
|
1692
|
+
identity: {
|
|
1693
|
+
namespace: module.namespace,
|
|
1694
|
+
kind: "VARIABLE",
|
|
1695
|
+
name: v.original.name,
|
|
1696
|
+
signature: "",
|
|
1697
|
+
},
|
|
1698
|
+
tsSignature: emitVariable(v, emitName(v.name), mapType),
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
for (const fn of nested.functions) {
|
|
1702
|
+
out.push({
|
|
1703
|
+
identity: fnIdentity(fn.original),
|
|
1704
|
+
tsSignature: emitFunction(fn, emitName(fn.name), mapType, resolver, urlParameters),
|
|
1666
1705
|
});
|
|
1667
1706
|
}
|
|
1668
1707
|
|
|
@@ -1671,7 +1710,7 @@ export function emitSymbolSignatures(module: ApiModule, options?: EmitOptions):
|
|
|
1671
1710
|
for (const prepared of group) {
|
|
1672
1711
|
out.push({
|
|
1673
1712
|
identity: fnIdentity(prepared.original),
|
|
1674
|
-
tsSignature: emitMethod(prepared, mapType, resolver),
|
|
1713
|
+
tsSignature: emitMethod(prepared, mapType, resolver, urlParameters),
|
|
1675
1714
|
});
|
|
1676
1715
|
}
|
|
1677
1716
|
}
|
|
@@ -1728,6 +1767,92 @@ interface PreparedVariable {
|
|
|
1728
1767
|
original: ApiVariable;
|
|
1729
1768
|
}
|
|
1730
1769
|
|
|
1770
|
+
// One level of the nested-member tree: the members declared directly under a
|
|
1771
|
+
// segment, plus the segments declared beneath it.
|
|
1772
|
+
interface NestedGroup {
|
|
1773
|
+
variables: PreparedVariable[];
|
|
1774
|
+
functions: PreparedFunction[];
|
|
1775
|
+
children: Map<string, NestedGroup>;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// A stripped local carrying one or two leading identifier segments before the
|
|
1779
|
+
// member name (`dns.toip`, `COLOR.TEXT`, `schema.integer`). Three levels deep is
|
|
1780
|
+
// beyond anything the vendored documents describe, so it stays dropped rather
|
|
1781
|
+
// than half-emitted.
|
|
1782
|
+
const NESTED_MEMBER_LOCAL = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*){1,2}$/;
|
|
1783
|
+
|
|
1784
|
+
function collectNestedGroups(module: ApiModule, prefix: string): Map<string, NestedGroup> {
|
|
1785
|
+
const root = new Map<string, NestedGroup>();
|
|
1786
|
+
const groupAt = (segments: readonly string[]): NestedGroup => {
|
|
1787
|
+
let level = root;
|
|
1788
|
+
let group: NestedGroup | undefined;
|
|
1789
|
+
for (const segment of segments) {
|
|
1790
|
+
let next = level.get(segment);
|
|
1791
|
+
if (next === undefined) {
|
|
1792
|
+
next = { variables: [], functions: [], children: new Map() };
|
|
1793
|
+
level.set(segment, next);
|
|
1794
|
+
}
|
|
1795
|
+
group = next;
|
|
1796
|
+
level = next.children;
|
|
1797
|
+
}
|
|
1798
|
+
return group as NestedGroup;
|
|
1799
|
+
};
|
|
1800
|
+
const pathOf = (local: string): string[] => local.split(".").slice(0, -1);
|
|
1801
|
+
|
|
1802
|
+
for (const v of module.variables) {
|
|
1803
|
+
const local = stripPrefix(v.name, prefix);
|
|
1804
|
+
if (!NESTED_MEMBER_LOCAL.test(local)) continue;
|
|
1805
|
+
const segments = pathOf(local);
|
|
1806
|
+
const prepared = prepareVariable(v, `${module.namespace}.${segments.join(".")}.`);
|
|
1807
|
+
if (prepared === null) continue;
|
|
1808
|
+
groupAt(segments).variables.push(prepared);
|
|
1809
|
+
}
|
|
1810
|
+
for (const fn of module.functions) {
|
|
1811
|
+
const local = stripPrefix(fn.name, prefix);
|
|
1812
|
+
if (!NESTED_MEMBER_LOCAL.test(local)) continue;
|
|
1813
|
+
const segments = pathOf(local);
|
|
1814
|
+
const prepared = prepareFunction(fn, `${module.namespace}.${segments.join(".")}.`);
|
|
1815
|
+
if (prepared === null) continue;
|
|
1816
|
+
groupAt(segments).functions.push(prepared);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
const sortLevel = (level: Map<string, NestedGroup>): void => {
|
|
1820
|
+
for (const group of level.values()) {
|
|
1821
|
+
group.variables.sort((a, b) => a.name.localeCompare(b.name));
|
|
1822
|
+
group.functions.sort((a, b) =>
|
|
1823
|
+
a.name === b.name
|
|
1824
|
+
? a.original.parameters.length - b.original.parameters.length
|
|
1825
|
+
: a.name.localeCompare(b.name),
|
|
1826
|
+
);
|
|
1827
|
+
sortLevel(group.children);
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
sortLevel(root);
|
|
1831
|
+
return root;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// Every member a nested tree holds, at any depth, in the order the declaration
|
|
1835
|
+
// emitter walks it (segments sorted, each group's own members before its
|
|
1836
|
+
// children). Callers that need no per-segment container read the tree through
|
|
1837
|
+
// this rather than re-deriving which members are nested and how deep.
|
|
1838
|
+
function flattenNestedGroups(level: ReadonlyMap<string, NestedGroup>): {
|
|
1839
|
+
variables: PreparedVariable[];
|
|
1840
|
+
functions: PreparedFunction[];
|
|
1841
|
+
} {
|
|
1842
|
+
const variables: PreparedVariable[] = [];
|
|
1843
|
+
const functions: PreparedFunction[] = [];
|
|
1844
|
+
const walk = (current: ReadonlyMap<string, NestedGroup>): void => {
|
|
1845
|
+
for (const segment of [...current.keys()].sort((a, b) => a.localeCompare(b))) {
|
|
1846
|
+
const group = current.get(segment) as NestedGroup;
|
|
1847
|
+
variables.push(...group.variables);
|
|
1848
|
+
functions.push(...group.functions);
|
|
1849
|
+
walk(group.children);
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
walk(level);
|
|
1853
|
+
return { variables, functions };
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1731
1856
|
function prepareFunction(fn: ApiFunction, prefix: string): PreparedFunction | null {
|
|
1732
1857
|
const stripped = stripPrefix(fn.name, prefix);
|
|
1733
1858
|
if (!TS_IDENTIFIER.test(stripped)) return null;
|
|
@@ -1813,13 +1938,23 @@ function memberSignature(
|
|
|
1813
1938
|
name: string,
|
|
1814
1939
|
mapType: (t: string) => string,
|
|
1815
1940
|
resolver: TableDocResolver,
|
|
1941
|
+
urlParameters: UrlParameterTable,
|
|
1816
1942
|
): string {
|
|
1817
1943
|
const original = prepared.original.parameters;
|
|
1818
1944
|
const elementName = prepared.original.name;
|
|
1819
1945
|
const cutoff = trailingOptionalCutoff(original);
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1822
|
-
|
|
1946
|
+
const varargIndex = original.findIndex(isVarargParameter);
|
|
1947
|
+
const positional = (varargIndex === -1 ? original : original.slice(0, varargIndex)).map((p, i) =>
|
|
1948
|
+
emitParameter(p, i, i >= cutoff, mapType, resolver, elementName, urlParameters),
|
|
1949
|
+
);
|
|
1950
|
+
const params = (
|
|
1951
|
+
varargIndex === -1
|
|
1952
|
+
? positional
|
|
1953
|
+
: [
|
|
1954
|
+
...positional,
|
|
1955
|
+
emitRestParameter(original, varargIndex, mapType, resolver, elementName, urlParameters),
|
|
1956
|
+
]
|
|
1957
|
+
).join(", ");
|
|
1823
1958
|
const ret = emitReturn(prepared.original.returnValues, mapType, resolver, elementName);
|
|
1824
1959
|
const predicateToken = TYPE_PREDICATES.get(elementName);
|
|
1825
1960
|
const soleParam = original[0];
|
|
@@ -1839,8 +1974,9 @@ function emitFunction(
|
|
|
1839
1974
|
name: string,
|
|
1840
1975
|
mapType: (t: string) => string,
|
|
1841
1976
|
resolver: TableDocResolver,
|
|
1977
|
+
urlParameters: UrlParameterTable,
|
|
1842
1978
|
): string {
|
|
1843
|
-
return `function ${memberSignature(prepared, name, mapType, resolver)}`;
|
|
1979
|
+
return `function ${memberSignature(prepared, name, mapType, resolver, urlParameters)}`;
|
|
1844
1980
|
}
|
|
1845
1981
|
|
|
1846
1982
|
// A colon-method member of a handle interface: identical signature machinery to a
|
|
@@ -1850,15 +1986,18 @@ function emitMethod(
|
|
|
1850
1986
|
prepared: PreparedFunction,
|
|
1851
1987
|
mapType: (t: string) => string,
|
|
1852
1988
|
resolver: TableDocResolver,
|
|
1989
|
+
urlParameters: UrlParameterTable,
|
|
1853
1990
|
): string {
|
|
1854
|
-
return memberSignature(prepared, prepared.name, mapType, resolver);
|
|
1991
|
+
return memberSignature(prepared, prepared.name, mapType, resolver, urlParameters);
|
|
1855
1992
|
}
|
|
1856
1993
|
|
|
1857
1994
|
// Build the indented JSDoc lines for a function from its ref-doc prose. The
|
|
1858
1995
|
// summary prefers the full `description`, falling back to the one-line `brief`;
|
|
1859
1996
|
// each `@param` name is the parameter's *emitted* name (the `arg<index>`
|
|
1860
|
-
// fallback applies to non-identifier names
|
|
1861
|
-
//
|
|
1997
|
+
// fallback applies to non-identifier names and a vararg drops its dots, matching
|
|
1998
|
+
// `emitParameter` and `emitRestParameter`) so the tag resolves on hover; a
|
|
1999
|
+
// parameter folded into a rest element union keeps its own tag, so the prose
|
|
2000
|
+
// documenting it survives. A single documented return becomes `@returns`. Returns `[]`
|
|
1862
2001
|
// for a fully-undocumented function, leaving its emission byte-identical.
|
|
1863
2002
|
function functionDocLines(
|
|
1864
2003
|
fn: ApiFunction,
|
|
@@ -1866,7 +2005,7 @@ function functionDocLines(
|
|
|
1866
2005
|
indent: string = INDENT,
|
|
1867
2006
|
): string[] {
|
|
1868
2007
|
const params = fn.parameters.map((p, index) => ({
|
|
1869
|
-
name:
|
|
2008
|
+
name: emittedParamName(p, index),
|
|
1870
2009
|
doc: htmlToDocText(p.doc),
|
|
1871
2010
|
}));
|
|
1872
2011
|
const onlyReturn = fn.returnValues.length === 1 ? fn.returnValues[0] : undefined;
|
|
@@ -1928,6 +2067,83 @@ function trailingOptionalCutoff(params: readonly ApiParameter[]): number {
|
|
|
1928
2067
|
return cutoff;
|
|
1929
2068
|
}
|
|
1930
2069
|
|
|
2070
|
+
const SCENE_ADDRESS_ALIASES: Readonly<Record<string, string>> = {
|
|
2071
|
+
"game-object": "SceneGameObjectAddress",
|
|
2072
|
+
component: "SceneComponentAddress",
|
|
2073
|
+
either: "SceneAddress",
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
// A classified address slot keeps every mapped member except `string`, which
|
|
2077
|
+
// becomes the matching scene-derived alias. Wrapping `mapType` rather than
|
|
2078
|
+
// rewriting the finished union leaves `mapSlotUnion`'s member ordering and
|
|
2079
|
+
// de-duplication in charge, so only the one token moves.
|
|
2080
|
+
function addressMapType(mapType: (t: string) => string, alias: string): (t: string) => string {
|
|
2081
|
+
return (token) => (token === "string" ? alias : mapType(token));
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// The mapped slot type of a parameter, without the name, `?` or `| undefined`
|
|
2085
|
+
// decoration — so a parameter folded into a rest element union contributes its
|
|
2086
|
+
// type alone.
|
|
2087
|
+
function parameterType(
|
|
2088
|
+
p: ApiParameter,
|
|
2089
|
+
mapType: (t: string) => string,
|
|
2090
|
+
resolver: TableDocResolver,
|
|
2091
|
+
elementName: string,
|
|
2092
|
+
urlParameters: UrlParameterTable,
|
|
2093
|
+
): string {
|
|
2094
|
+
const concrete = p.types.filter((t) => t !== "nil");
|
|
2095
|
+
// The table is keyed by the *raw* ref-doc parameter name, not the emitted
|
|
2096
|
+
// `safeParamName` fallback.
|
|
2097
|
+
const alias = SCENE_ADDRESS_ALIASES[classifyUrlParameter(urlParameters, elementName, p.name)];
|
|
2098
|
+
const slotMapType = alias === undefined ? mapType : addressMapType(mapType, alias);
|
|
2099
|
+
return concrete.length > 0
|
|
2100
|
+
? mapSlotUnion(concrete, p.doc, slotMapType, true, resolver, elementName, "param", p.name)
|
|
2101
|
+
: "unknown";
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
const VARARG_PREFIX = "...";
|
|
2105
|
+
|
|
2106
|
+
function isVarargParameter(p: ApiParameter): boolean {
|
|
2107
|
+
return p.name.startsWith(VARARG_PREFIX);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// A vararg's emitted name is its documented name minus the dots (`...commands`
|
|
2111
|
+
// -> `commands`); a bare `...` carries none, so it becomes `args`.
|
|
2112
|
+
function varargParamName(rawName: string, index: number): string {
|
|
2113
|
+
const named = rawName.slice(VARARG_PREFIX.length);
|
|
2114
|
+
return named === "" ? "args" : safeParamName(named, index);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
function emittedParamName(p: ApiParameter, index: number): string {
|
|
2118
|
+
return isVarargParameter(p) ? varargParamName(p.name, index) : safeParamName(p.name, index);
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// TS1266 forbids a positional parameter after a rest one, so every parameter
|
|
2122
|
+
// documented *after* the vararg folds into the rest's element union — which is
|
|
2123
|
+
// the only shape that types `editor.execute("git", "log", { out: "capture" })`,
|
|
2124
|
+
// where upstream documents a trailing options table behind the vararg.
|
|
2125
|
+
function emitRestParameter(
|
|
2126
|
+
params: readonly ApiParameter[],
|
|
2127
|
+
varargIndex: number,
|
|
2128
|
+
mapType: (t: string) => string,
|
|
2129
|
+
resolver: TableDocResolver,
|
|
2130
|
+
elementName: string,
|
|
2131
|
+
urlParameters: UrlParameterTable,
|
|
2132
|
+
): string {
|
|
2133
|
+
const vararg = params[varargIndex];
|
|
2134
|
+
if (vararg === undefined) return "";
|
|
2135
|
+
const members = [
|
|
2136
|
+
...new Set(
|
|
2137
|
+
params
|
|
2138
|
+
.slice(varargIndex)
|
|
2139
|
+
.map((p) => parameterType(p, mapType, resolver, elementName, urlParameters)),
|
|
2140
|
+
),
|
|
2141
|
+
];
|
|
2142
|
+
const first = members[0] ?? "unknown";
|
|
2143
|
+
const element = members.length > 1 ? `(${members.join(" | ")})` : first;
|
|
2144
|
+
return `...${varargParamName(vararg.name, varargIndex)}: ${element}[]`;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
1931
2147
|
function emitParameter(
|
|
1932
2148
|
p: ApiParameter,
|
|
1933
2149
|
index: number,
|
|
@@ -1935,13 +2151,10 @@ function emitParameter(
|
|
|
1935
2151
|
mapType: (t: string) => string,
|
|
1936
2152
|
resolver: TableDocResolver,
|
|
1937
2153
|
elementName: string,
|
|
2154
|
+
urlParameters: UrlParameterTable,
|
|
1938
2155
|
): string {
|
|
1939
2156
|
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";
|
|
2157
|
+
const ts = parameterType(p, mapType, resolver, elementName, urlParameters);
|
|
1945
2158
|
// An interior doc-optional param (a required param follows, so the trailing-`?`
|
|
1946
2159
|
// projection cannot mark it) keeps its optionality as `| undefined` — TSTL
|
|
1947
2160
|
// lowers `undefined` to `nil`, the faithful call. Trailing optionals keep the
|
|
@@ -2193,7 +2406,7 @@ export function isKnownDefoldTypeToken(token: string): boolean {
|
|
|
2193
2406
|
);
|
|
2194
2407
|
}
|
|
2195
2408
|
|
|
2196
|
-
function defaultMapType(token: string): string {
|
|
2409
|
+
export function defaultMapType(token: string): string {
|
|
2197
2410
|
if (Object.hasOwn(DEFOLD_TYPE_MAP, token)) {
|
|
2198
2411
|
const mapped = DEFOLD_TYPE_MAP[token];
|
|
2199
2412
|
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
|
@@ -91,3 +91,15 @@ export {
|
|
|
91
91
|
type SignatureOverride,
|
|
92
92
|
type SignatureStore,
|
|
93
93
|
} from "./signature-store";
|
|
94
|
+
export {
|
|
95
|
+
classifyUrlParameter,
|
|
96
|
+
collectParameterSlots,
|
|
97
|
+
collectUrlParameterSlots,
|
|
98
|
+
parameterTypesSatisfyClass,
|
|
99
|
+
REQUIRED_TYPES,
|
|
100
|
+
type UrlParameterClass,
|
|
101
|
+
type UrlParameterEntry,
|
|
102
|
+
type UrlParameterSlot,
|
|
103
|
+
type UrlParameterSource,
|
|
104
|
+
type UrlParameterTable,
|
|
105
|
+
} 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
|
}
|