From 92fe40d8d62b914777163b507d6d677803dc4908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Barthelet?= Date: Sun, 20 Dec 2020 12:07:41 +0100 Subject: [PATCH] Add quicktype, typescript source code and eslint --- .eslintrc.json | 106 +++++++++++++++++++++++ .github/workflows/definitionsBuilder.yml | 3 + .github/workflows/test.yml | 26 ++++++ .gitignore | 1 + .npmignore | 3 +- package.json | 17 +++- plugin.js | 62 ------------- serverless.yml | 2 +- src/plugin.ts | 49 +++++++++++ tsconfig.json | 17 ++++ 10 files changed, 220 insertions(+), 66 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .github/workflows/test.yml delete mode 100644 plugin.js create mode 100644 src/plugin.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..b120d41 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,106 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:prettier/recommended" + ], + "rules": { + "curly": [ + "error", + "all" + ], + "eqeqeq": [ + "error", + "smart" + ], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": true, + "optionalDependencies": false, + "peerDependencies": false + } + ], + "no-shadow": [ + "error", + { + "hoist": "all" + } + ], + "prefer-const": "error", + "import/order": [ + "error", + { + "groups": [ + [ + "external", + "builtin" + ], + "internal", + [ + "parent", + "sibling", + "index" + ] + ] + } + ], + "sort-imports": [ + "error", + { + "ignoreCase": true, + "ignoreDeclarationSort": true, + "ignoreMemberSort": false, + "memberSyntaxSortOrder": [ + "none", + "all", + "multiple", + "single" + ] + } + ], + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "*", + "next": "return" + } + ] + }, + "root": true, + "plugins": [ + "import" + ], + "env": { + "es6": true, + "node": true + }, + "overrides": [ + { + "files": [ + "src/**/*.ts" + ], + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier/@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json" + }, + "rules": { + "@typescript-eslint/prefer-optional-chain": "error", + "no-shadow": "off", + "@typescript-eslint/no-shadow": "error", + "@typescript-eslint/prefer-nullish-coalescing": "error", + "@typescript-eslint/strict-boolean-expressions": "error", + "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error", + "@typescript-eslint/no-unnecessary-condition": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + "@typescript-eslint/prefer-string-starts-ends-with": "error", + "@typescript-eslint/switch-exhaustiveness-check": "error" + } + } + ] +} diff --git a/.github/workflows/definitionsBuilder.yml b/.github/workflows/definitionsBuilder.yml index bc99793..ff6c6bb 100644 --- a/.github/workflows/definitionsBuilder.yml +++ b/.github/workflows/definitionsBuilder.yml @@ -20,6 +20,9 @@ jobs: - name: Install dependencies run: npm i + - name: Build plugin + run: npm run build + - id: serverless-version name: Set Serverless latest version run: echo "::set-output name=version::$(npm list serverless | grep serverless@ | sed 's/.*serverless@/v/g' | tr -d '[[:space:]]')" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..edb131a --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,26 @@ +name: Tests +on: + push + +jobs: + tests: + name: Run serverless/typescript tests + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Node.js and npm + uses: actions/setup-node@v1 + with: + node-version: 14.x + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: npm i + + - name: Run lint tests + run: npm run test:lint + + - name: Run type tests + run: npm run test:type diff --git a/.gitignore b/.gitignore index d5f19d8..91a3983 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +dist node_modules package-lock.json diff --git a/.npmignore b/.npmignore index e0a7f55..94e5a31 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,7 @@ .github .gitignore +dist node_modules package-lock.json -plugin.js +src serverless.yml diff --git a/package.json b/package.json index d5e77fb..4519629 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,13 @@ "version": "2.15.0", "description": "Serverless typescript definitions", "main": "index.d.ts", - "scripts": {}, + "scripts": { + "build": "tsc", + "lint:fix": "eslint src --fix", + "watch": "tsc -w", + "test:lint": "eslint src", + "test:type": "tsc --noEmit" + }, "repository": { "type": "git", "url": "git+https://github.com/serverless/typescript.git" @@ -21,7 +27,14 @@ "homepage": "https://github.com/serverless/typescript#readme", "dependencies": {}, "devDependencies": { - "json-schema-to-typescript": "^9.1.1", + "@typescript-eslint/eslint-plugin": "^4.10.0", + "@typescript-eslint/parser": "^4.10.0", + "eslint": "^7.16.0", + "eslint-config-prettier": "^7.1.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-prettier": "^3.3.0", + "prettier": "^2.2.1", + "quicktype-core": "^6.0.69", "serverless": "*", "typescript": "^4.0.5" } diff --git a/plugin.js b/plugin.js deleted file mode 100644 index 830789c..0000000 --- a/plugin.js +++ /dev/null @@ -1,62 +0,0 @@ -const { compile } = require('json-schema-to-typescript'); -const fs = require('fs'); - -class ConfigSchemaHandlerTypescriptDefinitionsPlugin { - constructor(serverless, options) { - this.schema = serverless.configSchemaHandler.schema - this.options = options || {}; - - this.commands = { - schema: { - usage: 'Get JSON schema definition and generate TS definitions', - lifecycleEvents: ['generate'], - } - } - - this.hooks = { - 'schema:generate': this.generateSchema.bind(this) - }; - } - - async generateSchema() { - // This definition is causing memory trouble - delete this.schema.properties.provider.properties.s3.additionalProperties.properties.replicationConfiguration - - /** - * https://github.com/serverless/typescript/issues/4 - * JSON Schema v6 `const` keyword converted to `enum` - */ - const normalizedSchema = replaceAllConstForEnum(this.schema); - - /** - * format: false -> improves generation performances - * ignoreMinAndMaxItems: true -> maxItems: 100 in provider.s3.corsConfiguration definition is generating 100 tuples - */ - const compiledDefinitions = await compile(normalizedSchema, 'AWS', { format: false, ignoreMinAndMaxItems: true, unreachableDefinitions: true }) - fs.writeFileSync('index.d.ts', compiledDefinitions) - } -} - -function replaceAllConstForEnum(schema) { - if ('object' !== typeof schema) { - return schema - } - - return Object.fromEntries(Object.entries(schema).map(([key, value]) => { - if (key === 'const') { - return ['enum', [value]] - } - - if (Array.isArray(value)) { - return [key, value.map(replaceAllConstForEnum)] - } - - if ('object' === typeof value && value !== null) { - return [key, replaceAllConstForEnum(value)] - } - - return [key, value] - })) -} - -module.exports = ConfigSchemaHandlerTypescriptDefinitionsPlugin diff --git a/serverless.yml b/serverless.yml index 9b99f82..41c2a8b 100644 --- a/serverless.yml +++ b/serverless.yml @@ -4,4 +4,4 @@ provider: name: aws plugins: - - ./plugin + - ./dist/plugin diff --git a/src/plugin.ts b/src/plugin.ts new file mode 100644 index 0000000..28071f1 --- /dev/null +++ b/src/plugin.ts @@ -0,0 +1,49 @@ +import { InputData, JSONSchemaInput, quicktype } from "quicktype-core"; +import { writeFileSync } from "fs"; + +interface Serverless { + configSchemaHandler: { + schema: Record; + }; +} + +class ConfigSchemaHandlerTypescriptDefinitionsPlugin { + private schema: Record; + + constructor(serverless: Serverless) { + this.schema = serverless.configSchemaHandler.schema; + } + + commands = { + schema: { + usage: "Get JSON schema definition and generate TS definitions", + lifecycleEvents: ["generate"], + }, + }; + + hooks = { + "schema:generate": this.generateSchema.bind(this), + }; + + async generateSchema() { + const schemaInput = new JSONSchemaInput(undefined); + await schemaInput.addSource({ + name: "AWS", + schema: JSON.stringify(this.schema), + }); + const inputData = new InputData(); + inputData.addInput(schemaInput); + + const { lines: serverlessTs } = await quicktype({ + inputData, + lang: "typescript", + rendererOptions: { + "just-types": "true", + }, + }); + + writeFileSync("index.d.ts", serverlessTs.join("\n")); + } +} + +module.exports = ConfigSchemaHandlerTypescriptDefinitionsPlugin; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..735050c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "declaration": false, + "esModuleInterop": true, + "module": "commonjs", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist", + "preserveConstEnums": true, + "strict": true, + "skipLibCheck": true, + "target": "es6" + }, + "include": ["src"], +}