@uipath/maestro-builder-sdk 6.4.0 → 6.5.1
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/dist/bpmn/uipath-moddle.v1.json +21 -0
- package/dist/cli/commands/registry.js +68 -12
- package/dist/registry/archive/entry-policy.d.ts +36 -0
- package/dist/registry/archive/entry-policy.js +60 -0
- package/dist/registry/archive/extract.d.ts +31 -0
- package/dist/registry/archive/extract.js +92 -0
- package/dist/registry/archive/zip-reader.d.ts +38 -0
- package/dist/registry/archive/zip-reader.js +256 -0
- package/dist/registry/codecs/pyjson.d.ts +62 -0
- package/dist/registry/codecs/pyjson.js +208 -0
- package/dist/registry/compat/compare.d.ts +18 -0
- package/dist/registry/compat/compare.js +32 -0
- package/dist/registry/compat/paths.d.ts +4 -0
- package/dist/registry/compat/paths.js +17 -0
- package/dist/registry/compat/pystr.d.ts +50 -0
- package/dist/registry/compat/pystr.js +221 -0
- package/dist/registry/concurrency.d.ts +10 -0
- package/dist/registry/concurrency.js +34 -0
- package/dist/registry/curated-overlay.d.ts +36 -4
- package/dist/registry/curated-overlay.js +87 -14
- package/dist/registry/errors.d.ts +26 -0
- package/dist/registry/errors.js +38 -0
- package/dist/registry/extractor.d.ts +9 -10
- package/dist/registry/extractor.js +5 -15
- package/dist/registry/files.d.ts +26 -0
- package/dist/registry/files.js +160 -0
- package/dist/registry/generators/descriptors.d.ts +81 -0
- package/dist/registry/generators/descriptors.js +405 -0
- package/dist/registry/generators/fields.d.ts +46 -0
- package/dist/registry/generators/fields.js +111 -0
- package/dist/registry/generators/markdown/common.d.ts +21 -0
- package/dist/registry/generators/markdown/common.js +55 -0
- package/dist/registry/generators/markdown/index.d.ts +33 -0
- package/dist/registry/generators/markdown/index.js +37 -0
- package/dist/registry/generators/markdown/page.d.ts +8 -0
- package/dist/registry/generators/markdown/page.js +52 -0
- package/dist/registry/generators/markdown/pyvalue.d.ts +34 -0
- package/dist/registry/generators/markdown/pyvalue.js +106 -0
- package/dist/registry/generators/markdown/sections/choosing-object.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/choosing-object.js +52 -0
- package/dist/registry/generators/markdown/sections/example.d.ts +22 -0
- package/dist/registry/generators/markdown/sections/example.js +295 -0
- package/dist/registry/generators/markdown/sections/filtering.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/filtering.js +76 -0
- package/dist/registry/generators/markdown/sections/header.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/header.js +37 -0
- package/dist/registry/generators/markdown/sections/inputs.d.ts +30 -0
- package/dist/registry/generators/markdown/sections/inputs.js +151 -0
- package/dist/registry/generators/markdown/sections/lookups.d.ts +12 -0
- package/dist/registry/generators/markdown/sections/lookups.js +150 -0
- package/dist/registry/generators/markdown/sections/outputs.d.ts +3 -0
- package/dist/registry/generators/markdown/sections/outputs.js +9 -0
- package/dist/registry/generators/markdown/sections/resolving-fields.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/resolving-fields.js +139 -0
- package/dist/registry/generators/markdown/sections/schema-dynamic.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/schema-dynamic.js +86 -0
- package/dist/registry/generators/materialize.d.ts +30 -0
- package/dist/registry/generators/materialize.js +132 -0
- package/dist/registry/generators/md-symbols.d.ts +22 -0
- package/dist/registry/generators/md-symbols.js +58 -0
- package/dist/registry/generators/triggers.d.ts +15 -0
- package/dist/registry/generators/triggers.js +85 -0
- package/dist/registry/generators/type-registry.d.ts +50 -0
- package/dist/registry/generators/type-registry.js +154 -0
- package/dist/registry/generators/type-tree.d.ts +65 -0
- package/dist/registry/generators/type-tree.js +179 -0
- package/dist/registry/library-build/build.d.ts +57 -0
- package/dist/registry/library-build/build.js +286 -0
- package/dist/registry/library-build/canonical.d.ts +119 -0
- package/dist/registry/library-build/canonical.js +512 -0
- package/dist/registry/library-build/cli.d.ts +45 -0
- package/dist/registry/library-build/cli.js +182 -0
- package/dist/registry/library-build/context.d.ts +107 -0
- package/dist/registry/library-build/context.js +267 -0
- package/dist/registry/library-build/enrich.d.ts +36 -0
- package/dist/registry/library-build/enrich.js +158 -0
- package/dist/registry/library-build/events.d.ts +108 -0
- package/dist/registry/library-build/events.js +476 -0
- package/dist/registry/library-build/generic-expand.d.ts +77 -0
- package/dist/registry/library-build/generic-expand.js +363 -0
- package/dist/registry/library-build/plan.d.ts +71 -0
- package/dist/registry/library-build/plan.js +270 -0
- package/dist/registry/library-build/py.d.ts +45 -0
- package/dist/registry/library-build/py.js +167 -0
- package/dist/registry/library-build/schema-action.d.ts +38 -0
- package/dist/registry/library-build/schema-action.js +107 -0
- package/dist/registry/library-build/write.d.ts +6 -0
- package/dist/registry/library-build/write.js +26 -0
- package/dist/registry/library-reader.d.ts +20 -0
- package/dist/registry/library-reader.js +50 -0
- package/dist/registry/lookup-specs.d.ts +55 -0
- package/dist/registry/lookup-specs.js +140 -0
- package/dist/registry/materialize-cli.js +28 -14
- package/dist/registry/materializer.d.ts +25 -3
- package/dist/registry/materializer.js +45 -29
- package/dist/registry/model/library.d.ts +254 -0
- package/dist/registry/model/library.js +23 -0
- package/dist/registry/naming.d.ts +54 -0
- package/dist/registry/naming.js +142 -0
- package/dist/registry/orphans.d.ts +4 -0
- package/dist/registry/orphans.js +86 -0
- package/dist/registry/prepare/actions.d.ts +26 -0
- package/dist/registry/prepare/actions.js +94 -0
- package/dist/registry/prepare/connections.d.ts +181 -0
- package/dist/registry/prepare/connections.js +399 -0
- package/dist/registry/prepare/event.d.ts +96 -0
- package/dist/registry/prepare/event.js +268 -0
- package/dist/registry/prepare/handoff.d.ts +21 -0
- package/dist/registry/prepare/handoff.js +91 -0
- package/dist/registry/prepare/ledger.d.ts +104 -0
- package/dist/registry/prepare/ledger.js +216 -0
- package/dist/registry/prepare/messages.d.ts +190 -0
- package/dist/registry/prepare/messages.js +472 -0
- package/dist/registry/prepare/objects.d.ts +130 -0
- package/dist/registry/prepare/objects.js +318 -0
- package/dist/registry/prepare/overlay.d.ts +149 -0
- package/dist/registry/prepare/overlay.js +487 -0
- package/dist/registry/prepare/parents.d.ts +41 -0
- package/dist/registry/prepare/parents.js +122 -0
- package/dist/registry/prepare/pipeline.d.ts +91 -0
- package/dist/registry/prepare/pipeline.js +376 -0
- package/dist/registry/prepare/regenerate.d.ts +9 -0
- package/dist/registry/prepare/regenerate.js +50 -0
- package/dist/registry/prepare/resolve.d.ts +199 -0
- package/dist/registry/prepare/resolve.js +470 -0
- package/dist/registry/prepare/retry.d.ts +83 -0
- package/dist/registry/prepare/retry.js +109 -0
- package/dist/registry/prepare/source-import.d.ts +54 -0
- package/dist/registry/prepare/source-import.js +192 -0
- package/dist/registry/prepare/support.d.ts +41 -0
- package/dist/registry/prepare/support.js +178 -0
- package/dist/registry/prepare-cli.d.ts +16 -5
- package/dist/registry/prepare-cli.js +60 -53
- package/dist/registry/pull-cli.js +8 -7
- package/dist/registry/reporter.d.ts +26 -0
- package/dist/registry/reporter.js +41 -0
- package/dist/registry/uip/client.d.ts +99 -0
- package/dist/registry/uip/client.js +226 -0
- package/dist/registry/uip/commands.d.ts +40 -0
- package/dist/registry/uip/commands.js +80 -0
- package/dist/registry/uip/envelope.d.ts +37 -0
- package/dist/registry/uip/envelope.js +84 -0
- package/dist/registry/uip/response-cache.d.ts +28 -0
- package/dist/registry/uip/response-cache.js +57 -0
- package/lib/README.md +10 -8
- package/package.json +3 -3
- package/dist/generators/_connections.py +0 -331
- package/dist/generators/_events.py +0 -355
- package/dist/generators/_lookups.py +0 -114
- package/dist/generators/_naming.py +0 -185
- package/dist/generators/_objects.py +0 -299
- package/dist/generators/_resolve.py +0 -319
- package/dist/generators/convert_library_to_md.py +0 -1441
- package/dist/generators/extract_library.py +0 -125
- package/dist/generators/generate_connectors_ts.py +0 -936
- package/dist/generators/generate_library_json.py +0 -2527
- package/dist/generators/generate_triggers_ts.py +0 -110
- package/dist/generators/materialize_registry.py +0 -155
- package/dist/generators/prepare_connector.py +0 -1860
- package/dist/registry/python.d.ts +0 -26
- package/dist/registry/python.js +0 -46
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type TriggerCatalogue, type TriggerCatalogueRow } from "../model/library.js";
|
|
2
|
+
export interface TriggerModulesOptions {
|
|
3
|
+
/** Module specifier for `import { triggerDescriptor }`. */
|
|
4
|
+
importSpecifier?: string;
|
|
5
|
+
/** Connector keys to emit; every connector when omitted or empty. */
|
|
6
|
+
connectors?: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* `{ "<connector-key>.triggers.ts" → module text }` for the catalogue.
|
|
10
|
+
*
|
|
11
|
+
* Modules come out sorted by connector key, triggers within a module sorted by
|
|
12
|
+
* node type, both by code point — the order the shared symbol derivation
|
|
13
|
+
* assumes.
|
|
14
|
+
*/
|
|
15
|
+
export declare function renderTriggerModules(catalogue: TriggerCatalogue | TriggerCatalogueRow[], options?: TriggerModulesOptions): Map<string, string>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity-only trigger descriptors from `registry-triggers.json`.
|
|
3
|
+
*
|
|
4
|
+
* The catalogue carries `{ NodeType, DisplayName, Description, Version,
|
|
5
|
+
* connectorKey }` and nothing else, because a trigger's field schema is
|
|
6
|
+
* connection-dependent. So one `triggerDescriptor()` const per event is
|
|
7
|
+
* emitted, one module per connector, and `onEvent`/`waitForEvent` take it in
|
|
8
|
+
* place of the stringly `{ connector, event }`. Ported from
|
|
9
|
+
* `generate_triggers_ts.py`. The module text was verified byte-for-byte
|
|
10
|
+
* against that script before the Python was deleted; the differential went
|
|
11
|
+
* with it, and `tests/registry-triggers-gen.test.ts` now pins the text.
|
|
12
|
+
*/
|
|
13
|
+
import { PACKAGE_NAME } from "../../package-name.js";
|
|
14
|
+
import { pyJsonString, pyJsonStringify } from "../codecs/pyjson.js";
|
|
15
|
+
import { sortedByCodePoint, sortedStrings } from "../compat/compare.js";
|
|
16
|
+
import { afterLast, pyRstrip, pyStrip, upperFirst } from "../compat/pystr.js";
|
|
17
|
+
import { TRIGGER_PREFIX } from "../model/library.js";
|
|
18
|
+
/** The trigger generator's own pascal: same split, `Event` as the empty fallback. */
|
|
19
|
+
function pascalEvent(eventId) {
|
|
20
|
+
const joined = eventId
|
|
21
|
+
.split(/[^A-Za-z0-9]+/)
|
|
22
|
+
.filter((w) => w.length > 0)
|
|
23
|
+
.map((w) => upperFirst(w))
|
|
24
|
+
.join("");
|
|
25
|
+
return joined || "Event";
|
|
26
|
+
}
|
|
27
|
+
function emitTrigger(row, seen) {
|
|
28
|
+
const eventId = afterLast(row.NodeType, ".");
|
|
29
|
+
let name = pascalEvent(eventId);
|
|
30
|
+
while (seen.has(name))
|
|
31
|
+
name += "_";
|
|
32
|
+
seen.add(name);
|
|
33
|
+
const version = "Version" in row ? row.Version : "1.0.0";
|
|
34
|
+
const label = row.DisplayName || eventId;
|
|
35
|
+
const description = pyStrip(String(row.Description || "")).replaceAll("\n", " ");
|
|
36
|
+
let doc = description ? `${label} — ${description}` : label;
|
|
37
|
+
doc = doc.replaceAll("*/", "* /"); // never let a description close the doc comment early
|
|
38
|
+
return [
|
|
39
|
+
`/** ${doc} */`,
|
|
40
|
+
`export const ${name} = triggerDescriptor()({`,
|
|
41
|
+
` connector: ${pyJsonString(row.connectorKey)},`,
|
|
42
|
+
` event: ${pyJsonString(eventId)},`,
|
|
43
|
+
` version: ${pyJsonStringify(version)},`,
|
|
44
|
+
` displayName: ${pyJsonString(label)},`,
|
|
45
|
+
"} as const);",
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `{ "<connector-key>.triggers.ts" → module text }` for the catalogue.
|
|
50
|
+
*
|
|
51
|
+
* Modules come out sorted by connector key, triggers within a module sorted by
|
|
52
|
+
* node type, both by code point — the order the shared symbol derivation
|
|
53
|
+
* assumes.
|
|
54
|
+
*/
|
|
55
|
+
export function renderTriggerModules(catalogue, options = {}) {
|
|
56
|
+
const rows = Array.isArray(catalogue) ? catalogue : catalogue.triggers;
|
|
57
|
+
const subset = new Set((options.connectors ?? []).filter((c) => c.length > 0));
|
|
58
|
+
const importSpecifier = options.importSpecifier ?? PACKAGE_NAME;
|
|
59
|
+
const byConnector = new Map();
|
|
60
|
+
for (const row of rows) {
|
|
61
|
+
const nodeType = row.NodeType ?? "";
|
|
62
|
+
if (!nodeType.startsWith(TRIGGER_PREFIX))
|
|
63
|
+
continue; // catalogue is trigger-only, but be defensive
|
|
64
|
+
const key = row.connectorKey;
|
|
65
|
+
if (subset.size > 0 && !subset.has(key))
|
|
66
|
+
continue;
|
|
67
|
+
const group = byConnector.get(key);
|
|
68
|
+
if (group)
|
|
69
|
+
group.push(row);
|
|
70
|
+
else
|
|
71
|
+
byConnector.set(key, [row]);
|
|
72
|
+
}
|
|
73
|
+
const modules = new Map();
|
|
74
|
+
for (const key of sortedStrings(byConnector.keys())) {
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const body = [`import { triggerDescriptor } from ${pyJsonString(importSpecifier)};`, ""];
|
|
77
|
+
for (const row of sortedByCodePoint(byConnector.get(key), (r) => r.NodeType)) {
|
|
78
|
+
body.push(...emitTrigger(row, seen), "");
|
|
79
|
+
}
|
|
80
|
+
// `"\n".join(body).rstrip() + "\n"`: `pyRstrip`, not `trimEnd`, because the
|
|
81
|
+
// two disagree on which characters are whitespace (`\x1f`, ``).
|
|
82
|
+
modules.set(`${key}.triggers.ts`, `${pyRstrip(body.join("\n"))}\n`);
|
|
83
|
+
}
|
|
84
|
+
return modules;
|
|
85
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type TypeNode, type TypeTree } from "./type-tree.js";
|
|
2
|
+
export interface NamedTypeRegistryOptions {
|
|
3
|
+
/** Appended to every interface name; `"Input"` for the input registry. */
|
|
4
|
+
suffix?: string;
|
|
5
|
+
/** Render every property optional (outputs); inputs follow `required`. */
|
|
6
|
+
allOptional?: boolean;
|
|
7
|
+
/** Merge same-named nodes into one definition (outputs) or reuse exact shapes only (inputs). */
|
|
8
|
+
mergeReused?: boolean;
|
|
9
|
+
/** Wrap property types in `ConnectorValue<…>` / `ConnectorLookupValue<…>`. */
|
|
10
|
+
isInput?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Renders one property line of an interface — `descriptors.ts`'s
|
|
14
|
+
* `emitNestedProperty`, handed to {@link NamedTypeRegistry.emit} so the
|
|
15
|
+
* registry need not import the module that imports it.
|
|
16
|
+
*/
|
|
17
|
+
export type PropertyRenderer = (name: string, node: TypeNode, indent: string, namedTypes: NamedTypeRegistry, allOptional: boolean, isInput: boolean) => string[];
|
|
18
|
+
export declare class NamedTypeRegistry {
|
|
19
|
+
readonly isInput: boolean;
|
|
20
|
+
readonly suffix: string;
|
|
21
|
+
readonly allOptional: boolean;
|
|
22
|
+
readonly mergeReused: boolean;
|
|
23
|
+
private readonly byName;
|
|
24
|
+
/** Node identity → the name it was registered under (the Python's `id(node)` map). */
|
|
25
|
+
private readonly byNode;
|
|
26
|
+
/** `(baseName, fingerprint)` → name, for the exact-shape reuse of the input registry. */
|
|
27
|
+
private readonly shapeNames;
|
|
28
|
+
/** Names in definition order; `emit()` walks it while `register()` may still append. */
|
|
29
|
+
private readonly definitions;
|
|
30
|
+
private readonly registering;
|
|
31
|
+
constructor(options?: NamedTypeRegistryOptions);
|
|
32
|
+
/** Name the node (and, recursively, its object-valued children); return the name. */
|
|
33
|
+
register(fieldName: string, node: TypeNode): string;
|
|
34
|
+
/** Register every root that renders as an interface. */
|
|
35
|
+
discover(roots: TypeTree): void;
|
|
36
|
+
/**
|
|
37
|
+
* The one registered interface an opaque `array` field can be the element
|
|
38
|
+
* type of: `Contact`, or a de-collided `Contact2`, but not when both exist.
|
|
39
|
+
*/
|
|
40
|
+
private knownArrayElement;
|
|
41
|
+
/** The TypeScript type of a property whose value is `node`. */
|
|
42
|
+
typeFor(fieldName: string, node: TypeNode): string;
|
|
43
|
+
/**
|
|
44
|
+
* Every registered interface, one blank line after each. Rendering a
|
|
45
|
+
* definition may register a further nested object, so the walk is by index
|
|
46
|
+
* over a list that can grow while it runs; a definition discovered late is
|
|
47
|
+
* emitted too.
|
|
48
|
+
*/
|
|
49
|
+
emit(renderProperty: PropertyRenderer): string[];
|
|
50
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable named interfaces shared by all operations in one connector module.
|
|
3
|
+
*
|
|
4
|
+
* Every nested object in a connector's field trees becomes an exported
|
|
5
|
+
* interface, named from its segment. The OUTPUT registry merges every node that
|
|
6
|
+
* takes a name into one canonical definition (`Address` is enriched by each
|
|
7
|
+
* operation that returns one). The INPUT registry reuses a name only for an
|
|
8
|
+
* exact shape, because an input type that gained a field from a sibling
|
|
9
|
+
* operation would let an author send a field this operation does not take;
|
|
10
|
+
* a different shape under the same segment gets `AddressInput2`, `…3`.
|
|
11
|
+
* Ported from `NamedTypeRegistry` in `generate_connectors_ts.py`.
|
|
12
|
+
*/
|
|
13
|
+
import { sortedStrings } from "../compat/compare.js";
|
|
14
|
+
import { mergeTypeNodes, nestedTypeName, typeFingerprint } from "./type-tree.js";
|
|
15
|
+
export class NamedTypeRegistry {
|
|
16
|
+
isInput;
|
|
17
|
+
suffix;
|
|
18
|
+
allOptional;
|
|
19
|
+
mergeReused;
|
|
20
|
+
byName = new Map();
|
|
21
|
+
/** Node identity → the name it was registered under (the Python's `id(node)` map). */
|
|
22
|
+
byNode = new Map();
|
|
23
|
+
/** `(baseName, fingerprint)` → name, for the exact-shape reuse of the input registry. */
|
|
24
|
+
shapeNames = new Map();
|
|
25
|
+
/** Names in definition order; `emit()` walks it while `register()` may still append. */
|
|
26
|
+
definitions = [];
|
|
27
|
+
registering = new Set();
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
this.suffix = options.suffix ?? "";
|
|
30
|
+
this.allOptional = options.allOptional ?? true;
|
|
31
|
+
this.mergeReused = options.mergeReused ?? true;
|
|
32
|
+
this.isInput = options.isInput ?? false;
|
|
33
|
+
}
|
|
34
|
+
/** Name the node (and, recursively, its object-valued children); return the name. */
|
|
35
|
+
register(fieldName, node) {
|
|
36
|
+
const known = this.byNode.get(node);
|
|
37
|
+
if (known)
|
|
38
|
+
return known;
|
|
39
|
+
const baseName = nestedTypeName(fieldName, node, this.suffix);
|
|
40
|
+
let typeName;
|
|
41
|
+
if (this.mergeReused) {
|
|
42
|
+
typeName = baseName;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const shapeKey = JSON.stringify([baseName, typeFingerprint(node)]);
|
|
46
|
+
typeName = this.shapeNames.get(shapeKey) ?? "";
|
|
47
|
+
if (!typeName) {
|
|
48
|
+
typeName = baseName;
|
|
49
|
+
let suffix = 2;
|
|
50
|
+
while (this.byName.has(typeName)) {
|
|
51
|
+
typeName = `${baseName}${suffix}`;
|
|
52
|
+
suffix += 1;
|
|
53
|
+
}
|
|
54
|
+
this.shapeNames.set(shapeKey, typeName);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let canonical = this.byName.get(typeName);
|
|
58
|
+
if (canonical === undefined) {
|
|
59
|
+
canonical = node;
|
|
60
|
+
this.byName.set(typeName, canonical);
|
|
61
|
+
this.definitions.push(typeName);
|
|
62
|
+
}
|
|
63
|
+
else if (canonical !== node) {
|
|
64
|
+
if (this.mergeReused)
|
|
65
|
+
mergeTypeNodes(canonical, node);
|
|
66
|
+
}
|
|
67
|
+
this.byNode.set(node, typeName);
|
|
68
|
+
// A schema can recursively repeat the same segment name
|
|
69
|
+
// (`children[*].children[*]…`). Merge it into the shared interface, but do
|
|
70
|
+
// not recursively rediscover that interface while it is active.
|
|
71
|
+
if (this.registering.has(typeName))
|
|
72
|
+
return typeName;
|
|
73
|
+
this.registering.add(typeName);
|
|
74
|
+
try {
|
|
75
|
+
// Registration can enrich a canonical node, so iterate a snapshot.
|
|
76
|
+
for (const [childName, child] of [...canonical.children]) {
|
|
77
|
+
if (child.children.size > 0 || child.opaqueObject)
|
|
78
|
+
this.register(childName, child);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
this.registering.delete(typeName);
|
|
83
|
+
}
|
|
84
|
+
return typeName;
|
|
85
|
+
}
|
|
86
|
+
/** Register every root that renders as an interface. */
|
|
87
|
+
discover(roots) {
|
|
88
|
+
for (const [fieldName, node] of roots) {
|
|
89
|
+
if (node.children.size > 0 || node.opaqueObject)
|
|
90
|
+
this.register(fieldName, node);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The one registered interface an opaque `array` field can be the element
|
|
95
|
+
* type of: `Contact`, or a de-collided `Contact2`, but not when both exist.
|
|
96
|
+
*/
|
|
97
|
+
knownArrayElement(fieldName, node) {
|
|
98
|
+
const candidate = nestedTypeName(fieldName, node, this.suffix);
|
|
99
|
+
const matches = [];
|
|
100
|
+
for (const name of this.byName.keys()) {
|
|
101
|
+
if (name === candidate || (name.startsWith(candidate) && /^[2-9][0-9]*$/.test(name.slice(candidate.length)))) {
|
|
102
|
+
matches.push(name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
106
|
+
}
|
|
107
|
+
/** The TypeScript type of a property whose value is `node`. */
|
|
108
|
+
typeFor(fieldName, node) {
|
|
109
|
+
let base;
|
|
110
|
+
if (node.children.size > 0 || node.opaqueObject) {
|
|
111
|
+
base = this.register(fieldName, node);
|
|
112
|
+
}
|
|
113
|
+
else if (node.opaqueArray) {
|
|
114
|
+
const knownElement = this.knownArrayElement(fieldName, node);
|
|
115
|
+
if (knownElement)
|
|
116
|
+
return `Array<${knownElement}>`;
|
|
117
|
+
return "unknown[]";
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
base = sortedStrings(node.declaredTypes).join(" | ") || "unknown";
|
|
121
|
+
}
|
|
122
|
+
const hasArray = node.arrayModes.has(true);
|
|
123
|
+
const hasScalar = node.arrayModes.has(false);
|
|
124
|
+
if (hasArray && hasScalar)
|
|
125
|
+
return `${base} | Array<${base}>`;
|
|
126
|
+
if (hasArray)
|
|
127
|
+
return `Array<${base}>`;
|
|
128
|
+
return base;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Every registered interface, one blank line after each. Rendering a
|
|
132
|
+
* definition may register a further nested object, so the walk is by index
|
|
133
|
+
* over a list that can grow while it runs; a definition discovered late is
|
|
134
|
+
* emitted too.
|
|
135
|
+
*/
|
|
136
|
+
emit(renderProperty) {
|
|
137
|
+
const lines = [];
|
|
138
|
+
let index = 0;
|
|
139
|
+
while (index < this.definitions.length) {
|
|
140
|
+
const typeName = this.definitions[index];
|
|
141
|
+
const node = this.byName.get(typeName);
|
|
142
|
+
lines.push(`export interface ${typeName} {`);
|
|
143
|
+
if (node.opaqueObject)
|
|
144
|
+
lines.push(" [key: string]: unknown;");
|
|
145
|
+
for (const [childName, child] of node.children) {
|
|
146
|
+
lines.push(...renderProperty(childName, child, " ", this, this.allOptional, this.isInput));
|
|
147
|
+
}
|
|
148
|
+
lines.push("}");
|
|
149
|
+
lines.push("");
|
|
150
|
+
index += 1;
|
|
151
|
+
}
|
|
152
|
+
return lines;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { LibraryField } from "../model/library.js";
|
|
2
|
+
/** Registry field `type` → TypeScript type; anything else is `unknown`. */
|
|
3
|
+
export declare const TYPE_MAP: Readonly<Record<string, string>>;
|
|
4
|
+
/**
|
|
5
|
+
* Python truthiness for a JSON-shaped value. JavaScript agrees on `null`,
|
|
6
|
+
* `false`, `0` and `""` but calls an empty array or object truthy; the Python
|
|
7
|
+
* generator tested `field.get("required")`, `runtime.get("requiresConnection")`
|
|
8
|
+
* and the like with a bare `if`, so the emitted bytes depend on this rule.
|
|
9
|
+
*/
|
|
10
|
+
export declare function pyTruthy(value: unknown): boolean;
|
|
11
|
+
/** `TYPE_MAP.get(str(field["type"] or "").lower(), "unknown")`. */
|
|
12
|
+
export declare function tsType(field: {
|
|
13
|
+
type?: unknown;
|
|
14
|
+
}): string;
|
|
15
|
+
/**
|
|
16
|
+
* A field as the tree holds it: the library's declaration plus the `__lookup`
|
|
17
|
+
* flag `descriptors.ts` sets on a field whose type must also accept a token.
|
|
18
|
+
*/
|
|
19
|
+
export type TreeField = LibraryField & {
|
|
20
|
+
__lookup?: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** `{ rootSegment → node }`: the roots of one operation's inputs or outputs. */
|
|
23
|
+
export type TypeTree = Map<string, TypeNode>;
|
|
24
|
+
/** One node in a tree reconstructed from flattened connector field paths. */
|
|
25
|
+
export declare class TypeNode {
|
|
26
|
+
/** Every cardinality this segment was declared with; `true` is `[*]`. */
|
|
27
|
+
readonly arrayModes: Set<boolean>;
|
|
28
|
+
/** Every TypeScript type a declaration of this segment mapped to. */
|
|
29
|
+
readonly declaredTypes: Set<string>;
|
|
30
|
+
/** The first field declared on this exact segment; its description is rendered. */
|
|
31
|
+
declared: TreeField | undefined;
|
|
32
|
+
opaqueObject: boolean;
|
|
33
|
+
opaqueArray: boolean;
|
|
34
|
+
required: boolean;
|
|
35
|
+
readonly children: TypeTree;
|
|
36
|
+
constructor(isArray?: boolean);
|
|
37
|
+
addDeclaration(field: TreeField): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Split `items[*].owner.id` into `[["items", true], ["owner", false], ["id", false]]`.
|
|
41
|
+
* A malformed name (an empty segment, as in `a..b` or `[*]`) is kept whole as
|
|
42
|
+
* one quoted property.
|
|
43
|
+
*/
|
|
44
|
+
export declare function splitFieldPath(name: string): Array<[segment: string, isArray: boolean]>;
|
|
45
|
+
/** The roots of the tree for one flat field list; a field without a name is skipped. */
|
|
46
|
+
export declare function buildTypeTree(fields: readonly TreeField[]): TypeTree;
|
|
47
|
+
/**
|
|
48
|
+
* Merge repeated occurrences into one reusable connector-level type. A child
|
|
49
|
+
* only the source has is adopted by reference, so the two trees share it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function mergeTypeNodes(target: TypeNode, source: TypeNode): void;
|
|
52
|
+
/**
|
|
53
|
+
* The interface name for a nested segment: singularised when the segment is an
|
|
54
|
+
* array, PascalCased, prefixed with `Nested` when it would start with a digit.
|
|
55
|
+
*/
|
|
56
|
+
export declare function nestedTypeName(fieldName: string, node: TypeNode, suffix?: string): string;
|
|
57
|
+
/** True when the node or any descendant is required. */
|
|
58
|
+
export declare function subtreeRequired(node: TypeNode): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Stable structural identity — the Python's nested tuple, as one canonical
|
|
61
|
+
* string. Input types reuse only exact shapes, so two nodes share an interface
|
|
62
|
+
* iff their fingerprints are equal. Children are ordered by name, as
|
|
63
|
+
* `sorted(node.children.items())` orders them.
|
|
64
|
+
*/
|
|
65
|
+
export declare function typeFingerprint(node: TypeNode): string;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type tree a descriptor's interfaces are rendered from.
|
|
3
|
+
*
|
|
4
|
+
* A connector declares its fields flat — `items[*].owner.id` — and the
|
|
5
|
+
* descriptor exposes them as natural nested objects and arrays. This module
|
|
6
|
+
* rebuilds that nesting: one {@link TypeNode} per path segment, carrying every
|
|
7
|
+
* declaration that landed on it (a segment can be declared both as a scalar and
|
|
8
|
+
* as an array, or by several fields with different types) so the renderer can
|
|
9
|
+
* union them. Ported from the `TypeNode` half of `generate_connectors_ts.py`;
|
|
10
|
+
* `type-registry.ts` names and de-duplicates the nodes and `descriptors.ts`
|
|
11
|
+
* renders them.
|
|
12
|
+
*/
|
|
13
|
+
import { sortedStrings } from "../compat/compare.js";
|
|
14
|
+
import { pyStr } from "../compat/pystr.js";
|
|
15
|
+
import { pascal, singular } from "../naming.js";
|
|
16
|
+
/** Registry field `type` → TypeScript type; anything else is `unknown`. */
|
|
17
|
+
export const TYPE_MAP = {
|
|
18
|
+
string: "string",
|
|
19
|
+
number: "number",
|
|
20
|
+
integer: "number",
|
|
21
|
+
float: "number",
|
|
22
|
+
double: "number",
|
|
23
|
+
long: "number",
|
|
24
|
+
boolean: "boolean",
|
|
25
|
+
bool: "boolean",
|
|
26
|
+
object: "Record<string, unknown>",
|
|
27
|
+
array: "unknown[]",
|
|
28
|
+
json: "unknown",
|
|
29
|
+
file: "string",
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Python truthiness for a JSON-shaped value. JavaScript agrees on `null`,
|
|
33
|
+
* `false`, `0` and `""` but calls an empty array or object truthy; the Python
|
|
34
|
+
* generator tested `field.get("required")`, `runtime.get("requiresConnection")`
|
|
35
|
+
* and the like with a bare `if`, so the emitted bytes depend on this rule.
|
|
36
|
+
*/
|
|
37
|
+
export function pyTruthy(value) {
|
|
38
|
+
if (value === null || value === undefined || value === false || value === "")
|
|
39
|
+
return false;
|
|
40
|
+
if (typeof value === "number")
|
|
41
|
+
return value !== 0; // NaN is truthy in Python
|
|
42
|
+
if (typeof value === "bigint")
|
|
43
|
+
return value !== 0n;
|
|
44
|
+
if (Array.isArray(value))
|
|
45
|
+
return value.length > 0;
|
|
46
|
+
if (value instanceof Map || value instanceof Set)
|
|
47
|
+
return value.size > 0;
|
|
48
|
+
if (typeof value === "object")
|
|
49
|
+
return Object.keys(value).length > 0;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/** `str(value or "")`: the coercion the generator applied before comparing a type name. */
|
|
53
|
+
function strOrEmpty(value) {
|
|
54
|
+
return pyTruthy(value) ? pyStr(value) : "";
|
|
55
|
+
}
|
|
56
|
+
/** `TYPE_MAP.get(str(field["type"] or "").lower(), "unknown")`. */
|
|
57
|
+
export function tsType(field) {
|
|
58
|
+
return TYPE_MAP[strOrEmpty(field.type).toLowerCase()] ?? "unknown";
|
|
59
|
+
}
|
|
60
|
+
/** One node in a tree reconstructed from flattened connector field paths. */
|
|
61
|
+
export class TypeNode {
|
|
62
|
+
/** Every cardinality this segment was declared with; `true` is `[*]`. */
|
|
63
|
+
arrayModes = new Set();
|
|
64
|
+
/** Every TypeScript type a declaration of this segment mapped to. */
|
|
65
|
+
declaredTypes = new Set();
|
|
66
|
+
/** The first field declared on this exact segment; its description is rendered. */
|
|
67
|
+
declared = undefined;
|
|
68
|
+
opaqueObject = false;
|
|
69
|
+
opaqueArray = false;
|
|
70
|
+
required = false;
|
|
71
|
+
children = new Map();
|
|
72
|
+
constructor(isArray = false) {
|
|
73
|
+
this.arrayModes.add(isArray);
|
|
74
|
+
}
|
|
75
|
+
addDeclaration(field) {
|
|
76
|
+
if (this.declared === undefined)
|
|
77
|
+
this.declared = field;
|
|
78
|
+
const declaredType = strOrEmpty(field.type).toLowerCase();
|
|
79
|
+
this.declaredTypes.add(tsType(field));
|
|
80
|
+
this.opaqueObject = this.opaqueObject || declaredType === "object";
|
|
81
|
+
this.opaqueArray = this.opaqueArray || declaredType === "array";
|
|
82
|
+
this.required = this.required || pyTruthy(field.required);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Split `items[*].owner.id` into `[["items", true], ["owner", false], ["id", false]]`.
|
|
87
|
+
* A malformed name (an empty segment, as in `a..b` or `[*]`) is kept whole as
|
|
88
|
+
* one quoted property.
|
|
89
|
+
*/
|
|
90
|
+
export function splitFieldPath(name) {
|
|
91
|
+
const parts = [];
|
|
92
|
+
for (const raw of name.split(".")) {
|
|
93
|
+
const isArray = raw.endsWith("[*]");
|
|
94
|
+
const segment = isArray ? raw.slice(0, -3) : raw;
|
|
95
|
+
if (!segment)
|
|
96
|
+
return [[name, false]];
|
|
97
|
+
parts.push([segment, isArray]);
|
|
98
|
+
}
|
|
99
|
+
return parts;
|
|
100
|
+
}
|
|
101
|
+
/** The roots of the tree for one flat field list; a field without a name is skipped. */
|
|
102
|
+
export function buildTypeTree(fields) {
|
|
103
|
+
const roots = new Map();
|
|
104
|
+
for (const field of fields) {
|
|
105
|
+
const name = field.name;
|
|
106
|
+
if (!pyTruthy(name))
|
|
107
|
+
continue;
|
|
108
|
+
let cursor = roots;
|
|
109
|
+
let node;
|
|
110
|
+
for (const [segment, isArray] of splitFieldPath(pyStr(name))) {
|
|
111
|
+
let next = cursor.get(segment);
|
|
112
|
+
if (next === undefined) {
|
|
113
|
+
next = new TypeNode(isArray);
|
|
114
|
+
cursor.set(segment, next);
|
|
115
|
+
}
|
|
116
|
+
node = next;
|
|
117
|
+
node.arrayModes.add(isArray);
|
|
118
|
+
cursor = node.children;
|
|
119
|
+
}
|
|
120
|
+
if (node !== undefined)
|
|
121
|
+
node.addDeclaration(field);
|
|
122
|
+
}
|
|
123
|
+
return roots;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Merge repeated occurrences into one reusable connector-level type. A child
|
|
127
|
+
* only the source has is adopted by reference, so the two trees share it.
|
|
128
|
+
*/
|
|
129
|
+
export function mergeTypeNodes(target, source) {
|
|
130
|
+
for (const mode of source.arrayModes)
|
|
131
|
+
target.arrayModes.add(mode);
|
|
132
|
+
for (const type of source.declaredTypes)
|
|
133
|
+
target.declaredTypes.add(type);
|
|
134
|
+
target.opaqueObject = target.opaqueObject || source.opaqueObject;
|
|
135
|
+
target.opaqueArray = target.opaqueArray || source.opaqueArray;
|
|
136
|
+
target.required = target.required || source.required;
|
|
137
|
+
if (target.declared === undefined)
|
|
138
|
+
target.declared = source.declared;
|
|
139
|
+
for (const [childName, sourceChild] of source.children) {
|
|
140
|
+
const targetChild = target.children.get(childName);
|
|
141
|
+
if (targetChild === undefined)
|
|
142
|
+
target.children.set(childName, sourceChild);
|
|
143
|
+
else
|
|
144
|
+
mergeTypeNodes(targetChild, sourceChild);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The interface name for a nested segment: singularised when the segment is an
|
|
149
|
+
* array, PascalCased, prefixed with `Nested` when it would start with a digit.
|
|
150
|
+
*/
|
|
151
|
+
export function nestedTypeName(fieldName, node, suffix = "") {
|
|
152
|
+
const source = node.arrayModes.has(true) || node.opaqueArray ? singular(fieldName) : fieldName;
|
|
153
|
+
let name = pascal(source);
|
|
154
|
+
name = /^[A-Za-z_$]/.test(name) ? name : `Nested${name}`;
|
|
155
|
+
return `${name}${suffix}`;
|
|
156
|
+
}
|
|
157
|
+
/** True when the node or any descendant is required. */
|
|
158
|
+
export function subtreeRequired(node) {
|
|
159
|
+
if (node.required)
|
|
160
|
+
return true;
|
|
161
|
+
for (const child of node.children.values())
|
|
162
|
+
if (subtreeRequired(child))
|
|
163
|
+
return true;
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Stable structural identity — the Python's nested tuple, as one canonical
|
|
168
|
+
* string. Input types reuse only exact shapes, so two nodes share an interface
|
|
169
|
+
* iff their fingerprints are equal. Children are ordered by name, as
|
|
170
|
+
* `sorted(node.children.items())` orders them.
|
|
171
|
+
*/
|
|
172
|
+
export function typeFingerprint(node) {
|
|
173
|
+
const modes = [...node.arrayModes].sort((a, b) => Number(a) - Number(b));
|
|
174
|
+
const types = sortedStrings(node.declaredTypes);
|
|
175
|
+
const children = sortedStrings(node.children.keys()).map((name) => [name, typeFingerprint(node.children.get(name))]);
|
|
176
|
+
// An internal key, never emitted: JSON is unambiguous for these shapes, so
|
|
177
|
+
// equal strings mean equal tuples.
|
|
178
|
+
return JSON.stringify([modes, types, node.opaqueObject, node.opaqueArray, node.required, children]);
|
|
179
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { LibraryEntry } from "../model/library.js";
|
|
2
|
+
import { type BuildContext, type BuildPorts } from "./context.js";
|
|
3
|
+
import { type LibraryPlan } from "./plan.js";
|
|
4
|
+
export type CatalogScope = "all" | "tier1" | "tier2";
|
|
5
|
+
export interface BuildOptions {
|
|
6
|
+
/** `--output-dir`: removed and rewritten. */
|
|
7
|
+
outputDir: string;
|
|
8
|
+
/** `--triggers-output`; defaults to `<dirname(normpath(outputDir))>/registry-triggers.json`. */
|
|
9
|
+
triggersOutput?: string;
|
|
10
|
+
/**
|
|
11
|
+
* `--connectors a,b`, already split and stripped. `undefined` is a full
|
|
12
|
+
* build (the published catalog); a list — even an empty one — is a curated
|
|
13
|
+
* subset, as `if args.connectors:` on the raw string was.
|
|
14
|
+
*/
|
|
15
|
+
connectors?: readonly string[];
|
|
16
|
+
/** `--catalog-scope` (default `all`). */
|
|
17
|
+
catalogScope?: CatalogScope;
|
|
18
|
+
skipEnrichment?: boolean;
|
|
19
|
+
skipConnectorEnrichment?: boolean;
|
|
20
|
+
skipGenericExpansion?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface BuildResult {
|
|
23
|
+
/** The node types the build materialized, after scope filtering. */
|
|
24
|
+
nodeTypes: string[];
|
|
25
|
+
/** The entries as planned, in planning order. */
|
|
26
|
+
entries: LibraryEntry[];
|
|
27
|
+
plan: LibraryPlan;
|
|
28
|
+
/** Entry files written — `write_library`'s return value. */
|
|
29
|
+
written: number;
|
|
30
|
+
triggersOutput: string;
|
|
31
|
+
triggerCount: number;
|
|
32
|
+
}
|
|
33
|
+
/** The Python's default: beside the output directory. */
|
|
34
|
+
export declare function defaultTriggersOutput(outputDir: string): string;
|
|
35
|
+
/** `{c.strip() for c in text.split(",") if c.strip()}`, in first-seen order. */
|
|
36
|
+
export declare function parseConnectorsFlag(text: string): string[];
|
|
37
|
+
/**
|
|
38
|
+
* `registry_search`: the connector node types the registry lists, from the
|
|
39
|
+
* cached raw stdout of `flow registry search --filter tags:in=connector` —
|
|
40
|
+
* fetched once when the cache has no `_search_results.json`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function registrySearch(ctx: BuildContext): Promise<string[]>;
|
|
43
|
+
/**
|
|
44
|
+
* `fetch_all`: the registry response of every node type, from the cache or
|
|
45
|
+
* fetched in parallel. `nodeType → cache name`; a node type whose fetch failed
|
|
46
|
+
* is absent (and was reported by `registryGet`).
|
|
47
|
+
*/
|
|
48
|
+
export declare function fetchAll(ctx: BuildContext, nodeTypes: readonly string[]): Promise<Map<string, string>>;
|
|
49
|
+
/**
|
|
50
|
+
* `fetch_connector_records_for_keys`: one `is connectors metadata` per key,
|
|
51
|
+
* sorted and deduplicated; `key → record`, `null` where the lookup failed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function fetchConnectorRecordsForKeys(ctx: BuildContext, keys: Iterable<string>): Promise<Map<string, unknown>>;
|
|
54
|
+
/** `fetch_connector_records`: one record per unique connector key in `entries`. */
|
|
55
|
+
export declare function fetchConnectorRecords(ctx: BuildContext, entries: readonly LibraryEntry[]): Promise<Map<string, unknown>>;
|
|
56
|
+
/** The whole generator, `main()` minus argument parsing and cache cleanup. */
|
|
57
|
+
export declare function buildLibrary(options: BuildOptions, ports: BuildPorts): Promise<BuildResult>;
|