From cbb7186a9d4afa4205efe7bd34a53498f53f641b Mon Sep 17 00:00:00 2001 From: dblock Date: Tue, 4 Jun 2024 08:24:23 -0400 Subject: [PATCH] WIP: Added YAML linter. Signed-off-by: dblock --- .github/workflows/check-links.yml | 4 +- eslint.config.mjs | 53 +++++++++++++++---- package-lock.json | 40 ++++++++++++++ package.json | 1 + tools/src/merger/GlobalParamsGenerator.ts | 4 +- tools/tests/linter/NamespacesFolder.test.ts | 2 +- ...lid_yaml.yaml => invalid_yaml.invalidyaml} | 0 7 files changed, 88 insertions(+), 16 deletions(-) rename tools/tests/linter/fixtures/folder_validators/namespaces/invalid_files/{invalid_yaml.yaml => invalid_yaml.invalidyaml} (100%) diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 907d053b9..20dc5205a 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -1,8 +1,6 @@ name: Check Links -on: - push: - pull_request: +on: [push, pull_request] jobs: check: diff --git a/eslint.config.mjs b/eslint.config.mjs index 9e13e3c1a..fe864c93b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,19 +1,37 @@ -import path from 'path' -import { fileURLToPath } from 'url' -import { FlatCompat } from '@eslint/eslintrc' import pluginJs from '@eslint/js' - -// mimic CommonJS variables -- not needed if using CommonJS -const _filename = fileURLToPath(import.meta.url) -const _dirname = path.dirname(_filename) -const compat = new FlatCompat({ baseDirectory: _dirname, recommendedConfig: pluginJs.configs.recommended }) +import pluginTs from '@typescript-eslint/eslint-plugin' +import parserTs from '@typescript-eslint/parser' +import eslintPluginYml from 'eslint-plugin-yml' +import parserYml from "yaml-eslint-parser" +import globals from 'globals' export default [ pluginJs.configs.recommended, - ...compat.extends('standard-with-typescript'), { files: ['**/*.{js,ts}'], + languageOptions: { + parser: parserTs, + parserOptions: { + project: './tsconfig.json' + }, + globals: { + ...globals.jest, + ...globals.node, + }, + }, + plugins: { + '@typescript-eslint': pluginTs + }, rules: { + ...pluginJs.configs.recommended.rules, + ...pluginTs.configs["recommended-type-checked"].rules, + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unused-vars': ['error', { "argsIgnorePattern": "^_" }], + '@typescript-eslint/require-await': 'off', '@typescript-eslint/consistent-indexed-object-style': 'error', '@typescript-eslint/consistent-type-assertions': 'error', '@typescript-eslint/dot-notation': 'error', @@ -51,7 +69,22 @@ export default [ 'array-callback-return': 'off', 'new-cap': 'off', 'no-return-assign': 'error', - 'object-shorthand': 'error' + 'object-shorthand': 'error', + 'no-constant-condition': 'off' + }, + }, + ...eslintPluginYml.configs['flat/recommended'], + { + files: ["**/*.yaml", "**/*.yml"], + ignores: ['*invalid*'], + languageOptions: { + parser: parserYml + }, + plugins: { + yml: eslintPluginYml + }, + rules: { + 'yml/no-empty-document': 'off' } } ] diff --git a/package-lock.json b/package-lock.json index f4b1b6149..4af8ed016 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-n": "^16.6.2", "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-yml": "^1.14.0", "globals": "^15.0.0", "jest": "^29.7.0", "json-schema-to-typescript": "^14.0.4", @@ -3503,6 +3504,28 @@ "eslint": "^7.0.0 || ^8.0.0" } }, + "node_modules/eslint-plugin-yml": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.14.0.tgz", + "integrity": "sha512-ESUpgYPOcAYQO9czugcX5OqRvn/ydDVwGCPXY4YjPqc09rHaUVUA6IE6HLQys4rXk/S+qx3EwTd1wHCwam/OWQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-compat-utils": "^0.5.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^1.2.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -7627,6 +7650,23 @@ "node": ">= 14" } }, + "node_modules/yaml-eslint-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.3.tgz", + "integrity": "sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 0c14289ab..05f6da26c 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-n": "^16.6.2", "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-yml": "^1.14.0", "globals": "^15.0.0", "jest": "^29.7.0", "json-schema-to-typescript": "^14.0.4", diff --git a/tools/src/merger/GlobalParamsGenerator.ts b/tools/src/merger/GlobalParamsGenerator.ts index d883e0812..4853cb368 100644 --- a/tools/src/merger/GlobalParamsGenerator.ts +++ b/tools/src/merger/GlobalParamsGenerator.ts @@ -15,8 +15,8 @@ export default class GlobalParamsGenerator { spec.components.parameters = { ...this.global_params, ...spec.components.parameters } const global_param_refs = Object.keys(this.global_params).map(param => ({ $ref: `#/components/parameters/${param}` })) - Object.entries(spec.paths as Document).forEach(([path, path_item]) => { - Object.entries(path_item as Document).forEach(([method, operation]) => { + Object.entries(spec.paths as Document).forEach(([_path, path_item]) => { + Object.entries(path_item as Document).forEach(([_method, operation]) => { const params = operation.parameters ?? [] operation.parameters = [...params, ...Object.values(global_param_refs)] }) diff --git a/tools/tests/linter/NamespacesFolder.test.ts b/tools/tests/linter/NamespacesFolder.test.ts index 08b1ac854..343b2cf58 100644 --- a/tools/tests/linter/NamespacesFolder.test.ts +++ b/tools/tests/linter/NamespacesFolder.test.ts @@ -29,7 +29,7 @@ test('validate() - When there invalid files', () => { message: "The 200 response must be a reference object to '#/components/responses/invalid_spec.fetch@200'." }, { - file: 'invalid_files/invalid_yaml.yaml', + file: 'invalid_files/invalid_yaml.invalidyaml', location: 'File Content', message: 'Unable to read or parse YAML.' } diff --git a/tools/tests/linter/fixtures/folder_validators/namespaces/invalid_files/invalid_yaml.yaml b/tools/tests/linter/fixtures/folder_validators/namespaces/invalid_files/invalid_yaml.invalidyaml similarity index 100% rename from tools/tests/linter/fixtures/folder_validators/namespaces/invalid_files/invalid_yaml.yaml rename to tools/tests/linter/fixtures/folder_validators/namespaces/invalid_files/invalid_yaml.invalidyaml