@n8n/workflow-sdk 0.2.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/LICENSE.md +88 -0
- package/README.md +30 -0
- package/dist/ast-interpreter/errors.d.ts +19 -0
- package/dist/ast-interpreter/errors.js +64 -0
- package/dist/ast-interpreter/errors.js.map +1 -0
- package/dist/ast-interpreter/index.d.ts +5 -0
- package/dist/ast-interpreter/index.js +18 -0
- package/dist/ast-interpreter/index.js.map +1 -0
- package/dist/ast-interpreter/interpreter.d.ts +2 -0
- package/dist/ast-interpreter/interpreter.js +471 -0
- package/dist/ast-interpreter/interpreter.js.map +1 -0
- package/dist/ast-interpreter/parser.d.ts +2 -0
- package/dist/ast-interpreter/parser.js +61 -0
- package/dist/ast-interpreter/parser.js.map +1 -0
- package/dist/ast-interpreter/validators.d.ts +13 -0
- package/dist/ast-interpreter/validators.js +243 -0
- package/dist/ast-interpreter/validators.js.map +1 -0
- package/dist/build.tsbuildinfo +1 -0
- package/dist/cli/code-to-json.d.ts +1 -0
- package/dist/cli/code-to-json.js +51 -0
- package/dist/cli/code-to-json.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +25 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/json-to-code.d.ts +1 -0
- package/dist/cli/json-to-code.js +60 -0
- package/dist/cli/json-to-code.js.map +1 -0
- package/dist/cli/utils.d.ts +1 -0
- package/dist/cli/utils.js +16 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/codegen/code-generator.d.ts +14 -0
- package/dist/codegen/code-generator.js +807 -0
- package/dist/codegen/code-generator.js.map +1 -0
- package/dist/codegen/composite-builder.d.ts +3 -0
- package/dist/codegen/composite-builder.js +718 -0
- package/dist/codegen/composite-builder.js.map +1 -0
- package/dist/codegen/composite-handlers/build-utils.d.ts +24 -0
- package/dist/codegen/composite-handlers/build-utils.js +79 -0
- package/dist/codegen/composite-handlers/build-utils.js.map +1 -0
- package/dist/codegen/composite-handlers/error-handler.d.ts +6 -0
- package/dist/codegen/composite-handlers/error-handler.js +51 -0
- package/dist/codegen/composite-handlers/error-handler.js.map +1 -0
- package/dist/codegen/composite-handlers/if-else-handler.d.ts +5 -0
- package/dist/codegen/composite-handlers/if-else-handler.js +57 -0
- package/dist/codegen/composite-handlers/if-else-handler.js.map +1 -0
- package/dist/codegen/composite-handlers/index.d.ts +1 -0
- package/dist/codegen/composite-handlers/index.js +17 -0
- package/dist/codegen/composite-handlers/index.js.map +1 -0
- package/dist/codegen/composite-handlers/merge-handler.d.ts +5 -0
- package/dist/codegen/composite-handlers/merge-handler.js +25 -0
- package/dist/codegen/composite-handlers/merge-handler.js.map +1 -0
- package/dist/codegen/composite-handlers/sib-handler.d.ts +5 -0
- package/dist/codegen/composite-handlers/sib-handler.js +57 -0
- package/dist/codegen/composite-handlers/sib-handler.js.map +1 -0
- package/dist/codegen/composite-handlers/switch-case-handler.d.ts +5 -0
- package/dist/codegen/composite-handlers/switch-case-handler.js +80 -0
- package/dist/codegen/composite-handlers/switch-case-handler.js.map +1 -0
- package/dist/codegen/composite-tree.d.ts +81 -0
- package/dist/codegen/composite-tree.js +3 -0
- package/dist/codegen/composite-tree.js.map +1 -0
- package/dist/codegen/config-builder.d.ts +7 -0
- package/dist/codegen/config-builder.js +22 -0
- package/dist/codegen/config-builder.js.map +1 -0
- package/dist/codegen/constants.d.ts +5 -0
- package/dist/codegen/constants.js +30 -0
- package/dist/codegen/constants.js.map +1 -0
- package/dist/codegen/deferred-connections.d.ts +20 -0
- package/dist/codegen/deferred-connections.js +46 -0
- package/dist/codegen/deferred-connections.js.map +1 -0
- package/dist/codegen/execution-schema-jsdoc.d.ts +3 -0
- package/dist/codegen/execution-schema-jsdoc.js +109 -0
- package/dist/codegen/execution-schema-jsdoc.js.map +1 -0
- package/dist/codegen/execution-status.d.ts +9 -0
- package/dist/codegen/execution-status.js +42 -0
- package/dist/codegen/execution-status.js.map +1 -0
- package/dist/codegen/expression-annotator.d.ts +2 -0
- package/dist/codegen/expression-annotator.js +38 -0
- package/dist/codegen/expression-annotator.js.map +1 -0
- package/dist/codegen/graph-annotator.d.ts +2 -0
- package/dist/codegen/graph-annotator.js +107 -0
- package/dist/codegen/graph-annotator.js.map +1 -0
- package/dist/codegen/index.d.ts +20 -0
- package/dist/codegen/index.js +60 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/merge-pattern.d.ts +12 -0
- package/dist/codegen/merge-pattern.js +119 -0
- package/dist/codegen/merge-pattern.js.map +1 -0
- package/dist/codegen/node-type-utils.d.ts +4 -0
- package/dist/codegen/node-type-utils.js +38 -0
- package/dist/codegen/node-type-utils.js.map +1 -0
- package/dist/codegen/output-utils.d.ts +9 -0
- package/dist/codegen/output-utils.js +68 -0
- package/dist/codegen/output-utils.js.map +1 -0
- package/dist/codegen/parse-workflow-code.d.ts +3 -0
- package/dist/codegen/parse-workflow-code.js +438 -0
- package/dist/codegen/parse-workflow-code.js.map +1 -0
- package/dist/codegen/semantic-graph.d.ts +3 -0
- package/dist/codegen/semantic-graph.js +216 -0
- package/dist/codegen/semantic-graph.js.map +1 -0
- package/dist/codegen/semantic-registry.d.ts +18 -0
- package/dist/codegen/semantic-registry.js +102 -0
- package/dist/codegen/semantic-registry.js.map +1 -0
- package/dist/codegen/sib-merge-handler.d.ts +20 -0
- package/dist/codegen/sib-merge-handler.js +92 -0
- package/dist/codegen/sib-merge-handler.js.map +1 -0
- package/dist/codegen/string-utils.d.ts +6 -0
- package/dist/codegen/string-utils.js +38 -0
- package/dist/codegen/string-utils.js.map +1 -0
- package/dist/codegen/subnode-generator.d.ts +17 -0
- package/dist/codegen/subnode-generator.js +219 -0
- package/dist/codegen/subnode-generator.js.map +1 -0
- package/dist/codegen/types.d.ts +40 -0
- package/dist/codegen/types.js +16 -0
- package/dist/codegen/types.js.map +1 -0
- package/dist/codegen/variable-names.d.ts +8 -0
- package/dist/codegen/variable-names.js +121 -0
- package/dist/codegen/variable-names.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +14 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/constants/node-types.d.ts +19 -0
- package/dist/constants/node-types.js +46 -0
- package/dist/constants/node-types.js.map +1 -0
- package/dist/expression/index.d.ts +6 -0
- package/dist/expression/index.js +181 -0
- package/dist/expression/index.js.map +1 -0
- package/dist/expression.d.ts +1 -0
- package/dist/expression.js +10 -0
- package/dist/expression.js.map +1 -0
- package/dist/generate-types/generate-node-defs-cli.d.ts +7 -0
- package/dist/generate-types/generate-node-defs-cli.js +99 -0
- package/dist/generate-types/generate-node-defs-cli.js.map +1 -0
- package/dist/generate-types/generate-types.d.ts +163 -0
- package/dist/generate-types/generate-types.js +2569 -0
- package/dist/generate-types/generate-types.js.map +1 -0
- package/dist/generate-types/generate-zod-schemas.d.ts +41 -0
- package/dist/generate-types/generate-zod-schemas.js +1129 -0
- package/dist/generate-types/generate-zod-schemas.js.map +1 -0
- package/dist/generate-types/index.d.ts +3 -0
- package/dist/generate-types/index.js +62 -0
- package/dist/generate-types/index.js.map +1 -0
- package/dist/generate-types/zod-helpers.d.ts +189 -0
- package/dist/generate-types/zod-helpers.js +76 -0
- package/dist/generate-types/zod-helpers.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/types/aliases.d.ts +5 -0
- package/dist/types/aliases.js +3 -0
- package/dist/types/aliases.js.map +1 -0
- package/dist/types/base.d.ts +395 -0
- package/dist/types/base.js +22 -0
- package/dist/types/base.js.map +1 -0
- package/dist/utils/code-helpers.d.ts +7 -0
- package/dist/utils/code-helpers.js +47 -0
- package/dist/utils/code-helpers.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/safe-access.d.ts +3 -0
- package/dist/utils/safe-access.js +21 -0
- package/dist/utils/safe-access.js.map +1 -0
- package/dist/utils/trigger-detection.d.ts +1 -0
- package/dist/utils/trigger-detection.js +17 -0
- package/dist/utils/trigger-detection.js.map +1 -0
- package/dist/validation/display-options.d.ts +18 -0
- package/dist/validation/display-options.js +194 -0
- package/dist/validation/display-options.js.map +1 -0
- package/dist/validation/index.d.ts +34 -0
- package/dist/validation/index.js +428 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/input-resolver.d.ts +2 -0
- package/dist/validation/input-resolver.js +23 -0
- package/dist/validation/input-resolver.js.map +1 -0
- package/dist/validation/resolve-schema.d.ts +14 -0
- package/dist/validation/resolve-schema.js +105 -0
- package/dist/validation/resolve-schema.js.map +1 -0
- package/dist/validation/schema-helpers.d.ts +164 -0
- package/dist/validation/schema-helpers.js +51 -0
- package/dist/validation/schema-helpers.js.map +1 -0
- package/dist/validation/schema-validator.d.ts +22 -0
- package/dist/validation/schema-validator.js +402 -0
- package/dist/validation/schema-validator.js.map +1 -0
- package/dist/validation/test-schema-setup.d.ts +2 -0
- package/dist/validation/test-schema-setup.js +108 -0
- package/dist/validation/test-schema-setup.js.map +1 -0
- package/dist/validation.d.ts +1 -0
- package/dist/validation.js +9 -0
- package/dist/validation.js.map +1 -0
- package/dist/workflow-builder/connection-utils.d.ts +4 -0
- package/dist/workflow-builder/connection-utils.js +42 -0
- package/dist/workflow-builder/connection-utils.js.map +1 -0
- package/dist/workflow-builder/constants.d.ts +3 -0
- package/dist/workflow-builder/constants.js +7 -0
- package/dist/workflow-builder/constants.js.map +1 -0
- package/dist/workflow-builder/control-flow-builders/if-else.d.ts +2 -0
- package/dist/workflow-builder/control-flow-builders/if-else.js +3 -0
- package/dist/workflow-builder/control-flow-builders/if-else.js.map +1 -0
- package/dist/workflow-builder/control-flow-builders/next-batch.d.ts +2 -0
- package/dist/workflow-builder/control-flow-builders/next-batch.js +7 -0
- package/dist/workflow-builder/control-flow-builders/next-batch.js.map +1 -0
- package/dist/workflow-builder/control-flow-builders/split-in-batches.d.ts +27 -0
- package/dist/workflow-builder/control-flow-builders/split-in-batches.js +268 -0
- package/dist/workflow-builder/control-flow-builders/split-in-batches.js.map +1 -0
- package/dist/workflow-builder/control-flow-builders/switch-case.d.ts +2 -0
- package/dist/workflow-builder/control-flow-builders/switch-case.js +3 -0
- package/dist/workflow-builder/control-flow-builders/switch-case.js.map +1 -0
- package/dist/workflow-builder/layout-utils.d.ts +2 -0
- package/dist/workflow-builder/layout-utils.js +54 -0
- package/dist/workflow-builder/layout-utils.js.map +1 -0
- package/dist/workflow-builder/node-builders/index.d.ts +2 -0
- package/dist/workflow-builder/node-builders/index.js +29 -0
- package/dist/workflow-builder/node-builders/index.js.map +1 -0
- package/dist/workflow-builder/node-builders/node-builder.d.ts +26 -0
- package/dist/workflow-builder/node-builders/node-builder.js +596 -0
- package/dist/workflow-builder/node-builders/node-builder.js.map +1 -0
- package/dist/workflow-builder/node-builders/subnode-builders.d.ts +25 -0
- package/dist/workflow-builder/node-builders/subnode-builders.js +110 -0
- package/dist/workflow-builder/node-builders/subnode-builders.js.map +1 -0
- package/dist/workflow-builder/pin-data-utils.d.ts +5 -0
- package/dist/workflow-builder/pin-data-utils.js +54 -0
- package/dist/workflow-builder/pin-data-utils.js.map +1 -0
- package/dist/workflow-builder/plugins/composite-handlers/branch-handler-utils.d.ts +9 -0
- package/dist/workflow-builder/plugins/composite-handlers/branch-handler-utils.js +162 -0
- package/dist/workflow-builder/plugins/composite-handlers/branch-handler-utils.js.map +1 -0
- package/dist/workflow-builder/plugins/composite-handlers/if-else-handler.d.ts +5 -0
- package/dist/workflow-builder/plugins/composite-handlers/if-else-handler.js +83 -0
- package/dist/workflow-builder/plugins/composite-handlers/if-else-handler.js.map +1 -0
- package/dist/workflow-builder/plugins/composite-handlers/index.d.ts +3 -0
- package/dist/workflow-builder/plugins/composite-handlers/index.js +10 -0
- package/dist/workflow-builder/plugins/composite-handlers/index.js.map +1 -0
- package/dist/workflow-builder/plugins/composite-handlers/split-in-batches-handler.d.ts +15 -0
- package/dist/workflow-builder/plugins/composite-handlers/split-in-batches-handler.js +216 -0
- package/dist/workflow-builder/plugins/composite-handlers/split-in-batches-handler.js.map +1 -0
- package/dist/workflow-builder/plugins/composite-handlers/switch-case-handler.d.ts +5 -0
- package/dist/workflow-builder/plugins/composite-handlers/switch-case-handler.js +91 -0
- package/dist/workflow-builder/plugins/composite-handlers/switch-case-handler.js.map +1 -0
- package/dist/workflow-builder/plugins/defaults.d.ts +2 -0
- package/dist/workflow-builder/plugins/defaults.js +53 -0
- package/dist/workflow-builder/plugins/defaults.js.map +1 -0
- package/dist/workflow-builder/plugins/index.d.ts +3 -0
- package/dist/workflow-builder/plugins/index.js +9 -0
- package/dist/workflow-builder/plugins/index.js.map +1 -0
- package/dist/workflow-builder/plugins/registry.d.ts +22 -0
- package/dist/workflow-builder/plugins/registry.js +98 -0
- package/dist/workflow-builder/plugins/registry.js.map +1 -0
- package/dist/workflow-builder/plugins/serializers/index.d.ts +1 -0
- package/dist/workflow-builder/plugins/serializers/index.js +6 -0
- package/dist/workflow-builder/plugins/serializers/index.js.map +1 -0
- package/dist/workflow-builder/plugins/serializers/json-serializer.d.ts +3 -0
- package/dist/workflow-builder/plugins/serializers/json-serializer.js +140 -0
- package/dist/workflow-builder/plugins/serializers/json-serializer.js.map +1 -0
- package/dist/workflow-builder/plugins/types.d.ts +76 -0
- package/dist/workflow-builder/plugins/types.js +29 -0
- package/dist/workflow-builder/plugins/types.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/agent-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/agent-validator.js +45 -0
- package/dist/workflow-builder/plugins/validators/agent-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/chain-llm-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/chain-llm-validator.js +39 -0
- package/dist/workflow-builder/plugins/validators/chain-llm-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/date-method-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/date-method-validator.js +28 -0
- package/dist/workflow-builder/plugins/validators/date-method-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/disconnected-node-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/disconnected-node-validator.js +142 -0
- package/dist/workflow-builder/plugins/validators/disconnected-node-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/expression-path-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/expression-path-validator.js +155 -0
- package/dist/workflow-builder/plugins/validators/expression-path-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/expression-prefix-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/expression-prefix-validator.js +32 -0
- package/dist/workflow-builder/plugins/validators/expression-prefix-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/from-ai-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/from-ai-validator.js +30 -0
- package/dist/workflow-builder/plugins/validators/from-ai-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/http-request-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/http-request-validator.js +55 -0
- package/dist/workflow-builder/plugins/validators/http-request-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/index.d.ts +15 -0
- package/dist/workflow-builder/plugins/validators/index.js +34 -0
- package/dist/workflow-builder/plugins/validators/index.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/max-nodes-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/max-nodes-validator.js +40 -0
- package/dist/workflow-builder/plugins/validators/max-nodes-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/merge-node-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/merge-node-validator.js +54 -0
- package/dist/workflow-builder/plugins/validators/merge-node-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/missing-trigger-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/missing-trigger-validator.js +27 -0
- package/dist/workflow-builder/plugins/validators/missing-trigger-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/no-nodes-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/no-nodes-validator.js +23 -0
- package/dist/workflow-builder/plugins/validators/no-nodes-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/set-node-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/set-node-validator.js +41 -0
- package/dist/workflow-builder/plugins/validators/set-node-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/subnode-connection-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/subnode-connection-validator.js +64 -0
- package/dist/workflow-builder/plugins/validators/subnode-connection-validator.js.map +1 -0
- package/dist/workflow-builder/plugins/validators/tool-node-validator.d.ts +2 -0
- package/dist/workflow-builder/plugins/validators/tool-node-validator.js +37 -0
- package/dist/workflow-builder/plugins/validators/tool-node-validator.js.map +1 -0
- package/dist/workflow-builder/string-utils.d.ts +9 -0
- package/dist/workflow-builder/string-utils.js +237 -0
- package/dist/workflow-builder/string-utils.js.map +1 -0
- package/dist/workflow-builder/subnode-utils.d.ts +2 -0
- package/dist/workflow-builder/subnode-utils.js +180 -0
- package/dist/workflow-builder/subnode-utils.js.map +1 -0
- package/dist/workflow-builder/type-guards.d.ts +15 -0
- package/dist/workflow-builder/type-guards.js +48 -0
- package/dist/workflow-builder/type-guards.js.map +1 -0
- package/dist/workflow-builder/validation-helpers.d.ts +27 -0
- package/dist/workflow-builder/validation-helpers.js +195 -0
- package/dist/workflow-builder/validation-helpers.js.map +1 -0
- package/dist/workflow-builder/workflow-import.d.ts +15 -0
- package/dist/workflow-builder/workflow-import.js +102 -0
- package/dist/workflow-builder/workflow-import.js.map +1 -0
- package/dist/workflow-builder.d.ts +2 -0
- package/dist/workflow-builder.js +636 -0
- package/dist/workflow-builder.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,2569 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.discoverSchemasForNode = discoverSchemasForNode;
|
|
37
|
+
exports.jsonSchemaToTypeScript = jsonSchemaToTypeScript;
|
|
38
|
+
exports.findSchemaForOperation = findSchemaForOperation;
|
|
39
|
+
exports.mapPropertyType = mapPropertyType;
|
|
40
|
+
exports.extractDiscriminatorCombinations = extractDiscriminatorCombinations;
|
|
41
|
+
exports.getPropertiesForCombination = getPropertiesForCombination;
|
|
42
|
+
exports.propertyAppliesToVersion = propertyAppliesToVersion;
|
|
43
|
+
exports.filterPropertiesForVersion = filterPropertiesForVersion;
|
|
44
|
+
exports.generateDiscriminatedUnion = generateDiscriminatedUnion;
|
|
45
|
+
exports.generatePropertyJSDoc = generatePropertyJSDoc;
|
|
46
|
+
exports.generateNodeJSDoc = generateNodeJSDoc;
|
|
47
|
+
exports.generatePropertyLine = generatePropertyLine;
|
|
48
|
+
exports.groupVersionsByProperties = groupVersionsByProperties;
|
|
49
|
+
exports.getHighestVersion = getHighestVersion;
|
|
50
|
+
exports.versionToTypeName = versionToTypeName;
|
|
51
|
+
exports.nodeNameToFileName = nodeNameToFileName;
|
|
52
|
+
exports.getPackageName = getPackageName;
|
|
53
|
+
exports.buildDiscriminatorPath = buildDiscriminatorPath;
|
|
54
|
+
exports.hasDiscriminatorPattern = hasDiscriminatorPattern;
|
|
55
|
+
exports.buildDiscriminatorTree = buildDiscriminatorTree;
|
|
56
|
+
exports.generateSharedFile = generateSharedFile;
|
|
57
|
+
exports.generateDiscriminatorFile = generateDiscriminatorFile;
|
|
58
|
+
exports.generateResourceIndexFile = generateResourceIndexFile;
|
|
59
|
+
exports.generateSplitVersionIndexFile = generateSplitVersionIndexFile;
|
|
60
|
+
exports.planSplitVersionFiles = planSplitVersionFiles;
|
|
61
|
+
exports.versionToFileName = versionToFileName;
|
|
62
|
+
exports.generateSingleVersionTypeFile = generateSingleVersionTypeFile;
|
|
63
|
+
exports.generateVersionIndexFile = generateVersionIndexFile;
|
|
64
|
+
exports.generateNodeTypeFile = generateNodeTypeFile;
|
|
65
|
+
exports.generateIndexFile = generateIndexFile;
|
|
66
|
+
exports.extractAIInputTypes = extractAIInputTypes;
|
|
67
|
+
exports.extractAIInputTypesFromBuilderHint = extractAIInputTypesFromBuilderHint;
|
|
68
|
+
exports.generateNarrowedSubnodeConfig = generateNarrowedSubnodeConfig;
|
|
69
|
+
exports.getSubnodeInstanceTypeImports = getSubnodeInstanceTypeImports;
|
|
70
|
+
exports.extractOutputTypes = extractOutputTypes;
|
|
71
|
+
exports.groupNodesByOutputType = groupNodesByOutputType;
|
|
72
|
+
exports.generateSubnodeUnionTypes = generateSubnodeUnionTypes;
|
|
73
|
+
exports.generateSubnodesFile = generateSubnodesFile;
|
|
74
|
+
exports.getSubnodeOutputType = getSubnodeOutputType;
|
|
75
|
+
exports.loadNodeTypes = loadNodeTypes;
|
|
76
|
+
exports.orchestrateGeneration = orchestrateGeneration;
|
|
77
|
+
exports.generateTypes = generateTypes;
|
|
78
|
+
const fs = __importStar(require("fs"));
|
|
79
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
80
|
+
const path = __importStar(require("path"));
|
|
81
|
+
const generate_zod_schemas_1 = require("./generate-zod-schemas");
|
|
82
|
+
const display_options_1 = require("../validation/display-options");
|
|
83
|
+
const INDENT = ' ';
|
|
84
|
+
const NODES_BASE_TYPES = path.resolve(__dirname, '../../../../nodes-base/dist/types/nodes.json');
|
|
85
|
+
const NODES_LANGCHAIN_TYPES = path.resolve(__dirname, '../../../nodes-langchain/dist/types/nodes.json');
|
|
86
|
+
const DEV_OUTPUT_PATH = path.resolve(__dirname, '../../dist/node-definitions');
|
|
87
|
+
const NODES_BASE_DIST = path.resolve(__dirname, '../../../../nodes-base/dist/nodes');
|
|
88
|
+
const DISCRIMINATOR_FIELDS = ['resource', 'operation', 'mode'];
|
|
89
|
+
const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__';
|
|
90
|
+
const ASSIGNMENT_TYPE_JSDOC = `/**
|
|
91
|
+
* Assignment type determines how the value is interpreted.
|
|
92
|
+
* - string: Direct string value or expression evaluating to string
|
|
93
|
+
* - number: Direct number value or expression evaluating to number
|
|
94
|
+
* - boolean: Direct boolean value or expression evaluating to boolean
|
|
95
|
+
* - array: Expression that evaluates to an array, e.g. ={{ [1, 2, 3] }} or ={{ $json.items }}
|
|
96
|
+
* - object: Expression that evaluates to a plain object (not an array — use the array type for arrays), e.g. ={{ { key: 'value' } }} or ={{ $json.data }}
|
|
97
|
+
* - binary: Property name of binary data in the input item, or expression to access binary data from previous nodes, e.g. ={{ $('Node').item.binary.data }}
|
|
98
|
+
*/`;
|
|
99
|
+
function generateFilterTypeDeclaration(exported) {
|
|
100
|
+
const prefix = exported ? 'export type' : 'type';
|
|
101
|
+
return `${prefix} FilterValue = { conditions: Array<{ leftValue: unknown; operator: { type: string; operation: string }; rightValue: unknown }> };`;
|
|
102
|
+
}
|
|
103
|
+
function generateAssignmentTypeDeclarations(exported) {
|
|
104
|
+
const prefix = exported ? 'export type' : 'type';
|
|
105
|
+
return `${ASSIGNMENT_TYPE_JSDOC}
|
|
106
|
+
${prefix} AssignmentType = 'string' | 'number' | 'boolean' | 'array' | 'object' | 'binary';
|
|
107
|
+
${prefix} AssignmentCollectionValue = { assignments: Array<{ id: string; name: string; value: unknown; type: AssignmentType }> };`;
|
|
108
|
+
}
|
|
109
|
+
function isCustomApiCall(operation) {
|
|
110
|
+
return operation === CUSTOM_API_CALL_KEY;
|
|
111
|
+
}
|
|
112
|
+
const RESERVED_WORDS = new Set([
|
|
113
|
+
'break',
|
|
114
|
+
'case',
|
|
115
|
+
'catch',
|
|
116
|
+
'class',
|
|
117
|
+
'const',
|
|
118
|
+
'continue',
|
|
119
|
+
'debugger',
|
|
120
|
+
'default',
|
|
121
|
+
'delete',
|
|
122
|
+
'do',
|
|
123
|
+
'else',
|
|
124
|
+
'enum',
|
|
125
|
+
'export',
|
|
126
|
+
'extends',
|
|
127
|
+
'false',
|
|
128
|
+
'finally',
|
|
129
|
+
'for',
|
|
130
|
+
'function',
|
|
131
|
+
'if',
|
|
132
|
+
'import',
|
|
133
|
+
'in',
|
|
134
|
+
'instanceof',
|
|
135
|
+
'new',
|
|
136
|
+
'null',
|
|
137
|
+
'return',
|
|
138
|
+
'super',
|
|
139
|
+
'switch',
|
|
140
|
+
'this',
|
|
141
|
+
'throw',
|
|
142
|
+
'true',
|
|
143
|
+
'try',
|
|
144
|
+
'typeof',
|
|
145
|
+
'var',
|
|
146
|
+
'void',
|
|
147
|
+
'while',
|
|
148
|
+
'with',
|
|
149
|
+
'yield',
|
|
150
|
+
]);
|
|
151
|
+
const GENERIC_AUTH_TYPE_VALUES = [
|
|
152
|
+
'httpBasicAuth',
|
|
153
|
+
'httpBearerAuth',
|
|
154
|
+
'httpDigestAuth',
|
|
155
|
+
'httpHeaderAuth',
|
|
156
|
+
'httpQueryAuth',
|
|
157
|
+
'httpCustomAuth',
|
|
158
|
+
'oAuth1Api',
|
|
159
|
+
'oAuth2Api',
|
|
160
|
+
];
|
|
161
|
+
const AI_TYPE_TO_SUBNODE_FIELD = {
|
|
162
|
+
ai_languageModel: {
|
|
163
|
+
fieldName: 'model',
|
|
164
|
+
instanceType: 'LanguageModelInstance',
|
|
165
|
+
isArray: false,
|
|
166
|
+
canBeMultiple: true,
|
|
167
|
+
},
|
|
168
|
+
ai_memory: {
|
|
169
|
+
fieldName: 'memory',
|
|
170
|
+
instanceType: 'MemoryInstance',
|
|
171
|
+
isArray: false,
|
|
172
|
+
canBeMultiple: false,
|
|
173
|
+
},
|
|
174
|
+
ai_tool: {
|
|
175
|
+
fieldName: 'tools',
|
|
176
|
+
instanceType: 'ToolInstance',
|
|
177
|
+
isArray: true,
|
|
178
|
+
canBeMultiple: false,
|
|
179
|
+
},
|
|
180
|
+
ai_outputParser: {
|
|
181
|
+
fieldName: 'outputParser',
|
|
182
|
+
instanceType: 'OutputParserInstance',
|
|
183
|
+
isArray: false,
|
|
184
|
+
canBeMultiple: false,
|
|
185
|
+
},
|
|
186
|
+
ai_embedding: {
|
|
187
|
+
fieldName: 'embedding',
|
|
188
|
+
instanceType: 'EmbeddingInstance',
|
|
189
|
+
isArray: false,
|
|
190
|
+
canBeMultiple: true,
|
|
191
|
+
},
|
|
192
|
+
ai_vectorStore: {
|
|
193
|
+
fieldName: 'vectorStore',
|
|
194
|
+
instanceType: 'VectorStoreInstance',
|
|
195
|
+
isArray: false,
|
|
196
|
+
canBeMultiple: false,
|
|
197
|
+
},
|
|
198
|
+
ai_retriever: {
|
|
199
|
+
fieldName: 'retriever',
|
|
200
|
+
instanceType: 'RetrieverInstance',
|
|
201
|
+
isArray: false,
|
|
202
|
+
canBeMultiple: false,
|
|
203
|
+
},
|
|
204
|
+
ai_document: {
|
|
205
|
+
fieldName: 'documentLoader',
|
|
206
|
+
instanceType: 'DocumentLoaderInstance',
|
|
207
|
+
isArray: false,
|
|
208
|
+
canBeMultiple: true,
|
|
209
|
+
},
|
|
210
|
+
ai_textSplitter: {
|
|
211
|
+
fieldName: 'textSplitter',
|
|
212
|
+
instanceType: 'TextSplitterInstance',
|
|
213
|
+
isArray: false,
|
|
214
|
+
canBeMultiple: false,
|
|
215
|
+
},
|
|
216
|
+
ai_reranker: {
|
|
217
|
+
fieldName: 'reranker',
|
|
218
|
+
instanceType: 'RerankerInstance',
|
|
219
|
+
isArray: false,
|
|
220
|
+
canBeMultiple: false,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
const schemaCache = new Map();
|
|
224
|
+
function findNestedSchemaDir(dir, targetNames) {
|
|
225
|
+
let entries;
|
|
226
|
+
try {
|
|
227
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
for (const entry of entries) {
|
|
233
|
+
if (!entry.isDirectory())
|
|
234
|
+
continue;
|
|
235
|
+
const entryPath = path.join(dir, entry.name);
|
|
236
|
+
if (targetNames.includes(entry.name)) {
|
|
237
|
+
const schemaPath = path.join(entryPath, '__schema__');
|
|
238
|
+
if (fs.existsSync(schemaPath)) {
|
|
239
|
+
return schemaPath;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (entry.name !== '__schema__' && entry.name !== 'node_modules') {
|
|
243
|
+
const found = findNestedSchemaDir(entryPath, targetNames);
|
|
244
|
+
if (found)
|
|
245
|
+
return found;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
function findSchemaDirectory(baseName, schemaPath) {
|
|
251
|
+
if (schemaPath) {
|
|
252
|
+
const explicitPath = path.join(NODES_BASE_DIST, schemaPath, '__schema__');
|
|
253
|
+
if (fs.existsSync(explicitPath)) {
|
|
254
|
+
return explicitPath;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const possibleNames = [
|
|
258
|
+
baseName.charAt(0).toUpperCase() + baseName.slice(1),
|
|
259
|
+
baseName,
|
|
260
|
+
baseName.toUpperCase(),
|
|
261
|
+
];
|
|
262
|
+
for (const folderName of possibleNames) {
|
|
263
|
+
const flatPath = path.join(NODES_BASE_DIST, folderName, '__schema__');
|
|
264
|
+
if (fs.existsSync(flatPath)) {
|
|
265
|
+
return flatPath;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return findNestedSchemaDir(NODES_BASE_DIST, possibleNames);
|
|
269
|
+
}
|
|
270
|
+
function discoverSchemasForNode(nodeName, version, schemaPath) {
|
|
271
|
+
const cacheKey = `${nodeName}:${version}`;
|
|
272
|
+
if (schemaCache.has(cacheKey)) {
|
|
273
|
+
return schemaCache.get(cacheKey);
|
|
274
|
+
}
|
|
275
|
+
const schemas = [];
|
|
276
|
+
const baseName = nodeName.split('.').pop() ?? '';
|
|
277
|
+
const schemaDir = findSchemaDirectory(baseName, schemaPath);
|
|
278
|
+
if (!schemaDir) {
|
|
279
|
+
schemaCache.set(cacheKey, schemas);
|
|
280
|
+
return schemas;
|
|
281
|
+
}
|
|
282
|
+
const versionDir = findVersionDirectory(schemaDir, version);
|
|
283
|
+
if (!versionDir) {
|
|
284
|
+
schemaCache.set(cacheKey, schemas);
|
|
285
|
+
return schemas;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const entries = fs.readdirSync(versionDir, { withFileTypes: true });
|
|
289
|
+
for (const entry of entries) {
|
|
290
|
+
if (entry.isFile() && entry.name.endsWith('.json')) {
|
|
291
|
+
const operationName = entry.name.replace('.json', '');
|
|
292
|
+
const filePath = path.join(versionDir, entry.name);
|
|
293
|
+
try {
|
|
294
|
+
const schemaContent = fs.readFileSync(filePath, 'utf-8');
|
|
295
|
+
const schema = JSON.parse(schemaContent);
|
|
296
|
+
schemas.push({
|
|
297
|
+
resource: '',
|
|
298
|
+
operation: operationName,
|
|
299
|
+
schema,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
}
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (!entry.isDirectory())
|
|
307
|
+
continue;
|
|
308
|
+
const resourceDir = path.join(versionDir, entry.name);
|
|
309
|
+
const operations = fs.readdirSync(resourceDir, { withFileTypes: true });
|
|
310
|
+
for (const opEntry of operations) {
|
|
311
|
+
if (!opEntry.isFile() || !opEntry.name.endsWith('.json'))
|
|
312
|
+
continue;
|
|
313
|
+
const operationName = opEntry.name.replace('.json', '');
|
|
314
|
+
const schemaPath = path.join(resourceDir, opEntry.name);
|
|
315
|
+
try {
|
|
316
|
+
const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
|
|
317
|
+
const schema = JSON.parse(schemaContent);
|
|
318
|
+
schemas.push({
|
|
319
|
+
resource: entry.name,
|
|
320
|
+
operation: operationName,
|
|
321
|
+
schema,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
}
|
|
331
|
+
schemaCache.set(cacheKey, schemas);
|
|
332
|
+
return schemas;
|
|
333
|
+
}
|
|
334
|
+
function findVersionDirectory(schemaDir, version) {
|
|
335
|
+
const exactPath = path.join(schemaDir, `v${version}.0.0`);
|
|
336
|
+
if (fs.existsSync(exactPath)) {
|
|
337
|
+
return exactPath;
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const entries = fs.readdirSync(schemaDir, { withFileTypes: true });
|
|
341
|
+
const versionDirs = entries
|
|
342
|
+
.filter((e) => e.isDirectory() && /^v\d+(\.\d+)*$/.test(e.name))
|
|
343
|
+
.map((e) => {
|
|
344
|
+
const match = e.name.match(/^v(\d+)/);
|
|
345
|
+
return {
|
|
346
|
+
name: e.name,
|
|
347
|
+
majorVersion: match ? parseInt(match[1], 10) : 0,
|
|
348
|
+
};
|
|
349
|
+
})
|
|
350
|
+
.filter((v) => v.majorVersion <= version)
|
|
351
|
+
.sort((a, b) => b.majorVersion - a.majorVersion);
|
|
352
|
+
if (versionDirs.length > 0) {
|
|
353
|
+
return path.join(schemaDir, versionDirs[0].name);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
}
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
function jsonSchemaToTypeScript(schema, indent = 0) {
|
|
361
|
+
const indentStr = INDENT.repeat(indent);
|
|
362
|
+
const nextIndent = INDENT.repeat(indent + 1);
|
|
363
|
+
if (Array.isArray(schema.type)) {
|
|
364
|
+
const types = schema.type.map((t) => jsonSchemaToTypeScript({ ...schema, type: t }, indent));
|
|
365
|
+
return types.join(' | ');
|
|
366
|
+
}
|
|
367
|
+
if (schema.enum) {
|
|
368
|
+
return schema.enum
|
|
369
|
+
.map((v) => {
|
|
370
|
+
if (typeof v === 'string')
|
|
371
|
+
return `'${v}'`;
|
|
372
|
+
if (v === null)
|
|
373
|
+
return 'null';
|
|
374
|
+
if (typeof v === 'object')
|
|
375
|
+
return JSON.stringify(v);
|
|
376
|
+
return String(v);
|
|
377
|
+
})
|
|
378
|
+
.join(' | ');
|
|
379
|
+
}
|
|
380
|
+
if (schema.const !== undefined) {
|
|
381
|
+
if (typeof schema.const === 'string')
|
|
382
|
+
return `'${schema.const}'`;
|
|
383
|
+
if (schema.const === null)
|
|
384
|
+
return 'null';
|
|
385
|
+
if (typeof schema.const === 'object')
|
|
386
|
+
return JSON.stringify(schema.const);
|
|
387
|
+
return String(schema.const);
|
|
388
|
+
}
|
|
389
|
+
if (schema.oneOf || schema.anyOf) {
|
|
390
|
+
const variants = schema.oneOf ?? schema.anyOf ?? [];
|
|
391
|
+
return variants.map((v) => jsonSchemaToTypeScript(v, indent)).join(' | ');
|
|
392
|
+
}
|
|
393
|
+
if (schema.allOf) {
|
|
394
|
+
return schema.allOf.map((v) => jsonSchemaToTypeScript(v, indent)).join(' & ');
|
|
395
|
+
}
|
|
396
|
+
switch (schema.type) {
|
|
397
|
+
case 'string':
|
|
398
|
+
return 'string';
|
|
399
|
+
case 'integer':
|
|
400
|
+
case 'number':
|
|
401
|
+
return 'number';
|
|
402
|
+
case 'boolean':
|
|
403
|
+
return 'boolean';
|
|
404
|
+
case 'null':
|
|
405
|
+
return 'null';
|
|
406
|
+
case 'array':
|
|
407
|
+
if (schema.items) {
|
|
408
|
+
return `Array<${jsonSchemaToTypeScript(schema.items, indent)}>`;
|
|
409
|
+
}
|
|
410
|
+
return 'unknown[]';
|
|
411
|
+
case 'object':
|
|
412
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
413
|
+
const required = new Set(schema.required ?? []);
|
|
414
|
+
const props = Object.entries(schema.properties).map(([key, propSchema]) => {
|
|
415
|
+
const optional = required.has(key) ? '' : '?';
|
|
416
|
+
const quotedKey = needsQuoting(key) ? `'${key}'` : key;
|
|
417
|
+
const propType = jsonSchemaToTypeScript(propSchema, indent + 1);
|
|
418
|
+
return `${nextIndent}${quotedKey}${optional}: ${propType};`;
|
|
419
|
+
});
|
|
420
|
+
return `{\n${props.join('\n')}\n${indentStr}}`;
|
|
421
|
+
}
|
|
422
|
+
if (schema.additionalProperties) {
|
|
423
|
+
if (typeof schema.additionalProperties === 'boolean') {
|
|
424
|
+
return 'Record<string, unknown>';
|
|
425
|
+
}
|
|
426
|
+
return `Record<string, ${jsonSchemaToTypeScript(schema.additionalProperties, indent)}>`;
|
|
427
|
+
}
|
|
428
|
+
return 'Record<string, unknown>';
|
|
429
|
+
default:
|
|
430
|
+
return 'unknown';
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function findSchemaForOperation(schemas, resource, operation) {
|
|
434
|
+
return schemas.find((s) => s.resource.toLowerCase() === resource.toLowerCase() && s.operation === operation);
|
|
435
|
+
}
|
|
436
|
+
function generateResourceLocatorType(prop) {
|
|
437
|
+
if (prop.modes && prop.modes.length > 0) {
|
|
438
|
+
const modeNames = prop.modes.map((m) => `'${m.name}'`).join(' | ');
|
|
439
|
+
return `{ __rl: true; mode: ${modeNames}; value: string; cachedResultName?: string }`;
|
|
440
|
+
}
|
|
441
|
+
return '{ __rl: true; mode: string; value: string; cachedResultName?: string }';
|
|
442
|
+
}
|
|
443
|
+
function mapNestedPropertyType(prop, discriminatorContext) {
|
|
444
|
+
const result = mapNestedPropertyTypeInner(prop, discriminatorContext);
|
|
445
|
+
if (prop.noDataExpression) {
|
|
446
|
+
return stripExpressionFromType(result);
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
function mapNestedPropertyTypeInner(prop, discriminatorContext) {
|
|
451
|
+
if (prop.typeOptions?.loadOptionsMethod || prop.typeOptions?.loadOptionsDependsOn) {
|
|
452
|
+
switch (prop.type) {
|
|
453
|
+
case 'options':
|
|
454
|
+
return 'string | Expression<string>';
|
|
455
|
+
case 'multiOptions':
|
|
456
|
+
return 'string[]';
|
|
457
|
+
case 'resourceLocator':
|
|
458
|
+
return generateResourceLocatorType(prop);
|
|
459
|
+
case 'filter':
|
|
460
|
+
return 'FilterValue';
|
|
461
|
+
case 'assignmentCollection':
|
|
462
|
+
return 'AssignmentCollectionValue';
|
|
463
|
+
default:
|
|
464
|
+
return 'string | Expression<string>';
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
switch (prop.type) {
|
|
468
|
+
case 'string':
|
|
469
|
+
if (prop.builderHint?.placeholderSupported === false) {
|
|
470
|
+
return 'string | Expression<string>';
|
|
471
|
+
}
|
|
472
|
+
return 'string | Expression<string> | PlaceholderValue';
|
|
473
|
+
case 'number':
|
|
474
|
+
return 'number | Expression<number>';
|
|
475
|
+
case 'boolean':
|
|
476
|
+
return 'boolean | Expression<boolean>';
|
|
477
|
+
case 'options':
|
|
478
|
+
if (prop.options && prop.options.length > 0 && prop.options[0].value !== undefined) {
|
|
479
|
+
const values = prop.options.map((opt) => {
|
|
480
|
+
if (typeof opt.value === 'string') {
|
|
481
|
+
const escaped = opt.value
|
|
482
|
+
.replace(/\\/g, '\\\\')
|
|
483
|
+
.replace(/'/g, "\\'")
|
|
484
|
+
.replace(/\n/g, '\\n')
|
|
485
|
+
.replace(/\r/g, '\\r')
|
|
486
|
+
.replace(/\t/g, '\\t');
|
|
487
|
+
return `'${escaped}'`;
|
|
488
|
+
}
|
|
489
|
+
return String(opt.value);
|
|
490
|
+
});
|
|
491
|
+
const valueType = typeof prop.options[0].value;
|
|
492
|
+
const expressionType = valueType === 'number'
|
|
493
|
+
? 'Expression<number>'
|
|
494
|
+
: valueType === 'boolean'
|
|
495
|
+
? 'Expression<boolean>'
|
|
496
|
+
: 'Expression<string>';
|
|
497
|
+
return `${values.join(' | ')} | ${expressionType}`;
|
|
498
|
+
}
|
|
499
|
+
return 'string | Expression<string>';
|
|
500
|
+
case 'multiOptions':
|
|
501
|
+
if (prop.options && prop.options.length > 0 && prop.options[0].value !== undefined) {
|
|
502
|
+
const values = prop.options.map((opt) => {
|
|
503
|
+
if (typeof opt.value === 'string') {
|
|
504
|
+
return `'${opt.value}'`;
|
|
505
|
+
}
|
|
506
|
+
return String(opt.value);
|
|
507
|
+
});
|
|
508
|
+
return `Array<${values.join(' | ')}>`;
|
|
509
|
+
}
|
|
510
|
+
return 'string[]';
|
|
511
|
+
case 'json':
|
|
512
|
+
return 'IDataObject | string | Expression<string>';
|
|
513
|
+
case 'resourceLocator':
|
|
514
|
+
return generateResourceLocatorType(prop);
|
|
515
|
+
case 'filter':
|
|
516
|
+
return 'FilterValue';
|
|
517
|
+
case 'assignmentCollection':
|
|
518
|
+
return 'AssignmentCollectionValue';
|
|
519
|
+
case 'fixedCollection':
|
|
520
|
+
return generateFixedCollectionType(prop, discriminatorContext);
|
|
521
|
+
case 'collection':
|
|
522
|
+
return generateCollectionType(prop, discriminatorContext);
|
|
523
|
+
case 'dateTime':
|
|
524
|
+
return 'string | Expression<string>';
|
|
525
|
+
case 'color':
|
|
526
|
+
return 'string | Expression<string>';
|
|
527
|
+
case 'hidden':
|
|
528
|
+
return 'unknown';
|
|
529
|
+
case 'notice':
|
|
530
|
+
case 'curlImport':
|
|
531
|
+
case 'credentials':
|
|
532
|
+
return '';
|
|
533
|
+
case 'credentialsSelect':
|
|
534
|
+
return 'string | Expression<string>';
|
|
535
|
+
default:
|
|
536
|
+
return 'unknown';
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function needsQuoting(name) {
|
|
540
|
+
return RESERVED_WORDS.has(name) || !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
541
|
+
}
|
|
542
|
+
function quotePropertyName(name) {
|
|
543
|
+
if (needsQuoting(name)) {
|
|
544
|
+
return `'${name.replace(/'/g, "\\'")}'`;
|
|
545
|
+
}
|
|
546
|
+
return name;
|
|
547
|
+
}
|
|
548
|
+
function isPropertyOptional(prop) {
|
|
549
|
+
const hasDefault = 'default' in prop && prop.default !== undefined;
|
|
550
|
+
return !prop.required || hasDefault;
|
|
551
|
+
}
|
|
552
|
+
function generateNestedPropertyJSDoc(prop, indent, discriminatorContext) {
|
|
553
|
+
const lines = [];
|
|
554
|
+
const description = prop.description ?? prop.displayName;
|
|
555
|
+
if (description) {
|
|
556
|
+
const safeDescription = description
|
|
557
|
+
.replace(/\*\//g, '*\\/')
|
|
558
|
+
.replace(/</g, '<')
|
|
559
|
+
.replace(/>/g, '>');
|
|
560
|
+
lines.push(`${indent}/** ${safeDescription}`);
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
lines.push(`${indent}/**`);
|
|
564
|
+
}
|
|
565
|
+
if (prop.hint) {
|
|
566
|
+
const safeHint = prop.hint.replace(/\*\//g, '*\\/').replace(/</g, '<').replace(/>/g, '>');
|
|
567
|
+
lines.push(`${indent} * @hint ${safeHint}`);
|
|
568
|
+
}
|
|
569
|
+
if (prop.builderHint) {
|
|
570
|
+
const safeBuilderHint = prop.builderHint.message
|
|
571
|
+
.replace(/\*\//g, '*\\/')
|
|
572
|
+
.replace(/</g, '<')
|
|
573
|
+
.replace(/>/g, '>');
|
|
574
|
+
lines.push(`${indent} * @builderHint ${safeBuilderHint}`);
|
|
575
|
+
}
|
|
576
|
+
if (prop.displayOptions) {
|
|
577
|
+
if (prop.displayOptions.show && Object.keys(prop.displayOptions.show).length > 0) {
|
|
578
|
+
const filteredShow = Object.entries(prop.displayOptions.show).filter(([key, values]) => {
|
|
579
|
+
if (key === '@version')
|
|
580
|
+
return false;
|
|
581
|
+
const normalizedKey = key.startsWith('/') ? key.slice(1) : key;
|
|
582
|
+
if (discriminatorContext?.[normalizedKey] !== undefined) {
|
|
583
|
+
const showValues = values;
|
|
584
|
+
if (showValues.includes(discriminatorContext[normalizedKey]))
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
return true;
|
|
588
|
+
});
|
|
589
|
+
if (filteredShow.length > 0) {
|
|
590
|
+
const showConditions = filteredShow
|
|
591
|
+
.map(([key, values]) => `${key}: [${values.map((v) => JSON.stringify(v)).join(', ')}]`)
|
|
592
|
+
.join(', ');
|
|
593
|
+
lines.push(`${indent} * @displayOptions.show { ${showConditions} }`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (prop.displayOptions.hide && Object.keys(prop.displayOptions.hide).length > 0) {
|
|
597
|
+
const filteredHide = Object.entries(prop.displayOptions.hide).filter(([key, values]) => {
|
|
598
|
+
if (key === '@version')
|
|
599
|
+
return false;
|
|
600
|
+
const normalizedKey = key.startsWith('/') ? key.slice(1) : key;
|
|
601
|
+
if (discriminatorContext?.[normalizedKey] !== undefined) {
|
|
602
|
+
const hideValues = values;
|
|
603
|
+
if (hideValues.includes(discriminatorContext[normalizedKey]))
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
return true;
|
|
607
|
+
});
|
|
608
|
+
if (filteredHide.length > 0) {
|
|
609
|
+
const hideConditions = filteredHide
|
|
610
|
+
.map(([key, values]) => `${key}: [${values.map((v) => JSON.stringify(v)).join(', ')}]`)
|
|
611
|
+
.join(', ');
|
|
612
|
+
lines.push(`${indent} * @displayOptions.hide { ${hideConditions} }`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (prop.default !== undefined && prop.default !== null && prop.default !== '') {
|
|
617
|
+
let defaultStr;
|
|
618
|
+
if (typeof prop.default === 'object') {
|
|
619
|
+
defaultStr = JSON.stringify(prop.default);
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
defaultStr = String(prop.default);
|
|
623
|
+
}
|
|
624
|
+
if (!defaultStr.includes('\n')) {
|
|
625
|
+
lines.push(`${indent} * @default ${defaultStr}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
lines.push(`${indent} */`);
|
|
629
|
+
return lines.join('\n');
|
|
630
|
+
}
|
|
631
|
+
function generateFixedCollectionType(prop, discriminatorContext) {
|
|
632
|
+
if (!prop.options || prop.options.length === 0) {
|
|
633
|
+
return 'Record<string, unknown>';
|
|
634
|
+
}
|
|
635
|
+
const isMultipleValues = prop.typeOptions?.multipleValues === true;
|
|
636
|
+
const groups = [];
|
|
637
|
+
for (const group of prop.options) {
|
|
638
|
+
if (group.value !== undefined || !group.values) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
const groupName = quotePropertyName(group.name);
|
|
642
|
+
const nestedProps = [];
|
|
643
|
+
for (const nestedProp of group.values) {
|
|
644
|
+
if (['notice', 'curlImport', 'credentials'].includes(nestedProp.type)) {
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
const nestedType = mapNestedPropertyType(nestedProp, discriminatorContext);
|
|
648
|
+
if (nestedType) {
|
|
649
|
+
const quotedName = quotePropertyName(nestedProp.name);
|
|
650
|
+
const jsDoc = generateNestedPropertyJSDoc(nestedProp, INDENT.repeat(3), discriminatorContext);
|
|
651
|
+
nestedProps.push(`${jsDoc}\n${INDENT.repeat(3)}${quotedName}?: ${nestedType}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (nestedProps.length > 0) {
|
|
655
|
+
const innerType = `{\n${nestedProps.join(';\n')};\n${INDENT.repeat(2)}}`;
|
|
656
|
+
const groupType = isMultipleValues ? `Array<${innerType}>` : innerType;
|
|
657
|
+
const groupJsDocLines = [];
|
|
658
|
+
if (group.displayName || group.description) {
|
|
659
|
+
const desc = (group.description ?? group.displayName ?? '')
|
|
660
|
+
.replace(/\*\//g, '*\\/')
|
|
661
|
+
.replace(/</g, '<')
|
|
662
|
+
.replace(/>/g, '>');
|
|
663
|
+
groupJsDocLines.push(`${INDENT.repeat(2)}/** ${desc}`);
|
|
664
|
+
}
|
|
665
|
+
if (group.builderHint) {
|
|
666
|
+
const safeBuilderHint = group.builderHint.message
|
|
667
|
+
.replace(/\*\//g, '*\\/')
|
|
668
|
+
.replace(/</g, '<')
|
|
669
|
+
.replace(/>/g, '>');
|
|
670
|
+
if (groupJsDocLines.length === 0) {
|
|
671
|
+
groupJsDocLines.push(`${INDENT.repeat(2)}/**`);
|
|
672
|
+
}
|
|
673
|
+
groupJsDocLines.push(`${INDENT.repeat(2)} * @builderHint ${safeBuilderHint}`);
|
|
674
|
+
}
|
|
675
|
+
if (groupJsDocLines.length > 0) {
|
|
676
|
+
groupJsDocLines.push(`${INDENT.repeat(2)} */`);
|
|
677
|
+
groups.push(`${groupJsDocLines.join('\n')}\n${INDENT.repeat(2)}${groupName}?: ${groupType}`);
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
groups.push(`${groupName}?: ${groupType}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (groups.length === 0) {
|
|
685
|
+
return 'Record<string, unknown>';
|
|
686
|
+
}
|
|
687
|
+
return `{\n${INDENT.repeat(2)}${groups.join(`;\n${INDENT.repeat(2)}`)};\n${INDENT}}`;
|
|
688
|
+
}
|
|
689
|
+
function mergeCollectionProperties(properties) {
|
|
690
|
+
const seenProps = new Map();
|
|
691
|
+
for (const prop of properties) {
|
|
692
|
+
if (['notice', 'curlImport', 'credentials'].includes(prop.type)) {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if (seenProps.has(prop.name)) {
|
|
696
|
+
const existingProp = seenProps.get(prop.name);
|
|
697
|
+
if ((prop.type === 'collection' || prop.type === 'fixedCollection') &&
|
|
698
|
+
prop.options &&
|
|
699
|
+
existingProp.options) {
|
|
700
|
+
const existingOptionNames = new Set(existingProp.options.map((o) => o.name));
|
|
701
|
+
for (const opt of prop.options) {
|
|
702
|
+
if (!existingOptionNames.has(opt.name)) {
|
|
703
|
+
existingProp.options.push(opt);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
seenProps.set(prop.name, {
|
|
710
|
+
...prop,
|
|
711
|
+
options: prop.options ? [...prop.options] : undefined,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
return Array.from(seenProps.values());
|
|
715
|
+
}
|
|
716
|
+
function generateCollectionType(prop, discriminatorContext) {
|
|
717
|
+
if (!prop.options || prop.options.length === 0) {
|
|
718
|
+
return 'Record<string, unknown>';
|
|
719
|
+
}
|
|
720
|
+
const nestedProps = [];
|
|
721
|
+
for (const nestedProp of prop.options) {
|
|
722
|
+
if (nestedProp.values !== undefined) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
const nestedType = nestedProp.type;
|
|
726
|
+
if (['notice', 'curlImport', 'credentials'].includes(nestedType)) {
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const propType = mapNestedPropertyType(nestedProp, discriminatorContext);
|
|
730
|
+
if (propType) {
|
|
731
|
+
const quotedName = quotePropertyName(nestedProp.name);
|
|
732
|
+
const jsDoc = generateNestedPropertyJSDoc(nestedProp, INDENT.repeat(2), discriminatorContext);
|
|
733
|
+
nestedProps.push(`${jsDoc}\n${INDENT.repeat(2)}${quotedName}?: ${propType}`);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (nestedProps.length === 0) {
|
|
737
|
+
return 'Record<string, unknown>';
|
|
738
|
+
}
|
|
739
|
+
return `{\n${nestedProps.join(';\n')};\n${INDENT}}`;
|
|
740
|
+
}
|
|
741
|
+
function stripExpressionFromType(typeStr) {
|
|
742
|
+
return typeStr
|
|
743
|
+
.replace(/\s*\|\s*Expression<[^>]+>/g, '')
|
|
744
|
+
.replace(/\s*\|\s*PlaceholderValue/g, '')
|
|
745
|
+
.trim();
|
|
746
|
+
}
|
|
747
|
+
function mapPropertyType(prop, discriminatorContext) {
|
|
748
|
+
const result = mapPropertyTypeInner(prop, discriminatorContext);
|
|
749
|
+
if (prop.noDataExpression) {
|
|
750
|
+
return stripExpressionFromType(result);
|
|
751
|
+
}
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
754
|
+
function mapPropertyTypeInner(prop, discriminatorContext) {
|
|
755
|
+
if (prop.type === 'credentialsSelect' && prop.name === 'genericAuthType') {
|
|
756
|
+
const values = GENERIC_AUTH_TYPE_VALUES.map((v) => `'${v}'`).join(' | ');
|
|
757
|
+
return `${values} | Expression<string>`;
|
|
758
|
+
}
|
|
759
|
+
if (prop.typeOptions?.loadOptionsMethod || prop.typeOptions?.loadOptionsDependsOn) {
|
|
760
|
+
switch (prop.type) {
|
|
761
|
+
case 'options':
|
|
762
|
+
return 'string | Expression<string>';
|
|
763
|
+
case 'multiOptions':
|
|
764
|
+
return 'string[]';
|
|
765
|
+
case 'resourceLocator':
|
|
766
|
+
return generateResourceLocatorType(prop);
|
|
767
|
+
case 'filter':
|
|
768
|
+
return 'FilterValue';
|
|
769
|
+
case 'assignmentCollection':
|
|
770
|
+
return 'AssignmentCollectionValue';
|
|
771
|
+
default:
|
|
772
|
+
return 'string | Expression<string>';
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
switch (prop.type) {
|
|
776
|
+
case 'string':
|
|
777
|
+
if (prop.builderHint?.placeholderSupported === false) {
|
|
778
|
+
return 'string | Expression<string>';
|
|
779
|
+
}
|
|
780
|
+
return 'string | Expression<string> | PlaceholderValue';
|
|
781
|
+
case 'number':
|
|
782
|
+
return 'number | Expression<number>';
|
|
783
|
+
case 'boolean':
|
|
784
|
+
return 'boolean | Expression<boolean>';
|
|
785
|
+
case 'options':
|
|
786
|
+
if (prop.options && prop.options.length > 0) {
|
|
787
|
+
const values = prop.options.map((opt) => {
|
|
788
|
+
if (typeof opt.value === 'string') {
|
|
789
|
+
const escaped = opt.value
|
|
790
|
+
.replace(/\\/g, '\\\\')
|
|
791
|
+
.replace(/'/g, "\\'")
|
|
792
|
+
.replace(/\n/g, '\\n')
|
|
793
|
+
.replace(/\r/g, '\\r')
|
|
794
|
+
.replace(/\t/g, '\\t');
|
|
795
|
+
return `'${escaped}'`;
|
|
796
|
+
}
|
|
797
|
+
return String(opt.value);
|
|
798
|
+
});
|
|
799
|
+
const valueType = typeof prop.options[0].value;
|
|
800
|
+
const expressionType = valueType === 'number'
|
|
801
|
+
? 'Expression<number>'
|
|
802
|
+
: valueType === 'boolean'
|
|
803
|
+
? 'Expression<boolean>'
|
|
804
|
+
: 'Expression<string>';
|
|
805
|
+
return `${values.join(' | ')} | ${expressionType}`;
|
|
806
|
+
}
|
|
807
|
+
return 'string | Expression<string>';
|
|
808
|
+
case 'multiOptions':
|
|
809
|
+
if (prop.options && prop.options.length > 0) {
|
|
810
|
+
const values = prop.options.map((opt) => {
|
|
811
|
+
if (typeof opt.value === 'string') {
|
|
812
|
+
return `'${opt.value}'`;
|
|
813
|
+
}
|
|
814
|
+
return String(opt.value);
|
|
815
|
+
});
|
|
816
|
+
return `Array<${values.join(' | ')}>`;
|
|
817
|
+
}
|
|
818
|
+
return 'string[]';
|
|
819
|
+
case 'json':
|
|
820
|
+
return 'IDataObject | string | Expression<string>';
|
|
821
|
+
case 'resourceLocator':
|
|
822
|
+
return generateResourceLocatorType(prop);
|
|
823
|
+
case 'filter':
|
|
824
|
+
return 'FilterValue';
|
|
825
|
+
case 'assignmentCollection':
|
|
826
|
+
return 'AssignmentCollectionValue';
|
|
827
|
+
case 'fixedCollection':
|
|
828
|
+
return generateFixedCollectionType(prop, discriminatorContext);
|
|
829
|
+
case 'collection':
|
|
830
|
+
return generateCollectionType(prop, discriminatorContext);
|
|
831
|
+
case 'dateTime':
|
|
832
|
+
return 'string | Expression<string>';
|
|
833
|
+
case 'color':
|
|
834
|
+
return 'string | Expression<string>';
|
|
835
|
+
case 'hidden':
|
|
836
|
+
return 'unknown';
|
|
837
|
+
case 'notice':
|
|
838
|
+
case 'curlImport':
|
|
839
|
+
case 'credentials':
|
|
840
|
+
return '';
|
|
841
|
+
case 'credentialsSelect':
|
|
842
|
+
return 'string | Expression<string>';
|
|
843
|
+
default:
|
|
844
|
+
return 'unknown';
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function extractDiscriminatorCombinations(node) {
|
|
848
|
+
const combinations = [];
|
|
849
|
+
const resourceProp = node.properties.find((p) => p.name === 'resource' && p.type === 'options');
|
|
850
|
+
const operationProps = node.properties.filter((p) => p.name === 'operation' && p.type === 'options');
|
|
851
|
+
if (resourceProp && operationProps.length > 0) {
|
|
852
|
+
const resources = resourceProp.options?.map((o) => String(o.value)) ?? [];
|
|
853
|
+
for (const resource of resources) {
|
|
854
|
+
const opProp = operationProps.find((op) => {
|
|
855
|
+
const showResource = op.displayOptions?.show?.resource;
|
|
856
|
+
return showResource?.includes(resource);
|
|
857
|
+
});
|
|
858
|
+
if (opProp?.options) {
|
|
859
|
+
for (const opOption of opProp.options) {
|
|
860
|
+
combinations.push({
|
|
861
|
+
resource,
|
|
862
|
+
operation: String(opOption.value),
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return combinations;
|
|
868
|
+
}
|
|
869
|
+
const otherDiscriminators = ['mode'];
|
|
870
|
+
for (const discName of otherDiscriminators) {
|
|
871
|
+
const discProp = node.properties.find((p) => p.name === discName && p.type === 'options' && p.options && p.options.length > 1);
|
|
872
|
+
if (discProp?.displayOptions) {
|
|
873
|
+
const hasNonVersionDisplayOptions = (discProp.displayOptions.show &&
|
|
874
|
+
Object.keys(discProp.displayOptions.show).some((k) => k !== '@version')) ||
|
|
875
|
+
(discProp.displayOptions.hide &&
|
|
876
|
+
Object.keys(discProp.displayOptions.hide).some((k) => k !== '@version'));
|
|
877
|
+
if (hasNonVersionDisplayOptions) {
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (discProp?.options) {
|
|
882
|
+
const hasDependentProps = node.properties.some((p) => p.displayOptions?.show?.[discName] !== undefined ||
|
|
883
|
+
p.displayOptions?.hide?.[discName] !== undefined);
|
|
884
|
+
if (hasDependentProps) {
|
|
885
|
+
for (const opt of discProp.options) {
|
|
886
|
+
combinations.push({
|
|
887
|
+
[discName]: String(opt.value),
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
return combinations;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return [];
|
|
895
|
+
}
|
|
896
|
+
function getPropertiesForCombination(node, combination) {
|
|
897
|
+
const result = [];
|
|
898
|
+
for (const prop of node.properties) {
|
|
899
|
+
if (DISCRIMINATOR_FIELDS.includes(prop.name)) {
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
if (['notice', 'curlImport', 'credentials'].includes(prop.type)) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
if (prop.displayOptions?.show) {
|
|
906
|
+
let matches = true;
|
|
907
|
+
for (const [key, conditions] of Object.entries(prop.displayOptions.show)) {
|
|
908
|
+
if (combination[key] !== undefined) {
|
|
909
|
+
if (!(0, display_options_1.checkConditions)(conditions, [combination[key]])) {
|
|
910
|
+
matches = false;
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
if (matches) {
|
|
916
|
+
result.push(prop);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
else if (prop.displayOptions?.hide) {
|
|
920
|
+
let excluded = false;
|
|
921
|
+
for (const [key, conditions] of Object.entries(prop.displayOptions.hide)) {
|
|
922
|
+
if (combination[key] !== undefined) {
|
|
923
|
+
if ((0, display_options_1.checkConditions)(conditions, [combination[key]])) {
|
|
924
|
+
excluded = true;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (!excluded) {
|
|
930
|
+
result.push(prop);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
result.push(prop);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return result;
|
|
938
|
+
}
|
|
939
|
+
function versionMatchesCondition(version, condition) {
|
|
940
|
+
if (typeof condition === 'number') {
|
|
941
|
+
return version === condition;
|
|
942
|
+
}
|
|
943
|
+
if (condition._cnd) {
|
|
944
|
+
const { gt, gte, lt, lte } = condition._cnd;
|
|
945
|
+
if (gt !== undefined && !(version > gt))
|
|
946
|
+
return false;
|
|
947
|
+
if (gte !== undefined && !(version >= gte))
|
|
948
|
+
return false;
|
|
949
|
+
if (lt !== undefined && !(version < lt))
|
|
950
|
+
return false;
|
|
951
|
+
if (lte !== undefined && !(version <= lte))
|
|
952
|
+
return false;
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
function propertyAppliesToVersion(prop, version) {
|
|
958
|
+
if (!prop.displayOptions) {
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
if (prop.displayOptions.show?.['@version']) {
|
|
962
|
+
const allowedVersions = prop.displayOptions.show['@version'];
|
|
963
|
+
const anyMatches = allowedVersions.some((cond) => versionMatchesCondition(version, cond));
|
|
964
|
+
if (!anyMatches) {
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (prop.displayOptions.hide?.['@version']) {
|
|
969
|
+
const hiddenVersions = prop.displayOptions.hide['@version'];
|
|
970
|
+
const anyMatches = hiddenVersions.some((cond) => versionMatchesCondition(version, cond));
|
|
971
|
+
if (anyMatches) {
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
return true;
|
|
976
|
+
}
|
|
977
|
+
function filterPropertiesForVersion(properties, version) {
|
|
978
|
+
return properties.filter((prop) => propertyAppliesToVersion(prop, version));
|
|
979
|
+
}
|
|
980
|
+
function generateDiscriminatedUnion(node) {
|
|
981
|
+
const combinations = extractDiscriminatorCombinations(node);
|
|
982
|
+
const prefix = getPackagePrefix(node.name);
|
|
983
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
984
|
+
const version = getHighestVersion(node.version);
|
|
985
|
+
const versionSuffix = versionToTypeName(version);
|
|
986
|
+
const lines = [];
|
|
987
|
+
if (combinations.length === 0) {
|
|
988
|
+
const configName = `${nodeName}${versionSuffix}Params`;
|
|
989
|
+
lines.push(`export interface ${configName} {`);
|
|
990
|
+
const mergedProps = mergeCollectionProperties(node.properties);
|
|
991
|
+
for (const prop of mergedProps) {
|
|
992
|
+
const propLine = generatePropertyLine(prop, isPropertyOptional(prop));
|
|
993
|
+
if (propLine) {
|
|
994
|
+
lines.push(propLine);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
lines.push('}');
|
|
998
|
+
return lines.join('\n');
|
|
999
|
+
}
|
|
1000
|
+
const configTypeNames = [];
|
|
1001
|
+
for (const combo of combinations) {
|
|
1002
|
+
const comboValues = Object.entries(combo)
|
|
1003
|
+
.filter(([_, v]) => v !== undefined)
|
|
1004
|
+
.map(([_, v]) => toPascalCase(v));
|
|
1005
|
+
const configName = `${nodeName}${comboValues.join('')}Params`;
|
|
1006
|
+
configTypeNames.push(configName);
|
|
1007
|
+
const props = getPropertiesForCombination(node, combo);
|
|
1008
|
+
let description;
|
|
1009
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1010
|
+
if (value === undefined)
|
|
1011
|
+
continue;
|
|
1012
|
+
const discProp = node.properties.find((p) => p.name === key && p.options?.some((o) => o.value === value));
|
|
1013
|
+
if (discProp) {
|
|
1014
|
+
description = discProp.options?.find((o) => o.value === value)?.description;
|
|
1015
|
+
if (description)
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (description) {
|
|
1020
|
+
lines.push(`/** ${description} */`);
|
|
1021
|
+
}
|
|
1022
|
+
lines.push(`export type ${configName} = {`);
|
|
1023
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1024
|
+
if (value !== undefined) {
|
|
1025
|
+
lines.push(`${INDENT}${key}: '${value}';`);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
const seenNames = new Set();
|
|
1029
|
+
for (const prop of props) {
|
|
1030
|
+
if (seenNames.has(prop.name)) {
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
seenNames.add(prop.name);
|
|
1034
|
+
const propLine = generatePropertyLine(prop, isPropertyOptional(prop), combo);
|
|
1035
|
+
if (propLine) {
|
|
1036
|
+
lines.push(propLine);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
lines.push('};');
|
|
1040
|
+
lines.push('');
|
|
1041
|
+
}
|
|
1042
|
+
return lines.join('\n');
|
|
1043
|
+
}
|
|
1044
|
+
function generatePropertyJSDoc(prop, discriminatorContext) {
|
|
1045
|
+
const lines = ['/**'];
|
|
1046
|
+
const description = prop.description ?? prop.displayName;
|
|
1047
|
+
const safeDescription = description
|
|
1048
|
+
.replace(/\*\//g, '*\\/')
|
|
1049
|
+
.replace(/</g, '<')
|
|
1050
|
+
.replace(/>/g, '>');
|
|
1051
|
+
lines.push(` * ${safeDescription}`);
|
|
1052
|
+
if (prop.hint) {
|
|
1053
|
+
const safeHint = prop.hint.replace(/\*\//g, '*\\/').replace(/</g, '<').replace(/>/g, '>');
|
|
1054
|
+
lines.push(` * @hint ${safeHint}`);
|
|
1055
|
+
}
|
|
1056
|
+
if (prop.builderHint) {
|
|
1057
|
+
const safeBuilderHint = prop.builderHint.message
|
|
1058
|
+
.replace(/\*\//g, '*\\/')
|
|
1059
|
+
.replace(/</g, '<')
|
|
1060
|
+
.replace(/>/g, '>');
|
|
1061
|
+
lines.push(` * @builderHint ${safeBuilderHint}`);
|
|
1062
|
+
}
|
|
1063
|
+
if (prop.displayOptions) {
|
|
1064
|
+
if (prop.displayOptions.show && Object.keys(prop.displayOptions.show).length > 0) {
|
|
1065
|
+
const filteredShow = Object.entries(prop.displayOptions.show).filter(([key, values]) => {
|
|
1066
|
+
if (key === '@version')
|
|
1067
|
+
return false;
|
|
1068
|
+
const normalizedKey = key.startsWith('/') ? key.slice(1) : key;
|
|
1069
|
+
if (discriminatorContext?.[normalizedKey] !== undefined) {
|
|
1070
|
+
const showValues = values;
|
|
1071
|
+
if (showValues.includes(discriminatorContext[normalizedKey]))
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
return true;
|
|
1075
|
+
});
|
|
1076
|
+
if (filteredShow.length > 0) {
|
|
1077
|
+
const showConditions = filteredShow
|
|
1078
|
+
.map(([key, values]) => `${key}: [${values.map((v) => JSON.stringify(v)).join(', ')}]`)
|
|
1079
|
+
.join(', ');
|
|
1080
|
+
lines.push(` * @displayOptions.show { ${showConditions} }`);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
if (prop.displayOptions.hide && Object.keys(prop.displayOptions.hide).length > 0) {
|
|
1084
|
+
const filteredHide = Object.entries(prop.displayOptions.hide).filter(([key, values]) => {
|
|
1085
|
+
if (key === '@version')
|
|
1086
|
+
return false;
|
|
1087
|
+
const normalizedKey = key.startsWith('/') ? key.slice(1) : key;
|
|
1088
|
+
if (discriminatorContext?.[normalizedKey] !== undefined) {
|
|
1089
|
+
const hideValues = values;
|
|
1090
|
+
if (hideValues.includes(discriminatorContext[normalizedKey]))
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
return true;
|
|
1094
|
+
});
|
|
1095
|
+
if (filteredHide.length > 0) {
|
|
1096
|
+
const hideConditions = filteredHide
|
|
1097
|
+
.map(([key, values]) => `${key}: [${values.map((v) => JSON.stringify(v)).join(', ')}]`)
|
|
1098
|
+
.join(', ');
|
|
1099
|
+
lines.push(` * @displayOptions.hide { ${hideConditions} }`);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
if (prop.default !== undefined && prop.default !== null && prop.default !== '') {
|
|
1104
|
+
let defaultStr;
|
|
1105
|
+
if (typeof prop.default === 'object') {
|
|
1106
|
+
defaultStr = JSON.stringify(prop.default);
|
|
1107
|
+
}
|
|
1108
|
+
else {
|
|
1109
|
+
defaultStr = String(prop.default);
|
|
1110
|
+
}
|
|
1111
|
+
if (!defaultStr.includes('\n')) {
|
|
1112
|
+
lines.push(` * @default ${defaultStr}`);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
lines.push(' */');
|
|
1116
|
+
return lines.join('\n');
|
|
1117
|
+
}
|
|
1118
|
+
function generateNodeJSDoc(node) {
|
|
1119
|
+
const lines = ['/**'];
|
|
1120
|
+
lines.push(` * ${node.displayName} Node Types`);
|
|
1121
|
+
lines.push(' *');
|
|
1122
|
+
if (node.description) {
|
|
1123
|
+
lines.push(` * ${node.description}`);
|
|
1124
|
+
}
|
|
1125
|
+
const subnodeType = getSubnodeOutputType(node);
|
|
1126
|
+
if (subnodeType) {
|
|
1127
|
+
lines.push(` * @subnodeType ${subnodeType}`);
|
|
1128
|
+
}
|
|
1129
|
+
lines.push(' */');
|
|
1130
|
+
return lines.join('\n');
|
|
1131
|
+
}
|
|
1132
|
+
function generatePropertyLine(prop, optional, discriminatorContext) {
|
|
1133
|
+
const tsType = mapPropertyType(prop, discriminatorContext);
|
|
1134
|
+
if (!tsType) {
|
|
1135
|
+
return '';
|
|
1136
|
+
}
|
|
1137
|
+
const lines = [];
|
|
1138
|
+
const hasDisplayOptions = prop.displayOptions &&
|
|
1139
|
+
((prop.displayOptions.show && Object.keys(prop.displayOptions.show).length > 0) ||
|
|
1140
|
+
(prop.displayOptions.hide && Object.keys(prop.displayOptions.hide).length > 0));
|
|
1141
|
+
if (prop.description || hasDisplayOptions || prop.hint || prop.builderHint) {
|
|
1142
|
+
lines.push(generatePropertyJSDoc(prop, discriminatorContext));
|
|
1143
|
+
}
|
|
1144
|
+
let propName = prop.name;
|
|
1145
|
+
const needsQuoting = RESERVED_WORDS.has(propName) || !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propName);
|
|
1146
|
+
if (needsQuoting) {
|
|
1147
|
+
propName = `'${propName.replace(/'/g, "\\'")}'`;
|
|
1148
|
+
}
|
|
1149
|
+
const optionalMarker = optional ? '?' : '';
|
|
1150
|
+
lines.push(`${INDENT}${propName}${optionalMarker}: ${tsType};`);
|
|
1151
|
+
return lines.join(`\n${INDENT}`);
|
|
1152
|
+
}
|
|
1153
|
+
function groupVersionsByProperties(nodes) {
|
|
1154
|
+
const groups = [];
|
|
1155
|
+
for (const node of nodes) {
|
|
1156
|
+
const versions = Array.isArray(node.version) ? node.version : [node.version];
|
|
1157
|
+
const propsHash = JSON.stringify(node.properties.map((p) => p.name).sort());
|
|
1158
|
+
const existing = groups.find((g) => JSON.stringify(g.properties.map((p) => p.name).sort()) === propsHash);
|
|
1159
|
+
if (existing) {
|
|
1160
|
+
existing.versions.push(...versions);
|
|
1161
|
+
existing.highestVersion = Math.max(existing.highestVersion, ...versions);
|
|
1162
|
+
}
|
|
1163
|
+
else {
|
|
1164
|
+
groups.push({
|
|
1165
|
+
versions,
|
|
1166
|
+
highestVersion: Math.max(...versions),
|
|
1167
|
+
properties: node.properties,
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return groups;
|
|
1172
|
+
}
|
|
1173
|
+
function getHighestVersion(version) {
|
|
1174
|
+
if (Array.isArray(version)) {
|
|
1175
|
+
return Math.max(...version);
|
|
1176
|
+
}
|
|
1177
|
+
return version;
|
|
1178
|
+
}
|
|
1179
|
+
function versionToTypeName(version) {
|
|
1180
|
+
return `V${String(version).replace('.', '')}`;
|
|
1181
|
+
}
|
|
1182
|
+
function nodeNameToFileName(nodeName) {
|
|
1183
|
+
const parts = nodeName.split('.');
|
|
1184
|
+
return parts[parts.length - 1];
|
|
1185
|
+
}
|
|
1186
|
+
function getPackageName(nodeName) {
|
|
1187
|
+
const parts = nodeName.split('.');
|
|
1188
|
+
const pkg = parts[0];
|
|
1189
|
+
if (pkg.startsWith('@n8n/')) {
|
|
1190
|
+
return pkg.replace('@n8n/', '');
|
|
1191
|
+
}
|
|
1192
|
+
return pkg;
|
|
1193
|
+
}
|
|
1194
|
+
function getNodeBaseName(nodeName) {
|
|
1195
|
+
const parts = nodeName.split('.');
|
|
1196
|
+
return parts[parts.length - 1];
|
|
1197
|
+
}
|
|
1198
|
+
function getPackagePrefix(nodeName) {
|
|
1199
|
+
const pkg = getPackageName(nodeName);
|
|
1200
|
+
if (pkg === 'n8n-nodes-base') {
|
|
1201
|
+
return '';
|
|
1202
|
+
}
|
|
1203
|
+
if (pkg.includes('langchain')) {
|
|
1204
|
+
return 'Lc';
|
|
1205
|
+
}
|
|
1206
|
+
return '';
|
|
1207
|
+
}
|
|
1208
|
+
function toPascalCase(str) {
|
|
1209
|
+
return str
|
|
1210
|
+
.replace(/[-_]+/g, ' ')
|
|
1211
|
+
.replace(/\./g, ' ')
|
|
1212
|
+
.split(' ')
|
|
1213
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
1214
|
+
.join('');
|
|
1215
|
+
}
|
|
1216
|
+
function toSnakeCase(str) {
|
|
1217
|
+
return str
|
|
1218
|
+
.replace(/([A-Z])/g, '_$1')
|
|
1219
|
+
.toLowerCase()
|
|
1220
|
+
.replace(/^_/, '')
|
|
1221
|
+
.replace(/[-\s]+/g, '_');
|
|
1222
|
+
}
|
|
1223
|
+
function buildDiscriminatorPath(combo) {
|
|
1224
|
+
const parts = [];
|
|
1225
|
+
if (combo.resource && combo.operation) {
|
|
1226
|
+
parts.push(`resource_${toSnakeCase(combo.resource)}`);
|
|
1227
|
+
parts.push(`operation_${toSnakeCase(combo.operation)}`);
|
|
1228
|
+
return parts.join('/');
|
|
1229
|
+
}
|
|
1230
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1231
|
+
if (value !== undefined) {
|
|
1232
|
+
parts.push(`${key}_${toSnakeCase(value)}`);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return parts.join('/');
|
|
1236
|
+
}
|
|
1237
|
+
function hasDiscriminatorPattern(node) {
|
|
1238
|
+
const combinations = extractDiscriminatorCombinations(node);
|
|
1239
|
+
if (combinations.length === 0) {
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1242
|
+
const first = combinations[0];
|
|
1243
|
+
if (first.resource !== undefined && first.operation !== undefined) {
|
|
1244
|
+
return true;
|
|
1245
|
+
}
|
|
1246
|
+
if (first.mode !== undefined) {
|
|
1247
|
+
return true;
|
|
1248
|
+
}
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
function buildDiscriminatorTree(combinations) {
|
|
1252
|
+
if (combinations.length === 0) {
|
|
1253
|
+
return { type: 'single' };
|
|
1254
|
+
}
|
|
1255
|
+
const first = combinations[0];
|
|
1256
|
+
if (first.resource !== undefined && first.operation !== undefined) {
|
|
1257
|
+
const resources = new Map();
|
|
1258
|
+
for (const combo of combinations) {
|
|
1259
|
+
if (combo.resource && combo.operation) {
|
|
1260
|
+
if (!resources.has(combo.resource)) {
|
|
1261
|
+
resources.set(combo.resource, []);
|
|
1262
|
+
}
|
|
1263
|
+
resources.get(combo.resource).push(combo.operation);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return { type: 'resource_operation', resources };
|
|
1267
|
+
}
|
|
1268
|
+
const discName = Object.keys(first).find((k) => first[k] !== undefined);
|
|
1269
|
+
if (discName) {
|
|
1270
|
+
const values = combinations.map((c) => c[discName]).filter(Boolean);
|
|
1271
|
+
return {
|
|
1272
|
+
type: 'single',
|
|
1273
|
+
discriminatorName: discName,
|
|
1274
|
+
discriminatorValues: [...new Set(values)],
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
return { type: 'single' };
|
|
1278
|
+
}
|
|
1279
|
+
function generateSharedFile(node, version, _importDepth = 5) {
|
|
1280
|
+
const prefix = getPackagePrefix(node.name);
|
|
1281
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1282
|
+
const isTrigger = isTriggerNode(node);
|
|
1283
|
+
const versionSuffix = versionToTypeName(version);
|
|
1284
|
+
const filteredProperties = filterPropertiesForVersion(node.properties, version);
|
|
1285
|
+
const lines = [];
|
|
1286
|
+
lines.push('/**');
|
|
1287
|
+
lines.push(` * ${node.displayName} Node - Version ${version} - Shared Types`);
|
|
1288
|
+
lines.push(' * ');
|
|
1289
|
+
lines.push(' * Contains credentials, base type, and helper types shared across all');
|
|
1290
|
+
lines.push(' * resource/operation combinations.');
|
|
1291
|
+
lines.push(' */');
|
|
1292
|
+
lines.push('');
|
|
1293
|
+
lines.push('');
|
|
1294
|
+
const outputProps = filteredProperties.filter((p) => !['notice', 'curlImport', 'credentials'].includes(p.type));
|
|
1295
|
+
const needsFilter = outputProps.some((p) => p.type === 'filter');
|
|
1296
|
+
const needsAssignment = outputProps.some((p) => p.type === 'assignmentCollection');
|
|
1297
|
+
if (needsFilter || needsAssignment) {
|
|
1298
|
+
lines.push('// Helper types for special n8n fields');
|
|
1299
|
+
if (needsFilter) {
|
|
1300
|
+
lines.push(generateFilterTypeDeclaration(true));
|
|
1301
|
+
}
|
|
1302
|
+
if (needsAssignment) {
|
|
1303
|
+
lines.push(generateAssignmentTypeDeclarations(true));
|
|
1304
|
+
}
|
|
1305
|
+
lines.push('');
|
|
1306
|
+
}
|
|
1307
|
+
const credTypeName = node.credentials && node.credentials.length > 0
|
|
1308
|
+
? `${nodeName}${versionSuffix}Credentials`
|
|
1309
|
+
: undefined;
|
|
1310
|
+
if (node.credentials && node.credentials.length > 0) {
|
|
1311
|
+
lines.push(`export interface ${credTypeName} {`);
|
|
1312
|
+
const seenCreds = new Set();
|
|
1313
|
+
for (const cred of node.credentials) {
|
|
1314
|
+
if (seenCreds.has(cred.name))
|
|
1315
|
+
continue;
|
|
1316
|
+
seenCreds.add(cred.name);
|
|
1317
|
+
const optional = !cred.required ? '?' : '';
|
|
1318
|
+
lines.push(`${INDENT}${cred.name}${optional}: CredentialReference;`);
|
|
1319
|
+
}
|
|
1320
|
+
const hasGenericAuthType = node.properties.some((p) => p.name === 'genericAuthType' && p.type === 'credentialsSelect');
|
|
1321
|
+
if (hasGenericAuthType) {
|
|
1322
|
+
lines.push(`${INDENT}/** Generic auth credentials - set the 'genericAuthType' config parameter to select which one to use */`);
|
|
1323
|
+
for (const credName of GENERIC_AUTH_TYPE_VALUES) {
|
|
1324
|
+
if (!seenCreds.has(credName)) {
|
|
1325
|
+
seenCreds.add(credName);
|
|
1326
|
+
lines.push(`${INDENT}${credName}?: CredentialReference;`);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
lines.push('}');
|
|
1331
|
+
lines.push('');
|
|
1332
|
+
}
|
|
1333
|
+
const baseTypeName = `${nodeName}${versionSuffix}NodeBase`;
|
|
1334
|
+
lines.push(`export interface ${baseTypeName} {`);
|
|
1335
|
+
lines.push(`${INDENT}type: '${node.name}';`);
|
|
1336
|
+
lines.push(`${INDENT}version: ${version};`);
|
|
1337
|
+
if (credTypeName) {
|
|
1338
|
+
lines.push(`${INDENT}credentials?: ${credTypeName};`);
|
|
1339
|
+
}
|
|
1340
|
+
if (isTrigger) {
|
|
1341
|
+
lines.push(`${INDENT}isTrigger: true;`);
|
|
1342
|
+
}
|
|
1343
|
+
lines.push('}');
|
|
1344
|
+
return lines.join('\n');
|
|
1345
|
+
}
|
|
1346
|
+
function generateDiscriminatorFile(node, version, combo, props, schema, _importDepth = 5) {
|
|
1347
|
+
const prefix = getPackagePrefix(node.name);
|
|
1348
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1349
|
+
const versionSuffix = versionToTypeName(version);
|
|
1350
|
+
const isTrigger = isTriggerNode(node);
|
|
1351
|
+
const comboValues = Object.entries(combo)
|
|
1352
|
+
.filter(([_, v]) => v !== undefined)
|
|
1353
|
+
.map(([_, v]) => toPascalCase(v));
|
|
1354
|
+
const comboSuffix = comboValues.join('');
|
|
1355
|
+
const configName = `${nodeName}${versionSuffix}${comboSuffix}Params`;
|
|
1356
|
+
const outputTypeName = `${nodeName}${versionSuffix}${comboSuffix}Output`;
|
|
1357
|
+
const nodeTypeName = `${nodeName}${versionSuffix}${comboSuffix}Node`;
|
|
1358
|
+
const aiInputTypes = extractAIInputTypesFromBuilderHint(node, combo);
|
|
1359
|
+
const subnodeConfigTypeName = aiInputTypes.length > 0 ? `${nodeName}${versionSuffix}${comboSuffix}SubnodeConfig` : undefined;
|
|
1360
|
+
const lines = [];
|
|
1361
|
+
const comboDesc = Object.entries(combo)
|
|
1362
|
+
.filter(([_, v]) => v !== undefined)
|
|
1363
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
1364
|
+
.join(', ');
|
|
1365
|
+
lines.push('/**');
|
|
1366
|
+
lines.push(` * ${node.displayName} Node - Version ${version}`);
|
|
1367
|
+
lines.push(` * Discriminator: ${comboDesc}`);
|
|
1368
|
+
lines.push(' */');
|
|
1369
|
+
lines.push('');
|
|
1370
|
+
lines.push('');
|
|
1371
|
+
const needsFilter = props.some((p) => p.type === 'filter');
|
|
1372
|
+
const needsAssignment = props.some((p) => p.type === 'assignmentCollection');
|
|
1373
|
+
if (needsFilter || needsAssignment) {
|
|
1374
|
+
lines.push('// Helper types for special n8n fields');
|
|
1375
|
+
if (needsFilter) {
|
|
1376
|
+
lines.push(generateFilterTypeDeclaration(false));
|
|
1377
|
+
}
|
|
1378
|
+
if (needsAssignment) {
|
|
1379
|
+
lines.push(generateAssignmentTypeDeclarations(false));
|
|
1380
|
+
}
|
|
1381
|
+
lines.push('');
|
|
1382
|
+
}
|
|
1383
|
+
if (node.credentials && node.credentials.length > 0) {
|
|
1384
|
+
lines.push('interface Credentials {');
|
|
1385
|
+
const seenCreds = new Set();
|
|
1386
|
+
for (const cred of node.credentials) {
|
|
1387
|
+
if (seenCreds.has(cred.name))
|
|
1388
|
+
continue;
|
|
1389
|
+
seenCreds.add(cred.name);
|
|
1390
|
+
const optional = !cred.required ? '?' : '';
|
|
1391
|
+
lines.push(`${INDENT}${cred.name}${optional}: CredentialReference;`);
|
|
1392
|
+
}
|
|
1393
|
+
const hasGenericAuthType = node.properties.some((p) => p.name === 'genericAuthType' && p.type === 'credentialsSelect');
|
|
1394
|
+
if (hasGenericAuthType) {
|
|
1395
|
+
lines.push(`${INDENT}/** Generic auth credentials - set the 'genericAuthType' config parameter to select which one to use */`);
|
|
1396
|
+
for (const credName of GENERIC_AUTH_TYPE_VALUES) {
|
|
1397
|
+
if (!seenCreds.has(credName)) {
|
|
1398
|
+
seenCreds.add(credName);
|
|
1399
|
+
lines.push(`${INDENT}${credName}?: CredentialReference;`);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
lines.push('}');
|
|
1404
|
+
lines.push('');
|
|
1405
|
+
}
|
|
1406
|
+
let description;
|
|
1407
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1408
|
+
if (value === undefined)
|
|
1409
|
+
continue;
|
|
1410
|
+
const discProp = node.properties.find((p) => p.name === key && p.options?.some((o) => o.value === value));
|
|
1411
|
+
if (discProp) {
|
|
1412
|
+
description = discProp.options?.find((o) => o.value === value)?.description;
|
|
1413
|
+
if (description)
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
if (description) {
|
|
1418
|
+
lines.push(`/** ${description} */`);
|
|
1419
|
+
}
|
|
1420
|
+
lines.push(`export type ${configName} = {`);
|
|
1421
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1422
|
+
if (value !== undefined) {
|
|
1423
|
+
lines.push(`${INDENT}${key}: '${value}';`);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
const seenNames = new Set();
|
|
1427
|
+
for (const prop of props) {
|
|
1428
|
+
if (seenNames.has(prop.name))
|
|
1429
|
+
continue;
|
|
1430
|
+
seenNames.add(prop.name);
|
|
1431
|
+
const propLine = generatePropertyLine(prop, isPropertyOptional(prop), combo);
|
|
1432
|
+
if (propLine) {
|
|
1433
|
+
lines.push(propLine);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
lines.push('};');
|
|
1437
|
+
lines.push('');
|
|
1438
|
+
if (schema) {
|
|
1439
|
+
lines.push(`export type ${outputTypeName} = ${jsonSchemaToTypeScript(schema)};`);
|
|
1440
|
+
lines.push('');
|
|
1441
|
+
}
|
|
1442
|
+
if (subnodeConfigTypeName && aiInputTypes.length > 0) {
|
|
1443
|
+
const subnodeConfigCode = generateNarrowedSubnodeConfig(aiInputTypes, nodeName, versionSuffix, comboSuffix);
|
|
1444
|
+
if (subnodeConfigCode) {
|
|
1445
|
+
lines.push(subnodeConfigCode);
|
|
1446
|
+
lines.push('');
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
lines.push(`export type ${nodeTypeName} = {`);
|
|
1450
|
+
lines.push(`${INDENT}type: '${node.name}';`);
|
|
1451
|
+
lines.push(`${INDENT}version: ${version};`);
|
|
1452
|
+
if (node.credentials && node.credentials.length > 0) {
|
|
1453
|
+
lines.push(`${INDENT}credentials?: Credentials;`);
|
|
1454
|
+
}
|
|
1455
|
+
if (isTrigger) {
|
|
1456
|
+
lines.push(`${INDENT}isTrigger: true;`);
|
|
1457
|
+
}
|
|
1458
|
+
const hasRequiredSubnodes = aiInputTypes.some((input) => input.required);
|
|
1459
|
+
const subnodeOptionalMark = hasRequiredSubnodes ? '' : '?';
|
|
1460
|
+
const configType = subnodeConfigTypeName
|
|
1461
|
+
? `NodeConfig<${configName}> & { subnodes${subnodeOptionalMark}: ${subnodeConfigTypeName} }`
|
|
1462
|
+
: `NodeConfig<${configName}>`;
|
|
1463
|
+
lines.push(`${INDENT}config: ${configType};`);
|
|
1464
|
+
if (schema) {
|
|
1465
|
+
lines.push(`${INDENT}output?: Items<${outputTypeName}>;`);
|
|
1466
|
+
}
|
|
1467
|
+
lines.push('};');
|
|
1468
|
+
return lines.join('\n');
|
|
1469
|
+
}
|
|
1470
|
+
function generateResourceIndexFile(node, version, resource, operations) {
|
|
1471
|
+
const prefix = getPackagePrefix(node.name);
|
|
1472
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1473
|
+
const versionSuffix = versionToTypeName(version);
|
|
1474
|
+
const lines = [];
|
|
1475
|
+
lines.push('/**');
|
|
1476
|
+
lines.push(` * ${node.displayName} - ${toPascalCase(resource)} Resource`);
|
|
1477
|
+
lines.push(' * Re-exports all operation types for this resource.');
|
|
1478
|
+
lines.push(' */');
|
|
1479
|
+
lines.push('');
|
|
1480
|
+
const nodeTypeNames = [];
|
|
1481
|
+
for (const op of operations.sort()) {
|
|
1482
|
+
const fileName = `operation_${toSnakeCase(op)}`;
|
|
1483
|
+
const nodeTypeName = `${nodeName}${versionSuffix}${toPascalCase(resource)}${toPascalCase(op)}Node`;
|
|
1484
|
+
nodeTypeNames.push(nodeTypeName);
|
|
1485
|
+
lines.push(`import type { ${nodeTypeName} } from './${fileName}';`);
|
|
1486
|
+
}
|
|
1487
|
+
lines.push('');
|
|
1488
|
+
for (const op of operations.sort()) {
|
|
1489
|
+
const fileName = `operation_${toSnakeCase(op)}`;
|
|
1490
|
+
lines.push(`export * from './${fileName}';`);
|
|
1491
|
+
}
|
|
1492
|
+
lines.push('');
|
|
1493
|
+
const resourceNodeTypeName = `${nodeName}${versionSuffix}${toPascalCase(resource)}Node`;
|
|
1494
|
+
if (nodeTypeNames.length === 1) {
|
|
1495
|
+
lines.push(`export type ${resourceNodeTypeName} = ${nodeTypeNames[0]};`);
|
|
1496
|
+
}
|
|
1497
|
+
else {
|
|
1498
|
+
lines.push(`export type ${resourceNodeTypeName} =`);
|
|
1499
|
+
for (const typeName of nodeTypeNames) {
|
|
1500
|
+
lines.push(`${INDENT}| ${typeName}`);
|
|
1501
|
+
}
|
|
1502
|
+
lines.push(`${INDENT};`);
|
|
1503
|
+
}
|
|
1504
|
+
return lines.join('\n');
|
|
1505
|
+
}
|
|
1506
|
+
function generateSplitVersionIndexFile(node, version, tree) {
|
|
1507
|
+
const prefix = getPackagePrefix(node.name);
|
|
1508
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1509
|
+
const versionSuffix = versionToTypeName(version);
|
|
1510
|
+
const lines = [];
|
|
1511
|
+
lines.push('/**');
|
|
1512
|
+
lines.push(` * ${node.displayName} Node - Version ${version}`);
|
|
1513
|
+
lines.push(' * Re-exports all discriminator combinations.');
|
|
1514
|
+
lines.push(' */');
|
|
1515
|
+
lines.push('');
|
|
1516
|
+
const nodeTypeNames = [];
|
|
1517
|
+
if (tree.type === 'resource_operation' && tree.resources) {
|
|
1518
|
+
for (const [resource] of tree.resources) {
|
|
1519
|
+
const resourceNodeTypeName = `${nodeName}${versionSuffix}${toPascalCase(resource)}Node`;
|
|
1520
|
+
nodeTypeNames.push(resourceNodeTypeName);
|
|
1521
|
+
const resourceDir = `resource_${toSnakeCase(resource)}`;
|
|
1522
|
+
lines.push(`import type { ${resourceNodeTypeName} } from './${resourceDir}';`);
|
|
1523
|
+
}
|
|
1524
|
+
lines.push('');
|
|
1525
|
+
for (const [resource] of tree.resources) {
|
|
1526
|
+
const resourceDir = `resource_${toSnakeCase(resource)}`;
|
|
1527
|
+
lines.push(`export * from './${resourceDir}';`);
|
|
1528
|
+
}
|
|
1529
|
+
lines.push('');
|
|
1530
|
+
}
|
|
1531
|
+
else if (tree.type === 'single' && tree.discriminatorName && tree.discriminatorValues) {
|
|
1532
|
+
const discName = tree.discriminatorName;
|
|
1533
|
+
for (const value of tree.discriminatorValues.sort()) {
|
|
1534
|
+
const fileName = `${discName}_${toSnakeCase(value)}`;
|
|
1535
|
+
const nodeTypeName = `${nodeName}${versionSuffix}${toPascalCase(value)}Node`;
|
|
1536
|
+
nodeTypeNames.push(nodeTypeName);
|
|
1537
|
+
lines.push(`import type { ${nodeTypeName} } from './${fileName}';`);
|
|
1538
|
+
}
|
|
1539
|
+
lines.push('');
|
|
1540
|
+
for (const value of tree.discriminatorValues.sort()) {
|
|
1541
|
+
const fileName = `${discName}_${toSnakeCase(value)}`;
|
|
1542
|
+
lines.push(`export * from './${fileName}';`);
|
|
1543
|
+
}
|
|
1544
|
+
lines.push('');
|
|
1545
|
+
}
|
|
1546
|
+
const nodeTypeName = `${nodeName}${versionSuffix}Node`;
|
|
1547
|
+
if (nodeTypeNames.length === 1) {
|
|
1548
|
+
lines.push(`export type ${nodeTypeName} = ${nodeTypeNames[0]};`);
|
|
1549
|
+
}
|
|
1550
|
+
else if (nodeTypeNames.length > 1) {
|
|
1551
|
+
lines.push(`export type ${nodeTypeName} =`);
|
|
1552
|
+
for (const typeName of nodeTypeNames) {
|
|
1553
|
+
lines.push(`${INDENT}| ${typeName}`);
|
|
1554
|
+
}
|
|
1555
|
+
lines.push(`${INDENT};`);
|
|
1556
|
+
}
|
|
1557
|
+
return lines.join('\n');
|
|
1558
|
+
}
|
|
1559
|
+
function planSplitVersionFiles(node, version) {
|
|
1560
|
+
const files = new Map();
|
|
1561
|
+
const combinations = extractDiscriminatorCombinations(node);
|
|
1562
|
+
const tree = buildDiscriminatorTree(combinations);
|
|
1563
|
+
const outputSchemas = discoverSchemasForNode(node.name, version, node.schemaPath);
|
|
1564
|
+
if (tree.type === 'resource_operation' && tree.resources) {
|
|
1565
|
+
for (const [resource, operations] of tree.resources) {
|
|
1566
|
+
const resourceDir = `resource_${toSnakeCase(resource)}`;
|
|
1567
|
+
for (const operation of operations) {
|
|
1568
|
+
if (isCustomApiCall(operation))
|
|
1569
|
+
continue;
|
|
1570
|
+
const combo = { resource, operation };
|
|
1571
|
+
const versionFilteredProps = filterPropertiesForVersion(node.properties, version);
|
|
1572
|
+
const nodeForCombination = { ...node, properties: versionFilteredProps };
|
|
1573
|
+
const props = getPropertiesForCombination(nodeForCombination, combo);
|
|
1574
|
+
const fileName = `operation_${toSnakeCase(operation)}.ts`;
|
|
1575
|
+
const filePath = `${resourceDir}/${fileName}`;
|
|
1576
|
+
const matchingSchema = findSchemaForOperation(outputSchemas, resource, operation);
|
|
1577
|
+
const content = generateDiscriminatorFile(node, version, combo, props, matchingSchema?.schema, 6);
|
|
1578
|
+
files.set(filePath, content);
|
|
1579
|
+
}
|
|
1580
|
+
const filteredOperations = operations.filter((op) => !isCustomApiCall(op));
|
|
1581
|
+
const resourceIndexContent = generateResourceIndexFile(node, version, resource, filteredOperations);
|
|
1582
|
+
files.set(`${resourceDir}/index.ts`, resourceIndexContent);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
else if (tree.type === 'single' && tree.discriminatorName && tree.discriminatorValues) {
|
|
1586
|
+
const discName = tree.discriminatorName;
|
|
1587
|
+
for (const value of tree.discriminatorValues) {
|
|
1588
|
+
const combo = { [discName]: value };
|
|
1589
|
+
const versionFilteredProps = filterPropertiesForVersion(node.properties, version);
|
|
1590
|
+
const nodeForCombination = { ...node, properties: versionFilteredProps };
|
|
1591
|
+
const props = getPropertiesForCombination(nodeForCombination, combo);
|
|
1592
|
+
const fileName = `${discName}_${toSnakeCase(value)}.ts`;
|
|
1593
|
+
const content = generateDiscriminatorFile(node, version, combo, props, undefined, 5);
|
|
1594
|
+
files.set(fileName, content);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
files.set('index.ts', generateSplitVersionIndexFile(node, version, tree));
|
|
1598
|
+
const schemaFiles = (0, generate_zod_schemas_1.planSplitVersionSchemaFiles)(node, version);
|
|
1599
|
+
for (const [path, content] of schemaFiles) {
|
|
1600
|
+
files.set(path, content);
|
|
1601
|
+
}
|
|
1602
|
+
return files;
|
|
1603
|
+
}
|
|
1604
|
+
function isTriggerNode(node) {
|
|
1605
|
+
const inputs = node.inputs;
|
|
1606
|
+
if (Array.isArray(inputs)) {
|
|
1607
|
+
if (inputs.length === 0)
|
|
1608
|
+
return true;
|
|
1609
|
+
if (typeof inputs[0] === 'string') {
|
|
1610
|
+
return !inputs.includes('main');
|
|
1611
|
+
}
|
|
1612
|
+
return !inputs.some((i) => typeof i === 'object' && i.type === 'main');
|
|
1613
|
+
}
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
function versionToFileName(version) {
|
|
1617
|
+
return `v${String(version).replace('.', '')}`;
|
|
1618
|
+
}
|
|
1619
|
+
function generateSingleVersionTypeFile(node, specificVersion) {
|
|
1620
|
+
const prefix = getPackagePrefix(node.name);
|
|
1621
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1622
|
+
const isTrigger = isTriggerNode(node);
|
|
1623
|
+
const versionSuffix = versionToTypeName(specificVersion);
|
|
1624
|
+
const filteredProperties = filterPropertiesForVersion(node.properties, specificVersion);
|
|
1625
|
+
const filteredNode = {
|
|
1626
|
+
...node,
|
|
1627
|
+
properties: filteredProperties,
|
|
1628
|
+
version: specificVersion,
|
|
1629
|
+
};
|
|
1630
|
+
const outputSchemas = discoverSchemasForNode(node.name, specificVersion, node.schemaPath);
|
|
1631
|
+
const lines = [];
|
|
1632
|
+
lines.push('/**');
|
|
1633
|
+
lines.push(` * ${node.displayName} Node - Version ${specificVersion}`);
|
|
1634
|
+
if (node.description) {
|
|
1635
|
+
lines.push(` * ${node.description}`);
|
|
1636
|
+
}
|
|
1637
|
+
lines.push(' */');
|
|
1638
|
+
lines.push('');
|
|
1639
|
+
lines.push('');
|
|
1640
|
+
const aiInputTypes = extractAIInputTypesFromBuilderHint(node);
|
|
1641
|
+
const subnodeConfigTypeName = aiInputTypes.length > 0 ? `${nodeName}${versionSuffix}SubnodeConfig` : undefined;
|
|
1642
|
+
const outputProps = filteredProperties.filter((p) => !['notice', 'curlImport', 'credentials'].includes(p.type));
|
|
1643
|
+
const needsFilter = outputProps.some((p) => p.type === 'filter');
|
|
1644
|
+
const needsAssignment = outputProps.some((p) => p.type === 'assignmentCollection');
|
|
1645
|
+
if (needsFilter || needsAssignment) {
|
|
1646
|
+
lines.push('// Helper types for special n8n fields');
|
|
1647
|
+
if (needsFilter) {
|
|
1648
|
+
lines.push(generateFilterTypeDeclaration(false));
|
|
1649
|
+
}
|
|
1650
|
+
if (needsAssignment) {
|
|
1651
|
+
lines.push(generateAssignmentTypeDeclarations(false));
|
|
1652
|
+
}
|
|
1653
|
+
lines.push('');
|
|
1654
|
+
}
|
|
1655
|
+
const unionResult = generateDiscriminatedUnionForEntry(filteredNode, nodeName, versionSuffix);
|
|
1656
|
+
lines.push(unionResult.code);
|
|
1657
|
+
lines.push('');
|
|
1658
|
+
const configToOutputType = new Map();
|
|
1659
|
+
const outputTypesToGenerate = [];
|
|
1660
|
+
for (const configInfo of unionResult.configTypes) {
|
|
1661
|
+
let matchingSchema = configInfo.resource && configInfo.operation
|
|
1662
|
+
? findSchemaForOperation(outputSchemas, configInfo.resource, configInfo.operation)
|
|
1663
|
+
: undefined;
|
|
1664
|
+
if (!matchingSchema && !configInfo.resource && !configInfo.operation) {
|
|
1665
|
+
matchingSchema = outputSchemas.find((s) => s.resource === '');
|
|
1666
|
+
}
|
|
1667
|
+
if (matchingSchema) {
|
|
1668
|
+
let outputTypeName = configInfo.typeName.replace(/Params$/, 'Output');
|
|
1669
|
+
if (outputTypeName === configInfo.typeName) {
|
|
1670
|
+
outputTypeName = `${configInfo.typeName}Output`;
|
|
1671
|
+
}
|
|
1672
|
+
outputTypesToGenerate.push({ typeName: outputTypeName, schema: matchingSchema.schema });
|
|
1673
|
+
configToOutputType.set(configInfo.typeName, outputTypeName);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
if (outputTypesToGenerate.length > 0) {
|
|
1677
|
+
for (const { typeName, schema } of outputTypesToGenerate) {
|
|
1678
|
+
lines.push(`export type ${typeName} = ${jsonSchemaToTypeScript(schema)};`);
|
|
1679
|
+
lines.push('');
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
if (subnodeConfigTypeName) {
|
|
1683
|
+
const subnodeConfigCode = generateNarrowedSubnodeConfig(aiInputTypes, nodeName, versionSuffix);
|
|
1684
|
+
if (subnodeConfigCode) {
|
|
1685
|
+
lines.push(subnodeConfigCode);
|
|
1686
|
+
lines.push('');
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
const credTypeName = node.credentials && node.credentials.length > 0
|
|
1690
|
+
? `${nodeName}${versionSuffix}Credentials`
|
|
1691
|
+
: undefined;
|
|
1692
|
+
if (node.credentials && node.credentials.length > 0) {
|
|
1693
|
+
lines.push(`export interface ${credTypeName} {`);
|
|
1694
|
+
const seenCreds = new Set();
|
|
1695
|
+
for (const cred of node.credentials) {
|
|
1696
|
+
if (seenCreds.has(cred.name))
|
|
1697
|
+
continue;
|
|
1698
|
+
seenCreds.add(cred.name);
|
|
1699
|
+
const optional = !cred.required ? '?' : '';
|
|
1700
|
+
lines.push(`${INDENT}${cred.name}${optional}: CredentialReference;`);
|
|
1701
|
+
}
|
|
1702
|
+
const hasGenericAuthType = node.properties.some((p) => p.name === 'genericAuthType' && p.type === 'credentialsSelect');
|
|
1703
|
+
if (hasGenericAuthType) {
|
|
1704
|
+
lines.push(`${INDENT}/** Generic auth credentials - set the 'genericAuthType' config parameter to select which one to use */`);
|
|
1705
|
+
for (const credName of GENERIC_AUTH_TYPE_VALUES) {
|
|
1706
|
+
if (!seenCreds.has(credName)) {
|
|
1707
|
+
seenCreds.add(credName);
|
|
1708
|
+
lines.push(`${INDENT}${credName}?: CredentialReference;`);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
lines.push('}');
|
|
1713
|
+
lines.push('');
|
|
1714
|
+
}
|
|
1715
|
+
const baseTypeName = `${nodeName}${versionSuffix}NodeBase`;
|
|
1716
|
+
lines.push(`interface ${baseTypeName} {`);
|
|
1717
|
+
lines.push(`${INDENT}type: '${node.name}';`);
|
|
1718
|
+
lines.push(`${INDENT}version: ${specificVersion};`);
|
|
1719
|
+
if (credTypeName) {
|
|
1720
|
+
lines.push(`${INDENT}credentials?: ${credTypeName};`);
|
|
1721
|
+
}
|
|
1722
|
+
if (isTrigger) {
|
|
1723
|
+
lines.push(`${INDENT}isTrigger: true;`);
|
|
1724
|
+
}
|
|
1725
|
+
lines.push('}');
|
|
1726
|
+
lines.push('');
|
|
1727
|
+
const individualNodeTypes = [];
|
|
1728
|
+
for (const configInfo of unionResult.configTypes) {
|
|
1729
|
+
const outputTypeName = configToOutputType.get(configInfo.typeName);
|
|
1730
|
+
const individualTypeName = configInfo.typeName.replace(/Config$/, 'Node');
|
|
1731
|
+
const finalTypeName = individualTypeName === configInfo.typeName
|
|
1732
|
+
? `${configInfo.typeName}Node`
|
|
1733
|
+
: individualTypeName;
|
|
1734
|
+
individualNodeTypes.push(finalTypeName);
|
|
1735
|
+
lines.push(`export type ${finalTypeName} = ${baseTypeName} & {`);
|
|
1736
|
+
if (subnodeConfigTypeName) {
|
|
1737
|
+
const hasRequiredSubnodes = aiInputTypes.some((input) => input.required);
|
|
1738
|
+
const subnodeOptionalMark = hasRequiredSubnodes ? '' : '?';
|
|
1739
|
+
lines.push(`${INDENT}config: NodeConfig<${configInfo.typeName}> & { subnodes${subnodeOptionalMark}: ${subnodeConfigTypeName} };`);
|
|
1740
|
+
}
|
|
1741
|
+
else {
|
|
1742
|
+
lines.push(`${INDENT}config: NodeConfig<${configInfo.typeName}>;`);
|
|
1743
|
+
}
|
|
1744
|
+
if (outputTypeName) {
|
|
1745
|
+
lines.push(`${INDENT}output?: Items<${outputTypeName}>;`);
|
|
1746
|
+
}
|
|
1747
|
+
lines.push('};');
|
|
1748
|
+
lines.push('');
|
|
1749
|
+
}
|
|
1750
|
+
const nodeTypeName = `${nodeName}${versionSuffix}Node`;
|
|
1751
|
+
if (individualNodeTypes.length === 1) {
|
|
1752
|
+
lines.push(`export type ${nodeTypeName} = ${individualNodeTypes[0]};`);
|
|
1753
|
+
}
|
|
1754
|
+
else if (individualNodeTypes.length > 1) {
|
|
1755
|
+
lines.push(`export type ${nodeTypeName} =`);
|
|
1756
|
+
for (let i = 0; i < individualNodeTypes.length; i++) {
|
|
1757
|
+
lines.push(`${INDENT}| ${individualNodeTypes[i]}`);
|
|
1758
|
+
}
|
|
1759
|
+
lines.push(`${INDENT};`);
|
|
1760
|
+
}
|
|
1761
|
+
else {
|
|
1762
|
+
lines.push(`export type ${nodeTypeName} = ${baseTypeName} & {`);
|
|
1763
|
+
lines.push(`${INDENT}config: NodeConfig<Record<string, unknown>>;`);
|
|
1764
|
+
lines.push('};');
|
|
1765
|
+
}
|
|
1766
|
+
return lines.join('\n');
|
|
1767
|
+
}
|
|
1768
|
+
function generateVersionIndexFile(node, versions, splitVersions = new Set()) {
|
|
1769
|
+
const prefix = getPackagePrefix(node.name);
|
|
1770
|
+
const typeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1771
|
+
const sortedVersions = [...versions].sort((a, b) => b - a);
|
|
1772
|
+
const lines = [];
|
|
1773
|
+
lines.push('/**');
|
|
1774
|
+
lines.push(` * ${node.displayName} Node Types`);
|
|
1775
|
+
lines.push(' *');
|
|
1776
|
+
lines.push(' * Re-exports all version-specific types and provides combined union type.');
|
|
1777
|
+
lines.push(' */');
|
|
1778
|
+
lines.push('');
|
|
1779
|
+
const nodeTypeNames = [];
|
|
1780
|
+
for (const version of sortedVersions) {
|
|
1781
|
+
const fileName = versionToFileName(version);
|
|
1782
|
+
const versionSuffix = versionToTypeName(version);
|
|
1783
|
+
const nodeTypeName = `${typeName}${versionSuffix}Node`;
|
|
1784
|
+
nodeTypeNames.push(nodeTypeName);
|
|
1785
|
+
const importPath = splitVersions.has(version) ? `./${fileName}` : `./${fileName}`;
|
|
1786
|
+
lines.push(`import type { ${nodeTypeName} } from '${importPath}';`);
|
|
1787
|
+
}
|
|
1788
|
+
lines.push('');
|
|
1789
|
+
for (const version of sortedVersions) {
|
|
1790
|
+
const fileName = versionToFileName(version);
|
|
1791
|
+
lines.push(`export * from './${fileName}';`);
|
|
1792
|
+
}
|
|
1793
|
+
lines.push('');
|
|
1794
|
+
lines.push('// Combined union type for all versions');
|
|
1795
|
+
lines.push(`export type ${typeName}Node = ${nodeTypeNames.join(' | ')};`);
|
|
1796
|
+
return lines.join('\n');
|
|
1797
|
+
}
|
|
1798
|
+
function generateNodeTypeFile(nodes) {
|
|
1799
|
+
const nodeArray = Array.isArray(nodes) ? nodes : [nodes];
|
|
1800
|
+
const node = nodeArray[0];
|
|
1801
|
+
const prefix = getPackagePrefix(node.name);
|
|
1802
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
1803
|
+
const isTrigger = isTriggerNode(node);
|
|
1804
|
+
const allVersions = [];
|
|
1805
|
+
for (const n of nodeArray) {
|
|
1806
|
+
const versions = Array.isArray(n.version) ? n.version : [n.version];
|
|
1807
|
+
allVersions.push(...versions);
|
|
1808
|
+
}
|
|
1809
|
+
const lines = [];
|
|
1810
|
+
lines.push(generateNodeJSDoc(node));
|
|
1811
|
+
lines.push('');
|
|
1812
|
+
lines.push('');
|
|
1813
|
+
const outputProps = nodeArray.flatMap((n) => n.properties.filter((p) => !['notice', 'curlImport', 'credentials'].includes(p.type)));
|
|
1814
|
+
const needsFilter = outputProps.some((p) => p.type === 'filter');
|
|
1815
|
+
const needsAssignment = outputProps.some((p) => p.type === 'assignmentCollection');
|
|
1816
|
+
if (needsFilter || needsAssignment) {
|
|
1817
|
+
lines.push('// Helper types for special n8n fields');
|
|
1818
|
+
if (needsFilter) {
|
|
1819
|
+
lines.push(generateFilterTypeDeclaration(false));
|
|
1820
|
+
}
|
|
1821
|
+
if (needsAssignment) {
|
|
1822
|
+
lines.push(generateAssignmentTypeDeclarations(false));
|
|
1823
|
+
}
|
|
1824
|
+
lines.push('');
|
|
1825
|
+
}
|
|
1826
|
+
const sortedNodes = [...nodeArray].sort((a, b) => {
|
|
1827
|
+
const aHighest = getHighestVersion(a.version);
|
|
1828
|
+
const bHighest = getHighestVersion(b.version);
|
|
1829
|
+
return bHighest - aHighest;
|
|
1830
|
+
});
|
|
1831
|
+
for (const n of sortedNodes) {
|
|
1832
|
+
const entryVersion = getHighestVersion(n.version);
|
|
1833
|
+
const entryVersionSuffix = versionToTypeName(entryVersion);
|
|
1834
|
+
const unionResult = generateDiscriminatedUnionForEntry(n, nodeName, entryVersionSuffix);
|
|
1835
|
+
lines.push(unionResult.code);
|
|
1836
|
+
lines.push('');
|
|
1837
|
+
}
|
|
1838
|
+
const allCredentials = [];
|
|
1839
|
+
const seenCreds = new Set();
|
|
1840
|
+
for (const n of nodeArray) {
|
|
1841
|
+
if (n.credentials) {
|
|
1842
|
+
for (const cred of n.credentials) {
|
|
1843
|
+
if (!seenCreds.has(cred.name)) {
|
|
1844
|
+
seenCreds.add(cred.name);
|
|
1845
|
+
allCredentials.push(cred);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
for (const n of sortedNodes) {
|
|
1851
|
+
const entryVersion = getHighestVersion(n.version);
|
|
1852
|
+
const entryVersionSuffix = versionToTypeName(entryVersion);
|
|
1853
|
+
if (n.credentials && n.credentials.length > 0) {
|
|
1854
|
+
lines.push(`export interface ${nodeName}${entryVersionSuffix}Credentials {`);
|
|
1855
|
+
const seenCreds = new Set();
|
|
1856
|
+
for (const cred of n.credentials) {
|
|
1857
|
+
if (seenCreds.has(cred.name))
|
|
1858
|
+
continue;
|
|
1859
|
+
seenCreds.add(cred.name);
|
|
1860
|
+
const optional = !cred.required ? '?' : '';
|
|
1861
|
+
lines.push(`${INDENT}${cred.name}${optional}: CredentialReference;`);
|
|
1862
|
+
}
|
|
1863
|
+
const hasGenericAuthType = n.properties.some((p) => p.name === 'genericAuthType' && p.type === 'credentialsSelect');
|
|
1864
|
+
if (hasGenericAuthType) {
|
|
1865
|
+
lines.push(`${INDENT}/** Generic auth credentials - set the 'genericAuthType' config parameter to select which one to use */`);
|
|
1866
|
+
for (const credName of GENERIC_AUTH_TYPE_VALUES) {
|
|
1867
|
+
if (!seenCreds.has(credName)) {
|
|
1868
|
+
seenCreds.add(credName);
|
|
1869
|
+
lines.push(`${INDENT}${credName}?: CredentialReference;`);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
lines.push('}');
|
|
1874
|
+
lines.push('');
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
const nodeTypeNames = [];
|
|
1878
|
+
for (const n of sortedNodes) {
|
|
1879
|
+
const entryVersion = getHighestVersion(n.version);
|
|
1880
|
+
const entryVersionSuffix = versionToTypeName(entryVersion);
|
|
1881
|
+
const versions = Array.isArray(n.version) ? n.version : [n.version];
|
|
1882
|
+
const versionUnion = versions
|
|
1883
|
+
.sort((a, b) => a - b)
|
|
1884
|
+
.map((v) => String(v))
|
|
1885
|
+
.join(' | ');
|
|
1886
|
+
const nodeTypeName = `${nodeName}${entryVersionSuffix}Node`;
|
|
1887
|
+
nodeTypeNames.push(nodeTypeName);
|
|
1888
|
+
const credType = n.credentials && n.credentials.length > 0
|
|
1889
|
+
? `${nodeName}${entryVersionSuffix}Credentials`
|
|
1890
|
+
: 'Record<string, never>';
|
|
1891
|
+
lines.push(`export type ${nodeTypeName} = {`);
|
|
1892
|
+
lines.push(`${INDENT}type: '${n.name}';`);
|
|
1893
|
+
lines.push(`${INDENT}version: ${versionUnion};`);
|
|
1894
|
+
lines.push(`${INDENT}config: NodeConfig<${nodeName}${entryVersionSuffix}Params>;`);
|
|
1895
|
+
lines.push(`${INDENT}credentials?: ${credType};`);
|
|
1896
|
+
if (isTrigger) {
|
|
1897
|
+
lines.push(`${INDENT}isTrigger: true;`);
|
|
1898
|
+
}
|
|
1899
|
+
lines.push('};');
|
|
1900
|
+
lines.push('');
|
|
1901
|
+
}
|
|
1902
|
+
lines.push(`export type ${nodeName}Node = ${nodeTypeNames.join(' | ')};`);
|
|
1903
|
+
return lines.join('\n');
|
|
1904
|
+
}
|
|
1905
|
+
function generateDiscriminatedUnionForEntry(node, nodeName, versionSuffix) {
|
|
1906
|
+
const combinations = extractDiscriminatorCombinations(node);
|
|
1907
|
+
const lines = [];
|
|
1908
|
+
const configTypes = [];
|
|
1909
|
+
if (combinations.length === 0) {
|
|
1910
|
+
const configName = `${nodeName}${versionSuffix}Params`;
|
|
1911
|
+
lines.push(`export interface ${configName} {`);
|
|
1912
|
+
const mergedProps = mergeCollectionProperties(node.properties);
|
|
1913
|
+
for (const prop of mergedProps) {
|
|
1914
|
+
const propLine = generatePropertyLine(prop, isPropertyOptional(prop));
|
|
1915
|
+
if (propLine) {
|
|
1916
|
+
lines.push(propLine);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
lines.push('}');
|
|
1920
|
+
configTypes.push({
|
|
1921
|
+
typeName: configName,
|
|
1922
|
+
discriminators: {},
|
|
1923
|
+
});
|
|
1924
|
+
return {
|
|
1925
|
+
code: lines.join('\n'),
|
|
1926
|
+
configTypes,
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
const configTypeNames = [];
|
|
1930
|
+
for (const combo of combinations) {
|
|
1931
|
+
const comboValues = Object.entries(combo)
|
|
1932
|
+
.filter(([_, v]) => v !== undefined)
|
|
1933
|
+
.map(([_, v]) => toPascalCase(v));
|
|
1934
|
+
const configName = `${nodeName}${versionSuffix}${comboValues.join('')}Params`;
|
|
1935
|
+
configTypeNames.push(configName);
|
|
1936
|
+
const configInfo = {
|
|
1937
|
+
typeName: configName,
|
|
1938
|
+
resource: combo.resource,
|
|
1939
|
+
operation: combo.operation,
|
|
1940
|
+
discriminators: {},
|
|
1941
|
+
};
|
|
1942
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1943
|
+
if (value !== undefined) {
|
|
1944
|
+
configInfo.discriminators[key] = value;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
configTypes.push(configInfo);
|
|
1948
|
+
const props = getPropertiesForCombination(node, combo);
|
|
1949
|
+
let description;
|
|
1950
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1951
|
+
if (value === undefined)
|
|
1952
|
+
continue;
|
|
1953
|
+
const discProp = node.properties.find((p) => p.name === key && p.options?.some((o) => o.value === value));
|
|
1954
|
+
if (discProp) {
|
|
1955
|
+
description = discProp.options?.find((o) => o.value === value)?.description;
|
|
1956
|
+
if (description)
|
|
1957
|
+
break;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
if (description) {
|
|
1961
|
+
lines.push(`/** ${description} */`);
|
|
1962
|
+
}
|
|
1963
|
+
lines.push(`export type ${configName} = {`);
|
|
1964
|
+
for (const [key, value] of Object.entries(combo)) {
|
|
1965
|
+
if (value !== undefined) {
|
|
1966
|
+
lines.push(`${INDENT}${key}: '${value}';`);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
const seenNames = new Set();
|
|
1970
|
+
for (const prop of props) {
|
|
1971
|
+
if (seenNames.has(prop.name)) {
|
|
1972
|
+
continue;
|
|
1973
|
+
}
|
|
1974
|
+
seenNames.add(prop.name);
|
|
1975
|
+
const propLine = generatePropertyLine(prop, isPropertyOptional(prop), combo);
|
|
1976
|
+
if (propLine) {
|
|
1977
|
+
lines.push(propLine);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
lines.push('};');
|
|
1981
|
+
lines.push('');
|
|
1982
|
+
}
|
|
1983
|
+
return {
|
|
1984
|
+
code: lines.join('\n'),
|
|
1985
|
+
configTypes,
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
function generateIndexFile(nodes) {
|
|
1989
|
+
const lines = [];
|
|
1990
|
+
lines.push('/**');
|
|
1991
|
+
lines.push(' * Generated Node Types');
|
|
1992
|
+
lines.push(' *');
|
|
1993
|
+
lines.push(' * This file is auto-generated by scripts/generate-types.ts');
|
|
1994
|
+
lines.push(' * Do not edit manually.');
|
|
1995
|
+
lines.push(' *');
|
|
1996
|
+
lines.push(' * To regenerate:');
|
|
1997
|
+
lines.push(' * pnpm generate-types');
|
|
1998
|
+
lines.push(' */');
|
|
1999
|
+
lines.push('');
|
|
2000
|
+
const byPackage = new Map();
|
|
2001
|
+
for (const node of nodes) {
|
|
2002
|
+
const pkg = getPackageName(node.name);
|
|
2003
|
+
if (!byPackage.has(pkg)) {
|
|
2004
|
+
byPackage.set(pkg, []);
|
|
2005
|
+
}
|
|
2006
|
+
byPackage.get(pkg).push(node);
|
|
2007
|
+
}
|
|
2008
|
+
lines.push('// Import node types for AllNodeTypes union');
|
|
2009
|
+
const sortedNodes = [...nodes].sort((a, b) => a.name.localeCompare(b.name));
|
|
2010
|
+
for (const [pkg, pkgNodes] of byPackage) {
|
|
2011
|
+
const sortedPkgNodes = pkgNodes.sort((a, b) => a.name.localeCompare(b.name));
|
|
2012
|
+
for (const node of sortedPkgNodes) {
|
|
2013
|
+
const fileName = nodeNameToFileName(node.name);
|
|
2014
|
+
const prefix = getPackagePrefix(node.name);
|
|
2015
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
2016
|
+
lines.push(`import type { ${nodeName}Node } from './nodes/${pkg}/${fileName}';`);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
lines.push('');
|
|
2020
|
+
for (const [pkg, pkgNodes] of byPackage) {
|
|
2021
|
+
lines.push(`// ${pkg}`);
|
|
2022
|
+
for (const node of pkgNodes.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
2023
|
+
const fileName = nodeNameToFileName(node.name);
|
|
2024
|
+
lines.push(`export * from './nodes/${pkg}/${fileName}';`);
|
|
2025
|
+
}
|
|
2026
|
+
lines.push('');
|
|
2027
|
+
}
|
|
2028
|
+
lines.push('// Combined type union of node type strings');
|
|
2029
|
+
lines.push('export type KnownNodeType =');
|
|
2030
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
2031
|
+
lines.push(`${INDENT}| '${nodes[i].name}'`);
|
|
2032
|
+
}
|
|
2033
|
+
lines.push(`${INDENT};`);
|
|
2034
|
+
lines.push('');
|
|
2035
|
+
lines.push('// Union of all node input types for type-safe node() function');
|
|
2036
|
+
lines.push('export type AllNodeTypes =');
|
|
2037
|
+
for (let i = 0; i < sortedNodes.length; i++) {
|
|
2038
|
+
const node = sortedNodes[i];
|
|
2039
|
+
const prefix = getPackagePrefix(node.name);
|
|
2040
|
+
const nodeName = prefix + toPascalCase(getNodeBaseName(node.name));
|
|
2041
|
+
lines.push(`${INDENT}| ${nodeName}Node`);
|
|
2042
|
+
}
|
|
2043
|
+
lines.push(`${INDENT};`);
|
|
2044
|
+
return lines.join('\n');
|
|
2045
|
+
}
|
|
2046
|
+
const AI_SUBNODE_TYPES = [
|
|
2047
|
+
{
|
|
2048
|
+
outputType: 'ai_languageModel',
|
|
2049
|
+
unionTypeName: 'ValidLanguageModelType',
|
|
2050
|
+
factoryName: 'languageModel',
|
|
2051
|
+
},
|
|
2052
|
+
{ outputType: 'ai_memory', unionTypeName: 'ValidMemoryType', factoryName: 'memory' },
|
|
2053
|
+
{ outputType: 'ai_tool', unionTypeName: 'ValidToolType', factoryName: 'tool' },
|
|
2054
|
+
{
|
|
2055
|
+
outputType: 'ai_outputParser',
|
|
2056
|
+
unionTypeName: 'ValidOutputParserType',
|
|
2057
|
+
factoryName: 'outputParser',
|
|
2058
|
+
},
|
|
2059
|
+
{ outputType: 'ai_embedding', unionTypeName: 'ValidEmbeddingType', factoryName: 'embedding' },
|
|
2060
|
+
{
|
|
2061
|
+
outputType: 'ai_vectorStore',
|
|
2062
|
+
unionTypeName: 'ValidVectorStoreType',
|
|
2063
|
+
factoryName: 'vectorStore',
|
|
2064
|
+
},
|
|
2065
|
+
{ outputType: 'ai_retriever', unionTypeName: 'ValidRetrieverType', factoryName: 'retriever' },
|
|
2066
|
+
{
|
|
2067
|
+
outputType: 'ai_document',
|
|
2068
|
+
unionTypeName: 'ValidDocumentLoaderType',
|
|
2069
|
+
factoryName: 'documentLoader',
|
|
2070
|
+
},
|
|
2071
|
+
{
|
|
2072
|
+
outputType: 'ai_textSplitter',
|
|
2073
|
+
unionTypeName: 'ValidTextSplitterType',
|
|
2074
|
+
factoryName: 'textSplitter',
|
|
2075
|
+
},
|
|
2076
|
+
];
|
|
2077
|
+
function extractAIInputTypes(node) {
|
|
2078
|
+
const inputs = node.inputs;
|
|
2079
|
+
const aiTypes = new Map();
|
|
2080
|
+
if (typeof inputs === 'string') {
|
|
2081
|
+
const aiTypeRegex = /["']ai_(\w+)["']/g;
|
|
2082
|
+
let match;
|
|
2083
|
+
while ((match = aiTypeRegex.exec(inputs)) !== null) {
|
|
2084
|
+
const aiType = `ai_${match[1]}`;
|
|
2085
|
+
const requiredRegex = new RegExp(`\\{[^}]*type:\\s*["']${aiType}["'][^}]*required:\\s*true[^}]*\\}`, 'g');
|
|
2086
|
+
const isRequired = requiredRegex.test(inputs);
|
|
2087
|
+
if (!aiTypes.has(aiType) || isRequired) {
|
|
2088
|
+
aiTypes.set(aiType, isRequired);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
return [...aiTypes.entries()].map(([type, required]) => ({ type, required }));
|
|
2092
|
+
}
|
|
2093
|
+
if (!Array.isArray(inputs)) {
|
|
2094
|
+
return [];
|
|
2095
|
+
}
|
|
2096
|
+
for (const input of inputs) {
|
|
2097
|
+
let inputType;
|
|
2098
|
+
let isRequired = false;
|
|
2099
|
+
if (typeof input === 'string') {
|
|
2100
|
+
inputType = input;
|
|
2101
|
+
}
|
|
2102
|
+
else if (typeof input === 'object' && input !== null && 'type' in input) {
|
|
2103
|
+
inputType = input.type;
|
|
2104
|
+
if ('required' in input && input.required === true) {
|
|
2105
|
+
isRequired = true;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
if (inputType?.startsWith('ai_')) {
|
|
2109
|
+
const existingRequired = aiTypes.get(inputType) ?? false;
|
|
2110
|
+
aiTypes.set(inputType, existingRequired || isRequired);
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
return [...aiTypes.entries()].map(([type, required]) => ({ type, required }));
|
|
2114
|
+
}
|
|
2115
|
+
function extractAIInputTypesFromBuilderHint(node, combo) {
|
|
2116
|
+
const nodeWithBuilderHint = node;
|
|
2117
|
+
const builderHint = nodeWithBuilderHint.builderHint;
|
|
2118
|
+
if (!builderHint?.inputs) {
|
|
2119
|
+
return extractAIInputTypes(node).map((input) => ({
|
|
2120
|
+
...input,
|
|
2121
|
+
required: false,
|
|
2122
|
+
}));
|
|
2123
|
+
}
|
|
2124
|
+
const result = [];
|
|
2125
|
+
for (const [inputType, config] of Object.entries(builderHint.inputs)) {
|
|
2126
|
+
if (!inputType.startsWith('ai_'))
|
|
2127
|
+
continue;
|
|
2128
|
+
if (combo && config.displayOptions?.show) {
|
|
2129
|
+
let applies = true;
|
|
2130
|
+
for (const [key, values] of Object.entries(config.displayOptions.show)) {
|
|
2131
|
+
if (DISCRIMINATOR_FIELDS.includes(key) && combo[key]) {
|
|
2132
|
+
const comboValue = combo[key];
|
|
2133
|
+
if (!values.includes(comboValue)) {
|
|
2134
|
+
applies = false;
|
|
2135
|
+
break;
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
if (!applies)
|
|
2140
|
+
continue;
|
|
2141
|
+
}
|
|
2142
|
+
const isRequired = config.required === true;
|
|
2143
|
+
const nonDiscriminatorOptions = getNonDiscriminatorDisplayOptions(config.displayOptions);
|
|
2144
|
+
const aiInput = {
|
|
2145
|
+
type: inputType,
|
|
2146
|
+
required: isRequired,
|
|
2147
|
+
};
|
|
2148
|
+
if (nonDiscriminatorOptions) {
|
|
2149
|
+
aiInput.displayOptions = nonDiscriminatorOptions;
|
|
2150
|
+
}
|
|
2151
|
+
result.push(aiInput);
|
|
2152
|
+
}
|
|
2153
|
+
return result;
|
|
2154
|
+
}
|
|
2155
|
+
function getNonDiscriminatorDisplayOptions(displayOptions) {
|
|
2156
|
+
if (!displayOptions)
|
|
2157
|
+
return undefined;
|
|
2158
|
+
const result = {};
|
|
2159
|
+
if (displayOptions.show) {
|
|
2160
|
+
const filteredShow = {};
|
|
2161
|
+
for (const [key, values] of Object.entries(displayOptions.show)) {
|
|
2162
|
+
if (!DISCRIMINATOR_FIELDS.includes(key)) {
|
|
2163
|
+
filteredShow[key] = values;
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
if (Object.keys(filteredShow).length > 0) {
|
|
2167
|
+
result.show = filteredShow;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
if (displayOptions.hide) {
|
|
2171
|
+
const filteredHide = {};
|
|
2172
|
+
for (const [key, values] of Object.entries(displayOptions.hide)) {
|
|
2173
|
+
if (!DISCRIMINATOR_FIELDS.includes(key)) {
|
|
2174
|
+
filteredHide[key] = values;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
if (Object.keys(filteredHide).length > 0) {
|
|
2178
|
+
result.hide = filteredHide;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
if (!result.show && !result.hide) {
|
|
2182
|
+
return undefined;
|
|
2183
|
+
}
|
|
2184
|
+
return result;
|
|
2185
|
+
}
|
|
2186
|
+
function formatSubnodeDisplayOptionsAsJSDoc(displayOptions) {
|
|
2187
|
+
if (!displayOptions)
|
|
2188
|
+
return undefined;
|
|
2189
|
+
const parts = [];
|
|
2190
|
+
if (displayOptions.show && Object.keys(displayOptions.show).length > 0) {
|
|
2191
|
+
const showObj = Object.entries(displayOptions.show)
|
|
2192
|
+
.map(([key, values]) => `${key}: ${JSON.stringify(values)}`)
|
|
2193
|
+
.join(', ');
|
|
2194
|
+
parts.push(`@displayOptions.show { ${showObj} }`);
|
|
2195
|
+
}
|
|
2196
|
+
if (displayOptions.hide && Object.keys(displayOptions.hide).length > 0) {
|
|
2197
|
+
const hideObj = Object.entries(displayOptions.hide)
|
|
2198
|
+
.map(([key, values]) => `${key}: ${JSON.stringify(values)}`)
|
|
2199
|
+
.join(', ');
|
|
2200
|
+
parts.push(`@displayOptions.hide { ${hideObj} }`);
|
|
2201
|
+
}
|
|
2202
|
+
return parts.length > 0 ? parts.join(`\n${INDENT} * `) : undefined;
|
|
2203
|
+
}
|
|
2204
|
+
function generateNarrowedSubnodeConfig(aiInputTypes, nodeName, versionSuffix, comboSuffix = '') {
|
|
2205
|
+
if (aiInputTypes.length === 0) {
|
|
2206
|
+
return null;
|
|
2207
|
+
}
|
|
2208
|
+
const lines = [];
|
|
2209
|
+
const interfaceName = `${nodeName}${versionSuffix}${comboSuffix}SubnodeConfig`;
|
|
2210
|
+
lines.push(`export interface ${interfaceName} {`);
|
|
2211
|
+
for (const aiInput of aiInputTypes) {
|
|
2212
|
+
const fieldInfo = AI_TYPE_TO_SUBNODE_FIELD[aiInput.type];
|
|
2213
|
+
if (!fieldInfo) {
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
let typeStr;
|
|
2217
|
+
if (fieldInfo.isArray) {
|
|
2218
|
+
typeStr = `${fieldInfo.instanceType}[]`;
|
|
2219
|
+
}
|
|
2220
|
+
else if (fieldInfo.canBeMultiple) {
|
|
2221
|
+
typeStr = `${fieldInfo.instanceType} | ${fieldInfo.instanceType}[]`;
|
|
2222
|
+
}
|
|
2223
|
+
else {
|
|
2224
|
+
typeStr = fieldInfo.instanceType;
|
|
2225
|
+
}
|
|
2226
|
+
if (aiInput.displayOptions) {
|
|
2227
|
+
const displayOptionsJSDoc = formatSubnodeDisplayOptionsAsJSDoc(aiInput.displayOptions);
|
|
2228
|
+
if (displayOptionsJSDoc) {
|
|
2229
|
+
lines.push(`${INDENT}/**`);
|
|
2230
|
+
lines.push(`${INDENT} * ${displayOptionsJSDoc}`);
|
|
2231
|
+
lines.push(`${INDENT} */`);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
const optional = aiInput.required ? '' : '?';
|
|
2235
|
+
lines.push(`${INDENT}${fieldInfo.fieldName}${optional}: ${typeStr};`);
|
|
2236
|
+
}
|
|
2237
|
+
lines.push('}');
|
|
2238
|
+
return lines.join('\n');
|
|
2239
|
+
}
|
|
2240
|
+
function getSubnodeInstanceTypeImports(aiInputTypes) {
|
|
2241
|
+
const imports = [];
|
|
2242
|
+
for (const aiInput of aiInputTypes) {
|
|
2243
|
+
const fieldInfo = AI_TYPE_TO_SUBNODE_FIELD[aiInput.type];
|
|
2244
|
+
if (fieldInfo && !imports.includes(fieldInfo.instanceType)) {
|
|
2245
|
+
imports.push(fieldInfo.instanceType);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
return imports;
|
|
2249
|
+
}
|
|
2250
|
+
function extractOutputTypes(node) {
|
|
2251
|
+
const outputs = node.outputs;
|
|
2252
|
+
if (!Array.isArray(outputs)) {
|
|
2253
|
+
return [];
|
|
2254
|
+
}
|
|
2255
|
+
const outputTypes = [];
|
|
2256
|
+
for (const output of outputs) {
|
|
2257
|
+
if (typeof output === 'string') {
|
|
2258
|
+
outputTypes.push(output);
|
|
2259
|
+
}
|
|
2260
|
+
else if (typeof output === 'object' && output !== null && 'type' in output) {
|
|
2261
|
+
outputTypes.push(output.type);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
return outputTypes;
|
|
2265
|
+
}
|
|
2266
|
+
function groupNodesByOutputType(nodes) {
|
|
2267
|
+
const grouped = {};
|
|
2268
|
+
for (const node of nodes) {
|
|
2269
|
+
const outputTypes = extractOutputTypes(node);
|
|
2270
|
+
for (const outputType of outputTypes) {
|
|
2271
|
+
if (!grouped[outputType]) {
|
|
2272
|
+
grouped[outputType] = [];
|
|
2273
|
+
}
|
|
2274
|
+
if (!grouped[outputType].includes(node.name)) {
|
|
2275
|
+
grouped[outputType].push(node.name);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
return grouped;
|
|
2280
|
+
}
|
|
2281
|
+
function generateSubnodeUnionTypes(nodes) {
|
|
2282
|
+
const grouped = groupNodesByOutputType(nodes);
|
|
2283
|
+
const lines = [];
|
|
2284
|
+
for (const { outputType, unionTypeName, factoryName } of AI_SUBNODE_TYPES) {
|
|
2285
|
+
const nodeNames = grouped[outputType] ?? [];
|
|
2286
|
+
lines.push('/**');
|
|
2287
|
+
lines.push(` * Union of all valid ${outputType.replace('ai_', '')} node types.`);
|
|
2288
|
+
lines.push(` * Use with ${factoryName}() factory for type-safe subnode creation.`);
|
|
2289
|
+
lines.push(' */');
|
|
2290
|
+
if (nodeNames.length === 0) {
|
|
2291
|
+
lines.push(`export type ${unionTypeName} = never;`);
|
|
2292
|
+
}
|
|
2293
|
+
else {
|
|
2294
|
+
lines.push(`export type ${unionTypeName} =`);
|
|
2295
|
+
for (let i = 0; i < nodeNames.length; i++) {
|
|
2296
|
+
lines.push(`${INDENT}| '${nodeNames[i]}'`);
|
|
2297
|
+
}
|
|
2298
|
+
lines.push(`${INDENT};`);
|
|
2299
|
+
}
|
|
2300
|
+
lines.push('');
|
|
2301
|
+
}
|
|
2302
|
+
return lines.join('\n');
|
|
2303
|
+
}
|
|
2304
|
+
function generateSubnodesFile(nodes) {
|
|
2305
|
+
const lines = [];
|
|
2306
|
+
lines.push('/**');
|
|
2307
|
+
lines.push(' * Generated Subnode Union Types');
|
|
2308
|
+
lines.push(' *');
|
|
2309
|
+
lines.push(' * This file is auto-generated by scripts/generate-types.ts');
|
|
2310
|
+
lines.push(' * Do not edit manually.');
|
|
2311
|
+
lines.push(' *');
|
|
2312
|
+
lines.push(' * These union types define valid node types for each subnode category.');
|
|
2313
|
+
lines.push(' * Use with the corresponding factory functions for type-safe subnode creation.');
|
|
2314
|
+
lines.push(' */');
|
|
2315
|
+
lines.push('');
|
|
2316
|
+
lines.push(generateSubnodeUnionTypes(nodes));
|
|
2317
|
+
return lines.join('\n');
|
|
2318
|
+
}
|
|
2319
|
+
function getSubnodeOutputType(node) {
|
|
2320
|
+
const outputTypes = extractOutputTypes(node);
|
|
2321
|
+
for (const outputType of outputTypes) {
|
|
2322
|
+
if (AI_SUBNODE_TYPES.some((t) => t.outputType === outputType)) {
|
|
2323
|
+
return outputType;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
return undefined;
|
|
2327
|
+
}
|
|
2328
|
+
async function loadNodeTypes(jsonPath, packageName) {
|
|
2329
|
+
const content = await fs.promises.readFile(jsonPath, 'utf-8');
|
|
2330
|
+
let nodes;
|
|
2331
|
+
try {
|
|
2332
|
+
nodes = JSON.parse(content);
|
|
2333
|
+
}
|
|
2334
|
+
catch (error) {
|
|
2335
|
+
throw new Error(`Failed to parse node types from ${jsonPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2336
|
+
}
|
|
2337
|
+
if (packageName) {
|
|
2338
|
+
for (const node of nodes) {
|
|
2339
|
+
if (!node.name.includes('.')) {
|
|
2340
|
+
node.name = `${packageName}.${node.name}`;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
return nodes;
|
|
2345
|
+
}
|
|
2346
|
+
function convertNodeToToolVariant(node) {
|
|
2347
|
+
if (!node.usableAsTool) {
|
|
2348
|
+
return null;
|
|
2349
|
+
}
|
|
2350
|
+
const toolNode = (0, n8n_workflow_1.deepCopy)(node);
|
|
2351
|
+
toolNode.name = toolNode.name + 'Tool';
|
|
2352
|
+
toolNode.displayName = toolNode.displayName + ' Tool';
|
|
2353
|
+
toolNode.outputs = [{ type: 'ai_tool', displayName: 'Tool' }];
|
|
2354
|
+
toolNode.inputs = [];
|
|
2355
|
+
delete toolNode.usableAsTool;
|
|
2356
|
+
const hasToolDescription = toolNode.properties.some((p) => p.name === 'toolDescription');
|
|
2357
|
+
if (!hasToolDescription) {
|
|
2358
|
+
const hasResource = toolNode.properties.some((p) => p.name === 'resource');
|
|
2359
|
+
const hasOperation = toolNode.properties.some((p) => p.name === 'operation');
|
|
2360
|
+
const toolDescriptionProp = {
|
|
2361
|
+
displayName: 'Description',
|
|
2362
|
+
name: 'toolDescription',
|
|
2363
|
+
type: 'string',
|
|
2364
|
+
default: toolNode.description ?? '',
|
|
2365
|
+
required: true,
|
|
2366
|
+
description: 'Explain to the LLM what this tool does, a good, specific description would allow LLMs to produce expected results much more often',
|
|
2367
|
+
};
|
|
2368
|
+
if (hasResource || hasOperation) {
|
|
2369
|
+
const descriptionTypeProp = {
|
|
2370
|
+
displayName: 'Tool Description',
|
|
2371
|
+
name: 'descriptionType',
|
|
2372
|
+
type: 'options',
|
|
2373
|
+
options: [
|
|
2374
|
+
{
|
|
2375
|
+
name: 'Set Automatically',
|
|
2376
|
+
value: 'auto',
|
|
2377
|
+
description: 'Automatically set based on resource and operation',
|
|
2378
|
+
},
|
|
2379
|
+
{
|
|
2380
|
+
name: 'Set Manually',
|
|
2381
|
+
value: 'manual',
|
|
2382
|
+
description: 'Manually set the description',
|
|
2383
|
+
},
|
|
2384
|
+
],
|
|
2385
|
+
default: 'auto',
|
|
2386
|
+
};
|
|
2387
|
+
toolDescriptionProp.displayOptions = {
|
|
2388
|
+
show: {
|
|
2389
|
+
descriptionType: ['manual'],
|
|
2390
|
+
},
|
|
2391
|
+
};
|
|
2392
|
+
const firstNonNoticeIdx = toolNode.properties.findIndex((p) => p.type !== 'notice');
|
|
2393
|
+
const insertIdx = firstNonNoticeIdx >= 0 ? firstNonNoticeIdx : 0;
|
|
2394
|
+
toolNode.properties.splice(insertIdx, 0, descriptionTypeProp, toolDescriptionProp);
|
|
2395
|
+
}
|
|
2396
|
+
else {
|
|
2397
|
+
const firstNonNoticeIdx = toolNode.properties.findIndex((p) => p.type !== 'notice');
|
|
2398
|
+
const insertIdx = firstNonNoticeIdx >= 0 ? firstNonNoticeIdx : 0;
|
|
2399
|
+
toolNode.properties.splice(insertIdx, 0, toolDescriptionProp);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return toolNode;
|
|
2403
|
+
}
|
|
2404
|
+
const WRITE_BATCH_SIZE = 100;
|
|
2405
|
+
async function writeFilesInBatches(files) {
|
|
2406
|
+
for (let i = 0; i < files.length; i += WRITE_BATCH_SIZE) {
|
|
2407
|
+
const batch = files.slice(i, i + WRITE_BATCH_SIZE);
|
|
2408
|
+
await Promise.all(batch.map((f) => fs.promises.writeFile(f.path, f.content)));
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
async function generateVersionSpecificFiles(packageDir, _packageName, nodesByName) {
|
|
2412
|
+
const allNodes = [];
|
|
2413
|
+
const allDirs = new Set();
|
|
2414
|
+
const allWrites = [];
|
|
2415
|
+
const splitPlans = [];
|
|
2416
|
+
for (const [nodeName, nodes] of nodesByName) {
|
|
2417
|
+
try {
|
|
2418
|
+
const nodeDir = path.join(packageDir, nodeName);
|
|
2419
|
+
const nodeWrites = [];
|
|
2420
|
+
const nodeDirs = new Set([nodeDir]);
|
|
2421
|
+
const nodeSplitPlans = [];
|
|
2422
|
+
const versionToNode = new Map();
|
|
2423
|
+
const allVersions = [];
|
|
2424
|
+
const splitVersionsSet = new Set();
|
|
2425
|
+
for (const node of nodes) {
|
|
2426
|
+
const versions = Array.isArray(node.version) ? node.version : [node.version];
|
|
2427
|
+
for (const version of versions) {
|
|
2428
|
+
if (!versionToNode.has(version)) {
|
|
2429
|
+
versionToNode.set(version, node);
|
|
2430
|
+
allVersions.push(version);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
for (const version of allVersions) {
|
|
2435
|
+
const sourceNode = versionToNode.get(version);
|
|
2436
|
+
const fileName = versionToFileName(version);
|
|
2437
|
+
if (hasDiscriminatorPattern(sourceNode)) {
|
|
2438
|
+
const versionDir = path.join(nodeDir, fileName);
|
|
2439
|
+
const plan = planSplitVersionFiles(sourceNode, version);
|
|
2440
|
+
nodeSplitPlans.push({ baseDir: versionDir, plan });
|
|
2441
|
+
splitVersionsSet.add(version);
|
|
2442
|
+
}
|
|
2443
|
+
else {
|
|
2444
|
+
const content = generateSingleVersionTypeFile(sourceNode, version);
|
|
2445
|
+
nodeWrites.push({ path: path.join(nodeDir, `${fileName}.ts`), content });
|
|
2446
|
+
const schemaContent = (0, generate_zod_schemas_1.generateSingleVersionSchemaFile)(sourceNode, version);
|
|
2447
|
+
nodeWrites.push({
|
|
2448
|
+
path: path.join(nodeDir, `${fileName}.schema.js`),
|
|
2449
|
+
content: schemaContent,
|
|
2450
|
+
});
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
const indexContent = generateVersionIndexFile(nodes[0], allVersions, splitVersionsSet);
|
|
2454
|
+
nodeWrites.push({ path: path.join(nodeDir, 'index.ts'), content: indexContent });
|
|
2455
|
+
allWrites.push(...nodeWrites);
|
|
2456
|
+
for (const d of nodeDirs)
|
|
2457
|
+
allDirs.add(d);
|
|
2458
|
+
splitPlans.push(...nodeSplitPlans);
|
|
2459
|
+
allNodes.push(nodes[0]);
|
|
2460
|
+
}
|
|
2461
|
+
catch (error) {
|
|
2462
|
+
console.error(` Error generating ${nodeName}:`, error);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
for (const { baseDir, plan } of splitPlans) {
|
|
2466
|
+
for (const [relativePath, content] of plan) {
|
|
2467
|
+
const fullPath = path.join(baseDir, relativePath);
|
|
2468
|
+
allDirs.add(path.dirname(fullPath));
|
|
2469
|
+
allWrites.push({ path: fullPath, content });
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
await Promise.all([...allDirs].map((d) => fs.promises.mkdir(d, { recursive: true })));
|
|
2473
|
+
await writeFilesInBatches(allWrites);
|
|
2474
|
+
return allNodes;
|
|
2475
|
+
}
|
|
2476
|
+
async function orchestrateGeneration(options) {
|
|
2477
|
+
const { nodes, outputDir } = options;
|
|
2478
|
+
const nodesByPackage = new Map();
|
|
2479
|
+
for (const node of nodes) {
|
|
2480
|
+
if (node.hidden)
|
|
2481
|
+
continue;
|
|
2482
|
+
const packageName = getPackageName(node.name);
|
|
2483
|
+
const fileName = nodeNameToFileName(node.name);
|
|
2484
|
+
if (!nodesByPackage.has(packageName)) {
|
|
2485
|
+
nodesByPackage.set(packageName, new Map());
|
|
2486
|
+
}
|
|
2487
|
+
const packageNodes = nodesByPackage.get(packageName);
|
|
2488
|
+
if (!packageNodes.has(fileName)) {
|
|
2489
|
+
packageNodes.set(fileName, []);
|
|
2490
|
+
}
|
|
2491
|
+
packageNodes.get(fileName).push(node);
|
|
2492
|
+
}
|
|
2493
|
+
const allNodes = [];
|
|
2494
|
+
for (const [packageName, nodesByName] of nodesByPackage) {
|
|
2495
|
+
const packageDir = path.join(outputDir, 'nodes', packageName);
|
|
2496
|
+
await fs.promises.rm(packageDir, { recursive: true, force: true });
|
|
2497
|
+
const packageNodes = await generateVersionSpecificFiles(packageDir, packageName, nodesByName);
|
|
2498
|
+
allNodes.push(...packageNodes);
|
|
2499
|
+
}
|
|
2500
|
+
if (allNodes.length > 0) {
|
|
2501
|
+
const indexContent = generateIndexFile(allNodes);
|
|
2502
|
+
await fs.promises.writeFile(path.join(outputDir, 'index.ts'), indexContent);
|
|
2503
|
+
}
|
|
2504
|
+
return { nodeCount: allNodes.length };
|
|
2505
|
+
}
|
|
2506
|
+
async function generateTypes() {
|
|
2507
|
+
console.log('Starting type generation...');
|
|
2508
|
+
const allNodes = [];
|
|
2509
|
+
if (fs.existsSync(NODES_BASE_TYPES)) {
|
|
2510
|
+
console.log(`Loading nodes from ${NODES_BASE_TYPES}...`);
|
|
2511
|
+
const nodesBase = await loadNodeTypes(NODES_BASE_TYPES, 'n8n-nodes-base');
|
|
2512
|
+
console.log(` Found ${nodesBase.length} node entries in nodes-base`);
|
|
2513
|
+
allNodes.push(...groupAndAddToolVariants(nodesBase));
|
|
2514
|
+
}
|
|
2515
|
+
else {
|
|
2516
|
+
console.log(`Warning: ${NODES_BASE_TYPES} not found. Run 'pnpm build' in nodes-base first.`);
|
|
2517
|
+
}
|
|
2518
|
+
if (fs.existsSync(NODES_LANGCHAIN_TYPES)) {
|
|
2519
|
+
console.log(`Loading nodes from ${NODES_LANGCHAIN_TYPES}...`);
|
|
2520
|
+
const nodesLangchain = await loadNodeTypes(NODES_LANGCHAIN_TYPES, '@n8n/n8n-nodes-langchain');
|
|
2521
|
+
console.log(` Found ${nodesLangchain.length} node entries in nodes-langchain`);
|
|
2522
|
+
allNodes.push(...groupAndAddToolVariants(nodesLangchain));
|
|
2523
|
+
}
|
|
2524
|
+
else {
|
|
2525
|
+
console.log(`Warning: ${NODES_LANGCHAIN_TYPES} not found. Run 'pnpm build' in nodes-langchain first.`);
|
|
2526
|
+
}
|
|
2527
|
+
const result = await orchestrateGeneration({ nodes: allNodes, outputDir: DEV_OUTPUT_PATH });
|
|
2528
|
+
if (result.nodeCount === 0) {
|
|
2529
|
+
const placeholderContent = `/**
|
|
2530
|
+
* Generated Node Types
|
|
2531
|
+
*
|
|
2532
|
+
* This file is auto-generated by scripts/generate-types.ts
|
|
2533
|
+
* Do not edit manually.
|
|
2534
|
+
*
|
|
2535
|
+
* No nodes were found. Run 'pnpm build' in nodes-base and nodes-langchain first.
|
|
2536
|
+
*
|
|
2537
|
+
* @generated
|
|
2538
|
+
*/
|
|
2539
|
+
|
|
2540
|
+
export {};
|
|
2541
|
+
`;
|
|
2542
|
+
await fs.promises.writeFile(path.join(DEV_OUTPUT_PATH, 'index.ts'), placeholderContent);
|
|
2543
|
+
console.log('Generated placeholder index.ts (no nodes found)');
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
console.log(`Generated definitions for ${result.nodeCount} nodes`);
|
|
2547
|
+
}
|
|
2548
|
+
console.log('Type generation complete!');
|
|
2549
|
+
}
|
|
2550
|
+
function groupAndAddToolVariants(nodes) {
|
|
2551
|
+
const result = [];
|
|
2552
|
+
for (const node of nodes) {
|
|
2553
|
+
if (node.hidden)
|
|
2554
|
+
continue;
|
|
2555
|
+
result.push(node);
|
|
2556
|
+
const toolVariant = convertNodeToToolVariant(node);
|
|
2557
|
+
if (toolVariant) {
|
|
2558
|
+
result.push(toolVariant);
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
return result;
|
|
2562
|
+
}
|
|
2563
|
+
if (require.main === module) {
|
|
2564
|
+
generateTypes().catch((error) => {
|
|
2565
|
+
console.error('Type generation failed:', error);
|
|
2566
|
+
process.exit(1);
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
//# sourceMappingURL=generate-types.js.map
|