diff --git a/README.md b/README.md index f3f9050..12be842 100644 --- a/README.md +++ b/README.md @@ -53,20 +53,22 @@ It will create a symbolic link from globally-installed `sdk-typescript` to `node #### Create Workflow using builder API ```typescript - const workflow = workflowJsonBuilder() - .id("helloworld") - .version("1.0") - .name("Hello World Workflow") - .description("Inject Hello World") - .start("Hello State") - .states([injectstateBuilder() - .type("inject") - .name("Hello State") - .data({ - "result": "Hello World!" - }) - .end(true).build()]) - .build()); +const workflow = workflowBuilder() + .id("helloworld") + .version("1.0") + .name("Hello World Workflow") + .description("Inject Hello World") + .start("Hello State") + .states([injectstateBuilder() + .type("inject") + .name("Hello State") + .data({ + "result": "Hello World!" + }) + .end(true) + .build() + ]) + .build()); ``` #### Load a file JSON/YAML to a Workflow instance @@ -83,20 +85,22 @@ Where `source` is a JSON or a YAML string. Having the following workflow instance: ```typescript - const workflow = workflowJsonBuilder() - .id("helloworld") - .version("1.0") - .name("Hello World Workflow") - .description("Inject Hello World") - .start("Hello State") - .states([injectstateBuilder() - .type("inject") - .name("Hello State") - .data({ - "result": "Hello World!" - }) - .end(true).build()]) - .build()); +const workflow = workflowBuilder() + .id("helloworld") + .version("1.0") + .name("Hello World Workflow") + .description("Inject Hello World") + .start("Hello State") + .states([injectstateBuilder() + .type("inject") + .name("Hello State") + .data({ + "result": "Hello World!" + }) + .end(true) + .build() + ]) + .build()); ``` You can convert it to its string representation in JSON or YAML format @@ -114,12 +118,13 @@ by using the static methods `toJson` or `toYaml` respectively: The sdk provides a way to validate if a workflow object is compliant with the serverlessworkflow specification. -`validators` provides a map of validation functions: +`WorkflowValidator` class provides a validation method: + +- `validate(): boolean` ```typescript -const validate = validators.get('WorkflowJson'); -const isValid = validate(workflow); -if (!isValid) { - validate.errors.forEach(error => console.error(error.message)); +const workflowValidator = new WorkflowValidator(workflow); +if (!workflowValidator.validate()) { + workflowValidator.validationErrors.forEach(error => console.error(error.message)); } ``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 89f32a9..9b7436b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,727 +1,8 @@ { "name": "sdk-typescript", "version": "0.1.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "version": "0.1.0", - "license": "http://www.apache.org/licenses/LICENSE-2.0.txt", - "dependencies": { - "ajv": "^8.1.0", - "js-yaml": "^4.1.0" - }, - "devDependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.7", - "@types/jasmine": "^3.6.10", - "@types/js-yaml": "^4.0.1", - "@types/node-fetch": "^2.5.10", - "@types/rimraf": "^3.0.0", - "dtsgenerator": "^3.10.0", - "jasmine": "^3.7.0", - "node-fetch": "^2.6.1", - "rimraf": "^3.0.2", - "shx": "^0.3.3", - "ts-node": "^9.1.1", - "typescript": "^4.2.4" - }, - "engines": { - "node": ">=15.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.7.tgz", - "integrity": "sha512-QdwOGF1+eeyFh+17v2Tz626WX0nucd1iKOm6JUTUvCZdbolblCOOQCxGrQPY0f7jEhn36PiAWqZnsC2r5vmUWg==", - "dev": true, - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.13.1" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/jasmine": { - "version": "3.6.10", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.10.tgz", - "integrity": "sha512-yfCl7JGtIc5LjScFpeIGBBNhJFkJdAAcsAnAd9ZRHwzh+sR2zkt257BKkTCF5VpJ8wMPnzzZ8QatRdXM8tqpKA==", - "dev": true - }, - "node_modules/@types/js-yaml": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.1.tgz", - "integrity": "sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", - "integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==", - "dev": true - }, - "node_modules/@types/node-fetch": { - "version": "2.5.10", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz", - "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/@types/rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==", - "dev": true, - "dependencies": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.2.0.tgz", - "integrity": "sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "dev": true, - "dependencies": { - "node-fetch": "2.6.1" - } - }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dtsgenerator": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/dtsgenerator/-/dtsgenerator-3.10.0.tgz", - "integrity": "sha512-3MOlYOB7Y9OcWhbInWr3ndasfvwi8K5eB1SCQT3MsyeYFJ49j8ffFnGv09fz8hptOzvhDW0SzutB/HuMoaUP8w==", - "dev": true, - "dependencies": { - "commander": "^7.2.0", - "cross-fetch": "^3.1.4", - "debug": "^4.3.1", - "glob": "^7.1.6", - "https-proxy-agent": "^5.0.0", - "js-yaml": "^4.1.0", - "tslib": "^2.2.0", - "typescript": "^4.2.4" - }, - "bin": { - "dtsgen": "bin/dtsgen" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.3.0.tgz", - "integrity": "sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jasmine": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.7.0.tgz", - "integrity": "sha512-wlzGQ+cIFzMEsI+wDqmOwvnjTvolLFwlcpYLCqSPPH0prOQaW3P+IzMhHYn934l1imNvw07oCyX+vGUv3wmtSQ==", - "dev": true, - "dependencies": { - "glob": "^7.1.6", - "jasmine-core": "~3.7.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, - "node_modules/jasmine-core": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.7.1.tgz", - "integrity": "sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "dev": true, - "dependencies": { - "mime-db": "1.47.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shx": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", - "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.4" - }, - "bin": { - "shx": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "typescript": ">=2.7" - } - }, - "node_modules/tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, "dependencies": { "@apidevtools/json-schema-ref-parser": { "version": "9.0.7", @@ -755,6 +36,16 @@ } } }, + "@dtsgenerator/replace-namespace": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@dtsgenerator/replace-namespace/-/replace-namespace-1.4.1.tgz", + "integrity": "sha512-L0DFdirXdb6CBYiV5ILYfcgqY83ThhhYBhauhn3MserpTPs+ODLLMGCRPyWPAxH9z7YUCho3y37si7EVGfJYJQ==", + "dev": true, + "requires": { + "dtsgenerator": "^3.5.0", + "tslib": "^2.0.3" + } + }, "@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", diff --git a/package.json b/package.json index 59e9f9e..3c36ddc 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.7", + "@dtsgenerator/replace-namespace": "^1.4.1", "@types/jasmine": "^3.6.10", "@types/js-yaml": "^4.0.1", "@types/node-fetch": "^2.5.10", diff --git a/src/builders/README.md b/src/builders/README.md new file mode 100644 index 0000000..7d5a864 --- /dev/null +++ b/src/builders/README.md @@ -0,0 +1,2 @@ +# Auto generated notice +This directory and its content has been generated automatically. Do not modify its content, it WILL be lost. \ No newline at end of file diff --git a/src/builders/action-builder.ts b/src/builders/action-builder.ts new file mode 100644 index 0000000..3ca703e --- /dev/null +++ b/src/builders/action-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Action = ServerlessWorkflow.Action; + +export function actionValidator(data: Action): (() => Action) { + return () => { + const validate = validators.get('Action'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Action is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function actionBuilder(): Builder { + return builder(actionValidator); +} \ No newline at end of file diff --git a/src/builders/actiondatafilter-builder.ts b/src/builders/actiondatafilter-builder.ts new file mode 100644 index 0000000..4f0129d --- /dev/null +++ b/src/builders/actiondatafilter-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Actiondatafilter = ServerlessWorkflow.Actiondatafilter; + +export function actiondatafilterValidator(data: Actiondatafilter): (() => Actiondatafilter) { + return () => { + const validate = validators.get('Actiondatafilter'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Actiondatafilter is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function actiondatafilterBuilder(): Builder { + return builder(actiondatafilterValidator); +} \ No newline at end of file diff --git a/src/builders/branch-builder.ts b/src/builders/branch-builder.ts new file mode 100644 index 0000000..7585855 --- /dev/null +++ b/src/builders/branch-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Branch = ServerlessWorkflow.Branch; + +export function branchValidator(data: Branch): (() => Branch) { + return () => { + const validate = validators.get('Branch'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Branch is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function branchBuilder(): Builder { + return builder(branchValidator); +} \ No newline at end of file diff --git a/src/builders/callbackstate-builder.ts b/src/builders/callbackstate-builder.ts new file mode 100644 index 0000000..070babc --- /dev/null +++ b/src/builders/callbackstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Callbackstate = ServerlessWorkflow.Callbackstate; + +export function callbackstateValidator(data: Callbackstate): (() => Callbackstate) { + return () => { + data.type = 'callback'; + const validate = validators.get('Callbackstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Callbackstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function callbackstateBuilder(): Builder { + return builder(callbackstateValidator); +} \ No newline at end of file diff --git a/src/builders/correlation-def-builder.ts b/src/builders/correlation-def-builder.ts new file mode 100644 index 0000000..0e10c92 --- /dev/null +++ b/src/builders/correlation-def-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import CorrelationDef = ServerlessWorkflow.CorrelationDef; + +export function correlationDefValidator(data: CorrelationDef): (() => CorrelationDef) { + return () => { + const validate = validators.get('CorrelationDef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`CorrelationDef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function correlationDefBuilder(): Builder { + return builder(correlationDefValidator); +} \ No newline at end of file diff --git a/src/builders/crondef-builder.ts b/src/builders/crondef-builder.ts new file mode 100644 index 0000000..59e1ff0 --- /dev/null +++ b/src/builders/crondef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Crondef = ServerlessWorkflow.Crondef; + +export function crondefValidator(data: Crondef): (() => Crondef) { + return () => { + const validate = validators.get('Crondef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Crondef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function crondefBuilder(): Builder { + return builder(crondefValidator); +} \ No newline at end of file diff --git a/src/builders/databasedswitch-builder.ts b/src/builders/databasedswitch-builder.ts new file mode 100644 index 0000000..db51966 --- /dev/null +++ b/src/builders/databasedswitch-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Databasedswitch = ServerlessWorkflow.Databasedswitch; + +export function databasedswitchValidator(data: Databasedswitch): (() => Databasedswitch) { + return () => { + data.type = 'switch'; + const validate = validators.get('Databasedswitch'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Databasedswitch is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function databasedswitchBuilder(): Builder { + return builder(databasedswitchValidator); +} \ No newline at end of file diff --git a/src/builders/datacondition-builder.ts b/src/builders/datacondition-builder.ts new file mode 100644 index 0000000..b16cddf --- /dev/null +++ b/src/builders/datacondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Datacondition = ServerlessWorkflow.Datacondition; + +export function dataconditionValidator(data: Datacondition): (() => Datacondition) { + return () => { + const validate = validators.get('Datacondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Datacondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function dataconditionBuilder(): Builder { + return builder(dataconditionValidator); +} \ No newline at end of file diff --git a/src/builders/defaultconditiondef-builder.ts b/src/builders/defaultconditiondef-builder.ts new file mode 100644 index 0000000..2ba98e6 --- /dev/null +++ b/src/builders/defaultconditiondef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Defaultconditiondef = ServerlessWorkflow.Defaultconditiondef; + +export function defaultconditiondefValidator(data: Defaultconditiondef): (() => Defaultconditiondef) { + return () => { + const validate = validators.get('Defaultconditiondef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Defaultconditiondef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function defaultconditiondefBuilder(): Builder { + return builder(defaultconditiondefValidator); +} \ No newline at end of file diff --git a/src/builders/delaystate-builder.ts b/src/builders/delaystate-builder.ts new file mode 100644 index 0000000..765609b --- /dev/null +++ b/src/builders/delaystate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Delaystate = ServerlessWorkflow.Delaystate; + +export function delaystateValidator(data: Delaystate): (() => Delaystate) { + return () => { + data.type = 'delay'; + const validate = validators.get('Delaystate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Delaystate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function delaystateBuilder(): Builder { + return builder(delaystateValidator); +} \ No newline at end of file diff --git a/src/builders/end-builder.ts b/src/builders/end-builder.ts new file mode 100644 index 0000000..afa56ae --- /dev/null +++ b/src/builders/end-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import End = ServerlessWorkflow.End; + +export function endValidator(data: End): (() => End) { + return () => { + const validate = validators.get('End'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`End is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function endBuilder(): Builder { + return builder(endValidator); +} \ No newline at end of file diff --git a/src/builders/enddatacondition-builder.ts b/src/builders/enddatacondition-builder.ts new file mode 100644 index 0000000..2e9435a --- /dev/null +++ b/src/builders/enddatacondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Enddatacondition = ServerlessWorkflow.Enddatacondition; + +export function enddataconditionValidator(data: Enddatacondition): (() => Enddatacondition) { + return () => { + const validate = validators.get('Enddatacondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Enddatacondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function enddataconditionBuilder(): Builder { + return builder(enddataconditionValidator); +} \ No newline at end of file diff --git a/src/builders/enddeventcondition-builder.ts b/src/builders/enddeventcondition-builder.ts new file mode 100644 index 0000000..2419f7d --- /dev/null +++ b/src/builders/enddeventcondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Enddeventcondition = ServerlessWorkflow.Enddeventcondition; + +export function enddeventconditionValidator(data: Enddeventcondition): (() => Enddeventcondition) { + return () => { + const validate = validators.get('Enddeventcondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Enddeventcondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function enddeventconditionBuilder(): Builder { + return builder(enddeventconditionValidator); +} \ No newline at end of file diff --git a/src/builders/error-builder.ts b/src/builders/error-builder.ts new file mode 100644 index 0000000..82af3af --- /dev/null +++ b/src/builders/error-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Error = ServerlessWorkflow.Error; + +export function errorValidator(data: Error): (() => Error) { + return () => { + const validate = validators.get('Error'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Error is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function errorBuilder(): Builder { + return builder(errorValidator); +} \ No newline at end of file diff --git a/src/builders/eventbasedswitch-builder.ts b/src/builders/eventbasedswitch-builder.ts new file mode 100644 index 0000000..b898d68 --- /dev/null +++ b/src/builders/eventbasedswitch-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventbasedswitch = ServerlessWorkflow.Eventbasedswitch; + +export function eventbasedswitchValidator(data: Eventbasedswitch): (() => Eventbasedswitch) { + return () => { + data.type = 'switch'; + const validate = validators.get('Eventbasedswitch'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventbasedswitch is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventbasedswitchBuilder(): Builder { + return builder(eventbasedswitchValidator); +} \ No newline at end of file diff --git a/src/builders/eventcondition-builder.ts b/src/builders/eventcondition-builder.ts new file mode 100644 index 0000000..9e4e49e --- /dev/null +++ b/src/builders/eventcondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventcondition = ServerlessWorkflow.Eventcondition; + +export function eventconditionValidator(data: Eventcondition): (() => Eventcondition) { + return () => { + const validate = validators.get('Eventcondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventcondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventconditionBuilder(): Builder { + return builder(eventconditionValidator); +} \ No newline at end of file diff --git a/src/builders/eventdatafilter-builder.ts b/src/builders/eventdatafilter-builder.ts new file mode 100644 index 0000000..06a9f2c --- /dev/null +++ b/src/builders/eventdatafilter-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventdatafilter = ServerlessWorkflow.Eventdatafilter; + +export function eventdatafilterValidator(data: Eventdatafilter): (() => Eventdatafilter) { + return () => { + const validate = validators.get('Eventdatafilter'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventdatafilter is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventdatafilterBuilder(): Builder { + return builder(eventdatafilterValidator); +} \ No newline at end of file diff --git a/src/builders/eventdef-builder.ts b/src/builders/eventdef-builder.ts new file mode 100644 index 0000000..5469bad --- /dev/null +++ b/src/builders/eventdef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventdef = ServerlessWorkflow.Eventdef; + +export function eventdefValidator(data: Eventdef): (() => Eventdef) { + return () => { + const validate = validators.get('Eventdef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventdef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventdefBuilder(): Builder { + return builder(eventdefValidator); +} \ No newline at end of file diff --git a/src/builders/eventref-builder.ts b/src/builders/eventref-builder.ts new file mode 100644 index 0000000..b739560 --- /dev/null +++ b/src/builders/eventref-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventref = ServerlessWorkflow.Eventref; + +export function eventrefValidator(data: Eventref): (() => Eventref) { + return () => { + const validate = validators.get('Eventref'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventref is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventrefBuilder(): Builder { + return builder(eventrefValidator); +} \ No newline at end of file diff --git a/src/builders/events-builder.ts b/src/builders/events-builder.ts new file mode 100644 index 0000000..1258643 --- /dev/null +++ b/src/builders/events-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Events = ServerlessWorkflow.Events; + +export function eventsValidator(data: Events): (() => Events) { + return () => { + const validate = validators.get('Events'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Events is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventsBuilder(): Builder { + return builder(eventsValidator); +} \ No newline at end of file diff --git a/src/builders/eventstate-builder.ts b/src/builders/eventstate-builder.ts new file mode 100644 index 0000000..0eed9f6 --- /dev/null +++ b/src/builders/eventstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Eventstate = ServerlessWorkflow.Eventstate; + +export function eventstateValidator(data: Eventstate): (() => Eventstate) { + return () => { + data.type = 'event'; + const validate = validators.get('Eventstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Eventstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function eventstateBuilder(): Builder { + return builder(eventstateValidator); +} \ No newline at end of file diff --git a/src/builders/exectimeout-builder.ts b/src/builders/exectimeout-builder.ts new file mode 100644 index 0000000..c15cbf9 --- /dev/null +++ b/src/builders/exectimeout-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Exectimeout = ServerlessWorkflow.Exectimeout; + +export function exectimeoutValidator(data: Exectimeout): (() => Exectimeout) { + return () => { + const validate = validators.get('Exectimeout'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Exectimeout is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function exectimeoutBuilder(): Builder { + return builder(exectimeoutValidator); +} \ No newline at end of file diff --git a/src/builders/foreachstate-builder.ts b/src/builders/foreachstate-builder.ts new file mode 100644 index 0000000..a07724e --- /dev/null +++ b/src/builders/foreachstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Foreachstate = ServerlessWorkflow.Foreachstate; + +export function foreachstateValidator(data: Foreachstate): (() => Foreachstate) { + return () => { + data.type = 'foreach'; + const validate = validators.get('Foreachstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Foreachstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function foreachstateBuilder(): Builder { + return builder(foreachstateValidator); +} \ No newline at end of file diff --git a/src/builders/function-builder.ts b/src/builders/function-builder.ts new file mode 100644 index 0000000..641d9b0 --- /dev/null +++ b/src/builders/function-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Function = ServerlessWorkflow.Function; + +export function functionValidator(data: Function): (() => Function) { + return () => { + const validate = validators.get('Function'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Function is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function functionBuilder(): Builder { + return builder(functionValidator); +} \ No newline at end of file diff --git a/src/builders/functions-builder.ts b/src/builders/functions-builder.ts new file mode 100644 index 0000000..6b43bab --- /dev/null +++ b/src/builders/functions-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Functions = ServerlessWorkflow.Functions; + +export function functionsValidator(data: Functions): (() => Functions) { + return () => { + const validate = validators.get('Functions'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Functions is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function functionsBuilder(): Builder { + return builder(functionsValidator); +} \ No newline at end of file diff --git a/src/builders/index.ts b/src/builders/index.ts new file mode 100644 index 0000000..dc91fb6 --- /dev/null +++ b/src/builders/index.ts @@ -0,0 +1,42 @@ +export * from './workflow-builder'; +export * from './action-builder'; +export * from './actiondatafilter-builder'; +export * from './branch-builder'; +export * from './callbackstate-builder'; +export * from './correlation-def-builder'; +export * from './crondef-builder'; +export * from './databasedswitch-builder'; +export * from './datacondition-builder'; +export * from './defaultconditiondef-builder'; +export * from './delaystate-builder'; +export * from './end-builder'; +export * from './enddatacondition-builder'; +export * from './enddeventcondition-builder'; +export * from './error-builder'; +export * from './eventbasedswitch-builder'; +export * from './eventcondition-builder'; +export * from './eventdatafilter-builder'; +export * from './eventdef-builder'; +export * from './eventref-builder'; +export * from './events-builder'; +export * from './eventstate-builder'; +export * from './exectimeout-builder'; +export * from './foreachstate-builder'; +export * from './function-builder'; +export * from './functions-builder'; +export * from './injectstate-builder'; +export * from './metadata-builder'; +export * from './onevents-builder'; +export * from './operationstate-builder'; +export * from './parallelstate-builder'; +export * from './produceeventdef-builder'; +export * from './retries-builder'; +export * from './retrydef-builder'; +export * from './schedule-builder'; +export * from './startdef-builder'; +export * from './statedatafilter-builder'; +export * from './subflowref-builder'; +export * from './switchstate-builder'; +export * from './transition-builder'; +export * from './transitiondatacondition-builder'; +export * from './transitioneventcondition-builder'; diff --git a/src/builders/injectstate-builder.ts b/src/builders/injectstate-builder.ts new file mode 100644 index 0000000..df617b6 --- /dev/null +++ b/src/builders/injectstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Injectstate = ServerlessWorkflow.Injectstate; + +export function injectstateValidator(data: Injectstate): (() => Injectstate) { + return () => { + data.type = 'inject'; + const validate = validators.get('Injectstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Injectstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function injectstateBuilder(): Builder { + return builder(injectstateValidator); +} \ No newline at end of file diff --git a/src/builders/metadata-builder.ts b/src/builders/metadata-builder.ts new file mode 100644 index 0000000..fad3740 --- /dev/null +++ b/src/builders/metadata-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Metadata = ServerlessWorkflow.Metadata; + +export function metadataValidator(data: Metadata): (() => Metadata) { + return () => { + const validate = validators.get('Metadata'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Metadata is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function metadataBuilder(): Builder { + return builder(metadataValidator); +} \ No newline at end of file diff --git a/src/builders/onevents-builder.ts b/src/builders/onevents-builder.ts new file mode 100644 index 0000000..756ef5b --- /dev/null +++ b/src/builders/onevents-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Onevents = ServerlessWorkflow.Onevents; + +export function oneventsValidator(data: Onevents): (() => Onevents) { + return () => { + const validate = validators.get('Onevents'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Onevents is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function oneventsBuilder(): Builder { + return builder(oneventsValidator); +} \ No newline at end of file diff --git a/src/builders/operationstate-builder.ts b/src/builders/operationstate-builder.ts new file mode 100644 index 0000000..d10e689 --- /dev/null +++ b/src/builders/operationstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Operationstate = ServerlessWorkflow.Operationstate; + +export function operationstateValidator(data: Operationstate): (() => Operationstate) { + return () => { + data.type = 'operation'; + const validate = validators.get('Operationstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Operationstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function operationstateBuilder(): Builder { + return builder(operationstateValidator); +} \ No newline at end of file diff --git a/src/builders/parallelstate-builder.ts b/src/builders/parallelstate-builder.ts new file mode 100644 index 0000000..1aed0b4 --- /dev/null +++ b/src/builders/parallelstate-builder.ts @@ -0,0 +1,23 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Parallelstate = ServerlessWorkflow.Parallelstate; + +export function parallelstateValidator(data: Parallelstate): (() => Parallelstate) { + return () => { + data.type = 'parallel'; + const validate = validators.get('Parallelstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Parallelstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function parallelstateBuilder(): Builder { + return builder(parallelstateValidator); +} \ No newline at end of file diff --git a/src/builders/produceeventdef-builder.ts b/src/builders/produceeventdef-builder.ts new file mode 100644 index 0000000..9f0aba9 --- /dev/null +++ b/src/builders/produceeventdef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Produceeventdef = ServerlessWorkflow.Produceeventdef; + +export function produceeventdefValidator(data: Produceeventdef): (() => Produceeventdef) { + return () => { + const validate = validators.get('Produceeventdef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Produceeventdef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function produceeventdefBuilder(): Builder { + return builder(produceeventdefValidator); +} \ No newline at end of file diff --git a/src/builders/retries-builder.ts b/src/builders/retries-builder.ts new file mode 100644 index 0000000..ffce694 --- /dev/null +++ b/src/builders/retries-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Retries = ServerlessWorkflow.Retries; + +export function retriesValidator(data: Retries): (() => Retries) { + return () => { + const validate = validators.get('Retries'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Retries is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function retriesBuilder(): Builder { + return builder(retriesValidator); +} \ No newline at end of file diff --git a/src/builders/retrydef-builder.ts b/src/builders/retrydef-builder.ts new file mode 100644 index 0000000..742ea74 --- /dev/null +++ b/src/builders/retrydef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Retrydef = ServerlessWorkflow.Retrydef; + +export function retrydefValidator(data: Retrydef): (() => Retrydef) { + return () => { + const validate = validators.get('Retrydef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Retrydef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function retrydefBuilder(): Builder { + return builder(retrydefValidator); +} \ No newline at end of file diff --git a/src/builders/schedule-builder.ts b/src/builders/schedule-builder.ts new file mode 100644 index 0000000..89e8edb --- /dev/null +++ b/src/builders/schedule-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Schedule = ServerlessWorkflow.Schedule; + +export function scheduleValidator(data: Schedule): (() => Schedule) { + return () => { + const validate = validators.get('Schedule'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Schedule is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function scheduleBuilder(): Builder { + return builder(scheduleValidator); +} \ No newline at end of file diff --git a/src/builders/startdef-builder.ts b/src/builders/startdef-builder.ts new file mode 100644 index 0000000..468f50e --- /dev/null +++ b/src/builders/startdef-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Startdef = ServerlessWorkflow.Startdef; + +export function startdefValidator(data: Startdef): (() => Startdef) { + return () => { + const validate = validators.get('Startdef'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Startdef is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function startdefBuilder(): Builder { + return builder(startdefValidator); +} \ No newline at end of file diff --git a/src/builders/statedatafilter-builder.ts b/src/builders/statedatafilter-builder.ts new file mode 100644 index 0000000..e9bbc7a --- /dev/null +++ b/src/builders/statedatafilter-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Statedatafilter = ServerlessWorkflow.Statedatafilter; + +export function statedatafilterValidator(data: Statedatafilter): (() => Statedatafilter) { + return () => { + const validate = validators.get('Statedatafilter'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Statedatafilter is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function statedatafilterBuilder(): Builder { + return builder(statedatafilterValidator); +} \ No newline at end of file diff --git a/src/builders/subflowref-builder.ts b/src/builders/subflowref-builder.ts new file mode 100644 index 0000000..0372677 --- /dev/null +++ b/src/builders/subflowref-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Subflowref = ServerlessWorkflow.Subflowref; + +export function subflowrefValidator(data: Subflowref): (() => Subflowref) { + return () => { + const validate = validators.get('Subflowref'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Subflowref is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function subflowrefBuilder(): Builder { + return builder(subflowrefValidator); +} \ No newline at end of file diff --git a/src/builders/switchstate-builder.ts b/src/builders/switchstate-builder.ts new file mode 100644 index 0000000..705f6b0 --- /dev/null +++ b/src/builders/switchstate-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Switchstate = ServerlessWorkflow.Switchstate; + +export function switchstateValidator(data: Switchstate): (() => Switchstate) { + return () => { + const validate = validators.get('Switchstate'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Switchstate is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function switchstateBuilder(): Builder { + return builder(switchstateValidator); +} \ No newline at end of file diff --git a/src/builders/transition-builder.ts b/src/builders/transition-builder.ts new file mode 100644 index 0000000..de1ca73 --- /dev/null +++ b/src/builders/transition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Transition = ServerlessWorkflow.Transition; + +export function transitionValidator(data: Transition): (() => Transition) { + return () => { + const validate = validators.get('Transition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Transition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function transitionBuilder(): Builder { + return builder(transitionValidator); +} \ No newline at end of file diff --git a/src/builders/transitiondatacondition-builder.ts b/src/builders/transitiondatacondition-builder.ts new file mode 100644 index 0000000..59927b9 --- /dev/null +++ b/src/builders/transitiondatacondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Transitiondatacondition = ServerlessWorkflow.Transitiondatacondition; + +export function transitiondataconditionValidator(data: Transitiondatacondition): (() => Transitiondatacondition) { + return () => { + const validate = validators.get('Transitiondatacondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Transitiondatacondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function transitiondataconditionBuilder(): Builder { + return builder(transitiondataconditionValidator); +} \ No newline at end of file diff --git a/src/builders/transitioneventcondition-builder.ts b/src/builders/transitioneventcondition-builder.ts new file mode 100644 index 0000000..7bb9d9e --- /dev/null +++ b/src/builders/transitioneventcondition-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Transitioneventcondition = ServerlessWorkflow.Transitioneventcondition; + +export function transitioneventconditionValidator(data: Transitioneventcondition): (() => Transitioneventcondition) { + return () => { + const validate = validators.get('Transitioneventcondition'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Transitioneventcondition is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function transitioneventconditionBuilder(): Builder { + return builder(transitioneventconditionValidator); +} \ No newline at end of file diff --git a/src/builders/workflow-builder.ts b/src/builders/workflow-builder.ts new file mode 100644 index 0000000..99f34c6 --- /dev/null +++ b/src/builders/workflow-builder.ts @@ -0,0 +1,22 @@ +import { DefinedError } from 'ajv'; +import { Builder, builder } from '../builder'; +import { validators } from '../validators'; +import Workflow = ServerlessWorkflow.Workflow; + +export function workflowValidator(data: Workflow): (() => Workflow) { + return () => { + const validate = validators.get('Workflow'); + // TODO: ignore validation if no validator or throw ? + if (!validate) return data; + if (!validate(data)) { + console.warn(validate.errors); + const firstError: DefinedError = (validate.errors as DefinedError[])[0]; + throw new Error(`Workflow is invalid: ${firstError.message}`); + } + return data; + }; +} + +export function workflowBuilder(): Builder { + return builder(workflowValidator); +} \ No newline at end of file diff --git a/src/definitions/README.md b/src/definitions/README.md new file mode 100644 index 0000000..7d5a864 --- /dev/null +++ b/src/definitions/README.md @@ -0,0 +1,2 @@ +# Auto generated notice +This directory and its content has been generated automatically. Do not modify its content, it WILL be lost. \ No newline at end of file diff --git a/src/definitions/workflow.d.ts b/src/definitions/workflow.d.ts new file mode 100644 index 0000000..9856afb --- /dev/null +++ b/src/definitions/workflow.d.ts @@ -0,0 +1,1157 @@ +declare namespace ServerlessWorkflow { + /** + * Serverless Workflow specification - workflow schema + */ + export type Workflow = /* Serverless Workflow specification - workflow schema */ { + /** + * Workflow unique identifier + */ + id: string; + /** + * Domain-specific workflow identifier + */ + key?: string; + /** + * Workflow name + */ + name: string; + /** + * Workflow description + */ + description?: string; + /** + * Workflow version + */ + version?: string; + /** + * List of helpful terms describing the workflows intended purpose, subject areas, or other important qualities + */ + annotations?: [ + string, + ...string[] + ]; + dataInputSchema?: string | { + /** + * URI of the JSON Schema used to validate the workflow data input + */ + schema: string; + /** + * Determines if workflow execution should continue if there are validation errors + */ + failOnValidationErrors: boolean; + }; + start: Startdef; + /** + * Serverless Workflow schema version + */ + schemaVersion?: string; + /** + * Identifies the expression language used for workflow expressions. Default is 'jq' + */ + expressionLang?: string; + execTimeout?: Exectimeout; + /** + * If 'true', workflow instances is not terminated when there are no active execution paths. Instance can be terminated via 'terminate end definition' or reaching defined 'execTimeout' + */ + keepActive?: boolean; + metadata?: /* Metadata information */ Metadata; + events?: Events; + functions?: Functions; + retries?: Retries; + /** + * State definitions + */ + states: [ + (/* Causes the workflow execution to delay for a specified duration */ Delaystate | /* This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel */ Eventstate | /* Defines actions be performed. Does not wait for incoming events */ Operationstate | /* Consists of a number of states that are executed in parallel */ Parallelstate | Switchstate | /* Inject static data into state data. Does not perform any actions */ Injectstate | /* Execute a set of defined actions or workflows for each element of a data array */ Foreachstate | /* This state performs an action, then waits for the callback event that denotes completion of the action */ Callbackstate), + ...(/* Causes the workflow execution to delay for a specified duration */ Delaystate | /* This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel */ Eventstate | /* Defines actions be performed. Does not wait for incoming events */ Operationstate | /* Consists of a number of states that are executed in parallel */ Parallelstate | Switchstate | /* Inject static data into state data. Does not perform any actions */ Injectstate | /* Execute a set of defined actions or workflows for each element of a data array */ Foreachstate | /* This state performs an action, then waits for the callback event that denotes completion of the action */ Callbackstate)[] + ]; + } | { + /** + * Workflow unique identifier + */ + id?: string; + /** + * Domain-specific workflow identifier + */ + key: string; + /** + * Workflow name + */ + name: string; + /** + * Workflow description + */ + description?: string; + /** + * Workflow version + */ + version?: string; + /** + * List of helpful terms describing the workflows intended purpose, subject areas, or other important qualities + */ + annotations?: [ + string, + ...string[] + ]; + dataInputSchema?: string | { + /** + * URI of the JSON Schema used to validate the workflow data input + */ + schema: string; + /** + * Determines if workflow execution should continue if there are validation errors + */ + failOnValidationErrors: boolean; + }; + start: Startdef; + /** + * Serverless Workflow schema version + */ + schemaVersion?: string; + /** + * Identifies the expression language used for workflow expressions. Default is 'jq' + */ + expressionLang?: string; + execTimeout?: Exectimeout; + /** + * If 'true', workflow instances is not terminated when there are no active execution paths. Instance can be terminated via 'terminate end definition' or reaching defined 'execTimeout' + */ + keepActive?: boolean; + metadata?: /* Metadata information */ Metadata; + events?: Events; + functions?: Functions; + retries?: Retries; + /** + * State definitions + */ + states: [ + (/* Causes the workflow execution to delay for a specified duration */ Delaystate | /* This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel */ Eventstate | /* Defines actions be performed. Does not wait for incoming events */ Operationstate | /* Consists of a number of states that are executed in parallel */ Parallelstate | Switchstate | /* Inject static data into state data. Does not perform any actions */ Injectstate | /* Execute a set of defined actions or workflows for each element of a data array */ Foreachstate | /* This state performs an action, then waits for the callback event that denotes completion of the action */ Callbackstate), + ...(/* Causes the workflow execution to delay for a specified duration */ Delaystate | /* This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel */ Eventstate | /* Defines actions be performed. Does not wait for incoming events */ Operationstate | /* Consists of a number of states that are executed in parallel */ Parallelstate | Switchstate | /* Inject static data into state data. Does not perform any actions */ Injectstate | /* Execute a set of defined actions or workflows for each element of a data array */ Foreachstate | /* This state performs an action, then waits for the callback event that denotes completion of the action */ Callbackstate)[] + ]; + }; + export type Action = { + /** + * Unique action definition name + */ + name?: string; + functionRef: string | { + /** + * Name of the referenced function + */ + refName: string; + /** + * Function arguments + */ + arguments?: { + [key: string]: any; + }; + }; + eventRef?: /* Event References */ Eventref; + subFlowRef?: Subflowref; + /** + * Time period to wait for function execution to complete (ISO 8601 format) + */ + timeout?: string; + actionDataFilter?: Actiondatafilter; + } | { + /** + * Unique action definition name + */ + name?: string; + functionRef?: string | { + /** + * Name of the referenced function + */ + refName: string; + /** + * Function arguments + */ + arguments?: { + [key: string]: any; + }; + }; + eventRef: /* Event References */ Eventref; + subFlowRef?: Subflowref; + /** + * Time period to wait for function execution to complete (ISO 8601 format) + */ + timeout?: string; + actionDataFilter?: Actiondatafilter; + } | { + /** + * Unique action definition name + */ + name?: string; + functionRef?: string | { + /** + * Name of the referenced function + */ + refName: string; + /** + * Function arguments + */ + arguments?: { + [key: string]: any; + }; + }; + eventRef?: /* Event References */ Eventref; + subFlowRef: Subflowref; + /** + * Time period to wait for function execution to complete (ISO 8601 format) + */ + timeout?: string; + actionDataFilter?: Actiondatafilter; + }; + export interface Actiondatafilter { + /** + * Workflow expression that selects state data that the state action can use + */ + fromStateData?: string; + /** + * Workflow expression that filters the actions data results + */ + results?: string; + /** + * Workflow expression that selects a state data element to which the action results should be added/merged into. If not specified, denote, the top-level state data element + */ + toStateData?: string; + } + /** + * Branch Definition + */ + export interface Branch { + /** + * Branch name + */ + name: string; + /** + * Actions to be executed in this branch + */ + actions: Action[]; + } + /** + * This state performs an action, then waits for the callback event that denotes completion of the action + */ + export interface Callbackstate { + /** + * Unique state id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "callback"; + /** + * Defines the action to be executed + */ + action?: Action; + /** + * References an unique callback event name in the defined workflow events + */ + eventRef?: string; + /** + * Time period to wait for incoming events (ISO 8601 format) + */ + timeout?: string; + /** + * Event data filter + */ + eventDataFilter?: Eventdatafilter; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Next transition of the workflow after all the actions have been performed + */ + transition?: Transition; + /** + * State end definition + */ + end?: End; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + /** + * CloudEvent correlation definition + */ + export interface CorrelationDef { + /** + * CloudEvent Extension Context Attribute name + */ + contextAttributeName: string; + /** + * CloudEvent Extension Context Attribute value + */ + contextAttributeValue?: string; + } + export type Crondef = string | { + /** + * Repeating interval (cron expression) describing when the workflow instance should be created + */ + expression: string; + /** + * Specific date and time (ISO 8601 format) when the cron expression invocation is no longer valid + */ + validUntil?: string; + }; + /** + * Permits transitions to other states based on data conditions + */ + export interface Databasedswitch { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name: string; + /** + * State type + */ + type: "switch"; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Defines conditions evaluated against state data + */ + dataConditions: Datacondition[]; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition + */ + defaultCondition?: /* DefaultCondition definition. Can be either a transition or end definition */ Defaultconditiondef; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + export type Datacondition = /* Switch state data based condition */ Transitiondatacondition | /* Switch state data based condition */ Enddatacondition; + /** + * DefaultCondition definition. Can be either a transition or end definition + */ + export type Defaultconditiondef = /* DefaultCondition definition. Can be either a transition or end definition */ { + transition: Transition; + end?: End; + } | { + transition?: Transition; + end: End; + }; + /** + * Causes the workflow execution to delay for a specified duration + */ + export interface Delaystate { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "delay"; + /** + * State end definition + */ + end?: End; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Amount of time (ISO 8601 format) to delay + */ + timeDelay?: string; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Next transition of the workflow after the time delay + */ + transition?: Transition; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + export type End = boolean | { + /** + * If true, completes all execution flows in the given workflow instance + */ + terminate?: boolean; + /** + * Defines events that should be produced + */ + produceEvents?: /* Produce an event and set its data */ Produceeventdef[]; + /** + * If set to true, triggers workflow compensation. Default is false + */ + compensate?: boolean; + }; + /** + * Switch state data based condition + */ + export interface Enddatacondition { + /** + * Data condition name + */ + name?: string; + /** + * Workflow expression evaluated against state data. Must evaluate to true or false + */ + condition: string; + /** + * Workflow end definition + */ + end: End; + metadata?: /* Metadata information */ Metadata; + } + /** + * Switch state data event condition + */ + export interface Enddeventcondition { + /** + * Event condition name + */ + name?: string; + /** + * References an unique event name in the defined workflow events + */ + eventRef: string; + /** + * Explicit transition to end + */ + end: End; + /** + * Event data filter definition + */ + eventDataFilter?: Eventdatafilter; + metadata?: /* Metadata information */ Metadata; + } + export type Error = { + /** + * Domain-specific error name, or '*' to indicate all possible errors + */ + error: string; + /** + * Error code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. Should not be defined if error is set to '*' + */ + code?: string; + /** + * References a unique name of a retry definition. + */ + retryRef?: string; + transition: Transition; + end?: End; + } | { + /** + * Domain-specific error name, or '*' to indicate all possible errors + */ + error: string; + /** + * Error code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. Should not be defined if error is set to '*' + */ + code?: string; + /** + * References a unique name of a retry definition. + */ + retryRef?: string; + transition?: Transition; + end: End; + }; + /** + * Permits transitions to other states based on events + */ + export interface Eventbasedswitch { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name: string; + /** + * State type + */ + type: "switch"; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Defines conditions evaluated against events + */ + eventConditions: Eventcondition[]; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * If eventConditions is used, defines the time period to wait for events (ISO 8601 format) + */ + eventTimeout?: string; + /** + * Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition + */ + defaultCondition?: /* DefaultCondition definition. Can be either a transition or end definition */ Defaultconditiondef; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + export type Eventcondition = /* Switch state data event condition */ Transitioneventcondition | /* Switch state data event condition */ Enddeventcondition; + export interface Eventdatafilter { + /** + * Workflow expression that filters of the event data (payload) + */ + data?: string; + /** + * Workflow expression that selects a state data element to which the event payload should be added/merged into. If not specified, denotes, the top-level state data element. + */ + toStateData?: string; + } + export interface Eventdef { + /** + * Unique event name + */ + name?: string; + /** + * CloudEvent source + */ + source?: string; + /** + * CloudEvent type + */ + type?: string; + /** + * Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. Default is 'consumed' + */ + kind?: "consumed" | "produced"; + /** + * CloudEvent correlation definitions + */ + correlation?: [ + /* CloudEvent correlation definition */ CorrelationDef, + .../* CloudEvent correlation definition */ CorrelationDef[] + ]; + /** + * Metadata information + */ + metadata?: /* Metadata information */ Metadata; + } + /** + * Event References + */ + export interface Eventref { + /** + * Reference to the unique name of a 'produced' event definition + */ + triggerEventRef: string; + /** + * Reference to the unique name of a 'consumed' event definition + */ + resultEventRef: string; + /** + * If string type, an expression which selects parts of the states data output to become the data (payload) of the event referenced by 'triggerEventRef'. If object type, a custom object to become the data (payload) of the event referenced by 'triggerEventRef'. + */ + data?: string | { + [key: string]: any; + }; + /** + * Add additional extension context attributes to the produced event + */ + contextAttributes?: { + [name: string]: string; + }; + } + export type Events = string /* uri */ | [ + Eventdef, + ...Eventdef[] + ]; + /** + * This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel + */ + export type Eventstate = /* This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel */ { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name: string; + /** + * State type + */ + type: "event"; + /** + * If true consuming one of the defined events causes its associated actions to be performed. If false all of the defined events must be consumed in order for actions to be performed + */ + exclusive?: boolean; + /** + * Define the events to be consumed and optional actions to be performed + */ + onEvents: Onevents[]; + /** + * Time period to wait for incoming events (ISO 8601 format) + */ + timeout?: string; + stateDataFilter?: Statedatafilter; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + transition?: Transition; + end: End; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + metadata?: /* Metadata information */ Metadata; + } | { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name: string; + /** + * State type + */ + type: "event"; + /** + * If true consuming one of the defined events causes its associated actions to be performed. If false all of the defined events must be consumed in order for actions to be performed + */ + exclusive?: boolean; + /** + * Define the events to be consumed and optional actions to be performed + */ + onEvents: Onevents[]; + /** + * Time period to wait for incoming events (ISO 8601 format) + */ + timeout?: string; + stateDataFilter?: Statedatafilter; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + transition: Transition; + end?: End; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + metadata?: /* Metadata information */ Metadata; + } | { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name: string; + /** + * State type + */ + type: "event"; + /** + * If true consuming one of the defined events causes its associated actions to be performed. If false all of the defined events must be consumed in order for actions to be performed + */ + exclusive?: boolean; + /** + * Define the events to be consumed and optional actions to be performed + */ + onEvents: Onevents[]; + /** + * Time period to wait for incoming events (ISO 8601 format) + */ + timeout?: string; + stateDataFilter?: Statedatafilter; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + transition?: Transition; + end: End; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + metadata?: /* Metadata information */ Metadata; + }; + export interface Exectimeout { + /** + * Timeout duration (ISO 8601 duration format) + */ + duration: string; + /** + * If `false`, workflow instance is allowed to finish current execution. If `true`, current workflow execution is abrupted. + */ + interrupt?: boolean; + /** + * Name of a workflow state to be executed before workflow instance is terminated + */ + runBefore?: string; + } + /** + * Execute a set of defined actions or workflows for each element of a data array + */ + export interface Foreachstate { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "foreach"; + /** + * State end definition + */ + end?: End; + /** + * Workflow expression selecting an array element of the states data + */ + inputCollection?: string; + /** + * Workflow expression specifying an array element of the states data to add the results of each iteration + */ + outputCollection?: string; + /** + * Name of the iteration parameter that can be referenced in actions/workflow. For each parallel iteration, this param should contain an unique element of the inputCollection array + */ + iterationParam?: string; + /** + * Specifies how upper bound on how many iterations may run in parallel + */ + max?: number | string; + /** + * Actions to be executed for each of the elements of inputCollection + */ + actions?: Action[]; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Next transition of the workflow after state has completed + */ + transition?: Transition; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + export interface Function { + /** + * Unique function name + */ + name: string; + /** + * If type is `rest`, #. If type is `rpc`, ##. If type is `expression`, defines the workflow expression. + */ + operation: string; + /** + * Defines the function type. Is either `rest`, `rpc` or `expression`. Default is `rest` + */ + type?: "rest" | "rpc" | "expression"; + } + export type Functions = string /* uri */ | [ + Function, + ...Function[] + ]; + /** + * Inject static data into state data. Does not perform any actions + */ + export interface Injectstate { + /** + * Unique state id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "inject"; + /** + * State end definition + */ + end?: End; + /** + * JSON object which can be set as states data input and can be manipulated via filters + */ + data?: { + [key: string]: any; + }; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Next transition of the workflow after injection has completed + */ + transition?: Transition; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + /** + * Metadata information + */ + export interface Metadata { + [name: string]: string; + } + export interface Onevents { + /** + * References one or more unique event names in the defined workflow events + */ + eventRefs: [ + string, + ...string[] + ]; + /** + * Specifies how actions are to be performed (in sequence of parallel) + */ + actionMode?: "sequential" | "parallel"; + /** + * Actions to be performed if expression matches + */ + actions?: Action[]; + /** + * Event data filter + */ + eventDataFilter?: Eventdatafilter; + } + /** + * Defines actions be performed. Does not wait for incoming events + */ + export interface Operationstate { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "operation"; + /** + * State end definition + */ + end?: End; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Specifies whether actions are performed in sequence or in parallel + */ + actionMode?: "sequential" | "parallel"; + /** + * Actions to be performed + */ + actions?: Action[]; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Next transition of the workflow after all the actions have been performed + */ + transition?: Transition; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + /** + * Consists of a number of states that are executed in parallel + */ + export interface Parallelstate { + /** + * Unique State id + */ + id?: string; + /** + * State name + */ + name?: string; + /** + * State type + */ + type?: "parallel"; + /** + * State end definition + */ + end?: End; + /** + * State data filter + */ + stateDataFilter?: Statedatafilter; + /** + * Branch Definitions + */ + branches?: /* Branch Definition */ Branch[]; + /** + * Option types on how to complete branch execution. + */ + completionType?: "allOf" | "atLeast"; + /** + * Used when completionType is set to 'atLeast' to specify the minimum number of branches that must complete before the state will transition. + */ + numCompleted?: number | string; + /** + * States error handling and retries definitions + */ + onErrors?: Error[]; + /** + * Next transition of the workflow after all branches have completed execution + */ + transition?: Transition; + /** + * Unique Name of a workflow state which is responsible for compensation of this state + */ + compensatedBy?: string; + /** + * If true, this state is used to compensate another state. Default is false + */ + usedForCompensation?: boolean; + metadata?: /* Metadata information */ Metadata; + } + /** + * Produce an event and set its data + */ + export interface Produceeventdef { + /** + * References a name of a defined event + */ + eventRef: string; + /** + * If String, expression which selects parts of the states data output to become the data of the produced event. If object a custom object to become the data of produced event. + */ + data?: string | { + [key: string]: any; + }; + /** + * Add additional event extension context attributes + */ + contextAttributes?: { + [name: string]: string; + }; + } + export type Retries = string /* uri */ | [ + Retrydef, + ...Retrydef[] + ]; + export interface Retrydef { + /** + * Unique retry strategy name + */ + name: string; + /** + * Time delay between retry attempts (ISO 8601 duration format) + */ + delay?: string; + /** + * Maximum time delay between retry attempts (ISO 8601 duration format) + */ + maxDelay?: string; + /** + * Static value by which the delay increases during each attempt (ISO 8601 time format) + */ + increment?: string; + /** + * Numeric value, if specified the delay between retries is multiplied by this value. + */ + multiplier?: number | string; + /** + * Maximum number of retry attempts. + */ + maxAttempts: number | string; + /** + * If float type, maximum amount of random time added or subtracted from the delay between each retry relative to total delay (between 0 and 1). If string type, absolute maximum amount of random time added or subtracted from the delay between each retry (ISO 8601 duration format) + */ + jitter?: number | string; + } + export type Schedule = string | /* Start state schedule definition */ ({ + /** + * Time interval (must be repeating interval) described with ISO 8601 format. Declares when workflow instances will be automatically created. + */ + interval: string; + cron?: Crondef; + /** + * Timezone name used to evaluate the interval & cron-expression. (default: UTC) + */ + timezone?: string; + } | { + /** + * Time interval (must be repeating interval) described with ISO 8601 format. Declares when workflow instances will be automatically created. + */ + interval?: string; + cron: Crondef; + /** + * Timezone name used to evaluate the interval & cron-expression. (default: UTC) + */ + timezone?: string; + }); + export type Startdef = string | { + /** + * Name of the starting workflow state + */ + stateName: string; + /** + * Define the time/repeating intervals or cron at which workflow instances should be automatically started. + */ + schedule: Schedule; + }; + export interface Statedatafilter { + /** + * Workflow expression to filter the state data input + */ + input?: string; + /** + * Workflow expression that filters the state data output + */ + output?: string; + } + export type Subflowref = string | { + /** + * Workflow execution must wait for sub-workflow to finish before continuing + */ + waitForCompletion?: boolean; + /** + * Unique id of the sub-workflow to be invoked + */ + workflowId: string; + }; + export type Switchstate = /* Permits transitions to other states based on data conditions */ Databasedswitch | /* Permits transitions to other states based on events */ Eventbasedswitch; + export type Transition = string | { + /** + * Name of state to transition to + */ + nextState: string; + /** + * Array of events to be produced before the transition happens + */ + produceEvents?: /* Produce an event and set its data */ Produceeventdef[]; + /** + * If set to true, triggers workflow compensation when before this transition is taken. Default is false + */ + compensate?: boolean; + }; + /** + * Switch state data based condition + */ + export interface Transitiondatacondition { + /** + * Data condition name + */ + name?: string; + /** + * Workflow expression evaluated against state data. Must evaluate to true or false + */ + condition: string; + /** + * Workflow transition if condition is evaluated to true + */ + transition: Transition; + metadata?: /* Metadata information */ Metadata; + } + /** + * Switch state data event condition + */ + export interface Transitioneventcondition { + /** + * Event condition name + */ + name?: string; + /** + * References an unique event name in the defined workflow events + */ + eventRef: string; + /** + * Next transition of the workflow if there is valid matches + */ + transition: Transition; + /** + * Event data filter definition + */ + eventDataFilter?: Eventdatafilter; + metadata?: /* Metadata information */ Metadata; + } +} diff --git a/src/schema/README.md b/src/schema/README.md new file mode 100644 index 0000000..7d5a864 --- /dev/null +++ b/src/schema/README.md @@ -0,0 +1,2 @@ +# Auto generated notice +This directory and its content has been generated automatically. Do not modify its content, it WILL be lost. \ No newline at end of file diff --git a/src/schema/common.json b/src/schema/common.json new file mode 100644 index 0000000..81c412c --- /dev/null +++ b/src/schema/common.json @@ -0,0 +1,15 @@ +{ + "$id": "https://serverlessworkflow.org/core/common.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - common schema", + "type": "object", + "definitions": { + "metadata": { + "type": "object", + "description": "Metadata information", + "additionalProperties": { + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/src/schema/events.json b/src/schema/events.json new file mode 100644 index 0000000..58c1043 --- /dev/null +++ b/src/schema/events.json @@ -0,0 +1,112 @@ +{ + "$id": "https://serverlessworkflow.org/core/events.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - events schema", + "type": "object", + "events": { + "oneOf": [ + { + "type": "string", + "format": "uri", + "description": "URI to a resource containing event definitions (json or yaml)" + }, + { + "type": "array", + "description": "Workflow CloudEvent definitions. Defines CloudEvents that can be consumed or produced", + "items": { + "type": "object", + "$ref": "#/definitions/eventdef" + }, + "additionalItems": false, + "minItems": 1 + } + ] + }, + "required": [ + "events" + ], + "definitions": { + "eventdef": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Unique event name", + "minLength": 1 + }, + "source": { + "type": "string", + "description": "CloudEvent source" + }, + "type": { + "type": "string", + "description": "CloudEvent type" + }, + "kind": { + "type": "string", + "enum": [ + "consumed", + "produced" + ], + "description": "Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. Default is 'consumed'", + "default": "consumed" + }, + "correlation": { + "type": "array", + "description": "CloudEvent correlation definitions", + "minItems": 1, + "items": { + "type": "object", + "$ref": "#/definitions/correlationDef" + }, + "additionalItems": false + }, + "metadata": { + "$ref": "common.json#/definitions/metadata", + "description": "Metadata information" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "kind": { + "const": "consumed" + } + } + }, + "then": { + "required": [ + "name", + "source", + "type" + ] + }, + "else": { + "required": [ + "name", + "type" + ] + } + }, + "correlationDef": { + "type": "object", + "description": "CloudEvent correlation definition", + "properties": { + "contextAttributeName": { + "type": "string", + "description": "CloudEvent Extension Context Attribute name", + "minLength": 1 + }, + "contextAttributeValue": { + "type": "string", + "description": "CloudEvent Extension Context Attribute value", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "contextAttributeName" + ] + } + } +} \ No newline at end of file diff --git a/src/schema/extensions/kpi.json b/src/schema/extensions/kpi.json new file mode 100644 index 0000000..4455c9a --- /dev/null +++ b/src/schema/extensions/kpi.json @@ -0,0 +1,282 @@ +{ + "$id": "https://serverlessworkflow.org/extensions/kpi.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - KPIs Extension Schema", + "type": "object", + "definitions": { + "kpi": { + "type": "object", + "description": "Serverless Workflow KPI Extension", + "properties": { + "extensionid": { + "type": "string", + "default": "workflow-kpi-extension", + "description": "Extension unique identifier" + }, + "workflowid": { + "type": "string", + "minLength": 1, + "description": "Workflow definition unique identifier (workflow id property)" + }, + "currency": { + "type": "string", + "default": "USD", + "description": "Unit for all cost-based KPI parameters. Default 'USD'" + }, + "events": { + "type": "array", + "description": "Events KPIs", + "items": { + "type": "object", + "$ref": "#/definitions/eventskpi" + } + }, + "functions": { + "type": "array", + "description": "Functions KPIs", + "items": { + "type": "object", + "$ref": "#/definitions/functionskpi" + } + }, + "states": { + "type": "array", + "description": "States KPIs", + "items": { + "type": "object", + "$ref": "#/definitions/stateskpi" + } + }, + "workflow": { + "description": "Workflow KPIs", + "$ref": "#/definitions/workflowkpi" + } + }, + "required": [ + "extensionid", + "workflowid" + ] + }, + "eventskpi": { + "type": "object", + "properties": { + "for": { + "type": "string", + "description": "References an unique event name in the defined workflow events" + }, + "per": { + "description": "Define the kpi thresholds in terms of time and/or num of workflow instances", + "$ref": "#/definitions/thresholds" + }, + "maxConsumed": { + "type": "string", + "description": "If event kind is 'consumed', the max amount of times this event is consumed" + }, + "minConsumed": { + "type": "string", + "description": "If event kind is 'consumed', the min amount of times this event is consumed" + }, + "avgConsumed": { + "type": "string", + "description": "If event kind is 'consumed', the avg amount of times this event is consumed" + }, + "maxProduced": { + "type": "string", + "description": "If event kind is 'produced', the max amount of times this event is produced" + }, + "minProduced": { + "type": "string", + "description": "If event kind is 'produced', the min amount times this event is produced" + }, + "avgProduced": { + "type": "string", + "description": "If event kind is 'produced', the avg amount of times this event is produced" + } + }, + "required": [ + "for", + "per" + ] + }, + "functionskpi": { + "type": "object", + "allOf": [ + { + "properties": { + "for": { + "type": "string", + "description": "References an unique function name in the defined workflow functions" + }, + "per": { + "description": "Define the kpi thresholds in terms of time and/or num of workflow instances", + "$ref": "#/definitions/thresholds" + }, + "maxErrors": { + "type": "string", + "description": "Max number of errors during function invocation" + }, + "maxRetry": { + "type": "string", + "description": "Max number of retries done for this function invocation" + }, + "maxTimeout": { + "type": "string", + "description": "Max number of times the function timeout time was reached" + } + } + }, + { + "$ref": "#/definitions/invocationkpis" + }, + { + "$ref": "#/definitions/costkpis" + } + ], + "required": [ + "for", + "per" + ] + }, + "stateskpi": { + "type": "object", + "allOf": [ + { + "properties": { + "for": { + "type": "string", + "description": "References an unique state name in the defined workflow events" + }, + "per": { + "description": "Define the kpi thresholds in terms of time and/or num of workflow instances", + "$ref": "#/definitions/thresholds" + } + } + }, + { + "$ref": "#/definitions/execkpis" + }, + { + "$ref": "#/definitions/durationkpis" + }, + { + "$ref": "#/definitions/costkpis" + } + ], + "required": [ + "for", + "per" + ] + }, + "workflowkpi": { + "type": "object", + "allOf": [ + { + "properties": { + "per": { + "description": "Define the kpi thresholds in terms of time and/or num of workflow instances", + "$ref": "#/definitions/thresholds" + } + } + }, + { + "$ref": "#/definitions/invocationkpis" + }, + { + "$ref": "#/definitions/durationkpis" + }, + { + "$ref": "#/definitions/costkpis" + } + ], + "required": [ + "per" + ] + }, + "thresholds": { + "type": "object", + "properties": { + "time": { + "type": "string", + "default": "PT1D", + "description": "ISO_8601 time. 1 day default" + }, + "instances": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "Number of workflow instances" + } + }, + "required": [ + ] + }, + "costkpis": { + "type": "object", + "properties": { + "maxCost": { + "type": "string", + "description": "Max cost" + }, + "minCost": { + "type": "string", + "description": "Min cost" + }, + "avgCost": { + "type": "string", + "description": "Avg cost" + } + } + }, + "invocationkpis": { + "type": "object", + "properties": { + "maxInvoked": { + "type": "string", + "description": "Max number of invocation times" + }, + "minInvoked": { + "type": "string", + "description": "Min number of invocation times" + }, + "avgInvoked": { + "type": "string", + "description": "Avg number of invocation times" + } + } + }, + "durationkpis": { + "type": "object", + "properties": { + "maxDuration": { + "type": "string", + "description": "ISO 8601. Max duration" + }, + "minDuration": { + "type": "string", + "description": "ISO 8601. Min duration" + }, + "avgDuration": { + "type": "string", + "description": "ISO 8601. Avg duration" + } + } + }, + "execkpis": { + "type": "object", + "properties": { + "maxExec": { + "type": "string", + "description": "Max exec number" + }, + "minExec": { + "type": "string", + "description": "Min exec numbe" + }, + "avgExec": { + "type": "string", + "description": "Avg exec number" + } + } + } + } +} \ No newline at end of file diff --git a/src/schema/functions.json b/src/schema/functions.json new file mode 100644 index 0000000..84388b9 --- /dev/null +++ b/src/schema/functions.json @@ -0,0 +1,60 @@ +{ + "$id": "https://serverlessworkflow.org/core/functions.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - functions schema", + "type": "object", + "functions": { + "oneOf": [ + { + "type": "string", + "format": "uri", + "description": "URI to a resource containing function definitions (json or yaml)" + }, + { + "type": "array", + "description": "Workflow function definitions", + "items": { + "type": "object", + "$ref": "#/definitions/function" + }, + "additionalItems": false, + "minItems": 1 + } + ] + }, + "required": [ + "functions" + ], + "definitions": { + "function": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Unique function name", + "minLength": 1 + }, + "operation": { + "type": "string", + "description": "If type is `rest`, #. If type is `rpc`, ##. If type is `expression`, defines the workflow expression.", + "minLength": 1 + }, + "type": { + "type": "string", + "description": "Defines the function type. Is either `rest`, `rpc` or `expression`. Default is `rest`", + "enum": [ + "rest", + "rpc", + "expression" + ], + "default": "rest" + } + }, + "additionalProperties": false, + "required": [ + "name", + "operation" + ] + } + } +} \ No newline at end of file diff --git a/src/schema/retries.json b/src/schema/retries.json new file mode 100644 index 0000000..b004b06 --- /dev/null +++ b/src/schema/retries.json @@ -0,0 +1,85 @@ +{ + "$id": "https://serverlessworkflow.org/core/retries.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - retries schema", + "type": "object", + "retries": { + "oneOf": [ + { + "type": "string", + "format": "uri", + "description": "URI to a resource containing retry definitions (json or yaml)" + }, + { + "type": "array", + "description": "Workflow Retry definitions. Define retry strategies that can be referenced in states onError definitions", + "items": { + "type": "object", + "$ref": "#/definitions/retrydef" + }, + "additionalItems": false, + "minItems": 1 + } + ] + }, + "required": [ + "retries" + ], + "definitions": { + "retrydef": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Unique retry strategy name", + "minLength": 1 + }, + "delay": { + "type": "string", + "description": "Time delay between retry attempts (ISO 8601 duration format)" + }, + "maxDelay": { + "type": "string", + "description": "Maximum time delay between retry attempts (ISO 8601 duration format)" + }, + "increment": { + "type": "string", + "description": "Static value by which the delay increases during each attempt (ISO 8601 time format)" + }, + "multiplier": { + "type": [ + "number", + "string" + ], + "minimum": 0, + "minLength": 1, + "multipleOf": 0.01, + "description": "Numeric value, if specified the delay between retries is multiplied by this value." + }, + "maxAttempts": { + "type": [ + "number", + "string" + ], + "minimum": 1, + "minLength": 0, + "description": "Maximum number of retry attempts." + }, + "jitter": { + "type": [ + "number", + "string" + ], + "minimum": 0, + "maximum": 1, + "description": "If float type, maximum amount of random time added or subtracted from the delay between each retry relative to total delay (between 0 and 1). If string type, absolute maximum amount of random time added or subtracted from the delay between each retry (ISO 8601 duration format)" + } + }, + "additionalProperties": false, + "required": [ + "name", + "maxAttempts" + ] + } + } +} diff --git a/src/schema/workflow.json b/src/schema/workflow.json new file mode 100644 index 0000000..cf005e5 --- /dev/null +++ b/src/schema/workflow.json @@ -0,0 +1,1720 @@ +{ + "$id": "https://serverlessworkflow.org/core/workflow.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Serverless Workflow specification - workflow schema", + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Workflow unique identifier", + "minLength": 1 + }, + "key": { + "type": "string", + "description": "Domain-specific workflow identifier", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "Workflow name", + "minLength": 1 + }, + "description": { + "type": "string", + "description": "Workflow description" + }, + "version": { + "type": "string", + "description": "Workflow version", + "minLength": 1 + }, + "annotations": { + "type": "array", + "description": "List of helpful terms describing the workflows intended purpose, subject areas, or other important qualities", + "minItems": 1, + "items": { + "type": "string" + }, + "additionalItems": false + }, + "dataInputSchema": { + "oneOf": [ + { + "type": "string", + "description": "URI of the JSON Schema used to validate the workflow data input", + "minLength": 1 + }, + { + "type": "object", + "description": "Workflow data input schema definition", + "properties": { + "schema": { + "type": "string", + "description": "URI of the JSON Schema used to validate the workflow data input", + "minLength": 1 + }, + "failOnValidationErrors": { + "type": "boolean", + "default": true, + "description": "Determines if workflow execution should continue if there are validation errors" + } + }, + "additionalProperties": false, + "required": [ + "schema", + "failOnValidationErrors" + ] + } + ] + }, + "start": { + "$ref": "#/definitions/startdef" + }, + "schemaVersion": { + "type": "string", + "description": "Serverless Workflow schema version", + "minLength": 1 + }, + "expressionLang": { + "type": "string", + "description": "Identifies the expression language used for workflow expressions. Default is 'jq'", + "default": "jq", + "minLength": 1 + }, + "execTimeout": { + "$ref": "#/definitions/exectimeout" + }, + "keepActive": { + "type": "boolean", + "default": false, + "description": "If 'true', workflow instances is not terminated when there are no active execution paths. Instance can be terminated via 'terminate end definition' or reaching defined 'execTimeout'" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + }, + "events": { + "$ref": "events.json#/events" + }, + "functions": { + "$ref": "functions.json#/functions" + }, + "retries": { + "$ref": "retries.json#/retries" + }, + "states": { + "type": "array", + "description": "State definitions", + "items": { + "anyOf": [ + { + "title": "Delay State", + "$ref": "#/definitions/delaystate" + }, + { + "title": "Event State", + "$ref": "#/definitions/eventstate" + }, + { + "title": "Operation State", + "$ref": "#/definitions/operationstate" + }, + { + "title": "Parallel State", + "$ref": "#/definitions/parallelstate" + }, + { + "title": "Switch State", + "$ref": "#/definitions/switchstate" + }, + { + "title": "Inject State", + "$ref": "#/definitions/injectstate" + }, + { + "title": "ForEach State", + "$ref": "#/definitions/foreachstate" + }, + { + "title": "Callback State", + "$ref": "#/definitions/callbackstate" + } + ] + }, + "additionalItems": false, + "minItems": 1 + } + }, + "oneOf": [ + { + "required": [ + "id", + "name", + "start", + "states" + ] + }, + { + "required": [ + "key", + "name", + "start", + "states" + ] + } + ], + "definitions": { + "crondef": { + "oneOf": [ + { + "type": "string", + "description": "Cron expression defining when workflow instances should be created (automatically)", + "minLength": 1 + }, + { + "type": "object", + "properties": { + "expression": { + "type": "string", + "description": "Repeating interval (cron expression) describing when the workflow instance should be created", + "minLength": 1 + }, + "validUntil": { + "type": "string", + "description": "Specific date and time (ISO 8601 format) when the cron expression invocation is no longer valid" + } + }, + "additionalProperties": false, + "required": ["expression"] + } + ] + }, + "exectimeout": { + "type": "object", + "properties": { + "duration": { + "type": "string", + "description": "Timeout duration (ISO 8601 duration format)", + "minLength": 1 + }, + "interrupt": { + "type": "boolean", + "description": "If `false`, workflow instance is allowed to finish current execution. If `true`, current workflow execution is abrupted.", + "default": false + }, + "runBefore": { + "type": "string", + "description": "Name of a workflow state to be executed before workflow instance is terminated", + "minLength": 1 + } + }, + "additionalProperties": false, + "required": [ + "duration" + ] + }, + "transition": { + "oneOf": [ + { + "type": "string", + "description": "Name of state to transition to", + "minLength": 1 + }, + { + "type": "object", + "description": "Function Reference", + "properties": { + "nextState": { + "type": "string", + "description": "Name of state to transition to", + "minLength": 1 + }, + "produceEvents": { + "type": "array", + "description": "Array of events to be produced before the transition happens", + "items": { + "type": "object", + "$ref": "#/definitions/produceeventdef" + }, + "additionalItems": false + }, + "compensate": { + "type": "boolean", + "default": false, + "description": "If set to true, triggers workflow compensation when before this transition is taken. Default is false" + } + }, + "additionalProperties": false, + "required": [ + "nextState" + ] + } + ] + }, + "error": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Domain-specific error name, or '*' to indicate all possible errors", + "minLength": 1 + }, + "code": { + "type": "string", + "description": "Error code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. Should not be defined if error is set to '*'", + "minLength": 1 + }, + "retryRef": { + "type": "string", + "description": "References a unique name of a retry definition.", + "minLength": 1 + }, + "transition": { + "description": "Transition to next state to handle the error. If retryRef is defined, this transition is taken only if retries were unsuccessful.", + "$ref": "#/definitions/transition" + }, + "end": { + "description": "End workflow execution in case of this error. If retryRef is defined, this ends workflow only if retries were unsuccessful.", + "$ref": "#/definitions/end" + } + }, + "additionalProperties": false, + "oneOf": [ + { + "required": [ + "error", + "transition" + ] + }, + { + "required": [ + "error", + "end" + ] + } + ] + }, + "onevents": { + "type": "object", + "properties": { + "eventRefs": { + "type": "array", + "description": "References one or more unique event names in the defined workflow events", + "minItems": 1, + "items": { + "type": "string" + }, + "additionalItems": false + }, + "actionMode": { + "type": "string", + "enum": [ + "sequential", + "parallel" + ], + "description": "Specifies how actions are to be performed (in sequence of parallel)", + "default": "sequential" + }, + "actions": { + "type": "array", + "description": "Actions to be performed if expression matches", + "items": { + "type": "object", + "$ref": "#/definitions/action" + }, + "additionalItems": false + }, + "eventDataFilter": { + "description": "Event data filter", + "$ref": "#/definitions/eventdatafilter" + } + }, + "additionalProperties": false, + "required": [ + "eventRefs" + ] + }, + "action": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Unique action definition name" + }, + "functionRef": { + "oneOf": [ + { + "type": "string", + "description": "Name of the referenced function", + "minLength": 1 + }, + { + "type": "object", + "description": "Function Reference", + "properties": { + "refName": { + "type": "string", + "description": "Name of the referenced function" + }, + "arguments": { + "type": "object", + "description": "Function arguments" + } + }, + "additionalProperties": false, + "required": [ + "refName" + ] + } + ] + }, + "eventRef": { + "description": "References a 'trigger' and 'result' reusable event definitions", + "$ref": "#/definitions/eventref" + }, + "subFlowRef": { + "description": "References a sub-workflow to invoke", + "$ref": "#/definitions/subflowref" + }, + "timeout": { + "type": "string", + "description": "Time period to wait for function execution to complete (ISO 8601 format)" + }, + "actionDataFilter": { + "description": "Action data filter", + "$ref": "#/definitions/actiondatafilter" + } + }, + "additionalProperties": false, + "oneOf": [ + { + "required": [ + "functionRef" + ] + }, + { + "required": [ + "eventRef" + ] + }, + { + "required": [ + "subFlowRef" + ] + } + ] + }, + "eventref": { + "type": "object", + "description": "Event References", + "properties": { + "triggerEventRef": { + "type": "string", + "description": "Reference to the unique name of a 'produced' event definition" + }, + "resultEventRef": { + "type": "string", + "description": "Reference to the unique name of a 'consumed' event definition" + }, + "data": { + "type": [ + "string", + "object" + ], + "description": "If string type, an expression which selects parts of the states data output to become the data (payload) of the event referenced by 'triggerEventRef'. If object type, a custom object to become the data (payload) of the event referenced by 'triggerEventRef'." + }, + "contextAttributes": { + "type": "object", + "description": "Add additional extension context attributes to the produced event", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "triggerEventRef", + "resultEventRef" + ] + }, + "subflowref": { + "oneOf": [ + { + "type": "string", + "description": "Unique id of the sub-workflow to be invoked", + "minLength": 1 + }, + { + "type": "object", + "description": "Specifies a sub-workflow to be invoked", + "properties": { + "waitForCompletion": { + "type": "boolean", + "default": true, + "description": "Workflow execution must wait for sub-workflow to finish before continuing" + }, + "workflowId": { + "type": "string", + "description": "Unique id of the sub-workflow to be invoked" + } + }, + "required": [ + "workflowId" + ] + } + ] + }, + "branch": { + "type": "object", + "description": "Branch Definition", + "properties": { + "name": { + "type": "string", + "description": "Branch name" + }, + "actions": { + "type": "array", + "description": "Actions to be executed in this branch", + "items": { + "type": "object", + "$ref": "#/definitions/action" + }, + "additionalItems": false + } + }, + "additionalProperties": false, + "required": [ + "name", + "actions" + ] + }, + "delaystate": { + "type": "object", + "description": "Causes the workflow execution to delay for a specified duration", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "delay", + "description": "State type" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "timeDelay": { + "type": "string", + "description": "Amount of time (ISO 8601 format) to delay" + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after the time delay", + "$ref": "#/definitions/transition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "timeDelay" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "timeDelay", + "end" + ] + }, + { + "required": [ + "name", + "type", + "timeDelay", + "transition" + ] + } + ] + } + }, + "eventstate": { + "type": "object", + "description": "This state is used to wait for events from event sources, then consumes them and invoke one or more actions to run in sequence or parallel", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "event", + "description": "State type" + }, + "exclusive": { + "type": "boolean", + "default": true, + "description": "If true consuming one of the defined events causes its associated actions to be performed. If false all of the defined events must be consumed in order for actions to be performed" + }, + "onEvents": { + "type": "array", + "description": "Define the events to be consumed and optional actions to be performed", + "items": { + "type": "object", + "$ref": "#/definitions/onevents" + }, + "additionalItems": false + }, + "timeout": { + "type": "string", + "description": "Time period to wait for incoming events (ISO 8601 format)" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after all the actions have been performed", + "$ref": "#/definitions/transition" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "oneOf": [ + { + "required": [ + "name", + "type", + "onEvents", + "end" + ] + }, + { + "required": [ + "name", + "type", + "onEvents", + "transition" + ] + }, + { + "required": [ + "name", + "type", + "onEvents", + "end" + ] + } + ] + }, + "operationstate": { + "type": "object", + "description": "Defines actions be performed. Does not wait for incoming events", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "operation", + "description": "State type" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "actionMode": { + "type": "string", + "enum": [ + "sequential", + "parallel" + ], + "description": "Specifies whether actions are performed in sequence or in parallel", + "default": "sequential" + }, + "actions": { + "type": "array", + "description": "Actions to be performed", + "items": { + "type": "object", + "$ref": "#/definitions/action" + } + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after all the actions have been performed", + "$ref": "#/definitions/transition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "actions" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "actions", + "end" + ] + }, + { + "required": [ + "name", + "type", + "actions", + "transition" + ] + }, + { + "required": [ + "name", + "type", + "actions", + "end" + ] + } + ] + } + }, + "parallelstate": { + "type": "object", + "description": "Consists of a number of states that are executed in parallel", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "parallel", + "description": "State type" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "branches": { + "type": "array", + "description": "Branch Definitions", + "items": { + "type": "object", + "$ref": "#/definitions/branch" + }, + "additionalItems": false + }, + "completionType": { + "type": "string", + "enum": [ + "allOf", + "atLeast" + ], + "description": "Option types on how to complete branch execution.", + "default": "allOf" + }, + "numCompleted": { + "type": [ + "number", + "string" + ], + "minimum": 0, + "minLength": 0, + "description": "Used when completionType is set to 'atLeast' to specify the minimum number of branches that must complete before the state will transition." + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after all branches have completed execution", + "$ref": "#/definitions/transition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "branches" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "branches", + "end" + ] + }, + { + "required": [ + "name", + "type", + "branches", + "transition" + ] + }, + { + "required": [ + "name", + "type", + "branches", + "end" + ] + } + ] + } + }, + "switchstate": { + "oneOf": [ + { + "$ref": "#/definitions/databasedswitch" + }, + { + "$ref": "#/definitions/eventbasedswitch" + } + ] + }, + "eventbasedswitch": { + "type": "object", + "description": "Permits transitions to other states based on events", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "switch", + "description": "State type" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "eventConditions": { + "type": "array", + "description": "Defines conditions evaluated against events", + "items": { + "type": "object", + "$ref": "#/definitions/eventcondition" + }, + "additionalItems": false + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "eventTimeout": { + "type": "string", + "description": "If eventConditions is used, defines the time period to wait for events (ISO 8601 format)" + }, + "defaultCondition": { + "description": "Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition", + "$ref": "#/definitions/defaultconditiondef" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "name", + "type", + "eventConditions" + ] + }, + "databasedswitch": { + "type": "object", + "description": "Permits transitions to other states based on data conditions", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "switch", + "description": "State type" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "dataConditions": { + "type": "array", + "description": "Defines conditions evaluated against state data", + "items": { + "type": "object", + "$ref": "#/definitions/datacondition" + }, + "additionalItems": false + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "defaultCondition": { + "description": "Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition", + "$ref": "#/definitions/defaultconditiondef" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "name", + "type", + "dataConditions" + ] + }, + "defaultconditiondef": { + "type": "object", + "description": "DefaultCondition definition. Can be either a transition or end definition", + "properties": { + "transition": { + "$ref": "#/definitions/transition" + }, + "end": { + "$ref": "#/definitions/end" + } + }, + "additionalProperties": false, + "oneOf": [ + { + "required": [ + "transition" + ] + }, + { + "required": [ + "end" + ] + } + ] + }, + "eventcondition": { + "oneOf": [ + { + "$ref": "#/definitions/transitioneventcondition" + }, + { + "$ref": "#/definitions/enddeventcondition" + } + ] + }, + "transitioneventcondition": { + "type": "object", + "description": "Switch state data event condition", + "properties": { + "name": { + "type": "string", + "description": "Event condition name" + }, + "eventRef": { + "type": "string", + "description": "References an unique event name in the defined workflow events" + }, + "transition": { + "description": "Next transition of the workflow if there is valid matches", + "$ref": "#/definitions/transition" + }, + "eventDataFilter": { + "description": "Event data filter definition", + "$ref": "#/definitions/eventdatafilter" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "eventRef", + "transition" + ] + }, + "enddeventcondition": { + "type": "object", + "description": "Switch state data event condition", + "properties": { + "name": { + "type": "string", + "description": "Event condition name" + }, + "eventRef": { + "type": "string", + "description": "References an unique event name in the defined workflow events" + }, + "end": { + "$ref": "#/definitions/end", + "description": "Explicit transition to end" + }, + "eventDataFilter": { + "description": "Event data filter definition", + "$ref": "#/definitions/eventdatafilter" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "eventRef", + "end" + ] + }, + "datacondition": { + "oneOf": [ + { + "$ref": "#/definitions/transitiondatacondition" + }, + { + "$ref": "#/definitions/enddatacondition" + } + ] + }, + "transitiondatacondition": { + "type": "object", + "description": "Switch state data based condition", + "properties": { + "name": { + "type": "string", + "description": "Data condition name" + }, + "condition": { + "type": "string", + "description": "Workflow expression evaluated against state data. Must evaluate to true or false" + }, + "transition": { + "description": "Workflow transition if condition is evaluated to true", + "$ref": "#/definitions/transition" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "condition", + "transition" + ] + }, + "enddatacondition": { + "type": "object", + "description": "Switch state data based condition", + "properties": { + "name": { + "type": "string", + "description": "Data condition name" + }, + "condition": { + "type": "string", + "description": "Workflow expression evaluated against state data. Must evaluate to true or false" + }, + "end": { + "$ref": "#/definitions/end", + "description": "Workflow end definition" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "required": [ + "condition", + "end" + ] + }, + "injectstate": { + "type": "object", + "description": "Inject static data into state data. Does not perform any actions", + "properties": { + "id": { + "type": "string", + "description": "Unique state id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "inject", + "description": "State type" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "data": { + "type": "object", + "description": "JSON object which can be set as states data input and can be manipulated via filters" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "transition": { + "description": "Next transition of the workflow after injection has completed", + "$ref": "#/definitions/transition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "data" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "data", + "end" + ] + }, + { + "required": [ + "name", + "type", + "data", + "transition" + ] + } + ] + } + }, + "foreachstate": { + "type": "object", + "description": "Execute a set of defined actions or workflows for each element of a data array", + "properties": { + "id": { + "type": "string", + "description": "Unique State id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "foreach", + "description": "State type" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "inputCollection": { + "type": "string", + "description": "Workflow expression selecting an array element of the states data" + }, + "outputCollection": { + "type": "string", + "description": "Workflow expression specifying an array element of the states data to add the results of each iteration" + }, + "iterationParam": { + "type": "string", + "description": "Name of the iteration parameter that can be referenced in actions/workflow. For each parallel iteration, this param should contain an unique element of the inputCollection array" + }, + "max": { + "type": [ + "number", + "string" + ], + "minimum": 0, + "minLength": 0, + "description": "Specifies how upper bound on how many iterations may run in parallel" + }, + "actions": { + "type": "array", + "description": "Actions to be executed for each of the elements of inputCollection", + "items": { + "type": "object", + "$ref": "#/definitions/action" + }, + "additionalItems": false + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after state has completed", + "$ref": "#/definitions/transition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "inputCollection", + "iterationParam", + "actions" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "inputCollection", + "iterationParam", + "actions", + "end" + ] + }, + { + "required": [ + "name", + "type", + "inputCollection", + "iterationParam", + "actions", + "transition" + ] + } + ] + } + }, + "callbackstate": { + "type": "object", + "description": "This state performs an action, then waits for the callback event that denotes completion of the action", + "properties": { + "id": { + "type": "string", + "description": "Unique state id", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "State name" + }, + "type": { + "type": "string", + "const": "callback", + "description": "State type" + }, + "action": { + "description": "Defines the action to be executed", + "$ref": "#/definitions/action" + }, + "eventRef": { + "type": "string", + "description": "References an unique callback event name in the defined workflow events" + }, + "timeout": { + "type": "string", + "description": "Time period to wait for incoming events (ISO 8601 format)" + }, + "eventDataFilter": { + "description": "Event data filter", + "$ref": "#/definitions/eventdatafilter" + }, + "stateDataFilter": { + "description": "State data filter", + "$ref": "#/definitions/statedatafilter" + }, + "onErrors": { + "type": "array", + "description": "States error handling and retries definitions", + "items": { + "type": "object", + "$ref": "#/definitions/error" + }, + "additionalItems": false + }, + "transition": { + "description": "Next transition of the workflow after all the actions have been performed", + "$ref": "#/definitions/transition" + }, + "end": { + "$ref": "#/definitions/end", + "description": "State end definition" + }, + "compensatedBy": { + "type": "string", + "minLength": 1, + "description": "Unique Name of a workflow state which is responsible for compensation of this state" + }, + "usedForCompensation": { + "type": "boolean", + "default": false, + "description": "If true, this state is used to compensate another state. Default is false" + }, + "metadata": { + "$ref": "common.json#/definitions/metadata" + } + }, + "additionalProperties": false, + "if": { + "properties": { + "usedForCompensation": { + "const": true + } + } + }, + "then": { + "required": [ + "name", + "type", + "action", + "eventRef", + "timeout" + ] + }, + "else": { + "oneOf": [ + { + "required": [ + "name", + "type", + "action", + "eventRef", + "timeout", + "end" + ] + }, + { + "required": [ + "name", + "type", + "action", + "eventRef", + "timeout", + "transition" + ] + } + ] + } + }, + "startdef": { + "oneOf": [ + { + "type": "string", + "description": "Name of the starting workflow state", + "minLength": 1 + }, + { + "type": "object", + "description": "Workflow start definition", + "properties": { + "stateName": { + "type": "string", + "description": "Name of the starting workflow state", + "minLength": 1 + }, + "schedule": { + "description": "Define the time/repeating intervals or cron at which workflow instances should be automatically started.", + "$ref": "#/definitions/schedule" + } + }, + "additionalProperties": false, + "required": [ + "stateName", + "schedule" + ] + } + ] + }, + "schedule": { + "oneOf": [ + { + "type": "string", + "description": "Time interval (must be repeating interval) described with ISO 8601 format. Declares when workflow instances will be automatically created. (UTC timezone is assumed)", + "minLength": 1 + }, + { + "type": "object", + "description": "Start state schedule definition", + "properties": { + "interval": { + "type": "string", + "description": "Time interval (must be repeating interval) described with ISO 8601 format. Declares when workflow instances will be automatically created.", + "minLength": 1 + }, + "cron": { + "$ref": "#/definitions/crondef" + }, + "timezone": { + "type": "string", + "description": "Timezone name used to evaluate the interval & cron-expression. (default: UTC)" + } + }, + "additionalProperties": false, + "oneOf": [ + { + "required": [ + "interval" + ] + }, + { + "required": [ + "cron" + ] + } + ] + } + ] + }, + "end": { + "oneOf": [ + { + "type": "boolean", + "description": "State end definition", + "default": true + }, + { + "type": "object", + "description": "State end definition", + "properties": { + "terminate": { + "type": "boolean", + "default": false, + "description": "If true, completes all execution flows in the given workflow instance" + }, + "produceEvents": { + "type": "array", + "description": "Defines events that should be produced", + "items": { + "type": "object", + "$ref": "#/definitions/produceeventdef" + }, + "additionalItems": false + }, + "compensate": { + "type": "boolean", + "default": false, + "description": "If set to true, triggers workflow compensation. Default is false" + } + }, + "additionalProperties": false, + "required": [ + ] + } + ] + }, + "produceeventdef": { + "type": "object", + "description": "Produce an event and set its data", + "properties": { + "eventRef": { + "type": "string", + "description": "References a name of a defined event" + }, + "data": { + "type": [ + "string", + "object" + ], + "description": "If String, expression which selects parts of the states data output to become the data of the produced event. If object a custom object to become the data of produced event." + }, + "contextAttributes": { + "type": "object", + "description": "Add additional event extension context attributes", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "eventRef" + ] + }, + "statedatafilter": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Workflow expression to filter the state data input" + }, + "output": { + "type": "string", + "description": "Workflow expression that filters the state data output" + } + }, + "additionalProperties": false, + "required": [] + }, + "eventdatafilter": { + "type": "object", + "properties": { + "data": { + "type": "string", + "description": "Workflow expression that filters of the event data (payload)" + }, + "toStateData": { + "type": "string", + "description": " Workflow expression that selects a state data element to which the event payload should be added/merged into. If not specified, denotes, the top-level state data element." + } + }, + "additionalProperties": false, + "required": [] + }, + "actiondatafilter": { + "type": "object", + "properties": { + "fromStateData": { + "type": "string", + "description": "Workflow expression that selects state data that the state action can use" + }, + "results": { + "type": "string", + "description": "Workflow expression that filters the actions data results" + }, + "toStateData": { + "type": "string", + "description": "Workflow expression that selects a state data element to which the action results should be added/merged into. If not specified, denote, the top-level state data element" + } + }, + "additionalProperties": false, + "required": [] + } + } +} \ No newline at end of file diff --git a/src/validation/README.md b/src/validation/README.md new file mode 100644 index 0000000..7d5a864 --- /dev/null +++ b/src/validation/README.md @@ -0,0 +1,2 @@ +# Auto generated notice +This directory and its content has been generated automatically. Do not modify its content, it WILL be lost. \ No newline at end of file diff --git a/src/validation/validators-paths.ts b/src/validation/validators-paths.ts new file mode 100644 index 0000000..e4ed772 --- /dev/null +++ b/src/validation/validators-paths.ts @@ -0,0 +1,44 @@ +export const validatorsPaths: [string, string][] = [ + ["Workflow", "https://serverlessworkflow.org/core/workflow.json"], + ['Crondef', 'https://serverlessworkflow.org/core/workflow.json#/definitions/crondef'], + ['Exectimeout', 'https://serverlessworkflow.org/core/workflow.json#/definitions/exectimeout'], + ['Transition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/transition'], + ['Error', 'https://serverlessworkflow.org/core/workflow.json#/definitions/error'], + ['Onevents', 'https://serverlessworkflow.org/core/workflow.json#/definitions/onevents'], + ['Action', 'https://serverlessworkflow.org/core/workflow.json#/definitions/action'], + ['Eventref', 'https://serverlessworkflow.org/core/workflow.json#/definitions/eventref'], + ['Subflowref', 'https://serverlessworkflow.org/core/workflow.json#/definitions/subflowref'], + ['Branch', 'https://serverlessworkflow.org/core/workflow.json#/definitions/branch'], + ['Delaystate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/delaystate'], + ['Eventstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/eventstate'], + ['Operationstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/operationstate'], + ['Parallelstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/parallelstate'], + ['Switchstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/switchstate'], + ['Eventbasedswitch', 'https://serverlessworkflow.org/core/workflow.json#/definitions/eventbasedswitch'], + ['Databasedswitch', 'https://serverlessworkflow.org/core/workflow.json#/definitions/databasedswitch'], + ['Defaultconditiondef', 'https://serverlessworkflow.org/core/workflow.json#/definitions/defaultconditiondef'], + ['Eventcondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/eventcondition'], + ['Transitioneventcondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/transitioneventcondition'], + ['Enddeventcondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/enddeventcondition'], + ['Datacondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/datacondition'], + ['Transitiondatacondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/transitiondatacondition'], + ['Enddatacondition', 'https://serverlessworkflow.org/core/workflow.json#/definitions/enddatacondition'], + ['Injectstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/injectstate'], + ['Foreachstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/foreachstate'], + ['Callbackstate', 'https://serverlessworkflow.org/core/workflow.json#/definitions/callbackstate'], + ['Startdef', 'https://serverlessworkflow.org/core/workflow.json#/definitions/startdef'], + ['Schedule', 'https://serverlessworkflow.org/core/workflow.json#/definitions/schedule'], + ['End', 'https://serverlessworkflow.org/core/workflow.json#/definitions/end'], + ['Produceeventdef', 'https://serverlessworkflow.org/core/workflow.json#/definitions/produceeventdef'], + ['Statedatafilter', 'https://serverlessworkflow.org/core/workflow.json#/definitions/statedatafilter'], + ['Eventdatafilter', 'https://serverlessworkflow.org/core/workflow.json#/definitions/eventdatafilter'], + ['Actiondatafilter', 'https://serverlessworkflow.org/core/workflow.json#/definitions/actiondatafilter'], + ['Metadata', 'https://serverlessworkflow.org/core/common.json#/definitions/metadata'], + ['Function', 'https://serverlessworkflow.org/core/functions.json#/definitions/function'], + ['Eventdef', 'https://serverlessworkflow.org/core/events.json#/definitions/eventdef'], + ['CorrelationDef', 'https://serverlessworkflow.org/core/events.json#/definitions/correlationDef'], + ['Retrydef', 'https://serverlessworkflow.org/core/retries.json#/definitions/retrydef'], + ['Events', 'https://serverlessworkflow.org/core/events.json#/events'], + ['Functions', 'https://serverlessworkflow.org/core/functions.json#/functions'], + ['Retries', 'https://serverlessworkflow.org/core/retries.json#/retries'], +] \ No newline at end of file diff --git a/src/validators.ts b/src/validators.ts index 1b04533..a0e3cf5 100644 --- a/src/validators.ts +++ b/src/validators.ts @@ -4,6 +4,7 @@ import eventsChema from './schema/events.json'; import functionsSchema from './schema/functions.json'; import retriesSchema from './schema/retries.json'; import workflowSchema from './schema/workflow.json'; +import { validatorsPaths } from './validation/validators-paths'; const schemas: any[] = [ commonSchema, @@ -14,54 +15,10 @@ const schemas: any[] = [ ]; const strict: boolean = false; const ajv = new Ajv({ schemas, strict }); -const validatorsInfo: [string, string][] = [ - ["Workflow", "https://serverlessworkflow.org/core/workflow.json"], - ["Action", "https://serverlessworkflow.org/core/workflow.json#/definitions/action"], - ["Actiondatafilter", "https://serverlessworkflow.org/core/workflow.json#/definitions/actiondatafilter"], - ["Branch", "https://serverlessworkflow.org/core/workflow.json#/definitions/branch"], - ["Callbackstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/callbackstate"], - ["CorrelationDef", "https://serverlessworkflow.org/core/events.json#/definitions/correlationDef"], - ["Crondef", "https://serverlessworkflow.org/core/workflow.json#/definitions/crondef"], - ["Databasedswitch", "https://serverlessworkflow.org/core/workflow.json#/definitions/databasedswitch"], - ["Datacondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/datacondition"], - ["Defaultconditiondef", "https://serverlessworkflow.org/core/workflow.json#/definitions/defaultconditiondef"], - ["Delaystate", "https://serverlessworkflow.org/core/workflow.json#/definitions/delaystate"], - ["End", "https://serverlessworkflow.org/core/workflow.json#/definitions/end"], - ["Enddatacondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/enddatacondition"], - ["Enddeventcondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/enddeventcondition"], - ["Error", "https://serverlessworkflow.org/core/workflow.json#/definitions/error"], - ["Eventbasedswitch", "https://serverlessworkflow.org/core/workflow.json#/definitions/eventbasedswitch"], - ["Eventcondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/eventcondition"], - ["Eventdatafilter", "https://serverlessworkflow.org/core/workflow.json#/definitions/eventdatafilter"], - ["Eventdef", "https://serverlessworkflow.org/core/events.json#/definitions/eventdef"], - ["Eventref", "https://serverlessworkflow.org/core/workflow.json#/definitions/eventref"], - ["Events", "https://serverlessworkflow.org/core/events.json#/events"], - ["Eventstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/eventstate"], - ["Exectimeout", "https://serverlessworkflow.org/core/workflow.json#/definitions/exectimeout"], - ["Foreachstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/foreachstate"], - ["Function", "https://serverlessworkflow.org/core/functions.json#/definitions/function"], - ["Functions", "https://serverlessworkflow.org/core/functions.json#/functions"], - ["Injectstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/injectstate"], - ["Metadata", "https://serverlessworkflow.org/core/common.json#/definitions/metadata"], - ["Onevents", "https://serverlessworkflow.org/core/workflow.json#/definitions/onevents"], - ["Operationstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/operationstate"], - ["Parallelstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/parallelstate"], - ["Produceeventdef", "https://serverlessworkflow.org/core/workflow.json#/definitions/produceeventdef"], - ["Retries", "https://serverlessworkflow.org/core/retries.json#/retries"], - ["Retrydef", "https://serverlessworkflow.org/core/retries.json#/definitions/retrydef"], - ["Schedule", "https://serverlessworkflow.org/core/workflow.json#/definitions/schedule"], - ["Startdef", "https://serverlessworkflow.org/core/workflow.json#/definitions/startdef"], - ["Statedatafilter", "https://serverlessworkflow.org/core/workflow.json#/definitions/statedatafilter"], - ["Subflowref", "https://serverlessworkflow.org/core/workflow.json#/definitions/subflowref"], - ["Switchstate", "https://serverlessworkflow.org/core/workflow.json#/definitions/switchstate"], - ["Transition", "https://serverlessworkflow.org/core/workflow.json#/definitions/transition"], - ["Transitiondatacondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/transitiondatacondition"], - ["Transitioneventcondition", "https://serverlessworkflow.org/core/workflow.json#/definitions/transitioneventcondition"] -]; export const validators: Map = new Map( - validatorsInfo.map(([type, schemaPath]) => { + validatorsPaths.map(([dataType, schemaPath]) => { const validate = ajv.getSchema(schemaPath); - if (!validate) throw `Unable to find schema '${schemaPath}' for type '${type}'`; - return [ type, validate as ValidateFunction ]; + if (!validate) throw `Unable to find schema '${schemaPath}' for type '${dataType}'`; + return [ dataType, validate as ValidateFunction ]; }) ); \ No newline at end of file diff --git a/src/workflow-converter.ts b/src/workflow-converter.ts index 575cb2b..fc60be0 100644 --- a/src/workflow-converter.ts +++ b/src/workflow-converter.ts @@ -1,18 +1,18 @@ import * as yaml from "js-yaml"; -import WorkflowJson = ServerlessworkflowOrg.Core.WorkflowJson; +import Workflow = ServerlessWorkflow.Workflow; /** - * Exposes utils to parse and serialize WorkflowJson + * Exposes utils to parse and serialize Workflow */ export const WorkflowConverter = { /** - * Parses the provided string as WorkflowJson + * Parses the provided string as Workflow * @param {string} data The JSON or YAML workflow to parse - * @returns {WorkflowJson} The parse WorkflowJson + * @returns {Workflow} The parse Workflow */ - fromString: (data: string): WorkflowJson => { + fromString: (data: string): Workflow => { try { - return yaml.load(data) as WorkflowJson; + return yaml.load(data) as Workflow; } catch (ex) { throw new Error('Format not supported'); @@ -20,14 +20,14 @@ export const WorkflowConverter = { }, /** * Stringifies the provided workflow to the JSON format - * @param {WorkflowJson} workflow The workflow to strigify + * @param {Workflow} workflow The workflow to strigify * @returns {string} The workflow as JSON */ - toJson: (workflow: WorkflowJson): string => JSON.stringify(workflow), + toJson: (workflow: Workflow): string => JSON.stringify(workflow), /** * Stringifies the provided workflow to the YAML format - * @param {WorkflowJson} workflow The workflow to strigify + * @param {Workflow} workflow The workflow to strigify * @returns {string} The workflow as YAML */ - toYaml: (workflow: WorkflowJson): string => yaml.dump(workflow), + toYaml: (workflow: Workflow): string => yaml.dump(workflow), } \ No newline at end of file diff --git a/src/workflow-validator.ts b/src/workflow-validator.ts new file mode 100644 index 0000000..c52935d --- /dev/null +++ b/src/workflow-validator.ts @@ -0,0 +1,26 @@ +import { DefinedError, ValidateFunction } from 'ajv'; +import { validators } from './validators'; +import Workflow = ServerlessWorkflow.Workflow; + +export class WorkflowValidator { + /** The validation errors after running validate(), if any */ + validationErrors: DefinedError[] | never[] = []; + /** The validate function */ + private validateFn: ValidateFunction; + /** + * Creates a new WorkflowValidator for the provided workflow + * @param {Workflow} workflow The workflow to validate + */ + constructor(private workflow: Workflow) { + this.validateFn = validators.get('Workflow') as ValidateFunction; + } + /** + * Validates the workflow, populates the validationErrors if any + * @returns {boolean} If the workflow is valid or not + */ + validate() { + const isValid = this.validateFn(this.workflow); + this.validationErrors = this.validateFn.errors as DefinedError[]; + return isValid; + } +} \ No newline at end of file diff --git a/tests/examples/applicantrequest.json b/tests/examples/applicantrequest.json new file mode 100644 index 0000000..7bf32cd --- /dev/null +++ b/tests/examples/applicantrequest.json @@ -0,0 +1,55 @@ +{ + "id": "applicantrequest", + "version": "1.0", + "name": "Applicant Request Decision Workflow", + "description": "Determine if applicant request is valid", + "start": "CheckApplication", + "functions": [ + { + "name": "sendRejectionEmailFunction", + "operation": "http://myapis.org/applicationapi.json#emailRejection", + "type": "rest" + } + ], + "states":[ + { + "name":"CheckApplication", + "type":"switch", + "dataConditions": [ + { + "condition": "${ .applicants | .age >= 18 }", + "transition": "StartApplication" + }, + { + "condition": "${ .applicants | .age < 18 }", + "transition": "RejectApplication" + } + ], + "default": { + "transition": "RejectApplication" + } + }, + { + "name": "StartApplication", + "type": "subflow", + "workflowId": "startApplicationWorkflowId", + "end": true + }, + { + "name":"RejectApplication", + "type":"operation", + "actionMode":"sequential", + "actions":[ + { + "functionRef": { + "refName": "sendRejectionEmailFunction", + "arguments": { + "applicant": "${ .applicant }" + } + } + } + ], + "end": true + } + ] +} diff --git a/tests/examples/applicantrequest.spec.old.ts b/tests/examples/applicantrequest.spec.old.ts new file mode 100644 index 0000000..2e71757 --- /dev/null +++ b/tests/examples/applicantrequest.spec.old.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as fs from "fs"; +import {WorkflowBuilder} from "../../src"; +import {FunctionDefBuilder} from "../../src"; +import {DatabasedSwitchBuilder} from "../../src"; +import {TransitionDataConditionBuilder} from "../../src"; +import {OperationStateBuilder} from "../../src"; +import {SubFlowStateBuilder} from "../../src"; +import {ActionBuilder} from "../../src"; +import {DefaultTransitionBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; + + +describe("applicationrequest workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("applicantrequest") + .withVersion("1.0") + .withName("Applicant Request Decision Workflow") + .withDescription("Determine if applicant request is valid") + .withStart("CheckApplication") + .withFunctions([new FunctionDefBuilder() + .withName("sendRejectionEmailFunction") + .withOperation("http://myapis.org/applicationapi.json#emailRejection") + .build()]) + .withStates([ + new DatabasedSwitchBuilder() + .withName("CheckApplication") + .withDataConditions( + [new TransitionDataConditionBuilder() + .withCondition("${ .applicants | .age >= 18 }") + .withTransition("StartApplication") + .build(), + new TransitionDataConditionBuilder() + .withCondition("${ .applicants | .age < 18 }") + .withTransition("RejectApplication") + .build()]) + .withDefault(new DefaultTransitionBuilder() + .withTransition( + "RejectApplication", + ).build()) + .build(), + new SubFlowStateBuilder().withName("StartApplication") + .withWorkflowId("startApplicationWorkflowId") + .withEnd(true) + .build(), + new OperationStateBuilder() + .withName("RejectApplication") + .withActionMode("sequential") + .withEnd(true) + .withActions([ + new ActionBuilder().withFunctionRef( + new FunctionRefBuilder() + .withRefName("sendRejectionEmailFunction") + .withArguments({applicant: '${ .applicant }'}) + .build(), + ) + .build(), + ]) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/applicantrequest.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/booklending.json b/tests/examples/booklending.json new file mode 100644 index 0000000..32e7a47 --- /dev/null +++ b/tests/examples/booklending.json @@ -0,0 +1,131 @@ +{ + "id": "booklending", + "name": "Book Lending Workflow", + "version": "1.0", + "start": "Book Lending Request", + "states": [ + { + "name": "Book Lending Request", + "type": "event", + "onEvents": [ + { + "eventRefs": [ + "Book Lending Request Event" + ] + } + ], + "transition": "Get Book Status" + }, + { + "name": "Get Book Status", + "type": "operation", + "actions": [ + { + "functionRef": { + "refName": "Get status for book", + "arguments": { + "bookid": "${ .book.id }" + } + } + } + ], + "transition": "Book Status Decision" + }, + { + "name": "Book Status Decision", + "type": "switch", + "dataConditions": [ + { + "name": "Book is on loan", + "condition": "${ .book.status == \"onloan\" }", + "transition": "Report Status To Lender" + }, + { + "name": "Check is available", + "condition": "${ .book.status == \"available\" }", + "transition": "Check Out Book" + } + ] + }, + { + "name": "Report Status To Lender", + "type": "operation", + "actions": [ + { + "functionRef": { + "refName": "Send status to lender", + "arguments": { + "bookid": "${ .book.id }", + "message": "Book ${ .book.title } is already on loan" + } + } + } + ], + "transition": "Wait for Lender response" + }, + { + "name": "Wait for Lender response", + "type": "switch", + "eventConditions": [ + { + "name": "Hold Book", + "eventRef": "Hold Book Event", + "transition": "Request Hold" + }, + { + "name": "Decline Book Hold", + "eventRef": "Decline Hold Event", + "transition": "Cancel Request" + } + ] + }, + { + "name": "Request Hold", + "type": "operation", + "actions": [ + { + "functionRef": { + "refName": "Request hold for lender", + "arguments": { + "bookid": "${ .book.id }", + "lender": "${ .lender }" + } + } + } + ], + "transition": "Wait two weeks" + }, + { + "name": "Wait two weeks", + "type": "delay", + "timeDelay": "PT2W", + "transition": "Get Book Status" + }, + { + "name": "Check Out Book", + "type": "operation", + "actions": [ + { + "functionRef": { + "refName": "Check out book with id", + "arguments": { + "bookid": "${ .book.id }" + } + } + }, + { + "functionRef": { + "refName": "Notify Lender for checkout", + "arguments": { + "bookid": "${ .book.id }", + "lender": "${ .lender }" + } + } + } + ], + "end": true + } + ], + "functions": "file://books/lending/functions.json", + "events": "file://books/lending/events.json" +} diff --git a/tests/examples/booklending.spec.old.ts b/tests/examples/booklending.spec.old.ts new file mode 100644 index 0000000..5cf1f53 --- /dev/null +++ b/tests/examples/booklending.spec.old.ts @@ -0,0 +1,179 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as fs from 'fs'; +import { + ActionBuilder, + DatabasedSwitchBuilder, + EventsBuilder, + OperationStateBuilder, + TransitionDataConditionBuilder, + WorkflowBuilder, +} from '../../src'; +import {StartBuilder} from "../../src"; +import {EventStateBuilder} from "../../src"; +import {OnEventBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; +import {FunctionsBuilder} from "../../src"; +import {EventBasedSwitchBuilder} from "../../src"; +import {TransitionEventConditionBuilder} from "../../src"; +import {DelayStateBuilder} from "../../src"; + + +describe("booklending workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("booklending") + .withName("Book Lending Workflow") + .withVersion("1.0") + .withStart(new StartBuilder() + .withName("Book Lending Request") + .build()) + .withStates([ + new EventStateBuilder() + .withName("Book Lending Request") + .withOnEvents([ + new OnEventBuilder() + .withEventsRef(["Book Lending Request Event"]) + .build(), + ]) + .withTransition("Get Book Status") + .build(), + new OperationStateBuilder() + .withName("Get Book Status") + .withActions([ + new ActionBuilder().withFunctionRef( + new FunctionRefBuilder() + .withRefName("Get status for book") + .withArguments({ + "bookid": "${ .book.id }", + }) + .build(), + ).build(), + ]) + .withTransition("Book Status Decision") + .build(), + new DatabasedSwitchBuilder() + .withName("Book Status Decision") + .withDataConditions([ + new TransitionDataConditionBuilder() + .withName("Book is on loan") + .withCondition("${ .book.status == \"onloan\" }") + .withTransition("Report Status To Lender") + .build(), + new TransitionDataConditionBuilder() + .withName("Check is available") + .withCondition("${ .book.status == \"available\" }") + .withTransition("Check Out Book") + .build(), + ]) + .build(), + new OperationStateBuilder() + .withName("Report Status To Lender") + .withActions([ + new ActionBuilder() + .withFunctionRef(new FunctionRefBuilder() + .withRefName("Send status to lender") + .withArguments({ + "bookid": "${ .book.id }", + "message": "Book ${ .book.title } is already on loan", + }) + .build()) + .build(), + ]) + .withTransition("Wait for Lender response") + .build(), + new EventBasedSwitchBuilder() + .withName("Wait for Lender response") + .withEventConditions([ + new TransitionEventConditionBuilder() + .withName("Hold Book") + .withEventRef("Hold Book Event") + .withTransition("Request Hold") + .build(), + new TransitionEventConditionBuilder() + .withName("Decline Book Hold") + .withEventRef("Decline Hold Event") + .withTransition("Cancel Request") + .build(), + ]) + .build(), + new OperationStateBuilder() + .withName("Request Hold") + .withActions([ + new ActionBuilder().withFunctionRef( + new FunctionRefBuilder() + .withRefName("Request hold for lender") + .withArguments({ + "bookid": "${ .book.id }", + "lender": "${ .lender }", + }).build()).build(), + ]) + .withTransition("Wait two weeks") + .build(), + new DelayStateBuilder() + .withName("Wait two weeks") + .withTimeDelay("PT2W") + .withTransition("Get Book Status") + .build(), + new OperationStateBuilder() + .withName("Check Out Book") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("Check out book with id") + .withArguments({ + "bookid": "${ .book.id }", + }) + .build()) + .build(), + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("Notify Lender for checkout") + .withArguments({ + "bookid": "${ .book.id }", + "lender": "${ .lender }", + }) + .build()) + .build(), + + ]) + .withEnd(true) + .build(), + + ]) + .withFunctions(new FunctionsBuilder() + .withURIDefinition("file://books/lending/functions.json") + .build()) + .withEvents(new EventsBuilder() + .withURIDefinition("file://books/lending/events.json") + .build()) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/booklending.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/carauctionbids.json b/tests/examples/carauctionbids.json new file mode 100644 index 0000000..e0814d4 --- /dev/null +++ b/tests/examples/carauctionbids.json @@ -0,0 +1,50 @@ +{ + "id": "handleCarAuctionBid", + "version": "1.0", + "name": "Car Auction Bidding Workflow", + "description": "Store a single bid whole the car auction is active", + "start": { + "stateName": "StoreCarAuctionBid", + "schedule": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" + }, + "functions": [ + { + "name": "StoreBidFunction", + "operation": "http://myapis.org/carauctionapi.json#storeBid", + "type": "rest" + } + ], + "events": [ + { + "name": "CarBidEvent", + "type": "carBidMadeType", + "source": "carBidEventSource", + "kind": "consumed" + } + ], + "states": [ + { + "name": "StoreCarAuctionBid", + "type": "event", + "exclusive": true, + "onEvents": [ + { + "eventRefs": [ + "CarBidEvent" + ], + "actions": [ + { + "functionRef": { + "refName": "StoreBidFunction", + "arguments": { + "bid": "${ .bid }" + } + } + } + ] + } + ], + "end": true + } + ] +} diff --git a/tests/examples/carauctionbids.spec.old.ts b/tests/examples/carauctionbids.spec.old.ts new file mode 100644 index 0000000..e0d8273 --- /dev/null +++ b/tests/examples/carauctionbids.spec.old.ts @@ -0,0 +1,80 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {ActionBuilder, FunctionDefBuilder, WorkflowBuilder} from '../../src'; +import * as fs from 'fs'; +import {StartBuilder} from "../../src"; +import {EventsBuilder} from "../../src"; +import {EventBuilder} from "../../src"; +import {EventStateBuilder} from "../../src"; +import {OnEventBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; + +describe("carauctionbids workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("handleCarAuctionBid") + .withVersion("1.0") + .withName("Car Auction Bidding Workflow") + .withDescription("Store a single bid whole the car auction is active") + .withStart(new StartBuilder() + .withName("StoreCarAuctionBid") + .withSchedule("2020-03-20T09:00:00Z/2020-03-20T15:00:00Z").build()) + .withFunctions([new FunctionDefBuilder() + .withName("StoreBidFunction") + .withOperation("http://myapis.org/carauctionapi.json#storeBid") + .build()]) + .withEvents(new EventsBuilder().withEvents( + [new EventBuilder() + .withName("CarBidEvent") + .withType("carBidMadeType") + .withSource("carBidEventSource") + .build()], + ).build()) + .withStates([ + new EventStateBuilder() + .withName("StoreCarAuctionBid") + .withExclusive(true) + .withOnEvents([ + new OnEventBuilder() + .withEventsRef(["CarBidEvent"]) + .withActions([ + new ActionBuilder().withFunctionRef( + new FunctionRefBuilder() + .withRefName("StoreBidFunction") + .withArguments({ + "bid": "${ .bid }", + }) + .build()).build(), + ]).build(), + ]) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/carauctionbids.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/checkcarvitals.json b/tests/examples/checkcarvitals.json new file mode 100644 index 0000000..96ab407 --- /dev/null +++ b/tests/examples/checkcarvitals.json @@ -0,0 +1,45 @@ +{ + "id": "checkcarvitals", + "name": "Check Car Vitals Workflow", + "version": "1.0", + "start": "WhenCarIsOn", + "states": [ + { + "name": "WhenCarIsOn", + "type": "event", + "onEvents": [ + { + "eventRefs": [ + "CarTurnedOnEvent" + ] + } + ], + "transition": "DoCarVitalsChecks" + }, + { + "name": "DoCarVitalsChecks", + "type": "subflow", + "workflowId": "vitalscheck", + "repeat": { + "stopOnEvents": [ + "CarTurnedOffEvent" + ] + }, + "end": true + } + ], + "events": [ + { + "name": "CarTurnedOnEvent", + "type": "car.events", + "source": "my/car/start", + "kind": "consumed" + }, + { + "name": "CarTurnedOffEvent", + "type": "car.events", + "source": "my/car/start", + "kind": "consumed" + } + ] +} diff --git a/tests/examples/checkcarvitals.spec.old.ts b/tests/examples/checkcarvitals.spec.old.ts new file mode 100644 index 0000000..da71d2c --- /dev/null +++ b/tests/examples/checkcarvitals.spec.old.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + EventBuilder, + EventsBuilder, + EventStateBuilder, + OnEventBuilder, + RepeatBuilder, + SubFlowStateBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("checkcarvitals workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("checkcarvitals") + .withVersion("1.0") + .withName("Check Car Vitals Workflow") + .withStart("WhenCarIsOn") + .withStates([ + new EventStateBuilder() + .withName("WhenCarIsOn") + .withOnEvents([ + new OnEventBuilder() + .withEventsRef(["CarTurnedOnEvent"]) + .build(), + ]) + .withTransition("DoCarVitalsChecks") + .build(), + new SubFlowStateBuilder() + .withName("DoCarVitalsChecks") + .withWorkflowId("vitalscheck") + .withRepeat(new RepeatBuilder() + .withStopOnEvents(["CarTurnedOffEvent"]) + .build()) + .withEnd(true) + .build(), + ]) + .withEvents( + new EventsBuilder() + .withEvents([ + new EventBuilder() + .withName("CarTurnedOnEvent") + .withType("car.events") + .withSource("my/car/start") + .build(), + new EventBuilder() + .withName("CarTurnedOffEvent") + .withType("car.events") + .withSource("my/car/start") + .build(), + + ]).build(), + ) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/checkcarvitals.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/jobmonitoring.json b/tests/examples/jobmonitoring.json new file mode 100644 index 0000000..a313280 --- /dev/null +++ b/tests/examples/jobmonitoring.json @@ -0,0 +1,142 @@ +{ + "id": "jobmonitoring", + "version": "1.0", + "name": "Job Monitoring", + "description": "Monitor finished execution of a submitted job", + "start": "SubmitJob", + "functions": [ + { + "name": "submitJob", + "operation": "http://myapis.org/monitorapi.json#doSubmit", + "type": "rest" + }, + { + "name": "checkJobStatus", + "operation": "http://myapis.org/monitorapi.json#checkStatus", + "type": "rest" + }, + { + "name": "reportJobSuceeded", + "operation": "http://myapis.org/monitorapi.json#reportSucceeded", + "type": "rest" + }, + { + "name": "reportJobFailed", + "operation": "http://myapis.org/monitorapi.json#reportFailure", + "type": "rest" + } + ], + "states": [ + { + "name": "SubmitJob", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "submitJob", + "arguments": { + "name": "${ .job.name }" + } + }, + "actionDataFilter": { + "results": "${ .jobuid }" + } + } + ], + "onErrors": [ + { + "error": "*", + "transition": "SubmitError" + } + ], + "stateDataFilter": { + "output": "${ .jobuid }" + }, + "transition": "WaitForCompletion" + }, + { + "name": "SubmitError", + "type": "subflow", + "workflowId": "handleJobSubmissionErrorWorkflow", + "end": true + }, + { + "name": "WaitForCompletion", + "type": "delay", + "timeDelay": "PT5S", + "transition": "GetJobStatus" + }, + { + "name": "GetJobStatus", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "checkJobStatus", + "arguments": { + "name": "${ .jobuid }" + } + }, + "actionDataFilter": { + "results": "${ .jobstatus }" + } + } + ], + "stateDataFilter": { + "output": "${ .jobstatus }" + }, + "transition": "DetermineCompletion" + }, + { + "name": "DetermineCompletion", + "type": "switch", + "dataConditions": [ + { + "condition": "${ .jobStatus == \"SUCCEEDED\" }", + "transition": "JobSucceeded" + }, + { + "condition": "${ .jobStatus == \"FAILED\" }", + "transition": "JobFailed" + } + ], + "default": { + "transition": "WaitForCompletion" + } + }, + { + "name": "JobSucceeded", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "reportJobSuceeded", + "arguments": { + "name": "${ .jobuid }" + } + } + } + ], + "end": true + }, + { + "name": "JobFailed", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "reportJobFailed", + "arguments": { + "name": "${ .jobuid }" + } + } + } + ], + "end": true + } + ] +} diff --git a/tests/examples/jobmonitoring.spec.old.ts b/tests/examples/jobmonitoring.spec.old.ts new file mode 100644 index 0000000..b1cf356 --- /dev/null +++ b/tests/examples/jobmonitoring.spec.old.ts @@ -0,0 +1,197 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + ActionBuilder, + ActionDataFilterBuilder, + DatabasedSwitchBuilder, + DefaultTransitionBuilder, + DelayStateBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + OnErrorBuilder, + OperationStateBuilder, + StateDataFilterBuilder, + SubFlowStateBuilder, + TransitionDataConditionBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("jobmonitoring workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("jobmonitoring") + .withVersion("1.0") + .withName("Job Monitoring") + .withDescription("Monitor finished execution of a submitted job") + .withStart("SubmitJob") + .withFunctions([ + new FunctionDefBuilder() + .withName("submitJob") + .withOperation("http://myapis.org/monitorapi.json#doSubmit") + .build(), + new FunctionDefBuilder() + .withName("checkJobStatus") + .withOperation("http://myapis.org/monitorapi.json#checkStatus") + .build(), + new FunctionDefBuilder() + .withName("reportJobSuceeded") + .withOperation("http://myapis.org/monitorapi.json#reportSucceeded") + .build(), + new FunctionDefBuilder() + .withName("reportJobFailed") + .withOperation("http://myapis.org/monitorapi.json#reportFailure") + .build(), + ]) + .withStates([ + new OperationStateBuilder() + .withName("SubmitJob") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("submitJob") + .withArguments({ + "name": "${ .job.name }", + }) + .build(), + ) + .withActionDataFilter( + new ActionDataFilterBuilder() + .withResults("${ .jobuid }") + .build(), + ) + .build(), + ]) + .withOnErrors([ + new OnErrorBuilder() + .withError("*") + .withTransition("SubmitError") + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .jobuid }") + .build(), + ) + .withTransition("WaitForCompletion") + .build(), + new SubFlowStateBuilder() + .withName("SubmitError") + .withWorkflowId("handleJobSubmissionErrorWorkflow") + .withEnd(true) + .build(), + new DelayStateBuilder() + .withName("WaitForCompletion") + .withTimeDelay("PT5S") + .withTransition("GetJobStatus") + .build(), + new OperationStateBuilder() + .withName("GetJobStatus") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("checkJobStatus") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .withActionDataFilter( + new ActionDataFilterBuilder() + .withResults("${ .jobstatus }") + .build(), + ) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .jobstatus }") + .build(), + ) + .withTransition("DetermineCompletion") + .build(), + new DatabasedSwitchBuilder() + .withName("DetermineCompletion") + .withDataConditions([ + new TransitionDataConditionBuilder() + .withCondition("${ .jobStatus == \"SUCCEEDED\" }") + .withTransition("JobSucceeded") + .build(), + new TransitionDataConditionBuilder() + .withCondition("${ .jobStatus == \"FAILED\" }") + .withTransition("JobFailed") + .build(), + ]) + .withDefault( + new DefaultTransitionBuilder() + .withTransition("WaitForCompletion") + .build()) + .build(), + new OperationStateBuilder() + .withName("JobSucceeded") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("reportJobSuceeded") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .build(), + ]) + .withEnd(true) + .build(), + new OperationStateBuilder() + .withName("JobFailed") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("reportJobFailed") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .build(), + ]) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/jobmonitoring.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/parallel.json b/tests/examples/parallel.json new file mode 100644 index 0000000..a9ffa00 --- /dev/null +++ b/tests/examples/parallel.json @@ -0,0 +1,25 @@ +{ + "id": "parallelexec", + "version": "1.0", + "name": "Parallel Execution Workflow", + "description": "Executes two branches in parallel", + "start": "ParallelExec", + "states":[ + { + "name": "ParallelExec", + "type": "parallel", + "completionType": "and", + "branches": [ + { + "name": "ShortDelayBranch", + "workflowId": "shortdelayworkflowid" + }, + { + "name": "LongDelayBranch", + "workflowId": "longdelayworkflowid" + } + ], + "end": true + } + ] +} diff --git a/tests/examples/parallel.spec.old.ts b/tests/examples/parallel.spec.old.ts new file mode 100644 index 0000000..8e68c76 --- /dev/null +++ b/tests/examples/parallel.spec.old.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as fs from "fs"; +import {BranchBuilder, ParallelStateBuilder, WorkflowBuilder} from '../../src'; + + +describe("parallel workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("parallelexec") + .withVersion("1.0") + .withName("Parallel Execution Workflow") + .withDescription("Executes two branches in parallel") + .withStart("ParallelExec") + .withStates([ + new ParallelStateBuilder() + .withName("ParallelExec") + .withCompletionType("and") + .withBranches([ + new BranchBuilder() + .withName("ShortDelayBranch") + .withWorkflowId("shortdelayworkflowid") + .build(), + new BranchBuilder() + .withName("LongDelayBranch") + .withWorkflowId("longdelayworkflowid") + .build(), + ]) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/parallel.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/provisionorder.json b/tests/examples/provisionorder.json new file mode 100644 index 0000000..8405975 --- /dev/null +++ b/tests/examples/provisionorder.json @@ -0,0 +1,73 @@ +{ + "id": "provisionorders", + "version": "1.0", + "name": "Provision Orders", + "description": "Provision Orders and handle errors thrown", + "start": "ProvisionOrder", + "functions": [ + { + "name": "provisionOrderFunction", + "operation": "http://myapis.org/provisioningapi.json#doProvision", + "type": "rest" + } + ], + "states": [ + { + "name": "ProvisionOrder", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "provisionOrderFunction", + "arguments": { + "order": "${ .order }" + } + } + } + ], + "stateDataFilter": { + "output": "${ .exceptions }" + }, + "transition": "ApplyOrder", + "onErrors": [ + { + "error": "Missing order id", + "transition": "MissingId" + }, + { + "error": "Missing order item", + "transition": "MissingItem" + }, + { + "error": "Missing order quantity", + "transition": "MissingQuantity" + } + ] + }, + { + "name": "MissingId", + "type": "subflow", + "workflowId": "handleMissingIdExceptionWorkflow", + "end": true + }, + { + "name": "MissingItem", + "type": "subflow", + "workflowId": "handleMissingItemExceptionWorkflow", + "end": true + }, + { + "name": "MissingQuantity", + "type": "subflow", + "workflowId": "handleMissingQuantityExceptionWorkflow", + "end": true + }, + { + "name": "ApplyOrder", + "type": "subflow", + "workflowId": "applyOrderWorkflowId", + "end": true + } + ] +} diff --git a/tests/examples/provisionorder.spec.old.ts b/tests/examples/provisionorder.spec.old.ts new file mode 100644 index 0000000..3be3c61 --- /dev/null +++ b/tests/examples/provisionorder.spec.old.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + ActionBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + OnErrorBuilder, + OperationStateBuilder, + StateDataFilterBuilder, + SubFlowStateBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("provisionorder workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("provisionorders") + .withVersion("1.0") + .withName("Provision Orders") + .withDescription("Provision Orders and handle errors thrown") + .withStart("ProvisionOrder") + .withFunctions([ + new FunctionDefBuilder() + .withName("provisionOrderFunction") + .withOperation("http://myapis.org/provisioningapi.json#doProvision") + .build(), + ]) + .withStates([ + new OperationStateBuilder() + .withName("ProvisionOrder") + .withActionMode("sequential") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("provisionOrderFunction") + .withArguments({ + "order": "${ .order }", + }) + .build(), + ) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .exceptions }") + .build()) + .withTransition("ApplyOrder") + .withOnErrors([ + new OnErrorBuilder() + .withError("Missing order id") + .withTransition("MissingId") + .build(), + new OnErrorBuilder() + .withError("Missing order item") + .withTransition("MissingItem") + .build(), + new OnErrorBuilder() + .withError("Missing order quantity") + .withTransition("MissingQuantity") + .build(), + ]) + .build(), + new SubFlowStateBuilder() + .withName("MissingId") + .withWorkflowId("handleMissingIdExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("MissingItem") + .withWorkflowId("handleMissingItemExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("MissingQuantity") + .withWorkflowId("handleMissingQuantityExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("ApplyOrder") + .withWorkflowId("applyOrderWorkflowId") + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/provisionorder.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/sendcloudevent.json b/tests/examples/sendcloudevent.json new file mode 100644 index 0000000..b629a29 --- /dev/null +++ b/tests/examples/sendcloudevent.json @@ -0,0 +1,47 @@ +{ + "id": "sendcloudeventonprovision", + "version": "1.0", + "name": "Send CloudEvent on provision completion", + "start": "ProvisionOrdersState", + "events": [ + { + "name": "provisioningCompleteEvent", + "type": "provisionCompleteType", + "kind": "produced" + } + ], + "functions": [ + { + "name": "provisionOrderFunction", + "operation": "http://myapis.org/provisioning.json#doProvision", + "type": "rest" + } + ], + "states": [ + { + "name": "ProvisionOrdersState", + "type": "foreach", + "inputCollection": "${ .orders }", + "iterationParam": "singleorder", + "outputCollection": "${ .provisionedOrders }", + "actions": [ + { + "functionRef": { + "refName": "provisionOrderFunction", + "arguments": { + "order": "${ .singleorder }" + } + } + } + ], + "end": { + "produceEvents": [ + { + "eventRef": "provisioningCompleteEvent", + "data": "${ .provisionedOrders }" + } + ] + } + } + ] +} diff --git a/tests/examples/sendcloudevent.spec.old.ts b/tests/examples/sendcloudevent.spec.old.ts new file mode 100644 index 0000000..9b5b14a --- /dev/null +++ b/tests/examples/sendcloudevent.spec.old.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {WorkflowBuilder} from "../../src"; +import * as fs from "fs"; +import { + ActionBuilder, EndBuilder, + EventBuilder, + EventsBuilder, + ForEachStateBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + ProduceEventDefBuilder, +} from '../../src'; + + +describe("sendcloudevent workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("sendcloudeventonprovision") + .withVersion("1.0") + .withName("Send CloudEvent on provision completion") + .withStart("ProvisionOrdersState") + .withEvents( + new EventsBuilder() + .withEvents([ + new EventBuilder() + .withName("provisioningCompleteEvent") + .withType("provisionCompleteType") + .withKind("produced") + .build(), + + ]).build(), + ) + .withFunctions([ + new FunctionDefBuilder() + .withName("provisionOrderFunction") + .withOperation("http://myapis.org/provisioning.json#doProvision") + .build(), + ]) + .withStates([ + new ForEachStateBuilder() + .withName("ProvisionOrdersState") + .withInputCollection("${ .orders }") + .withIterationParam("singleorder") + .withOutputCollection("${ .provisionedOrders }") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("provisionOrderFunction") + .withArguments({ + "order": "${ .singleorder }", + }) + .build(), + ) + .build(), + ]) + .withEnd( + new EndBuilder() + .withProduceEvents([ + new ProduceEventDefBuilder() + .withEventRef("provisioningCompleteEvent") + .withData("${ .provisionedOrders }") + .build(), + ]) + .build(), + ) + .build(), + ]) + .build(); + + + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/sendcloudevent.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/examples/solvemathproblems.json b/tests/examples/solvemathproblems.json new file mode 100644 index 0000000..7b39d1c --- /dev/null +++ b/tests/examples/solvemathproblems.json @@ -0,0 +1,37 @@ +{ + "id": "solvemathproblems", + "version": "1.0", + "name": "Solve Math Problems Workflow", + "description": "Solve math problems", + "start": "Solve", + "functions": [ + { + "name": "solveMathExpressionFunction", + "type": "rest", + "operation": "http://myapis.org/mapthapis.json#solveExpression" + } + ], + "states": [ + { + "name": "Solve", + "type": "foreach", + "inputCollection": "${ .expressions }", + "iterationParam": "singleexpression", + "outputCollection": "${ .results }", + "actions": [ + { + "functionRef": { + "refName": "solveMathExpressionFunction", + "arguments": { + "expression": "${ .singleexpression }" + } + } + } + ], + "stateDataFilter": { + "output": "${ .results }" + }, + "end": true + } + ] +} diff --git a/tests/examples/solvemathproblems.spec.old.ts b/tests/examples/solvemathproblems.spec.old.ts new file mode 100644 index 0000000..3bf2c2a --- /dev/null +++ b/tests/examples/solvemathproblems.spec.old.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {WorkflowBuilder} from "../../src/model/workflow.builder"; +import * as fs from "fs"; +import {ActionBuilder, FunctionDefBuilder, FunctionRefBuilder} from '../../src'; +import {ForEachStateBuilder} from '../../src/model/for-each-state.builder'; +import {StateDataFilterBuilder} from '../../src/model/state-data-filter.builder'; + + +describe("solvemathproblems workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("solvemathproblems") + .withVersion("1.0") + .withName("Solve Math Problems Workflow") + .withDescription("Solve math problems") + .withStart("Solve") + .withFunctions([ + new FunctionDefBuilder() + .withName("solveMathExpressionFunction") + .withOperation("http://myapis.org/mapthapis.json#solveExpression") + .build(), + ]) + .withStates([ + new ForEachStateBuilder() + .withName("Solve") + .withInputCollection("${ .expressions }") + .withIterationParam("singleexpression") + .withOutputCollection("${ .results }") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("solveMathExpressionFunction") + .withArguments({ + "expression": "${ .singleexpression }", + }) + .build()) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .results }") + .build(), + ) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/solvemathproblems.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/tests/model/action-builder.spec.old.ts b/tests/model/action-builder.spec.old.ts new file mode 100644 index 0000000..a08622d --- /dev/null +++ b/tests/model/action-builder.spec.old.ts @@ -0,0 +1,72 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {ActionBuilder, ActionDataFilter, EventRef} from '../../src'; +import {ActionDataFilterBuilder} from '../../src/model/action-data-filter.builder'; + + +describe("ActionBuilder", () => { + + it("should throws an error if mandatory fields are not set ", () => { + + expect(() => new ActionBuilder().build()).toThrowError(); + + expect(() => new ActionBuilder() + .withFunctionRef("").build()) + .toThrowError(); + }); + + + it("should throws an error if both functionRef and eventRef are set", () => { + + expect(() => new ActionBuilder().build()).toThrowError(); + + expect(() => new ActionBuilder() + .withFunctionRef("functionRef") + .withEventRef(validEventRef()).build()) + .toThrowError(); + }); + + it("should generate a populated object", () => { + expect(new ActionBuilder() + .withName("actionName") + .withEventRef(validEventRef()) + .withTimeOut("PT1H") + .withActionDataFilter(new ActionDataFilterBuilder().build()) + .build()).toEqual( + { + name: "actionName", + eventRef: validEventRef(), + timeout: "PT1H", + actionDataFilter: validActionDataFilter(), + }, + ); + + + }); + + +}); + + +function validActionDataFilter(): ActionDataFilter { + return {}; +} + +function validEventRef(): EventRef { + return {resultEventRef: "result"}; +} diff --git a/tests/model/action-data-filter-builder.spec.old.ts b/tests/model/action-data-filter-builder.spec.old.ts new file mode 100644 index 0000000..daeef70 --- /dev/null +++ b/tests/model/action-data-filter-builder.spec.old.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {ActionDataFilterBuilder} from '../../src/model/action-data-filter.builder'; + +describe("ActionDataFilter", () => { + + it("should generate an empty object", () => { + expect(new ActionDataFilterBuilder().build()).toEqual({}); + }); + + it("should generate a populated object", () => { + expect(new ActionDataFilterBuilder() + .withFromStateData("fromState") + .withToStateData("toState") + .withResults("result") + .build()).toEqual( + { + fromStateData: "fromState", + toStateData: "toState", + results: "result", + }, + ); + + + }); + + +}); + diff --git a/tests/model/cron-def-builder.spec.old.ts b/tests/model/cron-def-builder.spec.old.ts new file mode 100644 index 0000000..b7f7f2a --- /dev/null +++ b/tests/model/cron-def-builder.spec.old.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {CronDefBuilder} from '../../src/model/cron-def.builder'; + +const cronExpression = "0 * * ? * *"; + +describe("CronDefBuilder", () => { + + + it("Should create a valid object containing cron expresion", () => { + + expect(new CronDefBuilder() + .withCronExpresion(cronExpression) + .build(), + ).toEqual(cronExpression); + + }); + + + it("Should create a valid object containing expression and expiration time", () => { + + const dateTimeISO8601Format = "2013-07-16T19:23:51Z"; + expect(new CronDefBuilder() + .withCronExpresion(cronExpression) + .withValidUntil(dateTimeISO8601Format) + .build(), + ).toEqual({ + expression: cronExpression, + validUntil: dateTimeISO8601Format, + }); + + + }); + + + it("should throws an error if cron expression is not set", () => { + + expect(() => new CronDefBuilder().build()).toThrowError(); + + }); + +}); + diff --git a/tests/model/event-ref-builder.spec.old.ts b/tests/model/event-ref-builder.spec.old.ts new file mode 100644 index 0000000..ee52f7f --- /dev/null +++ b/tests/model/event-ref-builder.spec.old.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {EventRefBuilder} from '../../src/model/event-ref.builder'; + + +describe("event ref builder", () => { + + + it("should create an object with the required fields ", () => { + + expect(new EventRefBuilder() + .withResultEventRef("resultValue") + .withTriggerEventRef("triggerValue") + .build()).toEqual( + {resultEventRef: "resultValue", triggerEventRef: 'triggerValue'}, + ); + + }); + + + it("should create an object with all possible fields ", () => { + + expect(new EventRefBuilder() + .withResultEventRef("resultValue") + .withTriggerEventRef("triggerValue") + .withContextAttributes({key: "valuect"}) + .withData({key: "valuedata"}) + .build()).toEqual( + { + resultEventRef: "resultValue", + triggerEventRef: 'triggerValue', + contextAttributes: {key: "valuect"}, + data: {key: "valuedata"}, + }, + ); + }); + + + it("should throws an error if mandatory fields are not set ", () => { + + expect(() => new EventRefBuilder().build()).toThrowError(); + + expect(() => new EventRefBuilder() + .withResultEventRef("").build()) + .toThrowError(); + + expect(() => new EventRefBuilder() + .withTriggerEventRef("") + .build()).toThrowError(); + + }); + +}); diff --git a/tests/model/function-builder.spec.old.ts b/tests/model/function-builder.spec.old.ts new file mode 100644 index 0000000..48113ed --- /dev/null +++ b/tests/model/function-builder.spec.old.ts @@ -0,0 +1,77 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {FunctionDefBuilder} from '../../src'; + + +describe("FunctionBuilder", () => { + + + it("should throws an error if mandatory fields are not set ", () => { + + expect(() => new FunctionDefBuilder().build()).toThrowError(); + + expect(() => new FunctionDefBuilder() + .withName("") + .withOperation("") + .build()) + .toThrowError(); + + expect(() => new FunctionDefBuilder() + .withOperation("http://myapis.org/applicationapi.json#emailRejection") + .build()) + .toThrowError(); + + expect(() => new FunctionDefBuilder() + .withName("functionName") + .build()) + .toThrowError(); + }); + + + it("should generate a populated object with default type value", () => { + expect(new FunctionDefBuilder() + .withName("functionName") + .withOperation("http://myapis.org/applicationapi.json#emailRejection") + .build()).toEqual( + { + name: "functionName", + operation: "http://myapis.org/applicationapi.json#emailRejection", + type: "rest", + }, + ); + + }); + + it("should generate a populated object with default type value", () => { + expect(new FunctionDefBuilder() + .withName("functionName") + .withOperation("file#serviceName#method") + .withType("rpc") + .build()).toEqual( + { + name: "functionName", + operation: "file#serviceName#method", + type: "rpc", + }, + ); + + }); + +}); + + diff --git a/tests/model/metadata-builder.spec.old.ts b/tests/model/metadata-builder.spec.old.ts new file mode 100644 index 0000000..a3e6af8 --- /dev/null +++ b/tests/model/metadata-builder.spec.old.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {MetadataBuilder} from '../../src/model/metadata.builder'; + + +describe("MetadataBuilder", () => { + + it("should create an empty object ", () => { + + expect(new MetadataBuilder().build()).toEqual({}); + + }); + + it("should create an object with key/value strings ", () => { + + expect(new MetadataBuilder() + .withKeyValue("k1", "v1") + .build()).toEqual( + { + "k1": "v1", + }); + + + expect(new MetadataBuilder() + .withKeyValue("k2", "v2") + .withKeyValue("k3", "v3") + .build()).toEqual( + { + "k2": "v2", + "k3": "v3", + }); + + + }); + + + it("should allow to overwrite pairs of key/value ", () => { + + expect(new MetadataBuilder() + .withKeyValue("k1", "v1") + .withKeyValue("k1", "v2") + .build()).toEqual( + { + "k1": "v2", + }); + + + }); + + +}); + + + diff --git a/tests/model/produce-event-def-builder.spec.old.ts b/tests/model/produce-event-def-builder.spec.old.ts new file mode 100644 index 0000000..e4e6f0e --- /dev/null +++ b/tests/model/produce-event-def-builder.spec.old.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {ProduceEventDefBuilder} from '../../src/model/produce-event-def.builder'; + + +describe("ProduceEventDefBuilder", () => { + + it("should throws an error if mandatory fields are not set ", () => { + + expect(() => new ProduceEventDefBuilder() + .build()).toThrowError(); + + expect(() => new ProduceEventDefBuilder() + .withEventRef("").build()) + .toThrowError(); + }); + + it("should build a valid ProduceEventDef object ", () => { + + expect(new ProduceEventDefBuilder() + .withEventRef("ConfirmationCompletedEvent") + .withData("${ .payment }") + .withContextAttributes({ + kContext: "kcValue", + }) + .build()) + .toEqual({ + eventRef: "ConfirmationCompletedEvent", + data: "${ .payment }", + contextAttributes: { + kContext: "kcValue", + }, + }); + }); + + +}); + diff --git a/tests/model/repeat-builder.spec.old.ts b/tests/model/repeat-builder.spec.old.ts new file mode 100644 index 0000000..4b5dd39 --- /dev/null +++ b/tests/model/repeat-builder.spec.old.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {RepeatBuilder} from '../../src/model/repeat.builder'; + +describe('repeat builder', () => { + + it("Should create empty object", () => { + + expect(new RepeatBuilder().build()).toEqual({}); + + }); + + it("should create an object with all possible fields", () => { + + expect(new RepeatBuilder() + .withExpression("anyExpression") + .withCheckBefore(true) + .withMax(3) + .withContinueOnError(true) + .withStopOnEvents(["onStopEvent"]) + .build()) + .toEqual({ + expression: "anyExpression", + checkBefore: true, + max: 3, + continueOnError: true, + stopOnEvents: ["onStopEvent"], + }); + + }); + +}); diff --git a/tests/model/schedule-builder.spec.old.ts b/tests/model/schedule-builder.spec.old.ts new file mode 100644 index 0000000..5cf6e31 --- /dev/null +++ b/tests/model/schedule-builder.spec.old.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {ScheduleBuilder} from '../../src/model/schedule.builder'; +import {CronDef} from '../../src'; + + +describe("ScheduleBuilder", () => { + + it("should throws an error if mandatory fields are not set ", () => { + + expect(() => new ScheduleBuilder().build()).toThrowError(); + + expect(() => new ScheduleBuilder() + .withInterval("").build()) + .toThrowError(); + }); + + + it("should create a valid object when interval is set", () => { + expect(new ScheduleBuilder() + .withInterval("PT2S").build()) + .toEqual("PT2S"); + }); + + + it("should create a valid object when interval and cron are set", () => { + + expect(new ScheduleBuilder() + .withInterval("PT2S") + .withCron(validCronDef()) + .build()) + .toEqual({ + interval: "PT2S", + cron: validCronDef(), + timezone: "UTC", + }); + }); + + + it("should allow set timezone", () => { + + expect(new ScheduleBuilder() + .withInterval("PT2S") + .withCron(validCronDef()) + .withTimezone("CET") + .build()) + .toEqual({ + interval: "PT2S", + cron: validCronDef(), + timezone: "CET", + }); + }); +}); + + +function validCronDef(): CronDef { + return "0 * * ? * *"; +} + + diff --git a/tests/model/workflow.builder.spec.old.ts b/tests/model/workflow.builder.spec.old.ts new file mode 100644 index 0000000..6984ea6 --- /dev/null +++ b/tests/model/workflow.builder.spec.old.ts @@ -0,0 +1,144 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {InjectStateBuilder, Workflow, WorkflowBuilder} from "../../src"; +import {ValidationError, ValidationErrors, ValidatorFactory, WorkflowValidator} from "../../src/model/workflow.validator"; + + +describe("workflow builder", () => { + + + it("should create a workflow with mandatory fields", () => { + const workflow: Workflow = new WorkflowBuilder() + .withId("helloworld") + .withName("hello world") + .withVersion("0.6") + .withStart("hello builder") + .withStates([new InjectStateBuilder() + .withName("Hello State") + .withData({ + "result": "Hello World!", + }) + .withEnd(true).build()]) + .build(); + + expect(workflow).toEqual({ + "id": "helloworld", + "name": "hello world", + "version": "0.6", + "start": "hello builder", + "states": [{ + "type": "inject", "name": "Hello State", + "data": {"result": "Hello World!"}, + "end": true, + }], + }, + ); + + }); + + + it("should create a workflow with all fields", () => { + const workflow: Workflow = + new WorkflowBuilder() + .withId("helloworld") + .withName("hello world") + .withVersion("0.6") + .withStart("hello builder") + .withStates([new InjectStateBuilder() + .withName("Hello State") + .withData({ + "result": "Hello World!", + }) + .withEnd(true).build()]) + .withDescription("hello builder description") + .withSchemaVersion("0.6") + .withSchemaVersion("1.0") + .withExpressionLang("jq") + .withExecTimeout({duration: 'PT2M'}) + .withKeepActive(true) + .withMetadata({ + "key1": "value1", + "key2": "value2", + }) + .withEvents("http://myhost:8080/eventsdefs.json") + .withFunctions("http://myhost:8080/functionsdefs.json") + .withRetries("http://myhost:8080/retriesdefs.json") + .build(); + + expect(workflow).toEqual({ + "id": "helloworld", + "name": "hello world", + "version": "0.6", + "start": "hello builder", + "states": [{ + "type": "inject", "name": "Hello State", + "data": {"result": "Hello World!"}, + "end": true, + }], + "description": "hello builder description", + "schemaVersion": "1.0", + "expressionLang": "jq", + "execTimeout": {duration: 'PT2M'}, + "keepActive": true, + "metadata": { + "key1": "value1", + "key2": "value2", + }, + "events": "http://myhost:8080/eventsdefs.json", + "functions": "http://myhost:8080/functionsdefs.json", + "retries": "http://myhost:8080/retriesdefs.json", + }, + ); + + }); + + + it("should invoke validator class", () => { + + const workflowValidator = new WorkflowValidator({}); + spyOn(workflowValidator, 'isValid') + .and.returnValue(false); + spyOn(workflowValidator, 'validate') + .and.returnValue(new ValidationErrors([new ValidationError("any error")])); + + const validatorFactory = new ValidatorFactory(); + spyOn(validatorFactory, 'workflowValidator') + .and.returnValue(workflowValidator); + + try { + new WorkflowBuilder(validatorFactory) + .build(); + } catch (error) { + //Expected method build to throw an error + } + + + expect(workflowValidator.isValid).toHaveBeenCalled(); + expect(workflowValidator.validate).toHaveBeenCalled(); + + + }); + + + it("should thrown an error if any mandatory field is not set", () => { + expect(() => { + new WorkflowBuilder().build(); + }).toThrowError(); + }); + + +}); diff --git a/tests/model/workflow.validator.spec.old.ts b/tests/model/workflow.validator.spec.old.ts new file mode 100644 index 0000000..6f29987 --- /dev/null +++ b/tests/model/workflow.validator.spec.old.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {Workflow} from "../../src"; +import {ValidationError, WorkflowValidator} from "../../src/model/workflow.validator"; + + +const validWorkflow: Workflow = { + "id": "helloworld", + "name": "hello world", + "version": "0.6", + "start": "hello builder", + "states": [{ + "type": "inject", "name": "Hello State", "data": + {"result": "Hello World!"}, + "end": true, + }], +}; + + +describe("workflow validator", () => { + + + it("should recognize valid workflow", () => { + expect(new WorkflowValidator(validWorkflow).isValid()).toBeTruthy(); + }); + + + const testCases = [ + {field: "id"}, + {field: "name"}, + {field: "version"}, + {field: "start"}, + {field: "states"}]; + testCases.forEach(t => { + it(`should return error as field [${t.field}] is not set`, () => { + const field = t.field; + const invalidWorkflow = workflowWithoutFields([field]); + const validator = new WorkflowValidator(invalidWorkflow); + expect(validator.isValid()).toBeFalse(); + expect(validator.validate().errors().length).toBe(1); + expectErrorsToContainsMessage(validator.validate().errors(), `${t.field} can not be undefined`); + }); + }); + + + it(`should return two validationErrors if two mandatory fields are not set`, () => { + const invalidWorkflow = workflowWithoutFields(["name", "version"]); + const validator = new WorkflowValidator(invalidWorkflow); + expect(validator.isValid()).toBeFalse(); + expect(validator.validate().errors().length).toBe(2); + }); + + +}); + + +function workflowWithoutFields(fields: string[]): Workflow { + const invalidWorkflow = Object.assign({}, validWorkflow); + fields.forEach(field => { + delete invalidWorkflow[field]; + }); + return invalidWorkflow; +} + + +function expectErrorsToContainsMessage(validationErrors: ValidationError[], message: string): void { + const errorMessages = validationErrors.map(e => e.message()).join(";"); + expect(errorMessages).toMatch(message); +} diff --git a/tests/workflow-converter.spec.ts b/tests/workflow-converter.spec.ts index d6b3d58..c205ef5 100644 --- a/tests/workflow-converter.spec.ts +++ b/tests/workflow-converter.spec.ts @@ -1,5 +1,5 @@ /* - * Copyright 2021-Present The Serverless WorkflowJson Specification Authors + * Copyright 2021-Present The Serverless Workflow Specification Authors *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,129 +14,131 @@ * limitations under the License. * */ -import WorkflowJson = ServerlessworkflowOrg.Core.WorkflowJson; -import {workflowJsonBuilder} from "../src/builders/workflow-json-builder"; -import {injectstateBuilder} from "../src/builders/injectstate-builder"; -import {WorkflowConverter} from "../src/workflow-converter"; -import {readFileSync} from 'fs'; +import Workflow = ServerlessWorkflow.Workflow; +import { workflowBuilder } from "../src/builders/workflow-builder"; +import { injectstateBuilder } from "../src/builders/injectstate-builder"; +import { WorkflowConverter } from "../src/workflow-converter"; +import { readFileSync } from 'fs'; describe("workflow-converter fromSource", () => { - const testCases = [ - { - description: "should generate workflow object from JSON file", - file: "./tests/workflow-converter-hello-world.json", + const testCases = [ + { + description: "should generate workflow object from JSON file", + file: "./tests/workflow-converter-hello-world.json", - }, - { - description: "should generate workflow object from YAML file", - file: "./tests/workflow-converter-hello-world.yaml", + }, + { + description: "should generate workflow object from YAML file", + file: "./tests/workflow-converter-hello-world.yaml", - }, - { - description: "should generate workflow object from YML file", - file: "./tests/workflow-converter-hello-world.yml", + }, + { + description: "should generate workflow object from YML file", + file: "./tests/workflow-converter-hello-world.yml", - } - ]; - testCases.forEach(test => { - it(test.description, function () { - const workflow: WorkflowJson = WorkflowConverter.fromString(readFileSync(test.file, 'utf-8')); - expect(workflow.id).toBe("helloworld"); - expect(workflow.version).toBe("1.0"); - expect(workflow.name).toBe("Hello World Workflow"); - expect(workflow.description).toBe("Inject Hello World"); - expect(workflow.start).toBe("Hello State"); - expect(workflow).toEqual({ - "id": "helloworld", - "version": "1.0", - "name": "Hello World Workflow", - "description": "Inject Hello World", - "start": "Hello State", - "states": [ - { - "name": "Hello State", - "type": "inject", - "data": { - "result": "Hello World!" - }, - "end": true - } - ] - }); - }); - }) - - it('should throws error if format is not json or yaml', () => { - expect(() => { - WorkflowConverter.fromString(readFileSync("./tests/workflow-converter-hello-world.xxx", 'utf-8')) - } - ).toThrow(new Error("Format not supported")); + } + ]; + testCases.forEach(test => { + it(test.description, function () { + const workflow: Workflow = WorkflowConverter.fromString(readFileSync(test.file, 'utf-8')); + expect(workflow.id).toBe("helloworld"); + expect(workflow.version).toBe("1.0"); + expect(workflow.name).toBe("Hello World Workflow"); + expect(workflow.description).toBe("Inject Hello World"); + expect(workflow.start).toBe("Hello State"); + expect(workflow).toEqual({ + "id": "helloworld", + "version": "1.0", + "name": "Hello World Workflow", + "description": "Inject Hello World", + "start": "Hello State", + "states": [ + { + "name": "Hello State", + "type": "inject", + "data": { + "result": "Hello World!" + }, + "end": true + } + ] + }); }); + }) + + it('should throws error if format is not json or yaml', () => { + expect(() => { + WorkflowConverter.fromString(readFileSync("./tests/workflow-converter-hello-world.xxx", 'utf-8')); + } + ).toThrow(new Error("Format not supported")); + }); }); describe("workflow-converter", () => { - it('should generate JSON from workflow object', () => { - const jsonWorkflow: string = WorkflowConverter.toJson(workflowJsonBuilder() - .id("helloworld") - .version("1.0") - .name("Hello World Workflow") - .description("Inject Hello World") - .start("Hello State") - .states([injectstateBuilder() - .type("inject") - .name("Hello State") - .data({ - "result": "Hello World!" - }) - .end(true).build()]) - .build()); - expect(jsonWorkflow).toBe("{" + - "\"id\":\"helloworld\"," + - "\"version\":\"1.0\"," + - "\"name\":\"Hello World Workflow\"," + - "\"description\":\"Inject Hello World\"," + - "\"start\":\"Hello State\"," + - "\"states\":[" + - "{" + - "\"type\":\"inject\"," + - "\"name\":\"Hello State\"," + - "\"data\":{" + - "\"result\":\"Hello World!\"" + - "}," + - "\"end\":true" + - "}" + - "]" + - "}"); - }); + it('should generate JSON from workflow object', () => { + const jsonWorkflow: string = WorkflowConverter.toJson(workflowBuilder() + .id("helloworld") + .version("1.0") + .name("Hello World Workflow") + .description("Inject Hello World") + .start("Hello State") + .states([injectstateBuilder() + .name("Hello State") + .data({ + "result": "Hello World!" + }) + .end(true) + .build() + ]) + .build()); + expect(jsonWorkflow).toBe("{" + + "\"id\":\"helloworld\"," + + "\"version\":\"1.0\"," + + "\"name\":\"Hello World Workflow\"," + + "\"description\":\"Inject Hello World\"," + + "\"start\":\"Hello State\"," + + "\"states\":[" + + "{" + + "\"name\":\"Hello State\"," + + "\"data\":{" + + "\"result\":\"Hello World!\"" + + "}," + + "\"end\":true," + + "\"type\":\"inject\"" + + "}" + + "]" + + "}"); + }); - it('should generate YAML from workflow object', () => { - const yamlWorkflow: string = WorkflowConverter.toYaml(workflowJsonBuilder() - .id("helloworld") - .version("1.0") - .name("Hello World Workflow") - .description("Inject Hello World") - .start("Hello State") - .states([injectstateBuilder() - .type("inject") - .name("Hello State") - .data({ - "result": "Hello World!" - }) - .end(true).build()]) - .build()); - expect(yamlWorkflow).toBe("id: helloworld\n" + - "version: '1.0'\n" + - "name: Hello World Workflow\n" + - "description: Inject Hello World\n" + - "start: Hello State\n" + - "states:\n" + - " - type: inject\n" + - " name: Hello State\n" + - " data:\n" + - " result: Hello World!\n" + - " end: true\n"); - }); + it('should generate YAML from workflow object', () => { + const yamlWorkflow: string = WorkflowConverter.toYaml(workflowBuilder() + .id("helloworld") + .version("1.0") + .name("Hello World Workflow") + .description("Inject Hello World") + .start("Hello State") + .states([injectstateBuilder() + .name("Hello State") + .data({ + "result": "Hello World!" + }) + .end(true) + .build() + ]) + .build()); + expect(yamlWorkflow).toBe("id: helloworld\n" + + "version: '1.0'\n" + + "name: Hello World Workflow\n" + + "description: Inject Hello World\n" + + "start: Hello State\n" + + "states:\n" + + " - name: Hello State\n" + + " data:\n" + + " result: Hello World!\n" + + " end: true\n" + + " type: inject\n"); + }); }) diff --git a/tools/generate-builders.ts b/tools/generate-builders.ts index 4f9c169..27eec9f 100644 --- a/tools/generate-builders.ts +++ b/tools/generate-builders.ts @@ -23,6 +23,41 @@ if (!String.prototype.matchAll) { return results; }; } + +interface BuilderExtension { + preValidate: string; +}; +/** Stores additional code that needs to be added to builders depending on their type */ +const buildersExtensions: { [key: string]: BuilderExtension } = { + "Callbackstate": { + preValidate: `\r\n data.type = 'callback';` + }, + "Databasedswitch": { + preValidate: `\r\n data.type = 'switch';` + }, + "Delaystate": { + preValidate: `\r\n data.type = 'delay';` + }, + "Eventbasedswitch": { + preValidate: `\r\n data.type = 'switch';` + }, + "Eventstate": { + preValidate: `\r\n data.type = 'event';` + }, + "Foreachstate": { + preValidate: `\r\n data.type = 'foreach';` + }, + "Injectstate": { + preValidate: `\r\n data.type = 'inject';` + }, + "Operationstate": { + preValidate: `\r\n data.type = 'operation';` + }, + "Parallelstate": { + preValidate: `\r\n data.type = 'parallel';` + } +}; + /** * Transforms PascalCase/camelCase/snake_case into kebab-case * @param {string} value A string @@ -60,13 +95,14 @@ const toCamelCase = (value: string): string => { const createBuilder = async (destDir: string, dataType: string): Promise => { try { const camelType = toCamelCase(dataType); + const extension = buildersExtensions[dataType]; const builderCode = `import { DefinedError } from 'ajv'; import { Builder, builder } from '../builder'; import { validators } from '../validators'; -import ${dataType} = ${ dataType === 'WorkflowJson' ? 'ServerlessworkflowOrg.Core.WorkflowJson' : 'ServerlessworkflowOrg.Core.WorkflowJson.Definitions.' + dataType }; +import ${dataType} = ServerlessWorkflow.${dataType}; export function ${camelType}Validator(data: ${dataType}): (() => ${dataType}) { - return () => { + return () => {${extension?.preValidate ? extension.preValidate : ''} const validate = validators.get('${dataType}'); // TODO: ignore validation if no validator or throw ? if (!validate) return data; diff --git a/tools/generate-definitions.ts b/tools/generate-definitions.ts index 16e31d5..7c55bc3 100644 --- a/tools/generate-definitions.ts +++ b/tools/generate-definitions.ts @@ -10,7 +10,16 @@ const rimrafP = async (f: string): Promise => new Promise((resolve, resolve(); }) ); - +/** + * Capitalized the first letter of the provided string + * @param {} value The string to capitalize + * @returns {string} The capitalized string + */ +const capitalizeFirstLetter = (value: string):string => { + if (!value) return ''; + const transformable = value.trim(); + return transformable[0].toUpperCase() + transformable.slice(1); +}; /** * Tells if the provided objects hold a reference to another definition * @param {any} obj The object to test @@ -44,7 +53,7 @@ const getPropName = ($ref: string, known$Refs: Map): string => propName = baseName + variantIndex; } return propName; -} +}; /** * Merges the definitions founds in the schemas in path into the root schema's definitions @@ -54,29 +63,34 @@ const getPropName = ($ref: string, known$Refs: Map): string => * @param {string[]} parentPaths (internal) The previously known paths */ const mergeDefinitions = async ($refParser: $RefParser, paths: string[], known$Refs: Map, parentPaths: string[] = []): Promise => { - if (!parentPaths?.length) { - Object.keys($refParser.schema.definitions||{}).forEach((key: string) => { - if (!known$Refs.has(key)) { - known$Refs.set(key, `#/definitions/${key}`); - } - }); - parentPaths = paths; - } - await Promise.all( - paths.map(async (schemaPath: string) => { - const fileName = path.basename(schemaPath); - const schema = await $RefParser.parse(schemaPath); - Object.entries(schema.definitions||{}).forEach(([key, value]) => { - const propName = getPropName(key, known$Refs); - known$Refs.set(propName, `${fileName}#/definitions/${key}`); - $refParser.$refs.set(`#/definitions/${propName}`, value); + try { + if (!parentPaths?.length) { + Object.keys($refParser.schema.definitions||{}).forEach((key: string) => { + if (!known$Refs.has(key)) { + known$Refs.set(key, `#/definitions/${key}`); + } }); - const $schemaRefs = await $RefParser.resolve(schemaPath); - const otherPaths = $schemaRefs.paths().filter(p => !parentPaths.includes(p)); - otherPaths.forEach(p => parentPaths.push(p)); - await mergeDefinitions($refParser, otherPaths, known$Refs, parentPaths); - }) - ); + parentPaths = paths; + } + await Promise.all( + paths.map(async (schemaPath: string) => { + const fileName = path.basename(schemaPath); + const schema = await $RefParser.parse(schemaPath); + Object.entries(schema.definitions||{}).forEach(([key, value]) => { + const propName = getPropName(key, known$Refs); + known$Refs.set(propName, `${fileName}#/definitions/${key}`); + $refParser.$refs.set(`#/definitions/${propName}`, value); + }); + const $schemaRefs = await $RefParser.resolve(schemaPath); + const otherPaths = $schemaRefs.paths().filter(p => !parentPaths.includes(p)); + otherPaths.forEach(p => parentPaths.push(p)); + await mergeDefinitions($refParser, otherPaths, known$Refs, parentPaths); + }) + ); + } + catch(ex) { + return Promise.reject(ex); + } }; /** @@ -124,7 +138,31 @@ const mergeSchemas = ($refParser: $RefParser, known$Refs: Map, t $refParser.$refs.set(`#/definitions/${propName}`, referencedSchema); } }); -} +}; + +/** + * Creates the type->path map for the ajv validators + * @param {string} dest The output path + * @param {Map} known$Refs The know references map + * @returns {void} + */ +const createValidatorsPaths = async (dest: string, known$Refs: Map): Promise => { + try { + const validatorsPathsCode = `export const validatorsPaths: [string, string][] = [ + ["Workflow", "https://serverlessworkflow.org/core/workflow.json"], +${Array.from(known$Refs).map(([dataType, path]) => ` ['${capitalizeFirstLetter(dataType)}', 'https://serverlessworkflow.org/core/${path.includes('.json') ? path : 'workflow.json' + path}'],`).join('\r\n')} +]`; + const destDir = path.dirname(dest); + await rimrafP(destDir); + await mkdir(destDir, { recursive: true }); + await writeFile(path.resolve(destDir, 'README.md'), `# Auto generated notice +This directory and its content has been generated automatically. Do not modify its content, it WILL be lost.`); + await writeFile(dest, validatorsPathsCode); + } + catch(ex) { + return Promise.reject(ex); + } +}; /** * Generates TypeScript equivalent of the provided JSON Schema @@ -135,20 +173,41 @@ const mergeSchemas = ($refParser: $RefParser, known$Refs: Map, t const generate = async (source: string, dest: string, additionnalSchemas: string[] = []): Promise => { try { const $refParser = new $RefParser(); - const refsMap = new Map(); + const known$Refs = new Map(); await $refParser.resolve(source); const paths = [ ...$refParser.$refs.paths(), ...additionnalSchemas ].filter((p, index, arr) => arr.indexOf(p) === index && p !== source); - await mergeDefinitions($refParser, paths, refsMap); - mergeSchemas($refParser, refsMap, $refParser.schema, '#/'); - const generatedTS = await dtsGenerator({ - contents: [parseSchema($refParser.schema as dtsGeneratorJsonSchema)] - }); + await mergeDefinitions($refParser, paths, known$Refs); + mergeSchemas($refParser, known$Refs, $refParser.schema, '#/'); + const generatedTS = (await dtsGenerator({ + contents: [parseSchema($refParser.schema as dtsGeneratorJsonSchema)], + config: { + plugins: { + "@dtsgenerator/replace-namespace": { + map: [ + { + from: ["ServerlessworkflowOrg", "Core", "WorkflowJson"], + to: ["ServerlessWorkflow"] + }, + { + from: ["ServerlessworkflowOrg", "Core", "WorkflowJson", "Definitions"], + to: ["ServerlessWorkflow"] + } + ] + } + } + } + })) + .replace(/WorkflowJson\.Definitions\./g, '') + .replace(/WorkflowJson/g, 'Workflow') + ; const destDir = path.dirname(dest); await rimrafP(destDir); await mkdir(destDir, { recursive: true }); await writeFile(path.resolve(destDir, 'README.md'), `# Auto generated notice This directory and its content has been generated automatically. Do not modify its content, it WILL be lost.`); await writeFile(dest, generatedTS); + const validatorsDest = path.resolve(path.dirname(dest), '../validation/validators-paths.ts'); + await createValidatorsPaths(validatorsDest, known$Refs); return Promise.resolve(); } catch (ex) { diff --git a/tsconfig.spec.json b/tsconfig.spec.json index d972945..74b0353 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -1,15 +1,11 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "outDir": "./out-tsc/tests", - "types": [ - "jasmine", - "node" - ] + "outDir": "./out-tsc/tests" }, "include": [ "./src/**/*.ts", - "./tests/**/*.ts", + "./tests/**/*.spec.ts", ], "exclude": [ "node_modules",