diff --git a/package.json b/package.json new file mode 100644 index 000000000..a57813b59 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "atlas-sdk-go-tools", + "version": "0.1.0", + "private": true, + "description": "Root package to expose the transformer CLI for npx usage", + "bin": { + "atlas-openapi-transformer": "tools/transformer/src/cli.js" + }, + "dependencies": { + "simple-node-logger": "^21.8.12", + "yaml": "2.8.1", + "yargs": "^17.7.2" + }, + "engines": { + "node": ">= 16", + "npm": ">= 8" + } +} + + diff --git a/tools/README.md b/tools/README.md index cfea1ab22..e7ed190ae 100644 --- a/tools/README.md +++ b/tools/README.md @@ -18,6 +18,21 @@ Typically a SDK is generated by: - `releaser` - release automation scripts and documentation - `transformer` - OpenAPI transformation engine and it's documentation +### Transformer CLI usage + +The transformer is also available as a CLI for local use: + +```bash +# Full transform (in-place) +node ./transformer/bin/atlas-openapi-transformer.js transform -i ../openapi/atlas-api-transformed.yaml + +# Flatten-only, reading from stdin and writing to stdout +cat ../openapi/atlas-api.yaml | node ./transformer/bin/atlas-openapi-transformer.js flatten --stdin --stdout > ../openapi/atlas-api-flattened.yaml + +# Adjust log level +node ./transformer/bin/atlas-openapi-transformer.js transform -i ../openapi/atlas-api-transformed.yaml --log-level info +``` + ## SDK Generation Workflow ```mermaid diff --git a/tools/package-lock.json b/tools/package-lock.json index 3aec6162f..fcb5ce5d9 100644 --- a/tools/package-lock.json +++ b/tools/package-lock.json @@ -9,7 +9,11 @@ "version": "0.1.0", "dependencies": { "simple-node-logger": "^21.8.12", - "yaml": "2.8.1" + "yaml": "2.8.1", + "yargs": "^17.7.2" + }, + "bin": { + "atlas-openapi-transformer": "transformer/src/cli.js" }, "devDependencies": { "@openapitools/openapi-generator-cli": "2.24.0", @@ -1897,7 +1901,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1906,7 +1909,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2381,7 +2383,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -2423,7 +2424,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2434,8 +2434,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -2712,8 +2711,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/error-ex": { "version": "1.3.4", @@ -2778,7 +2776,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3123,7 +3120,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -3496,7 +3492,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -5110,7 +5105,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5390,7 +5384,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5420,7 +5413,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5860,7 +5852,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5931,7 +5922,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -5959,7 +5949,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -5978,7 +5967,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -7246,14 +7234,12 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -7551,7 +7537,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -7580,7 +7565,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -7588,8 +7572,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "combined-stream": { "version": "1.0.8", @@ -7776,8 +7759,7 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "error-ex": { "version": "1.3.4", @@ -7824,8 +7806,7 @@ "escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-string-regexp": { "version": "1.0.5", @@ -8043,8 +8024,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { "version": "1.3.0", @@ -8295,8 +8275,7 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-generator-fn": { "version": "2.1.0", @@ -9393,8 +9372,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "resolve-cwd": { "version": "3.0.0", @@ -9585,7 +9563,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9607,7 +9584,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -9902,7 +9878,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9947,8 +9922,7 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "3.1.1", @@ -9965,7 +9939,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "requires": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9979,8 +9952,7 @@ "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" }, "yocto-queue": { "version": "0.1.0", diff --git a/tools/package.json b/tools/package.json index 83fb9c09f..ba9a1d7ea 100644 --- a/tools/package.json +++ b/tools/package.json @@ -4,9 +4,13 @@ "version": "0.1.0", "private": "true", "main": "transformer/src/index.js", + "bin": { + "atlas-openapi-transformer": "./transformer/src/cli.js" + }, "dependencies": { "simple-node-logger": "^21.8.12", - "yaml": "2.8.1" + "yaml": "2.8.1", + "yargs": "^17.7.2" }, "devDependencies": { "@openapitools/openapi-generator-cli": "2.24.0", @@ -15,7 +19,8 @@ "prettier": "3.6.2" }, "scripts": { - "sdk:transform": "node ./transformer/src/transform", + "sdk:transform": "node ./transformer/src/cli.js transform", + "sdk:flatten": "node ./transformer/src/cli.js flatten", "format": "prettier --write .", "format:check": "prettier --check .", "test": "jest **/__tests__/**.test.js", diff --git a/tools/scripts/transform.sh b/tools/scripts/transform.sh index 60e03e9bb..f4f163f3a 100755 --- a/tools/scripts/transform.sh +++ b/tools/scripts/transform.sh @@ -19,4 +19,4 @@ echo "# Running transformation from $transformed_file OpenAPI from $OPENAPI_FILE cp "$OPENAPI_FOLDER/$OPENAPI_FILE_NAME" "$openapiFileLocation" npm install -npm run sdk:transform -- "$openapiFileLocation" +npx atlas-openapi-transformer transform --input "$openapiFileLocation" diff --git a/tools/transformer/src/atlasTransformations.js b/tools/transformer/src/atlasTransformations.js index 10030b1c7..b9676e97e 100644 --- a/tools/transformer/src/atlasTransformations.js +++ b/tools/transformer/src/atlasTransformations.js @@ -21,17 +21,43 @@ const ignoredModelNames = require("./name.ignore.json").ignoreModels; /** * Function specifies list of transformations to run */ -module.exports = function runTransformations(openapi) { +function runFlatteningTransformations(openapi) { + // Flattening transformations openapi = searchAPIIssuesTransformation(openapi); openapi = applyDiscriminatorTransformations(openapi); openapi = applyOneOfTransformations(openapi); openapi = applyAnyOfTransformations(openapi); openapi = applyAllOfTransformations(openapi); + openapi = applyFieldTransformations(openapi); + + if (openapi.components.schemas.ApiAtlasFTSAnalyzersViewManual) { + filtersObj = openapi.components.schemas.ApiAtlasFTSAnalyzersViewManual; + if (filtersObj.properties.tokenFilters) { + filtersObj.properties.tokenFilters.items = {}; + } + if (filtersObj.properties.charFilters) { + filtersObj.properties.charFilters.items = {}; + } + } + + let hasSchemaChanges = true; + // Remove referencing objects that become unused + while (hasSchemaChanges) { + console.info("Checking for unused schemas"); + hasSchemaChanges = removeUnusedSchemas(openapi); + } + + return openapi; +} + +function runSDKTransformations(openapi) { + openapi = runFlatteningTransformations(openapi); + + // SDK specific transformations openapi = applyRemoveEnumsTransformations(openapi); openapi = applyRemoveNullableTransformations(openapi); openapi = applyRemoveObjectAdditionalProperties(openapi); openapi = reorderResponseBodies(openapi); - openapi = applyFieldTransformations(openapi); openapi = applyModelNameTransformations( openapi, @@ -46,23 +72,6 @@ module.exports = function runTransformations(openapi) { ignoredModelNames, ); - if (openapi.components.schemas.ApiAtlasFTSAnalyzers) { - filtersObj = openapi.components.schemas.ApiAtlasFTSAnalyzers; - if (filtersObj.properties.tokenFilters) { - filtersObj.properties.tokenFilters.items = {}; - } - if (filtersObj.properties.charFilters) { - filtersObj.properties.charFilters.items = {}; - } - } - - let hasSchemaChanges = true; - // Remove referencing objects that become unused - while (hasSchemaChanges) { - console.info("Checking for unused schemas"); - hasSchemaChanges = removeUnusedSchemas(openapi); - } - if (openapi.components.schemas.ApiError) { openapi.components.schemas.ApiError.properties.parameters.items = {}; } @@ -77,6 +86,11 @@ module.exports = function runTransformations(openapi) { return openapi; }; +module.exports = { + runFlatteningTransformations: runFlatteningTransformations, + runSDKTransformations: runSDKTransformations, +}; + // Temporary transformation until new search version is introduced. function searchAPIIssuesTransformation(openapi) { const modelsToFix = [ diff --git a/tools/transformer/src/cli.js b/tools/transformer/src/cli.js new file mode 100755 index 000000000..8f6fbc165 --- /dev/null +++ b/tools/transformer/src/cli.js @@ -0,0 +1,99 @@ +#!/usr/bin/env node +const yargs = require("yargs/yargs"); +const { hideBin } = require("yargs/helpers"); +const { parse, stringify } = require("yaml"); +const fs = require("fs"); +const simpleLogger = require("simple-node-logger"); +const { runSDKTransformations, runFlatteningTransformations } = require("./atlasTransformations"); + +function readInput({ input, stdin }) { + if (stdin) { + return new Promise((resolve, reject) => { + let data = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", (chunk) => (data += chunk)); + process.stdin.on("end", () => { + try { + resolve(parse(data)); + } catch (e) { + reject(e); + } + }); + process.stdin.on("error", reject); + }); + } + if (!input) { + throw new Error("Missing --input or use --stdin"); + } + return Promise.resolve(parse(fs.readFileSync(input, "utf8"))); +} + +function writeOutput({ doc, output, stdout, input }) { + const yaml = stringify(doc, { lineWidth: 9999 }); + if (stdout || (!output && !input)) { + process.stdout.write(yaml); + return; + } + const outPath = output || input; + fs.writeFileSync(outPath, yaml); +} + +function configureLogger(level) { + const log = simpleLogger.createSimpleLogger(); + log.setLevel(level || process.env.XGEN_LOGGING_LEVEL || "warn"); + return log; +} + +yargs(hideBin(process.argv)) + .command( + "flatten", + "Apply flattening transformations", + (y) => + y + .option("input", { alias: "i", type: "string" }) + .option("output", { alias: "o", type: "string" }) + .option("stdin", { type: "boolean", default: false }) + .option("stdout", { type: "boolean", default: false }) + .option("log-level", { type: "string" }), + async (args) => { + const log = configureLogger(args["log-level"]); + const originalConsole = global.console; + global.console = log; // direct internal console usage to our logger during CLI execution + try { + const doc = await readInput(args); + const out = runFlatteningTransformations(doc); + writeOutput({ doc: out, ...args }); + } finally { + global.console = originalConsole; + } + }, + ) + .command( + "transform", + "Apply full transformations", + (y) => + y + .option("input", { alias: "i", type: "string" }) + .option("output", { alias: "o", type: "string" }) + .option("stdin", { type: "boolean", default: false }) + .option("stdout", { type: "boolean", default: false }) + .option("log-level", { type: "string" }), + async (args) => { + const log = configureLogger(args["log-level"]); + const originalConsole = global.console; + global.console = log; + try { + const doc = await readInput(args); + const out = runSDKTransformations(doc); + writeOutput({ doc: out, ...args }); + } finally { + global.console = originalConsole; + } + }, + ) + .demandCommand(1) + .strict() + .help() + .parse(); + + diff --git a/tools/transformer/src/engine/apifile.js b/tools/transformer/src/engine/apifile.js index cb4f1a2b9..4c7b2a92e 100644 --- a/tools/transformer/src/engine/apifile.js +++ b/tools/transformer/src/engine/apifile.js @@ -32,4 +32,24 @@ function saveAPI(doc, apiFileLocation) { writeFileSync(apiFileLocation, stringify(doc, { lineWidth: 9999 })); // default is 80 and would add newlines, we want to stay close to the original that uses long lines. } -module.exports = { getAPI, saveAPI }; +function readFromStdin() { + return new Promise((resolve, reject) => { + let data = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", (chunk) => (data += chunk)); + process.stdin.on("end", () => { + try { + resolve(parse(data)); + } catch (e) { + reject(e); + } + }); + process.stdin.on("error", reject); + }); +} + +function writeToStdout(doc) { + process.stdout.write(stringify(doc, { lineWidth: 9999 })); +} + +module.exports = { getAPI, saveAPI, readFromStdin, writeToStdout };