diff --git a/.changeset/pink-hairs-fail.md b/.changeset/pink-hairs-fail.md new file mode 100644 index 00000000..ffcf4acb --- /dev/null +++ b/.changeset/pink-hairs-fail.md @@ -0,0 +1,5 @@ +--- +"@intlify/eslint-plugin-vue-i18n": minor +--- + +feat: support flat config diff --git a/.eslintignore b/.eslintignore index 40b12723..d0192527 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,6 +7,7 @@ /dist /docs/.vitepress/cache /docs/.vitepress/dist +/lib/configs/**/*.ts /node_modules -# /tests/fixtures Used testcases -/tests-integrations/config-recommended +#/tests/fixtures # use testing +/tests/integrations diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 10e57f7b..0924e612 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Enable corepack run: corepack enable - name: Install @@ -30,7 +30,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node: [16, 18, 20] + node: [18, 20] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.prettierignore b/.prettierignore index 8d985a7a..fbe1bbfd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,6 +10,7 @@ /tests/fixtures /tests-integrations/config-recommended /docs/.vitepress/cache +/scripts/update-**.ts # ignore files /CHANGELOG.md diff --git a/docs/rules/index.md b/docs/rules/index.md index f74db57b..3291d81b 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -1,6 +1,6 @@ # Available Rules -- :star: mark: the rule which is enabled by `plugin:@intlify/vue-i18n/recommended` preset. +- :star: mark: the rule which is enabled by `plugin:@intlify/vue-i18n/recommended` or `*.configs["flat/recommended"]` preset. - :black_nib: mark: the rule which is fixable by `eslint --fix` command. ## Recommended diff --git a/docs/rules/no-html-messages.md b/docs/rules/no-html-messages.md index fbac9616..71f63196 100644 --- a/docs/rules/no-html-messages.md +++ b/docs/rules/no-html-messages.md @@ -8,7 +8,7 @@ since: v0.1.0 > disallow use HTML localization messages -- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule. +- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule. This rule reports in order to reduce the risk of injecting potentially unsafe localization message into the browser leading to supply-chain attack or XSS attack. diff --git a/docs/rules/no-missing-keys.md b/docs/rules/no-missing-keys.md index 60905092..26937fa9 100644 --- a/docs/rules/no-missing-keys.md +++ b/docs/rules/no-missing-keys.md @@ -8,7 +8,7 @@ since: v0.1.0 > disallow missing locale message key at localization methods -- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule. +- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule. This rule warns locale message key missing if the key does not exist in locale messages. diff --git a/docs/rules/no-raw-text.md b/docs/rules/no-raw-text.md index 363829f0..3fc20d81 100644 --- a/docs/rules/no-raw-text.md +++ b/docs/rules/no-raw-text.md @@ -8,7 +8,7 @@ since: v0.2.0 > disallow to string literal in template or JSX -- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule. +- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule. This rule warns the usage of literal the bellow: diff --git a/docs/rules/no-v-html.md b/docs/rules/no-v-html.md index b1001a68..77acadc6 100644 --- a/docs/rules/no-v-html.md +++ b/docs/rules/no-v-html.md @@ -8,7 +8,7 @@ since: v0.1.0 > disallow use of localization methods on v-html to prevent XSS attack -- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule. +- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule. This rule reports all uses of localization methods on `v-html` directive in order to reduce the risk of injecting potentially unsafe / unescaped html into the browser leading to Cross-Site Scripting (XSS) attacks. diff --git a/docs/started.md b/docs/started.md index d63e3350..ce1f2c50 100644 --- a/docs/started.md +++ b/docs/started.md @@ -17,7 +17,83 @@ npm install --save-dev eslint @intlify/eslint-plugin-vue-i18n ## :rocket: Usage -Configure your `.eslintrc.*` file. +### Configuration `eslint.config.[c|m]js` + +Use `eslint.config.[c|m]js` file to configure rules. This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new. + +Example eslint.config.js: + +```js +import vueI18n from '@intlify/eslint-plugin-vue-i18n' + +export default [ + // add more generic rulesets here, such as: + // js.configs.recommended, // '@eslint/js' + // ...vue.configs['flat/recommended'], // 'eslint-plugin-vue' + + ...vueI18n.configs['flat/recommended'], + { + rules: { + // Optional. + '@intlify/vue-i18n/no-dynamic-keys': 'error', + '@intlify/vue-i18n/no-unused-keys': [ + 'error', + { + extensions: ['.js', '.vue'] + } + ] + }, + settings: { + 'vue-i18n': { + localeDir: './path/to/locales/*.{json,json5,yaml,yml}', // extension is glob formatting! + // or + // localeDir: { + // pattern: './path/to/locales/*.{json,json5,yaml,yml}', // extension is glob formatting! + // localeKey: 'file' // or 'path' or 'key' + // } + // or + // localeDir: [ + // { + // // 'file' case + // pattern: './path/to/locales1/*.{json,json5,yaml,yml}', + // localeKey: 'file' + // }, + // { + // // 'path' case + // pattern: './path/to/locales2/*.{json,json5,yaml,yml}', + // localePattern: /^.*\/(?[A-Za-z0-9-_]+)\/.*\.(json5?|ya?ml)$/, + // localeKey: 'path' + // }, + // { + // // 'key' case + // pattern: './path/to/locales3/*.{json,json5,yaml,yml}', + // localeKey: 'key' + // }, + // ] + + // Specify the version of `vue-i18n` you are using. + // If not specified, the message will be parsed twice. + messageSyntaxVersion: '^9.0.0' + } + } + } +] +``` + +See the [rule list](./rules/index.md) to get the `configs` & `rules` that this plugin provides. + +#### Bundle Configurations `eslint.config.[c|m]js` + +This plugin provides some predefined configs. You can use the following configs by adding them to `eslint.config.[c|m]js`. (All flat configs in this plugin are provided as arrays, so spread syntax is required when combining them with other configs.) + +- `*.configs["flat/base"]`: Settings and rules to enable correct ESLint parsing. +- `*.configs["flat/recommended"]`: Above, plus rules to enforce subjective community defaults to ensure consistency. + +### Configuration `.eslintrc.*` + +Use `.eslintrc.*` file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/. + +Example `.eslintrc.js`: For example: @@ -74,7 +150,14 @@ module.export = { } ``` -See [the rule list](/rules/) +See the [rule list](./rules/index.md) to get the `configs` & `rules` that this plugin provides. + +#### Bundle Configurations `.eslintrc.*` + +This plugin provides some predefined configs. You can use the following configs by adding them to `.eslintrc.*`. (All flat configs in this plugin are provided as arrays, so spread syntax is required when combining them with other configs.) + +- `"plugin:@intlify/vue-i18n/base"`: Settings and rules to enable correct ESLint parsing. +- `"plugin:@intlify/vue-i18n/recommended"`: Above, plus rules to enforce subjective community defaults to ensure consistency. ### `settings['vue-i18n']` @@ -102,7 +185,7 @@ If you want to run `eslint` from command line, make sure you include the `.vue`, Examples: -```bash +```sh eslint --ext .js,.vue,.json src eslint "src/**/*.{js,vue,json}" # Specify the extension you use. diff --git a/lib/configs.ts b/lib/configs.ts deleted file mode 100644 index 0c142de8..00000000 --- a/lib/configs.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** DON'T EDIT THIS FILE; was created by scripts. */ -import base from './configs/base' -import recommended from './configs/recommended' - -export = { - base, - recommended -} diff --git a/lib/configs/base.ts b/lib/configs/base.ts index 6cfa657b..0d47b2cc 100644 --- a/lib/configs/base.ts +++ b/lib/configs/base.ts @@ -1,11 +1,10 @@ +/** DON'T EDIT THIS FILE; was created by scripts. */ export = { parser: require.resolve('vue-eslint-parser'), plugins: ['@intlify/vue-i18n'], overrides: [ { files: ['*.json', '*.json5'], - // TODO: If you do not use vue-eslint-parser, you will get an error in vue rules. - // see https://github.com/vuejs/eslint-plugin-vue/pull/1262 parser: require.resolve('vue-eslint-parser'), parserOptions: { parser: require.resolve('jsonc-eslint-parser') @@ -13,15 +12,11 @@ export = { }, { files: ['*.yaml', '*.yml'], - // TODO: If you do not use vue-eslint-parser, you will get an error in vue rules. - // see https://github.com/vuejs/eslint-plugin-vue/pull/1262 parser: require.resolve('vue-eslint-parser'), parserOptions: { parser: require.resolve('yaml-eslint-parser') }, rules: { - // ESLint core rules known to cause problems with YAML. - // https://github.com/ota-meshi/eslint-plugin-yml/blob/4e468109b9d2f4376b8d4d1221adba27c6ee04b2/src/configs/base.ts#L7-L11 'no-irregular-whitespace': 'off', 'spaced-comment': 'off' } diff --git a/lib/configs/flat/base.ts b/lib/configs/flat/base.ts new file mode 100644 index 00000000..b8a14988 --- /dev/null +++ b/lib/configs/flat/base.ts @@ -0,0 +1,35 @@ +/** DON'T EDIT THIS FILE; was created by scripts. */ +export = [ + { + name: '@intlify/vue-i18n:base:setup', + plugins: { + get '@intlify/vue-i18n'() { + return require('../../index') + } + } + }, + { + name: '@intlify/vue-i18n:base:setup:json', + files: ['*.json', '**/*.json', '*.json5', '**/*.json5'], + languageOptions: { + parser: require('vue-eslint-parser'), + parserOptions: { + parser: require('jsonc-eslint-parser') + } + } + }, + { + name: '@intlify/vue-i18n:base:setup:yaml', + files: ['*.yaml', '**/*.yaml', '*.yml', '**/*.yml'], + languageOptions: { + parser: require('vue-eslint-parser'), + parserOptions: { + parser: require('yaml-eslint-parser') + } + }, + rules: { + 'no-irregular-whitespace': 'off', + 'spaced-comment': 'off' + } + } +] diff --git a/lib/configs/flat/recommended.ts b/lib/configs/flat/recommended.ts new file mode 100644 index 00000000..72361b85 --- /dev/null +++ b/lib/configs/flat/recommended.ts @@ -0,0 +1,28 @@ +/** DON'T EDIT THIS FILE; was created by scripts. */ +const globals = require('globals') +const config = require('./base') +export = [ + ...config, + { + name: '@intlify/vue-i18n:recommended:setup', + languageOptions: { + ecmaVersion: 2018, + sourceType: 'module', + globals: globals.browser, + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + } + }, + { + name: '@intlify/vue-i18n:recommended:rules', + rules: { + '@intlify/vue-i18n/no-html-messages': 'warn', + '@intlify/vue-i18n/no-missing-keys': 'warn', + '@intlify/vue-i18n/no-raw-text': 'warn', + '@intlify/vue-i18n/no-v-html': 'warn' + } + } +] diff --git a/lib/index.ts b/lib/index.ts index 7bc6da8f..2e6afd45 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,11 +1,59 @@ -/** - * @fileoverview ESLint plugin for vue-i18n - * @author kazuya kawaguchi (a.k.a. kazupon) - */ -import configs from './configs' -import rules from './rules' +/** DON'T EDIT THIS FILE; was created by scripts. */ +// configs +import base from './configs/base' +import recommended from './configs/recommended' +import flatBase from './configs/flat/base' +import flatRecommended from './configs/flat/recommended' +// rules +import keyFormatStyle from './rules/key-format-style' +import noDeprecatedI18nComponent from './rules/no-deprecated-i18n-component' +import noDeprecatedI18nPlaceAttr from './rules/no-deprecated-i18n-place-attr' +import noDeprecatedI18nPlacesProp from './rules/no-deprecated-i18n-places-prop' +import noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale' +import noDynamicKeys from './rules/no-dynamic-keys' +import noHtmlMessages from './rules/no-html-messages' +import noI18nTPathProp from './rules/no-i18n-t-path-prop' +import noMissingKeysInOtherLocales from './rules/no-missing-keys-in-other-locales' +import noMissingKeys from './rules/no-missing-keys' +import noRawText from './rules/no-raw-text' +import noUnknownLocale from './rules/no-unknown-locale' +import noUnusedKeys from './rules/no-unused-keys' +import noVHtml from './rules/no-v-html' +import preferLinkedKeyWithParen from './rules/prefer-linked-key-with-paren' +import preferSfcLangAttr from './rules/prefer-sfc-lang-attr' +import sfcLocaleAttr from './rules/sfc-locale-attr' +import validMessageSyntax from './rules/valid-message-syntax' + +// export plugin export = { - configs, - rules + configs: { + // eslintrc configs + base, + recommended, + + // flat configs + 'flat/base': flatBase, + 'flat/recommended': flatRecommended + }, + rules: { + 'key-format-style': keyFormatStyle, + 'no-deprecated-i18n-component': noDeprecatedI18nComponent, + 'no-deprecated-i18n-place-attr': noDeprecatedI18nPlaceAttr, + 'no-deprecated-i18n-places-prop': noDeprecatedI18nPlacesProp, + 'no-duplicate-keys-in-locale': noDuplicateKeysInLocale, + 'no-dynamic-keys': noDynamicKeys, + 'no-html-messages': noHtmlMessages, + 'no-i18n-t-path-prop': noI18nTPathProp, + 'no-missing-keys-in-other-locales': noMissingKeysInOtherLocales, + 'no-missing-keys': noMissingKeys, + 'no-raw-text': noRawText, + 'no-unknown-locale': noUnknownLocale, + 'no-unused-keys': noUnusedKeys, + 'no-v-html': noVHtml, + 'prefer-linked-key-with-paren': preferLinkedKeyWithParen, + 'prefer-sfc-lang-attr': preferSfcLangAttr, + 'sfc-locale-attr': sfcLocaleAttr, + 'valid-message-syntax': validMessageSyntax + } } diff --git a/lib/rules.ts b/lib/rules.ts deleted file mode 100644 index 898d71f3..00000000 --- a/lib/rules.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** DON'T EDIT THIS FILE; was created by scripts. */ -import keyFormatStyle from './rules/key-format-style' -import noDeprecatedI18nComponent from './rules/no-deprecated-i18n-component' -import noDeprecatedI18nPlaceAttr from './rules/no-deprecated-i18n-place-attr' -import noDeprecatedI18nPlacesProp from './rules/no-deprecated-i18n-places-prop' -import noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale' -import noDynamicKeys from './rules/no-dynamic-keys' -import noHtmlMessages from './rules/no-html-messages' -import noI18nTPathProp from './rules/no-i18n-t-path-prop' -import noMissingKeysInOtherLocales from './rules/no-missing-keys-in-other-locales' -import noMissingKeys from './rules/no-missing-keys' -import noRawText from './rules/no-raw-text' -import noUnknownLocale from './rules/no-unknown-locale' -import noUnusedKeys from './rules/no-unused-keys' -import noVHtml from './rules/no-v-html' -import preferLinkedKeyWithParen from './rules/prefer-linked-key-with-paren' -import preferSfcLangAttr from './rules/prefer-sfc-lang-attr' -import sfcLocaleAttr from './rules/sfc-locale-attr' -import validMessageSyntax from './rules/valid-message-syntax' - -export = { - 'key-format-style': keyFormatStyle, - 'no-deprecated-i18n-component': noDeprecatedI18nComponent, - 'no-deprecated-i18n-place-attr': noDeprecatedI18nPlaceAttr, - 'no-deprecated-i18n-places-prop': noDeprecatedI18nPlacesProp, - 'no-duplicate-keys-in-locale': noDuplicateKeysInLocale, - 'no-dynamic-keys': noDynamicKeys, - 'no-html-messages': noHtmlMessages, - 'no-i18n-t-path-prop': noI18nTPathProp, - 'no-missing-keys-in-other-locales': noMissingKeysInOtherLocales, - 'no-missing-keys': noMissingKeys, - 'no-raw-text': noRawText, - 'no-unknown-locale': noUnknownLocale, - 'no-unused-keys': noUnusedKeys, - 'no-v-html': noVHtml, - 'prefer-linked-key-with-paren': preferLinkedKeyWithParen, - 'prefer-sfc-lang-attr': preferSfcLangAttr, - 'sfc-locale-attr': sfcLocaleAttr, - 'valid-message-syntax': validMessageSyntax -} diff --git a/lib/utils.ts b/lib/utils.ts deleted file mode 100644 index cbbde54b..00000000 --- a/lib/utils.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** DON'T EDIT THIS FILE; was created by scripts. */ -import * as cacheFunction from './utils/cache-function' -import * as cacheLoader from './utils/cache-loader' -import * as casing from './utils/casing' -import * as collectKeys from './utils/collect-keys' -import * as collectLinkedKeys from './utils/collect-linked-keys' -import * as compat from './utils/compat' -import * as defaultTimeouts from './utils/default-timeouts' -import * as getCwd from './utils/get-cwd' -import * as globUtils from './utils/glob-utils' -import * as ignoredPaths from './utils/ignored-paths' -import * as index from './utils/index' -import * as keyPath from './utils/key-path' -import * as localeMessages from './utils/locale-messages' -import * as parsers from './utils/parsers' -import * as pathUtils from './utils/path-utils' -import * as regexp from './utils/regexp' -import * as resourceLoader from './utils/resource-loader' -import * as rule from './utils/rule' - -export = { - 'cache-function': cacheFunction, - 'cache-loader': cacheLoader, - casing, - 'collect-keys': collectKeys, - 'collect-linked-keys': collectLinkedKeys, - compat, - 'default-timeouts': defaultTimeouts, - 'get-cwd': getCwd, - 'glob-utils': globUtils, - 'ignored-paths': ignoredPaths, - index, - 'key-path': keyPath, - 'locale-messages': localeMessages, - parsers, - 'path-utils': pathUtils, - regexp, - 'resource-loader': resourceLoader, - rule -} diff --git a/package.json b/package.json index 5e8078db..57a0eeaa 100644 --- a/package.json +++ b/package.json @@ -41,20 +41,20 @@ "coverage": "nyc report --reporter lcov && opener coverage/lcov-report/index.html", "docs": "vitepress dev docs", "docs:build": "vitepress build docs", - "generate": "ts-node scripts/update.ts", + "generate": "jiti scripts/update.ts", "fix": "run-p fix:*", "fix:eslint": "pnpm run lint:eslint --fix", "fix:prettier": "prettier --write .", "lint": "run-s lint:*", - "lint:eslint": "eslint . --ext js,ts,vue,md --ignore-pattern \"/tests/fixtures\"", + "lint:eslint": "eslint . --ext js,ts,vue,md --ignore-pattern \"/tests/fixtures\" --ignore-pattern \"/tests/integrations\"", "lint:prettier": "prettier --check .", "prerelease": "pnpm run test && pnpm run build", "release": "changeset publish", - "test": "mocha --require ts-node/register/transpile-only \"./tests/**/*.ts\"", - "test:debug": "mocha --require ts-node/register/transpile-only \"./tests/**/*.ts\"", - "test:coverage": "nyc mocha --require ts-node/register/transpile-only \"./tests/**/*.ts\" --timeout 60000", - "test:integrations": "mocha ./tests-integrations/*.cjs --timeout 60000", - "new": "ts-node ./scripts/new-rule.ts", + "test": "mocha --require jiti/register \"./tests/lib/**/*.ts\"", + "test:debug": "mocha --require jiti/register \"./tests/lib/**/*.ts\"", + "test:coverage": "nyc mocha --require jiti/register \"./tests/lib/**/*.ts\" --timeout 60000", + "test:integrations": "mocha --require jiti/register \"./tests/integrations/*.ts\" --timeout 60000", + "new": "jiti ./scripts/new-rule.ts", "version:ci": "env-cmd -e version-ci pnpm run generate && changeset version", "changeset": "changeset" }, @@ -65,6 +65,7 @@ "debug": "^4.3.4", "eslint-compat-utils": "^0.5.0", "glob": "^10.3.3", + "globals": "^15.0.0", "ignore": "^5.2.4", "import-fresh": "^3.3.0", "is-language-code": "^3.1.0", @@ -95,7 +96,7 @@ "@typescript-eslint/parser": "^6.2.0", "entities": "^4.5.0", "env-cmd": "^10.1.0", - "eslint": "^8.45.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-markdown": "^3.0.0", "eslint-plugin-prettier": "^4.2.1", @@ -103,6 +104,7 @@ "eslint4b": "^7.32.0", "espree": "^9.6.1", "esquery": "^1.5.0", + "jiti": "^1.21.0", "json-schema": "^0.4.0", "lint-staged": "^15.0.0", "mocha": "^10.2.0", @@ -112,7 +114,6 @@ "opener": "^1.5.2", "path-scurry": "^1.10.1", "prettier": "^2.8.8", - "ts-node": "^10.9.1", "typescript": "^5.1.6", "vitepress": "1.0.0-beta.7", "vue-eslint-editor": "^1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49003bbf..8948764c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,13 @@ dependencies: version: 4.3.4(supports-color@8.1.1) eslint-compat-utils: specifier: ^0.5.0 - version: 0.5.0(eslint@8.45.0) + version: 0.5.0(eslint@8.57.0) glob: specifier: ^10.3.3 version: 10.3.3 + globals: + specifier: ^15.0.0 + version: 15.0.0 ignore: specifier: ^5.2.4 version: 5.2.4 @@ -52,7 +55,7 @@ dependencies: version: 7.5.4 vue-eslint-parser: specifier: ^9.3.1 - version: 9.3.1(eslint@8.45.0) + version: 9.3.1(eslint@8.57.0) yaml-eslint-parser: specifier: ^1.2.2 version: 1.2.2 @@ -99,10 +102,10 @@ devDependencies: version: 7.5.0 '@typescript-eslint/eslint-plugin': specifier: ^6.2.0 - version: 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.1.6) + version: 6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': specifier: ^6.2.0 - version: 6.2.0(eslint@8.45.0)(typescript@5.1.6) + version: 6.2.0(eslint@8.57.0)(typescript@5.1.6) entities: specifier: ^4.5.0 version: 4.5.0 @@ -110,20 +113,20 @@ devDependencies: specifier: ^10.1.0 version: 10.1.0 eslint: - specifier: ^8.45.0 - version: 8.45.0 + specifier: ^8.57.0 + version: 8.57.0 eslint-config-prettier: specifier: ^9.0.0 - version: 9.0.0(eslint@8.45.0) + version: 9.0.0(eslint@8.57.0) eslint-plugin-markdown: specifier: ^3.0.0 - version: 3.0.0(eslint@8.45.0) + version: 3.0.0(eslint@8.57.0) eslint-plugin-prettier: specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@9.0.0)(eslint@8.45.0)(prettier@2.8.8) + version: 4.2.1(eslint-config-prettier@9.0.0)(eslint@8.57.0)(prettier@2.8.8) eslint-plugin-vue: specifier: ^9.15.1 - version: 9.15.1(eslint@8.45.0) + version: 9.15.1(eslint@8.57.0) eslint4b: specifier: ^7.32.0 version: 7.32.0 @@ -133,6 +136,9 @@ devDependencies: esquery: specifier: ^1.5.0 version: 1.5.0 + jiti: + specifier: ^1.21.0 + version: 1.21.0 json-schema: specifier: ^0.4.0 version: 0.4.0 @@ -160,9 +166,6 @@ devDependencies: prettier: specifier: ^2.8.8 version: 2.8.8 - ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@20.4.5)(typescript@5.1.6) typescript: specifier: ^5.1.6 version: 5.1.6 @@ -793,13 +796,6 @@ packages: prettier: 2.8.8 dev: true - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - /@docsearch/css@3.5.1: resolution: {integrity: sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA==} dev: true @@ -1038,21 +1034,21 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.45.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.45.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.1 /@eslint-community/regexpp@4.6.2: resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - /@eslint/eslintrc@2.1.0: - resolution: {integrity: sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==} + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -1084,15 +1080,15 @@ packages: - supports-color dev: false - /@eslint/js@8.44.0: - resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: @@ -1102,8 +1098,8 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} /@intlify/core-base@9.3.0-beta.27: resolution: {integrity: sha512-hWI8dZh9rRLxDt1IqPJQnXgMW5KZrNX2Z4uJCN348gsPVvsN8eB/J71TcNJs+C1mfIjQPwtmzUWPNhTewi8QGg==} @@ -1185,11 +1181,6 @@ packages: engines: {node: '>=6.0.0'} dev: true - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} @@ -1210,13 +1201,6 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: @@ -1262,22 +1246,6 @@ packages: dev: false optional: true - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - /@types/debug@4.1.8: resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} dependencies: @@ -1377,7 +1345,7 @@ packages: resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} dev: true - /@typescript-eslint/eslint-plugin@6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.45.0)(typescript@5.1.6): + /@typescript-eslint/eslint-plugin@6.2.0(@typescript-eslint/parser@6.2.0)(eslint@8.57.0)(typescript@5.1.6): resolution: {integrity: sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1389,13 +1357,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.2.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/parser': 6.2.0(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/scope-manager': 6.2.0 - '@typescript-eslint/type-utils': 6.2.0(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/utils': 6.2.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/type-utils': 6.2.0(eslint@8.57.0)(typescript@5.1.6) + '@typescript-eslint/utils': 6.2.0(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/visitor-keys': 6.2.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -1407,7 +1375,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.2.0(eslint@8.45.0)(typescript@5.1.6): + /@typescript-eslint/parser@6.2.0(eslint@8.57.0)(typescript@5.1.6): resolution: {integrity: sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1422,7 +1390,7 @@ packages: '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.1.6) '@typescript-eslint/visitor-keys': 6.2.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.57.0 typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -1436,7 +1404,7 @@ packages: '@typescript-eslint/visitor-keys': 6.2.0 dev: true - /@typescript-eslint/type-utils@6.2.0(eslint@8.45.0)(typescript@5.1.6): + /@typescript-eslint/type-utils@6.2.0(eslint@8.57.0)(typescript@5.1.6): resolution: {integrity: sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1447,9 +1415,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.1.6) - '@typescript-eslint/utils': 6.2.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/utils': 6.2.0(eslint@8.57.0)(typescript@5.1.6) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.57.0 ts-api-utils: 1.0.1(typescript@5.1.6) typescript: 5.1.6 transitivePeerDependencies: @@ -1482,19 +1450,19 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@6.2.0(eslint@8.45.0)(typescript@5.1.6): + /@typescript-eslint/utils@6.2.0(eslint@8.57.0)(typescript@5.1.6): resolution: {integrity: sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.2.0 '@typescript-eslint/types': 6.2.0 '@typescript-eslint/typescript-estree': 6.2.0(typescript@5.1.6) - eslint: 8.45.0 + eslint: 8.57.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -1509,6 +1477,9 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + /@vitejs/plugin-vue@4.2.3(vite@4.5.2)(vue@3.3.4): resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1697,11 +1668,6 @@ packages: dependencies: acorn: 8.10.0 - /acorn-walk@8.2.0: - resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} - engines: {node: '>=0.4.0'} - dev: true - /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} @@ -1811,10 +1777,6 @@ packages: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} dev: true - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -2125,10 +2087,6 @@ packages: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: @@ -2240,11 +2198,6 @@ packages: engines: {node: '>=8'} dev: true - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - /diff@5.0.0: resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} engines: {node: '>=0.3.1'} @@ -2430,38 +2383,38 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - /eslint-compat-utils@0.5.0(eslint@8.45.0): + /eslint-compat-utils@0.5.0(eslint@8.57.0): resolution: {integrity: sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 8.45.0 + eslint: 8.57.0 semver: 7.5.4 dev: false - /eslint-config-prettier@9.0.0(eslint@8.45.0): + /eslint-config-prettier@9.0.0(eslint@8.57.0): resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.45.0 + eslint: 8.57.0 dev: true - /eslint-plugin-markdown@3.0.0(eslint@8.45.0): + /eslint-plugin-markdown@3.0.0(eslint@8.57.0): resolution: {integrity: sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.45.0 + eslint: 8.57.0 mdast-util-from-markdown: 0.8.5 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@9.0.0)(eslint@8.45.0)(prettier@2.8.8): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@9.0.0)(eslint@8.57.0)(prettier@2.8.8): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -2472,25 +2425,25 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.45.0 - eslint-config-prettier: 9.0.0(eslint@8.45.0) + eslint: 8.57.0 + eslint-config-prettier: 9.0.0(eslint@8.57.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-vue@9.15.1(eslint@8.45.0): + /eslint-plugin-vue@9.15.1(eslint@8.57.0): resolution: {integrity: sha512-CJE/oZOslvmAR9hf8SClTdQ9JLweghT6JCBQNrT2Iel1uVw0W0OLJxzvPd6CxmABKCvLrtyDnqGV37O7KQv6+A==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - eslint: 8.45.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + eslint: 8.57.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.5.4 - vue-eslint-parser: 9.3.1(eslint@8.45.0) + vue-eslint-parser: 9.3.1(eslint@8.57.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -2511,6 +2464,13 @@ packages: esrecurse: 4.3.0 estraverse: 5.3.0 + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + /eslint-utils@2.1.0: resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} engines: {node: '>=6'} @@ -2532,6 +2492,10 @@ packages: resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint4b@7.32.0: resolution: {integrity: sha512-b7WugntTQ87VupqHxLOk4OoxLLPZbvpl/6K2FP5TvGbp5FmT6hyZUZjhR22xqGEOMCLdPEQeAmCRW2FAkfr4+Q==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2556,26 +2520,27 @@ packages: - supports-color dev: true - /eslint@8.45.0: - resolution: {integrity: sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==} + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.6.2 - '@eslint/eslintrc': 2.1.0 - '@eslint/js': 8.44.0 - '@humanwhocodes/config-array': 0.11.10 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.1 - eslint-visitor-keys: 3.4.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 @@ -2959,6 +2924,11 @@ packages: dependencies: type-fest: 0.20.2 + /globals@15.0.0: + resolution: {integrity: sha512-m/C/yR4mjO6pXDTm9/R/SpYTAIyaUB4EOzcaaMEl7mds7Mshct9GfejiJNQGjHHbdMPey13Kpu4TMbYi9ex1pw==} + engines: {node: '>=18'} + dev: false + /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} @@ -3415,6 +3385,11 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: false + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -3640,10 +3615,6 @@ packages: semver: 7.5.4 dev: true - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -3754,7 +3725,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: false /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} @@ -4757,37 +4727,6 @@ packages: typescript: 5.1.6 dev: true - /ts-node@10.9.1(@types/node@20.4.5)(typescript@5.1.6): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.4.5 - acorn: 8.10.0 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.1.6 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - /tty-table@4.2.1: resolution: {integrity: sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==} engines: {node: '>=8.0.0'} @@ -4922,10 +4861,6 @@ packages: hasBin: true dev: true - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -5041,14 +4976,14 @@ packages: engines: {node: '>=10.0.0'} dev: true - /vue-eslint-parser@9.3.1(eslint@8.45.0): + /vue-eslint-parser@9.3.1(eslint@8.57.0): resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.45.0 + eslint: 8.57.0 eslint-scope: 7.2.1 eslint-visitor-keys: 3.4.1 espree: 9.6.1 @@ -5304,11 +5239,6 @@ packages: yargs-parser: 21.1.1 dev: true - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/scripts/lib/configs.ts b/scripts/lib/configs.ts new file mode 100644 index 00000000..ed68b4ad --- /dev/null +++ b/scripts/lib/configs.ts @@ -0,0 +1 @@ +export const PRESETS = ['base', 'recommended'] as const diff --git a/scripts/lib/rules.ts b/scripts/lib/rules.ts index c93af84f..b8ff99c7 100644 --- a/scripts/lib/rules.ts +++ b/scripts/lib/rules.ts @@ -1,43 +1,80 @@ -/** - * @fileoverview Rules loading script library - * @author kazuya kawaguchi (a.k.a. kazupon) - * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/lib/rules.js - */ - -import rulesImported from '../../lib/rules' +import fs from 'node:fs' +import path from 'node:path' +import jitiFactory from 'jiti' export type RuleInfo = { id: string name: string category: string description: string + url: string recommended: boolean fixable: boolean deprecated: boolean replacedBy: string[] | null } -const rules = Object.entries(rulesImported).map(rule => { - const name = rule[0] - const meta = rule[1].meta - return { - id: `@intlify/vue-i18n/${name}`, - name, - category: String(meta.docs.category), - description: String(meta.docs.description), - recommended: Boolean(meta.docs.recommended), - fixable: Boolean(meta.fixable), - deprecated: Boolean(meta.deprecated), - replacedBy: meta.docs.replacedBy - } as RuleInfo -}) - -export default rules -export const withCategories = [ - 'Recommended', - 'Best Practices', - 'Stylistic Issues' -].map(category => ({ - category, - rules: rules.filter(rule => rule.category === category && !rule.deprecated) -})) +const RULES_DIR = path.resolve(__dirname, '../../lib/rules') + +let jiti: ReturnType | null = null + +function dynamicImport() { + return jiti ?? (jiti = jitiFactory(__filename)) +} + +let _rules: RuleInfo[] | null = null + +async function getRules() { + if (_rules) { + return _rules + } + + const files = fs + .readdirSync(RULES_DIR) + .filter(file => path.extname(file) === '.ts') + .map(file => path.basename(file, '.ts')) + _rules = await Promise.all( + files.map(async name => { + const rule = dynamicImport()(`${path.join(RULES_DIR, name)}`) + const meta = { ...rule.meta } + return { + id: `@intlify/vue-i18n/${name}`, + name, + category: String(meta.docs.category), + description: String(meta.docs.description), + url: String(meta.docs.url), + recommended: Boolean(meta.docs.recommended), + fixable: Boolean(meta.fixable), + deprecated: Boolean(meta.deprecated), + replacedBy: meta.docs.replacedBy + } satisfies RuleInfo + }) + ) + return _rules +} + +async function getRuleNames() { + const rules = await getRules() + return rules.map(rule => rule.name) +} + +async function getRulesWithCategories() { + const rules = await getRules() + return ['Recommended', 'Best Practices', 'Stylistic Issues'].map( + category => ({ + category, + rules: rules.filter( + rule => rule.category === category && !rule.deprecated + ) + }) + ) +} + +const disableRules = { + // ESLint core rules known to cause problems with YAML. + // https://github.com/ota-meshi/eslint-plugin-yml/blob/4e468109b9d2f4376b8d4d1221adba27c6ee04b2/src/configs/base.ts#L7-L11 + 'no-irregular-whitespace': 'off', + 'spaced-comment': 'off' +} + +export { getRules, getRuleNames, getRulesWithCategories, disableRules } diff --git a/scripts/lib/utils.ts b/scripts/lib/utils.ts index fd6a8a3b..1dfcb985 100644 --- a/scripts/lib/utils.ts +++ b/scripts/lib/utils.ts @@ -1,52 +1,28 @@ -/** - * @fileoverview Utility script library - * @author kazuya kawaguchi (a.k.a. kazupon) - * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/lib/utils.js - */ -import { readdirSync, existsSync } from 'fs' -import { basename, extname, join } from 'path' +import fs from 'node:fs/promises' +import { join } from 'path' +import { load } from 'js-yaml' import { ESLint } from '../lib/eslint-compat' +import { type Options, format } from 'prettier' const eslint = new ESLint({ fix: true }) -async function format(text: string, filename: string): Promise { +async function lint(text: string, filename: string): Promise { const lintResults = await eslint.lintText(text, { filePath: filename }) - return lintResults[0].output || text + return lintResults.length > 0 ? lintResults[0].output || text : text } -/** - * Convert text to camelCase - */ function camelCase(str: string) { return str.replace(/[-_](\w)/gu, (_, c) => (c ? c.toUpperCase() : '')) } -async function createIndex( - dirPath: string, - prefix = '', - all = false -): Promise { - const dirName = basename(dirPath) - const tsFiles = readdirSync(dirPath) - .filter( - file => - file.endsWith('.ts') || existsSync(join(dirPath, file, 'index.ts')) - ) - .map(file => basename(file, extname(file))) - return format( - `/** DON'T EDIT THIS FILE; was created by scripts. */ -${tsFiles - .map( - id => - `import ${all ? '* as ' : ''}${camelCase(id)} from './${dirName}/${id}';` - ) - .join('\n')} - -export = { - ${tsFiles.map(id => `'${prefix}${id}': ${camelCase(id)},`).join('\n ')} - } - `, - 'input.ts' +async function writeFile(filePath: string, content: string) { + const linted = await lint(content, filePath) + const prettierrc = load( + await fs.readFile(join(__dirname, '../../.prettierrc.yaml'), 'utf-8') + ) as Options + await fs.writeFile( + filePath, + format(linted, { filepath: filePath, ...prettierrc }) ) } -export { createIndex, format } +export { writeFile, camelCase } diff --git a/scripts/update-flat-base-configs.ts b/scripts/update-flat-base-configs.ts new file mode 100644 index 00000000..fa3c9549 --- /dev/null +++ b/scripts/update-flat-base-configs.ts @@ -0,0 +1,41 @@ +import path from 'node:path' +import { disableRules } from './lib/rules' +import { writeFile } from './lib/utils' + +export async function update() { + // base.ts + const raw = `/** DON'T EDIT THIS FILE; was created by scripts. */ +export = [ + { + name: "@intlify/vue-i18n:base:setup", + plugins: { + get "@intlify/vue-i18n"() { + return require('../../index') + } + } + }, + { + name: "@intlify/vue-i18n:base:setup:json", + files: ['*.json', '**/*.json', '*.json5', '**/*.json5'], + languageOptions: { + parser: require('vue-eslint-parser'), + parserOptions: { + parser: require('jsonc-eslint-parser') + } + } + }, + { + name: "@intlify/vue-i18n:base:setup:yaml", + files: ['*.yaml', '**/*.yaml', '*.yml', '**/*.yml'], + languageOptions: { + parser: require('vue-eslint-parser'), + parserOptions: { + parser: require('yaml-eslint-parser') + } + }, + rules: ${JSON.stringify(disableRules, null, 2)} + } +]` + + await writeFile(path.resolve(__dirname, '../lib/configs/flat/base.ts'), raw) +} diff --git a/scripts/update-flat-recommended-configs.ts b/scripts/update-flat-recommended-configs.ts new file mode 100644 index 00000000..3bcfb064 --- /dev/null +++ b/scripts/update-flat-recommended-configs.ts @@ -0,0 +1,42 @@ +import path from 'node:path' +import { getRules } from './lib/rules' +import { writeFile } from './lib/utils' + +export async function update() { + const rules = await getRules() + + // recommended.ts + const raw = `/** DON'T EDIT THIS FILE; was created by scripts. */ +const globals = require('globals') +const config = require('./base') +export = [ + ...config, + { + name: "@intlify/vue-i18n:recommended:setup", + languageOptions: { + ecmaVersion: 2018, + sourceType: 'module', + globals: globals.browser, + parserOptions: { + ecmaFeatures: { + jsx: true + }, + }, + }, + }, + { + name: "@intlify/vue-i18n:recommended:rules", + rules: { + ${rules + .filter(rule => rule.recommended) + .map(rule => `'${rule.id}': 'warn',`) + .join('\n')} + }, + }, +]` + + await writeFile( + path.resolve(__dirname, '../lib/configs/flat/recommended.ts'), + raw + ) +} diff --git a/scripts/update-docs-index.ts b/scripts/update-index-docs.ts similarity index 58% rename from scripts/update-docs-index.ts rename to scripts/update-index-docs.ts index 7d020f4a..4daf2294 100644 --- a/scripts/update-docs-index.ts +++ b/scripts/update-index-docs.ts @@ -1,18 +1,9 @@ -/** - * @fileoverview Update docs index script - * @author kazuya kawaguchi (a.k.a. kazupon) - * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/update-docs-index.js - */ import { type Options, format } from 'prettier' -import { writeFileSync, readFileSync } from 'fs' +import fs from 'node:fs/promises' import { join, resolve } from 'node:path' import { load } from 'js-yaml' import type { RuleInfo } from './lib/rules' -import { withCategories } from './lib/rules' - -const prettierrc = load( - readFileSync(join(__dirname, '../.prettierrc.yaml'), 'utf8') -) as Options +import { getRulesWithCategories } from './lib/rules' function toTableRow(rule: RuleInfo) { const mark = `${rule.recommended ? ':star:' : ''}${ @@ -39,12 +30,28 @@ ${rules.map(toTableRow).join('\n')} ` } -const filePath = resolve(__dirname, '../docs/rules/index.md') -const content = `# Available Rules +export async function update() { + // load prettier config + const prettierrc = load( + await fs.readFile(join(__dirname, '../.prettierrc.yaml'), 'utf8') + ) as Options + + // get rules with categories + const withCategories = await getRulesWithCategories() + + // generate docs index + const filePath = resolve(__dirname, '../docs/rules/index.md') + const content = `# Available Rules -- :star: mark: the rule which is enabled by \`plugin:@intlify/vue-i18n/recommended\` preset. +- :star: mark: the rule which is enabled by \`plugin:@intlify/vue-i18n/recommended\` or \`*.configs["flat/recommended"]\` preset. - :black_nib: mark: the rule which is fixable by \`eslint --fix\` command. ${withCategories.map(toCategorySection).join('\n')} ` -writeFileSync(filePath, format(content, { filepath: filePath, ...prettierrc })) + + // write docs index + await fs.writeFile( + filePath, + format(content, { filepath: filePath, ...prettierrc }) + ) +} diff --git a/scripts/update-index.ts b/scripts/update-index.ts new file mode 100644 index 00000000..847355a6 --- /dev/null +++ b/scripts/update-index.ts @@ -0,0 +1,44 @@ +import path from 'node:path' +import { getRuleNames } from './lib/rules' +import { PRESETS } from './lib/configs' +import { camelCase, writeFile } from './lib/utils' + +export async function update() { + const ruleNames = await getRuleNames() + + const raw = `/** DON'T EDIT THIS FILE; was created by scripts. */ +// configs +${PRESETS.map( + preset => `import ${camelCase(preset)} from './configs/${preset}';` +).join('\n')} +${PRESETS.map( + preset => + `import ${camelCase(`flat-${preset}`)} from './configs/flat/${preset}';` +).join('\n')} + +// rules +${ruleNames + .map(ruleName => `import ${camelCase(ruleName)} from './rules/${ruleName}';`) + .join('\n')} + +// export plugin +export = { + configs: { + // eslintrc configs + ${PRESETS.map(preset => `'${preset}': ${camelCase(preset)},`).join('\n')} + + // flat configs + ${PRESETS.map( + preset => `'flat/${preset}': ${camelCase(`flat-${preset}`)},` + ).join('\n')} + }, + rules: { + ${ruleNames + .map(ruleName => `'${ruleName}': ${camelCase(ruleName)},`) + .join('\n')} + } +} +` + + await writeFile(path.resolve(__dirname, '../lib/index.ts'), raw) +} diff --git a/scripts/update-legacy-base-configs.ts b/scripts/update-legacy-base-configs.ts new file mode 100644 index 00000000..bcf8852f --- /dev/null +++ b/scripts/update-legacy-base-configs.ts @@ -0,0 +1,31 @@ +import path from 'node:path' +import { disableRules } from './lib/rules' +import { writeFile } from './lib/utils' + +export async function update() { + // base.ts + const raw = `/** DON'T EDIT THIS FILE; was created by scripts. */ +export = { + parser: require.resolve('vue-eslint-parser'), + plugins: ['@intlify/vue-i18n'], + overrides: [ + { + files: ['*.json', '*.json5'], + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + parser: require.resolve('jsonc-eslint-parser') + } + }, + { + files: ['*.yaml', '*.yml'], + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + parser: require.resolve('yaml-eslint-parser') + }, + rules: ${JSON.stringify(disableRules, null, 2)} + } + ] +}` + + await writeFile(path.resolve(__dirname, '../lib/configs/base.ts'), raw) +} diff --git a/scripts/update-legacy-recommended-configs.ts b/scripts/update-legacy-recommended-configs.ts new file mode 100644 index 00000000..cd278011 --- /dev/null +++ b/scripts/update-legacy-recommended-configs.ts @@ -0,0 +1,31 @@ +import path from 'node:path' +import { getRules } from './lib/rules' +import { writeFile } from './lib/utils' + +export async function update() { + const rules = await getRules() + // recommended.ts + const raw = `/** DON'T EDIT THIS FILE; was created by scripts. */ +export = { + extends: [require.resolve('./base')], + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + ecmaFeatures: { + jsx: true + } + }, + env: { + browser: true, + es6: true + }, + rules: { + ${rules + .filter(rule => rule.recommended) + .map(rule => `'${rule.id}': 'warn',`) + .join('\n')} + }, +}` + + await writeFile(path.resolve(__dirname, '../lib/configs/recommended.ts'), raw) +} diff --git a/scripts/update-recommended-rules.ts b/scripts/update-recommended-rules.ts deleted file mode 100644 index d91f4da0..00000000 --- a/scripts/update-recommended-rules.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @fileoverview Update recommended rules - * @author kazuya kawaguchi (a.k.a. kazupon) - * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/update-recommended-rules.js - */ -import { writeFileSync } from 'fs' -import { resolve } from 'node:path' -import rules from './lib/rules' -import { format } from './lib/utils' - -main() - -async function main() { - // recommended.ts - writeFileSync( - resolve(__dirname, '../lib/configs/recommended.ts'), - await format( - `/** DON'T EDIT THIS FILE; was created by scripts. */ -export = { - extends: [require.resolve('./base')], - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true - } - }, - env: { - browser: true, - es6: true - }, - rules: { - ${rules - .filter(rule => rule.recommended) - .map(rule => `'${rule.id}': 'warn',`) - .join('\n ')} - }, -}`, - resolve(__dirname, '../lib/configs/recommended.ts') - ) - ) -} diff --git a/scripts/update-rule-docs.ts b/scripts/update-rule-docs.ts index ff10bbed..201947bf 100644 --- a/scripts/update-rule-docs.ts +++ b/scripts/update-rule-docs.ts @@ -4,11 +4,11 @@ * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/update-docs-headers.js */ import { type Options, format } from 'prettier' -import { writeFileSync, readFileSync } from 'fs' +import { writeFileSync, readFileSync } from 'node:fs' import { join } from 'node:path' import { load } from 'js-yaml' import type { RuleInfo } from './lib/rules' -import rules from './lib/rules' +import { getRules } from './lib/rules' import { getNewVersion } from './lib/changesets-util' const PLACE_HOLDER = /#[^\n]*\n+> .+\n+(?:- .+\n)*\n*/u @@ -102,7 +102,7 @@ class DocFile { } } else if (rule.recommended) { headerLines.push( - '- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule.' + '- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule.' ) } @@ -164,8 +164,8 @@ This rule was introduced in \`@intlify/eslint-plugin-vue-i18n\` ${this.since} } } -export async function updateRuleDocs(): Promise { - for (const rule of rules) { +export async function update(): Promise { + for (const rule of await getRules()) { const doc = await new DocFile(rule).init() doc .updateFileIntro() diff --git a/scripts/update.ts b/scripts/update.ts index 5605a7ea..f9625f4e 100644 --- a/scripts/update.ts +++ b/scripts/update.ts @@ -1,30 +1,29 @@ -/** - * @fileoverview Update script - * @author kazuya kawaguchi (a.k.a. kazupon) - * Forked by https://github.com/mysticatea/eslint-plugin-eslint-comments/tree/master/scripts/update.js - */ -import { writeFileSync } from 'fs' -import { resolve } from 'node:path' -import { createIndex } from './lib/utils' +import { update as updateRuleDocs } from './update-rule-docs' +import { update as updateDocsIndex } from './update-index-docs' +import { update as updateLegacyBaseConfigs } from './update-legacy-base-configs' +import { update as updateLegacyRecommentedConfigs } from './update-legacy-recommended-configs' +import { update as updateFlatBaseConfigs } from './update-flat-base-configs' +import { update as updateFlatRecommentedConfigs } from './update-flat-recommended-configs' +import { update as updateIndex } from './update-index' -// docs. -import { updateRuleDocs } from './update-rule-docs' -updateRuleDocs() -import './update-docs-index' +async function main() { + // update docs. + await updateRuleDocs() + await updateDocsIndex() -// recommended rules. -import './update-recommended-rules' + // legacy configs + await updateLegacyBaseConfigs() + await updateLegacyRecommentedConfigs() -main() + // flat configs + await updateFlatBaseConfigs() + await updateFlatRecommentedConfigs() -async function main() { - // indices. - for (const pairs of [ - [resolve(__dirname, '../lib/configs')], - [resolve(__dirname, '../lib/rules')], - [resolve(__dirname, '../lib/utils'), '', true] - ] as const) { - const [dirPath, prefix, all] = pairs - writeFileSync(`${dirPath}.ts`, await createIndex(dirPath, prefix, all)) - } + // lib index + await updateIndex() } + +main().catch(error => { + console.error(error) + process.exit(1) +}) diff --git a/tests-integrations/config-recommended.cjs b/tests-integrations/config-recommended.cjs deleted file mode 100644 index acba0768..00000000 --- a/tests-integrations/config-recommended.cjs +++ /dev/null @@ -1,41 +0,0 @@ -'use strict' - -const cp = require('child_process') -const path = require('path') -const assert = require('assert') - -const TEST_CWD = path.join(__dirname, 'config-recommended') - -describe('Integration with "plugin:@intlify/vue-i18n/recommended"', () => { - let originalCwd - - before(() => { - originalCwd = process.cwd() - process.chdir(TEST_CWD) - cp.execSync('pnpm install', { stdio: 'inherit' }) - }) - after(() => { - process.chdir(originalCwd) - }) - - it('should work with shareable config', async () => { - const ESLint = require('./config-recommended/node_modules/eslint').ESLint - const engine = new ESLint({ - cwd: TEST_CWD, - extensions: ['.js', '.vue', '.json'] - }) - const results = await engine.lintFiles(['./src']) - const enJson = results.find(r => path.basename(r.filePath) === 'en.json') - assert.strictEqual(enJson.messages.length, 1) - assert.strictEqual( - enJson.messages[0].ruleId, - '@intlify/vue-i18n/no-html-messages' - ) - const aVue = results.find(r => path.basename(r.filePath) === 'a.vue') - assert.strictEqual(aVue.messages.length, 1) - assert.strictEqual( - aVue.messages[0].ruleId, - '@intlify/vue-i18n/no-missing-keys' - ) - }) -}) diff --git a/tests-integrations/config-recommended/.vscode/settings.json b/tests-integrations/config-recommended/.vscode/settings.json deleted file mode 100644 index b9d096c7..00000000 --- a/tests-integrations/config-recommended/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "eslint.validate": [ - "javascript", - "vue", - "json" - ] -} diff --git a/tests-integrations/config-recommended/package.json b/tests-integrations/config-recommended/package.json deleted file mode 100644 index 203340f4..00000000 --- a/tests-integrations/config-recommended/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "integration-test-for-config-recommended", - "version": "1.0.0", - "description": "", - "main": "index.js", - "author": "", - "license": "MIT", - "devDependencies": { - "@intlify/eslint-plugin-vue-i18n": "file:../..", - "eslint": "^8.0.0" - } -} diff --git a/tests/integrations/flat-config.ts b/tests/integrations/flat-config.ts new file mode 100644 index 00000000..b407e9f8 --- /dev/null +++ b/tests/integrations/flat-config.ts @@ -0,0 +1,51 @@ +import cp from 'node:child_process' +import path from 'node:path' +import assert from 'node:assert' +import semver from 'semver' +import { readPackageJson } from './helper' + +const ESLINT = `.${path.sep}node_modules${path.sep}.bin${path.sep}eslint` + +describe('Integration with flat config', () => { + let originalCwd + + before(() => { + originalCwd = process.cwd() + process.chdir(path.join(__dirname, 'flat-config')) + cp.execSync('pnpm install', { stdio: 'inherit' }) + }) + after(() => { + originalCwd && process.chdir(originalCwd) + }) + + it('should work with flat config', async () => { + if ( + !semver.satisfies( + process.version, + readPackageJson( + path.resolve(__dirname, 'flat-config/node_modules/eslint') + ).engines.node + ) + ) { + return + } + + const result = JSON.parse( + cp.execSync(`${ESLINT} src/* --format=json`, { + encoding: 'utf-8' + }) + ) + const enJson = result.find(r => path.basename(r.filePath) === 'en.json') + assert.strictEqual(enJson.messages.length, 1) + assert.strictEqual( + enJson.messages[0].ruleId, + '@intlify/vue-i18n/no-html-messages' + ) + const aVue = result.find(r => path.basename(r.filePath) === 'a.vue') + assert.strictEqual(aVue.messages.length, 1) + assert.strictEqual( + aVue.messages[0].ruleId, + '@intlify/vue-i18n/no-missing-keys' + ) + }) +}) diff --git a/tests-integrations/config-recommended/.npmrc b/tests/integrations/flat-config/.npmrc similarity index 100% rename from tests-integrations/config-recommended/.npmrc rename to tests/integrations/flat-config/.npmrc diff --git a/tests/integrations/flat-config/.vscode/settings.json b/tests/integrations/flat-config/.vscode/settings.json new file mode 100644 index 00000000..64c2bf7d --- /dev/null +++ b/tests/integrations/flat-config/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "eslint.validate": ["javascript", "vue", "json"] +} diff --git a/tests/integrations/flat-config/eslint.config.js b/tests/integrations/flat-config/eslint.config.js new file mode 100644 index 00000000..4ab5e454 --- /dev/null +++ b/tests/integrations/flat-config/eslint.config.js @@ -0,0 +1,17 @@ +import vue from 'eslint-plugin-vue' +import vueI18n from '@intlify/eslint-plugin-vue-i18n' + +export default [ + ...vue.configs['flat/recommended'], + ...vueI18n.configs['flat/recommended'], + { + rules: { + 'vue/multi-word-component-names': 'off' + }, + settings: { + 'vue-i18n': { + localeDir: './src/resources/*.json' + } + } + } +] diff --git a/tests/integrations/flat-config/package.json b/tests/integrations/flat-config/package.json new file mode 100644 index 00000000..a2e07708 --- /dev/null +++ b/tests/integrations/flat-config/package.json @@ -0,0 +1,11 @@ +{ + "name": "integration-test-for-flat-config", + "version": "1.0.0", + "private": true, + "type": "module", + "devDependencies": { + "eslint-plugin-vue": "^9.24.0", + "@intlify/eslint-plugin-vue-i18n": "file:../../..", + "eslint": "^8.57.0" + } +} diff --git a/tests-integrations/config-recommended/src/a.vue b/tests/integrations/flat-config/src/a.vue similarity index 71% rename from tests-integrations/config-recommended/src/a.vue rename to tests/integrations/flat-config/src/a.vue index 0d18c9cd..50330757 100644 --- a/tests-integrations/config-recommended/src/a.vue +++ b/tests/integrations/flat-config/src/a.vue @@ -1,5 +1,4 @@ - + diff --git a/tests-integrations/config-recommended/src/resources/en.json b/tests/integrations/flat-config/src/resources/en.json similarity index 100% rename from tests-integrations/config-recommended/src/resources/en.json rename to tests/integrations/flat-config/src/resources/en.json diff --git a/tests/integrations/helper.ts b/tests/integrations/helper.ts new file mode 100644 index 00000000..0cafc698 --- /dev/null +++ b/tests/integrations/helper.ts @@ -0,0 +1,8 @@ +import fs from 'node:fs' +import path from 'node:path' + +export function readPackageJson(base: string) { + return JSON.parse( + fs.readFileSync(path.resolve(base, 'package.json'), 'utf-8') + ) +} diff --git a/tests/integrations/legacy-config.ts b/tests/integrations/legacy-config.ts new file mode 100644 index 00000000..dd53cae0 --- /dev/null +++ b/tests/integrations/legacy-config.ts @@ -0,0 +1,51 @@ +import cp from 'node:child_process' +import path from 'node:path' +import assert from 'node:assert' +import semver from 'semver' +import { readPackageJson } from './helper' + +const ESLINT = `.${path.sep}node_modules${path.sep}.bin${path.sep}eslint` + +describe('Integration with legacy config', () => { + let originalCwd + + before(() => { + originalCwd = process.cwd() + process.chdir(path.join(__dirname, 'legacy-config')) + cp.execSync('pnpm install', { stdio: 'inherit' }) + }) + after(() => { + originalCwd && process.chdir(originalCwd) + }) + + it('should work with legacy config', async () => { + if ( + !semver.satisfies( + process.version, + readPackageJson( + path.resolve(__dirname, 'legacy-config/node_modules/eslint') + ).engines.node + ) + ) { + return + } + + const result = JSON.parse( + cp.execSync(`${ESLINT} src/* --format=json`, { + encoding: 'utf-8' + }) + ) + const enJson = result.find(r => path.basename(r.filePath) === 'en.json') + assert.strictEqual(enJson.messages.length, 1) + assert.strictEqual( + enJson.messages[0].ruleId, + '@intlify/vue-i18n/no-html-messages' + ) + const aVue = result.find(r => path.basename(r.filePath) === 'a.vue') + assert.strictEqual(aVue.messages.length, 1) + assert.strictEqual( + aVue.messages[0].ruleId, + '@intlify/vue-i18n/no-missing-keys' + ) + }) +}) diff --git a/tests-integrations/config-recommended/.eslintrc.cjs b/tests/integrations/legacy-config/.eslintrc.cjs similarity index 100% rename from tests-integrations/config-recommended/.eslintrc.cjs rename to tests/integrations/legacy-config/.eslintrc.cjs diff --git a/tests/integrations/legacy-config/.npmrc b/tests/integrations/legacy-config/.npmrc new file mode 100644 index 00000000..43c97e71 --- /dev/null +++ b/tests/integrations/legacy-config/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/tests/integrations/legacy-config/.vscode/settings.json b/tests/integrations/legacy-config/.vscode/settings.json new file mode 100644 index 00000000..64c2bf7d --- /dev/null +++ b/tests/integrations/legacy-config/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "eslint.validate": ["javascript", "vue", "json"] +} diff --git a/tests/integrations/legacy-config/package.json b/tests/integrations/legacy-config/package.json new file mode 100644 index 00000000..558cb94a --- /dev/null +++ b/tests/integrations/legacy-config/package.json @@ -0,0 +1,10 @@ +{ + "name": "integration-test-for-legacy-config", + "version": "1.0.0", + "private": true, + "devDependencies": { + "eslint-plugin-vue": "^9.24.0", + "@intlify/eslint-plugin-vue-i18n": "file:../../..", + "eslint": "^8.57.0" + } +} diff --git a/tests/integrations/legacy-config/src/a.vue b/tests/integrations/legacy-config/src/a.vue new file mode 100644 index 00000000..50330757 --- /dev/null +++ b/tests/integrations/legacy-config/src/a.vue @@ -0,0 +1,4 @@ + + diff --git a/tests/integrations/legacy-config/src/resources/en.json b/tests/integrations/legacy-config/src/resources/en.json new file mode 100644 index 00000000..26ee198f --- /dev/null +++ b/tests/integrations/legacy-config/src/resources/en.json @@ -0,0 +1,3 @@ +{ + "hello": "Hello! DIO!" +} diff --git a/tests/lib/utils/rule.ts b/tests/lib/utils/rule.ts index 711c38e0..70edfe30 100644 --- a/tests/lib/utils/rule.ts +++ b/tests/lib/utils/rule.ts @@ -1,14 +1,13 @@ import { strictEqual } from 'assert' -import rules from '../../../lib/rules' +import { getRules } from '../../../scripts/lib/rules' -describe('valid rule meta', () => { - for (const ruleId of Object.keys(rules)) { - const rule = rules[ruleId as keyof typeof rules] - - it(`should be valid rule url for ${ruleId}.`, () => { +describe('valid rule meta', async () => { + const rules = await getRules() + for (const rule of rules) { + it(`should be valid rule url for ${rule.id}.`, () => { strictEqual( - rule.meta.docs.url, - `https://eslint-plugin-vue-i18n.intlify.dev/rules/${ruleId}.html` + rule.url, + `https://eslint-plugin-vue-i18n.intlify.dev/rules/${rule.name}.html` ) }) }