From b8c3ec4d7f510bb8f83ed51c1d311f0997329994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Jona=C5=A1?= Date: Tue, 8 Aug 2023 20:08:43 +0200 Subject: [PATCH] feat(linter): add generator for converting to flat config (#17532) --- docs/generated/manifests/menus.json | 8 + docs/generated/manifests/packages.json | 9 + docs/generated/packages-metadata.json | 9 + .../generators/convert-to-flat-config.json | 28 + docs/shared/reference/sitemap.md | 1 + e2e/linter/src/linter.test.ts | 75 +++ package.json | 2 + .../migrate-from-angular-cli.spec.ts.snap | 2 + .../generators/ng-add/utilities/workspace.ts | 10 +- packages/linter/generators.json | 5 + packages/linter/package.json | 3 +- .../linter/src/executors/eslint/lint.impl.ts | 5 +- .../__snapshots__/generator.spec.ts.snap | 385 +++++++++++++ .../converters/generate-ast.ts | 68 +++ .../converters/json-converter.spec.ts | 234 ++++++++ .../converters/json-converter.ts | 524 +++++++++++++++++ .../convert-to-flat-config/generator.spec.ts | 350 +++++++++++ .../convert-to-flat-config/generator.ts | 129 +++++ .../convert-to-flat-config/schema.d.ts | 3 + .../convert-to-flat-config/schema.json | 17 + .../linter/src/generators/init/init.spec.ts | 1 + packages/linter/src/generators/init/init.ts | 2 + packages/linter/src/utils/versions.ts | 1 + .../angular/standalone-workspace.ts | 7 +- pnpm-lock.yaml | 543 ++++++++++++++---- 25 files changed, 2290 insertions(+), 131 deletions(-) create mode 100644 docs/generated/packages/linter/generators/convert-to-flat-config.json create mode 100644 packages/linter/src/generators/convert-to-flat-config/__snapshots__/generator.spec.ts.snap create mode 100644 packages/linter/src/generators/convert-to-flat-config/converters/generate-ast.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/converters/json-converter.spec.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/converters/json-converter.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/generator.spec.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/generator.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/schema.d.ts create mode 100644 packages/linter/src/generators/convert-to-flat-config/schema.json diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 1cf3461b201ef..14a5ab9b8ceeb 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -6344,6 +6344,14 @@ "children": [], "isExternal": false, "disableCollapsible": false + }, + { + "id": "convert-to-flat-config", + "path": "/packages/linter/generators/convert-to-flat-config", + "name": "convert-to-flat-config", + "children": [], + "isExternal": false, + "disableCollapsible": false } ], "isExternal": false, diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index 0184c03194c99..8ff6e10ae836c 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -1140,6 +1140,15 @@ "originalFilePath": "/packages/linter/src/generators/workspace-rule/schema.json", "path": "/packages/linter/generators/workspace-rule", "type": "generator" + }, + "/packages/linter/generators/convert-to-flat-config": { + "description": "Convert an Nx workspace to a Flat ESLint config.", + "file": "generated/packages/linter/generators/convert-to-flat-config.json", + "hidden": false, + "name": "convert-to-flat-config", + "originalFilePath": "/packages/linter/src/generators/convert-to-flat-config/schema.json", + "path": "/packages/linter/generators/convert-to-flat-config", + "type": "generator" } }, "path": "/packages/linter" diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 824b968d3701a..3a571a38f6aa5 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1123,6 +1123,15 @@ "originalFilePath": "/packages/linter/src/generators/workspace-rule/schema.json", "path": "linter/generators/workspace-rule", "type": "generator" + }, + { + "description": "Convert an Nx workspace to a Flat ESLint config.", + "file": "generated/packages/linter/generators/convert-to-flat-config.json", + "hidden": false, + "name": "convert-to-flat-config", + "originalFilePath": "/packages/linter/src/generators/convert-to-flat-config/schema.json", + "path": "linter/generators/convert-to-flat-config", + "type": "generator" } ], "githubRoot": "https://github.com/nrwl/nx/blob/master", diff --git a/docs/generated/packages/linter/generators/convert-to-flat-config.json b/docs/generated/packages/linter/generators/convert-to-flat-config.json new file mode 100644 index 0000000000000..c06ebc0738ec5 --- /dev/null +++ b/docs/generated/packages/linter/generators/convert-to-flat-config.json @@ -0,0 +1,28 @@ +{ + "name": "convert-to-flat-config", + "factory": "./src/generators/convert-to-flat-config/generator", + "schema": { + "$schema": "http://json-schema.org/schema", + "$id": "ConvertToFlatConfig", + "cli": "nx", + "description": "Convert an Nx workspace to a Flat ESLint config.", + "type": "object", + "properties": { + "skipFormat": { + "type": "boolean", + "description": "Skip formatting files.", + "default": false, + "x-priority": "internal" + } + }, + "additionalProperties": false, + "required": [], + "presets": [] + }, + "description": "Convert an Nx workspace to a Flat ESLint config.", + "implementation": "/packages/linter/src/generators/convert-to-flat-config/generator.ts", + "aliases": [], + "hidden": false, + "path": "/packages/linter/src/generators/convert-to-flat-config/schema.json", + "type": "generator" +} diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 607784eb073ad..e3af1d40d74a5 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -411,6 +411,7 @@ - [generators](/packages/linter/generators) - [workspace-rules-project](/packages/linter/generators/workspace-rules-project) - [workspace-rule](/packages/linter/generators/workspace-rule) + - [convert-to-flat-config](/packages/linter/generators/convert-to-flat-config) - [nest](/packages/nest) - [documents](/packages/nest/documents) - [Overview](/packages/nest/documents/overview) diff --git a/e2e/linter/src/linter.test.ts b/e2e/linter/src/linter.test.ts index 01e83670d880c..a4158028eb26a 100644 --- a/e2e/linter/src/linter.test.ts +++ b/e2e/linter/src/linter.test.ts @@ -1,12 +1,15 @@ import * as path from 'path'; import { + checkFilesDoNotExist, checkFilesExist, cleanupProject, createFile, + getSelectedPackageManager, newProject, readFile, readJson, runCLI, + runCreateWorkspace, uniq, updateFile, updateJson, @@ -537,6 +540,78 @@ describe('Linter', () => { }); }); + describe('Flat config', () => { + const packageManager = getSelectedPackageManager() || 'pnpm'; + + afterEach(() => cleanupProject()); + + it('should convert integrated to flat config', () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + + runCreateWorkspace(myapp, { + preset: 'react-monorepo', + appName: myapp, + style: 'css', + packageManager, + bundler: 'vite', + e2eTestRunner: 'none', + }); + runCLI(`generate @nx/js:lib ${mylib}`); + + // migrate to flat structure + runCLI(`generate @nx/linter:convert-to-flat-config`); + checkFilesExist( + 'eslint.config.js', + `apps/${myapp}/eslint.config.js`, + `libs/${mylib}/eslint.config.js` + ); + checkFilesDoNotExist( + '.eslintrc.json', + `apps/${myapp}/.eslintrc.json`, + `libs/${mylib}/.eslintrc.json` + ); + + const outFlat = runCLI(`affected -t lint`, { + silenceError: true, + }); + expect(outFlat).toContain('All files pass linting'); + }, 1000000); + + it('should convert standalone to flat config', () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + + runCreateWorkspace(myapp, { + preset: 'react-standalone', + appName: myapp, + style: 'css', + packageManager, + bundler: 'vite', + e2eTestRunner: 'none', + }); + runCLI(`generate @nx/js:lib ${mylib}`); + + // migrate to flat structure + runCLI(`generate @nx/linter:convert-to-flat-config`); + checkFilesExist( + 'eslint.config.js', + `${mylib}/eslint.config.js`, + 'eslint.base.config.js' + ); + checkFilesDoNotExist( + '.eslintrc.json', + `${mylib}/.eslintrc.json`, + '.eslintrc.base.json' + ); + + const outFlat = runCLI(`affected -t lint`, { + silenceError: true, + }); + expect(outFlat).toContain('All files pass linting'); + }, 1000000); + }); + describe('Root projects migration', () => { beforeEach(() => newProject()); afterEach(() => cleanupProject()); diff --git a/package.json b/package.json index 8e5deebb1c893..2b934d00ca8f3 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,8 @@ "@babel/preset-react": "^7.22.5", "@babel/preset-typescript": "^7.22.5", "@babel/runtime": "^7.22.6", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", "@floating-ui/react": "0.19.2", "@jest/reporters": "^29.4.1", "@jest/test-result": "^29.4.1", diff --git a/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap b/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap index a591aba84e102..f23d2916aa358 100644 --- a/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap +++ b/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap @@ -95,6 +95,7 @@ exports[`workspace move to nx layout should create nx.json 1`] = ` "!{projectRoot}/**/*.spec.[jt]s", "!{projectRoot}/karma.conf.js", "!{projectRoot}/.eslintrc.json", + "!{projectRoot}/eslint.config.js", ], "sharedGlobals": [], }, @@ -118,6 +119,7 @@ exports[`workspace move to nx layout should create nx.json 1`] = ` "inputs": [ "default", "{workspaceRoot}/.eslintrc.json", + "{workspaceRoot}/eslint.config.js", ], }, "test": { diff --git a/packages/angular/src/generators/ng-add/utilities/workspace.ts b/packages/angular/src/generators/ng-add/utilities/workspace.ts index 696d68609cd26..69a6985c2d4cb 100644 --- a/packages/angular/src/generators/ng-add/utilities/workspace.ts +++ b/packages/angular/src/generators/ng-add/utilities/workspace.ts @@ -76,7 +76,9 @@ export function createNxJson( '!{projectRoot}/karma.conf.js', ] : []), - targets.lint ? '!{projectRoot}/.eslintrc.json' : undefined, + ...(targets.lint + ? ['!{projectRoot}/.eslintrc.json', '!{projectRoot}/eslint.config.js'] + : []), ].filter(Boolean), }, targetDefaults: { @@ -91,7 +93,11 @@ export function createNxJson( : undefined, lint: targets.lint ? { - inputs: ['default', '{workspaceRoot}/.eslintrc.json'], + inputs: [ + 'default', + '{workspaceRoot}/.eslintrc.json', + '{workspaceRoot}/eslint.config.js', + ], } : undefined, e2e: targets.e2e diff --git a/packages/linter/generators.json b/packages/linter/generators.json index 79aae1043216b..8a40aeba824ae 100644 --- a/packages/linter/generators.json +++ b/packages/linter/generators.json @@ -25,6 +25,11 @@ "factory": "./src/generators/workspace-rule/workspace-rule#lintWorkspaceRuleGenerator", "schema": "./src/generators/workspace-rule/schema.json", "description": "Create a new Workspace ESLint rule." + }, + "convert-to-flat-config": { + "factory": "./src/generators/convert-to-flat-config/generator", + "schema": "./src/generators/convert-to-flat-config/schema.json", + "description": "Convert an Nx workspace to a Flat ESLint config." } } } diff --git a/packages/linter/package.json b/packages/linter/package.json index 0dd3d494d10c5..fe353a6c4459e 100644 --- a/packages/linter/package.json +++ b/packages/linter/package.json @@ -37,7 +37,8 @@ "tmp": "~0.2.1", "tslib": "^2.3.0", "@nx/devkit": "file:../devkit", - "@nx/js": "file:../js" + "@nx/js": "file:../js", + "typescript": "~5.1.3" }, "peerDependenciesMeta": { "eslint": { diff --git a/packages/linter/src/executors/eslint/lint.impl.ts b/packages/linter/src/executors/eslint/lint.impl.ts index 263250a3871f6..f7e7721ad729e 100644 --- a/packages/linter/src/executors/eslint/lint.impl.ts +++ b/packages/linter/src/executors/eslint/lint.impl.ts @@ -130,10 +130,13 @@ Please see https://nx.dev/guides/eslint for full guidance on how to resolve this .filter((pattern) => !!pattern) .map((pattern) => `- '${pattern}'`); if (ignoredPatterns.length) { + const ignoreSection = useFlatConfig + ? `'ignores' configuration` + : `'.eslintignore' file`; throw new Error( `All files matching the following patterns are ignored:\n${ignoredPatterns.join( '\n' - )}\n\nPlease check your '.eslintignore' file.` + )}\n\nPlease check your ${ignoreSection}.` ); } throw new Error( diff --git a/packages/linter/src/generators/convert-to-flat-config/__snapshots__/generator.spec.ts.snap b/packages/linter/src/generators/convert-to-flat-config/__snapshots__/generator.spec.ts.snap new file mode 100644 index 0000000000000..3e7d29711e308 --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/__snapshots__/generator.spec.ts.snap @@ -0,0 +1,385 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`convert-to-flat-config generator should add env configuration 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const globals = require('globals'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { languageOptions: { globals: { ...globals.browser, ...globals.node } } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should add global and env configuration 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const globals = require('globals'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { + languageOptions: { + globals: { ...globals.browser, myCustomGlobal: 'readonly' }, + }, + }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should add global configuration 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { languageOptions: { globals: { myCustomGlobal: 'readonly' } } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should add global gitignores 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), + { ignores: ['ignore/me'] }, +]; +" +`; + +exports[`convert-to-flat-config generator should add parser 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const typescriptEslintParser = require('@typescript-eslint/parser'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { languageOptions: { parser: typescriptEslintParser } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should add plugins 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const eslintPluginImport = require('eslint-plugin-import'); +const eslintPluginSingleName = require('eslint-plugin-single-name'); +const scopeEslintPluginWithName = require('@scope/eslint-plugin-with-name'); +const justScopeEslintPlugin = require('@just-scope/eslint-plugin'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { + plugins: { + 'eslint-plugin-import': eslintPluginImport, + 'single-name': eslintPluginSingleName, + '@scope/with-name': scopeEslintPluginWithName, + '@just-scope': justScopeEslintPlugin, + }, + }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should add settings 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { settings: { sharedData: 'Hello' } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should run successfully 1`] = ` +"const { FlatCompat } = require('@eslint/eslintrc'); +const nxEslintPlugin = require('@nx/eslint-plugin'); +const js = require('@eslint/js'); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), +]; +" +`; + +exports[`convert-to-flat-config generator should run successfully 2`] = ` +"const baseConfig = require('../../eslint.config.js'); +module.exports = [ + ...baseConfig, + { + files: [ + 'libs/test-lib/**/*.ts', + 'libs/test-lib/**/*.tsx', + 'libs/test-lib/**/*.js', + 'libs/test-lib/**/*.jsx', + ], + rules: {}, + }, + { + files: ['libs/test-lib/**/*.ts', 'libs/test-lib/**/*.tsx'], + rules: {}, + }, + { + files: ['libs/test-lib/**/*.js', 'libs/test-lib/**/*.jsx'], + rules: {}, + }, +]; +" +`; diff --git a/packages/linter/src/generators/convert-to-flat-config/converters/generate-ast.ts b/packages/linter/src/generators/convert-to-flat-config/converters/generate-ast.ts new file mode 100644 index 0000000000000..5a956bc2ba051 --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/converters/generate-ast.ts @@ -0,0 +1,68 @@ +import * as ts from 'typescript'; + +/** + * Generates an AST from a JSON-type input + */ +export function generateAst(input: unknown): T { + if (Array.isArray(input)) { + return ts.factory.createArrayLiteralExpression( + input.map((item) => generateAst(item)), + input.length > 1 // multiline only if more than one item + ) as T; + } + if (input === null) { + return ts.factory.createNull() as T; + } + if (typeof input === 'object') { + return ts.factory.createObjectLiteralExpression( + Object.entries(input) + .filter(([_, value]) => value !== undefined) + .map(([key, value]) => + ts.factory.createPropertyAssignment( + isValidKey(key) ? key : ts.factory.createStringLiteral(key), + generateAst(value) + ) + ), + Object.keys(input).length > 1 // multiline only if more than one property + ) as T; + } + if (typeof input === 'string') { + return ts.factory.createStringLiteral(input) as T; + } + if (typeof input === 'number') { + return ts.factory.createNumericLiteral(input) as T; + } + if (typeof input === 'boolean') { + return (input ? ts.factory.createTrue() : ts.factory.createFalse()) as T; + } + // since we are parsing JSON, this should never happen + throw new Error(`Unknown type: ${typeof input}`); +} + +export function generateRequire( + variableName: string | ts.ObjectBindingPattern, + imp: string +): ts.VariableStatement { + return ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ + ts.factory.createVariableDeclaration( + variableName, + undefined, + undefined, + ts.factory.createCallExpression( + ts.factory.createIdentifier('require'), + undefined, + [ts.factory.createStringLiteral(imp)] + ) + ), + ], + ts.NodeFlags.Const + ) + ); +} + +function isValidKey(key: string): boolean { + return /^[a-zA-Z0-9_]+$/.test(key); +} diff --git a/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.spec.ts b/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.spec.ts new file mode 100644 index 0000000000000..93b33ab9fbc05 --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.spec.ts @@ -0,0 +1,234 @@ +import { Tree } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { convertEslintJsonToFlatConfig } from './json-converter'; + +describe('convertEslintJsonToFlatConfig', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + }); + + it('should convert root configs', async () => { + tree.write( + '.eslintrc.json', + JSON.stringify({ + root: true, + ignorePatterns: ['**/*', 'src/ignore/to/keep.ts'], + plugins: ['@nx'], + overrides: [ + { + files: ['*.ts', '*.tsx', '*.js', '*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + { + files: ['*.ts', '*.tsx'], + extends: ['plugin:@nx/typescript'], + rules: {}, + }, + { + files: [ + '**/*.spec.ts', + '**/*.spec.tsx', + '**/*.spec.js', + '**/*.spec.jsx', + ], + env: { + jest: true, + }, + rules: {}, + }, + ], + }) + ); + + tree.write('.eslintignore', 'node_modules\nsomething/else'); + + convertEslintJsonToFlatConfig( + tree, + '', + '.eslintrc.json', + 'eslint.config.js' + ); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchInlineSnapshot(` + "const { FlatCompat } = require("@eslint/eslintrc"); + const nxEslintPlugin = require("@nx/eslint-plugin"); + const js = require("@eslint/js"); + const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + }); + module.exports = [ + { plugins: { "@nx": nxEslintPlugin } }, + { + files: [ + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jsx" + ], + rules: { "@nx/enforce-module-boundaries": [ + "error", + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [{ + sourceTag: "*", + onlyDependOnLibsWithTags: ["*"] + }] + } + ] } + }, + ...compat.config({ extends: ["plugin:@nx/typescript"] }).map(config => ({ + ...config, + files: [ + "**/*.ts", + "**/*.tsx" + ], + rules: {} + })), + ...compat.config({ env: { jest: true } }).map(config => ({ + ...config, + files: [ + "**/*.spec.ts", + "**/*.spec.tsx", + "**/*.spec.js", + "**/*.spec.jsx" + ], + rules: {} + })), + { ignores: ["src/ignore/to/keep.ts"] }, + { ignores: ["something/else"] } + ]; + " + `); + + expect(tree.exists('.eslintrc.json')).toBeFalsy(); + expect(tree.exists('.eslintignore')).toBeFalsy(); + }); + + it('should convert project configs', async () => { + tree.write( + 'mylib/.eslintrc.json', + JSON.stringify({ + extends: [ + 'plugin:@nx/react-typescript', + 'next', + 'next/core-web-vitals', + '../../.eslintrc.json', + ], + ignorePatterns: ['!**/*', '.next/**/*'], + overrides: [ + { + files: ['*.ts', '*.tsx', '*.js', '*.jsx'], + rules: { + '@next/next/no-html-link-for-pages': [ + 'error', + 'apps/test-next/pages', + ], + }, + }, + { + files: ['*.ts', '*.tsx'], + rules: {}, + }, + { + files: ['*.js', '*.jsx'], + rules: {}, + }, + { + files: ['*.json'], + parser: 'jsonc-eslint-parser', + rules: { + '@nx/dependency-checks': 'error', + }, + }, + ], + rules: { + '@next/next/no-html-link-for-pages': 'off', + }, + env: { + jest: true, + }, + }) + ); + + tree.write('mylib/.eslintignore', 'node_modules\nsomething/else'); + + convertEslintJsonToFlatConfig( + tree, + 'mylib', + '.eslintrc.json', + 'eslint.config.js' + ); + + expect(tree.read('mylib/eslint.config.js', 'utf-8')).toMatchInlineSnapshot(` + "const { FlatCompat } = require("@eslint/eslintrc"); + const baseConfig = require("../../eslint.config.js"); + const globals = require("globals"); + const js = require("@eslint/js"); + const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + }); + module.exports = [ + ...baseConfig, + ...compat.extends("plugin:@nx/react-typescript", "next", "next/core-web-vitals"), + { languageOptions: { globals: { ...globals.jest } } }, + { rules: { "@next/next/no-html-link-for-pages": "off" } }, + { + files: [ + "mylib/**/*.ts", + "mylib/**/*.tsx", + "mylib/**/*.js", + "mylib/**/*.jsx" + ], + rules: { "@next/next/no-html-link-for-pages": [ + "error", + "apps/test-next/pages" + ] } + }, + { + files: [ + "mylib/**/*.ts", + "mylib/**/*.tsx" + ], + rules: {} + }, + { + files: [ + "mylib/**/*.js", + "mylib/**/*.jsx" + ], + rules: {} + }, + ...compat.config({ parser: "jsonc-eslint-parser" }).map(config => ({ + ...config, + files: ["mylib/**/*.json"], + rules: { "@nx/dependency-checks": "error" } + })), + { ignores: ["mylib/.next/**/*"] }, + { ignores: ["mylib/something/else"] } + ]; + " + `); + + expect(tree.exists('mylib/.eslintrc.json')).toBeFalsy(); + expect(tree.exists('mylib/.eslintignore')).toBeFalsy(); + }); +}); diff --git a/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.ts b/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.ts new file mode 100644 index 0000000000000..a745f4efb38ec --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/converters/json-converter.ts @@ -0,0 +1,524 @@ +import { + Tree, + addDependenciesToPackageJson, + names, + readJson, +} from '@nx/devkit'; +import { join } from 'path'; +import { ESLint, Linter } from 'eslint'; +import * as ts from 'typescript'; +import { generateAst, generateRequire } from './generate-ast'; +import { eslintrcVersion } from '../../../utils/versions'; + +/** + * Converts an ESLint JSON config to a flat config. + * Deletes the original file along with .eslintignore if it exists. + */ +export function convertEslintJsonToFlatConfig( + tree: Tree, + root: string, + sourceFile: string, + destinationFile: string +) { + const importsMap = new Map(); + const exportElements: ts.Expression[] = []; + let isFlatCompatNeeded = false; + let combinedConfig: ts.PropertyAssignment[] = []; + let languageOptions: ts.PropertyAssignment[] = []; + + // read original config + const config: ESLint.ConfigData = readJson(tree, `${root}/${sourceFile}`); + + if (config.extends) { + isFlatCompatNeeded = addExtends(importsMap, exportElements, config, tree); + } + + if (config.plugins) { + addPlugins(importsMap, exportElements, config); + } + + if (config.parser) { + languageOptions.push(addParser(importsMap, config)); + } + + if (config.parserOptions) { + languageOptions.push( + ts.factory.createPropertyAssignment( + 'parserOptions', + generateAst(config.parserOptions) + ) + ); + } + + if (config.globals || config.env) { + if (config.env) { + importsMap.set('globals', 'globals'); + } + + languageOptions.push( + ts.factory.createPropertyAssignment( + 'globals', + ts.factory.createObjectLiteralExpression([ + ...Object.keys(config.env || {}).map((env) => + ts.factory.createSpreadAssignment( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('globals'), + ts.factory.createIdentifier(env) + ) + ) + ), + ...Object.keys(config.globals || {}).map((key) => + ts.factory.createPropertyAssignment( + key, + generateAst(config.globals[key]) + ) + ), + ]) + ) + ); + } + + if (config.settings) { + combinedConfig.push( + ts.factory.createPropertyAssignment( + 'settings', + generateAst(config.settings) + ) + ); + } + + if ( + config.noInlineConfig !== undefined || + config.reportUnusedDisableDirectives !== undefined + ) { + combinedConfig.push( + ts.factory.createPropertyAssignment( + 'linterOptions', + generateAst({ + noInlineConfig: config.noInlineConfig, + reportUnusedDisableDirectives: config.reportUnusedDisableDirectives, + }) + ) + ); + } + + if (languageOptions.length > 0) { + combinedConfig.push( + ts.factory.createPropertyAssignment( + 'languageOptions', + ts.factory.createObjectLiteralExpression( + languageOptions, + languageOptions.length > 1 + ) + ) + ); + } + + if (combinedConfig.length > 0) { + exportElements.push( + ts.factory.createObjectLiteralExpression( + combinedConfig, + combinedConfig.length > 1 + ) + ); + } + + if (config.rules) { + exportElements.push(generateAst({ rules: config.rules })); + } + + if (config.overrides) { + config.overrides.forEach((override) => { + updateFiles(override, root); + if ( + override.env || + override.extends || + override.plugins || + override.parser + ) { + isFlatCompatNeeded = true; + addFlattenedOverride(override, exportElements); + } else { + exportElements.push(generateAst(override)); + } + }); + } + + if (config.ignorePatterns) { + const patterns = ( + Array.isArray(config.ignorePatterns) + ? config.ignorePatterns + : [config.ignorePatterns] + ).filter((pattern) => !['**/*', '!**/*', 'node_modules'].includes(pattern)); // these are useless in a flat config + if (patterns.length > 0) { + exportElements.push( + generateAst({ + ignores: patterns.map((path) => mapFilePath(path, root)), + }) + ); + } + } + + if (tree.exists(`${root}/.eslintignore`)) { + const patterns = tree + .read(`${root}/.eslintignore`, 'utf-8') + .split('\n') + .filter((line) => line.length > 0 && line !== 'node_modules') + .map((path) => mapFilePath(path, root)); + if (patterns.length > 0) { + exportElements.push(generateAst({ ignores: patterns })); + } + } + + tree.delete(join(root, sourceFile)); + tree.delete(join(root, '.eslintignore')); + + // create the node list and print it to new file + const nodeList = createNodeList( + importsMap, + exportElements, + isFlatCompatNeeded + ); + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + const resultFile = ts.createSourceFile( + join(root, destinationFile), + '', + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.JS + ); + const result = printer.printList( + ts.ListFormat.MultiLine, + nodeList, + resultFile + ); + tree.write(join(root, destinationFile), result); + + if (isFlatCompatNeeded) { + addDependenciesToPackageJson( + tree, + {}, + { + '@eslint/eslintrc': eslintrcVersion, + } + ); + } +} + +function updateFiles( + override: Linter.ConfigOverride, + root: string +) { + if (override.files) { + override.files = Array.isArray(override.files) + ? override.files + : [override.files]; + override.files = override.files.map((file) => mapFilePath(file, root)); + } + return override; +} + +function mapFilePath(filePath: string, root: string) { + if (filePath.startsWith('!')) { + const fileWithoutBang = filePath.slice(1); + if (fileWithoutBang.startsWith('*.')) { + return `!${join(root, '**', fileWithoutBang)}`; + } else { + return `!${join(root, fileWithoutBang)}`; + } + } + if (filePath.startsWith('*.')) { + return join(root, '**', filePath); + } else { + return join(root, filePath); + } +} + +// add parsed extends to export blocks and add import statements +function addExtends( + importsMap: Map, + configBlocks: ts.Expression[], + config: ESLint.ConfigData, + tree: Tree +): boolean { + let isFlatCompatNeeded = false; + const extendsConfig = Array.isArray(config.extends) + ? config.extends + : [config.extends]; + + const eslintrcConfigs = []; + + // add base extends + extendsConfig + .filter((imp) => imp.match(/^\.?(\.\/)/)) + .forEach((imp, index) => { + if (imp.match(/\.eslintrc(.base)?\.json$/)) { + const localName = index ? `baseConfig${index}` : 'baseConfig'; + configBlocks.push( + ts.factory.createSpreadElement(ts.factory.createIdentifier(localName)) + ); + const newImport = imp.replace( + /^(.*)\.eslintrc(.base)?\.json$/, + '$1eslint$2.config.js' + ); + importsMap.set(newImport, localName); + } else { + eslintrcConfigs.push(imp); + } + }); + // add plugin extends + const pluginExtends = extendsConfig.filter((imp) => !imp.match(/^\.?(\.\/)/)); + if (pluginExtends.length) { + const eslintPluginExtends = pluginExtends.filter((imp) => + imp.startsWith('eslint:') + ); + pluginExtends.forEach((imp) => { + if (!imp.startsWith('eslint:')) { + eslintrcConfigs.push(imp); + } + }); + + if (eslintPluginExtends.length) { + addDependenciesToPackageJson( + tree, + {}, + { + '@eslint/js': eslintrcVersion, + } + ); + + importsMap.set('@eslint/js', 'js'); + eslintPluginExtends.forEach((plugin) => { + configBlocks.push( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('js'), + ts.factory.createIdentifier('configs') + ), + ts.factory.createIdentifier(plugin.slice(7)) // strip 'eslint:' prefix + ) + ); + }); + } + } + if (eslintrcConfigs.length) { + isFlatCompatNeeded = true; + addDependenciesToPackageJson( + tree, + {}, + { + '@eslint/js': eslintrcVersion, + } + ); + + const pluginExtendsSpread = ts.factory.createSpreadElement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('compat'), + ts.factory.createIdentifier('extends') + ), + undefined, + eslintrcConfigs.map((plugin) => ts.factory.createStringLiteral(plugin)) + ) + ); + configBlocks.push(pluginExtendsSpread); + } + + return isFlatCompatNeeded; +} + +function getPluginImport(pluginName: string): string { + if (pluginName.includes('eslint-plugin-')) { + return pluginName; + } + if (!pluginName.startsWith('@')) { + return `eslint-plugin-${pluginName}`; + } + if (!pluginName.includes('/')) { + return `${pluginName}/eslint-plugin`; + } + const [scope, name] = pluginName.split('/'); + return `${scope}/eslint-plugin-${name}`; +} + +function addPlugins( + importsMap: Map, + configBlocks: ts.Expression[], + config: ESLint.ConfigData +) { + const mappedPlugins: { name: string; varName: string; imp: string }[] = []; + config.plugins.forEach((name) => { + const imp = getPluginImport(name); + const varName = names(imp).propertyName; + mappedPlugins.push({ name, varName, imp }); + }); + mappedPlugins.forEach(({ varName, imp }) => { + importsMap.set(imp, varName); + }); + const pluginsAst = ts.factory.createObjectLiteralExpression( + [ + ts.factory.createPropertyAssignment( + 'plugins', + ts.factory.createObjectLiteralExpression( + mappedPlugins.map(({ name, varName }) => { + return ts.factory.createPropertyAssignment( + ts.factory.createStringLiteral(name), + ts.factory.createIdentifier(varName) + ); + }), + mappedPlugins.length > 1 + ) + ), + ...(config.processor + ? [ + ts.factory.createPropertyAssignment( + 'processor', + ts.factory.createStringLiteral(config.processor) + ), + ] + : []), + ], + false + ); + configBlocks.push(pluginsAst); +} + +function addParser( + importsMap: Map, + config: ESLint.ConfigData +): ts.PropertyAssignment { + const imp = config.parser; + const parserName = names(imp).propertyName; + importsMap.set(imp, parserName); + + return ts.factory.createPropertyAssignment( + 'parser', + ts.factory.createIdentifier(parserName) + ); +} + +function addFlattenedOverride( + override: Linter.ConfigOverride, + configBlocks: ts.Expression[] +) { + const { files, excludedFiles, rules, ...rest } = override; + + const objectLiteralElements: ts.ObjectLiteralElementLike[] = [ + ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')), + ]; + if (files) { + objectLiteralElements.push( + ts.factory.createPropertyAssignment('files', generateAst(files)) + ); + } + if (excludedFiles) { + objectLiteralElements.push( + ts.factory.createPropertyAssignment( + 'excludedFiles', + generateAst(excludedFiles) + ) + ); + } + if (rules) { + objectLiteralElements.push( + ts.factory.createPropertyAssignment('rules', generateAst(rules)) + ); + } + + const overrideSpread = ts.factory.createSpreadElement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('compat'), + ts.factory.createIdentifier('config') + ), + undefined, + [generateAst(rest)] + ), + ts.factory.createIdentifier('map') + ), + undefined, + [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + 'config' + ), + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createParenthesizedExpression( + ts.factory.createObjectLiteralExpression( + objectLiteralElements, + true + ) + ) + ), + ] + ) + ); + configBlocks.push(overrideSpread); +} + +const DEFAULT_FLAT_CONFIG = ` +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); +`; + +function createNodeList( + importsMap: Map, + exportElements: ts.Expression[], + isFlatCompatNeeded: boolean +): ts.NodeArray< + ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile +> { + const importsList = []; + if (isFlatCompatNeeded) { + importsMap.set('@eslint/js', 'js'); + + importsList.push( + generateRequire( + ts.factory.createObjectBindingPattern([ + ts.factory.createBindingElement(undefined, undefined, 'FlatCompat'), + ]), + '@eslint/eslintrc' + ) + ); + } + + // generateRequire(varName, imp, ts.factory); + Array.from(importsMap.entries()).forEach(([imp, varName]) => { + importsList.push(generateRequire(varName, imp)); + }); + + return ts.factory.createNodeArray([ + // add plugin imports + ...importsList, + ts.createSourceFile( + '', + isFlatCompatNeeded ? DEFAULT_FLAT_CONFIG : '', + ts.ScriptTarget.Latest, + false, + ts.ScriptKind.JS + ), + // creates: + // module.exports = [ ... ]; + ts.factory.createExpressionStatement( + ts.factory.createBinaryExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('module'), + ts.factory.createIdentifier('exports') + ), + ts.factory.createToken(ts.SyntaxKind.EqualsToken), + ts.factory.createArrayLiteralExpression(exportElements, true) + ) + ), + ]); +} diff --git a/packages/linter/src/generators/convert-to-flat-config/generator.spec.ts b/packages/linter/src/generators/convert-to-flat-config/generator.spec.ts new file mode 100644 index 0000000000000..59cd3cb591530 --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/generator.spec.ts @@ -0,0 +1,350 @@ +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { + NxJsonConfiguration, + Tree, + addProjectConfiguration, + readJson, + updateJson, +} from '@nx/devkit'; + +import { convertToFlatConfigGenerator } from './generator'; +import { ConvertToFlatConfigGeneratorSchema } from './schema'; +import { lintProjectGenerator } from '../lint-project/lint-project'; +import { Linter } from '../utils/linter'; +import { eslintrcVersion } from '../../utils/versions'; + +describe('convert-to-flat-config generator', () => { + let tree: Tree; + const options: ConvertToFlatConfigGeneratorSchema = { skipFormat: false }; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + addProjectConfiguration(tree, 'test-lib', { + root: 'libs/test-lib', + targets: {}, + }); + updateJson(tree, 'nx.json', (json: NxJsonConfiguration) => { + json.targetDefaults = { + lint: { + inputs: ['default'], + }, + }; + json.namedInputs = { + default: ['{projectRoot}/**/*', 'sharedGlobals'], + production: [ + 'default', + '!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)', + ], + sharedGlobals: [], + }; + return json; + }); + }); + + it('should run successfully', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.exists('eslint.config.js')).toBeTruthy(); + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + expect(tree.exists('libs/test-lib/eslint.config.js')).toBeTruthy(); + expect( + tree.read('libs/test-lib/eslint.config.js', 'utf-8') + ).toMatchSnapshot(); + // check nx.json changes + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.targetDefaults.lint.inputs).toContain( + '{workspaceRoot}/eslint.config.js' + ); + expect(nxJson.namedInputs.production).toContain( + '!{projectRoot}/eslint.config.js' + ); + }); + + it('should add plugin extends', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.extends = ['plugin:storybook/recommended']; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchInlineSnapshot(` + "const { FlatCompat } = require('@eslint/eslintrc'); + const nxEslintPlugin = require('@nx/eslint-plugin'); + const js = require('@eslint/js'); + const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + }); + module.exports = [ + ...compat.extends('plugin:storybook/recommended'), + { plugins: { '@nx': nxEslintPlugin } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), + ]; + " + `); + expect(tree.read('libs/test-lib/eslint.config.js', 'utf-8')) + .toMatchInlineSnapshot(` + "const baseConfig = require('../../eslint.config.js'); + module.exports = [ + ...baseConfig, + { + files: [ + 'libs/test-lib/**/*.ts', + 'libs/test-lib/**/*.tsx', + 'libs/test-lib/**/*.js', + 'libs/test-lib/**/*.jsx', + ], + rules: {}, + }, + { + files: ['libs/test-lib/**/*.ts', 'libs/test-lib/**/*.tsx'], + rules: {}, + }, + { + files: ['libs/test-lib/**/*.js', 'libs/test-lib/**/*.jsx'], + rules: {}, + }, + ]; + " + `); + expect( + readJson(tree, 'package.json').devDependencies['@eslint/eslintrc'] + ).toEqual(eslintrcVersion); + }); + + it('should add global gitignores', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + tree.write('.eslintignore', 'ignore/me'); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add settings', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.settings = { + sharedData: 'Hello', + }; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add env configuration', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.env = { + browser: true, + node: true, + }; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add global configuration', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.globals = { + myCustomGlobal: 'readonly', + }; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add global and env configuration', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.globals = { + myCustomGlobal: 'readonly', + }; + json.env = { + browser: true, + }; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add plugins', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.plugins = [ + 'eslint-plugin-import', + 'single-name', + '@scope/with-name', + '@just-scope', + ]; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add parser', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.parser = '@typescript-eslint/parser'; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should add linter options', async () => { + await lintProjectGenerator(tree, { + skipFormat: false, + linter: Linter.EsLint, + eslintFilePatterns: ['**/*.ts'], + project: 'test-lib', + setParserOptionsProject: false, + }); + updateJson(tree, '.eslintrc.json', (json) => { + json.noInlineConfig = true; + return json; + }); + await convertToFlatConfigGenerator(tree, options); + + expect(tree.read('eslint.config.js', 'utf-8')).toMatchInlineSnapshot(` + "const { FlatCompat } = require('@eslint/eslintrc'); + const nxEslintPlugin = require('@nx/eslint-plugin'); + const js = require('@eslint/js'); + const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + }); + module.exports = [ + { plugins: { '@nx': nxEslintPlugin } }, + { + linterOptions: { + noInlineConfig: true, + }, + }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [], + depConstraints: [ + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + ...compat.config({ extends: ['plugin:@nx/typescript'] }).map((config) => ({ + ...config, + files: ['**/*.ts', '**/*.tsx'], + rules: {}, + })), + ...compat.config({ extends: ['plugin:@nx/javascript'] }).map((config) => ({ + ...config, + files: ['**/*.js', '**/*.jsx'], + rules: {}, + })), + ]; + " + `); + }); +}); diff --git a/packages/linter/src/generators/convert-to-flat-config/generator.ts b/packages/linter/src/generators/convert-to-flat-config/generator.ts new file mode 100644 index 0000000000000..8047e18cf76ee --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/generator.ts @@ -0,0 +1,129 @@ +import { + formatFiles, + getProjects, + NxJsonConfiguration, + ProjectConfiguration, + readNxJson, + Tree, + updateJson, + updateProjectConfiguration, +} from '@nx/devkit'; +import { ConvertToFlatConfigGeneratorSchema } from './schema'; +import { findEslintFile } from '../utils/eslint-file'; +import { convertEslintJsonToFlatConfig } from './converters/json-converter'; + +export async function convertToFlatConfigGenerator( + tree: Tree, + options: ConvertToFlatConfigGeneratorSchema +) { + const eslintFile = findEslintFile(tree); + if (!eslintFile) { + throw new Error('Could not find root eslint file'); + } + if (!eslintFile.endsWith('.json')) { + throw new Error( + 'Only json eslint config files are supported for conversion' + ); + } + + // rename root eslint config to eslint.config.js + convertRootToFlatConfig(tree, eslintFile); + // rename and map files + const projects = getProjects(tree); + for (const [project, projectConfig] of projects) { + convertProjectToFlatConfig(tree, project, projectConfig, readNxJson(tree)); + } + // replace references in nx.json + updateNxJsonConfig(tree); + // install missing packages + + if (!options.skipFormat) { + await formatFiles(tree); + } +} + +export default convertToFlatConfigGenerator; + +function convertRootToFlatConfig(tree: Tree, eslintFile: string) { + if (eslintFile.endsWith('.base.json')) { + convertConfigToFlatConfig( + tree, + '', + '.eslintrc.base.json', + 'eslint.base.config.js' + ); + } + convertConfigToFlatConfig(tree, '', '.eslintrc.json', 'eslint.config.js'); +} + +function convertProjectToFlatConfig( + tree: Tree, + project: string, + projectConfig: ProjectConfiguration, + nxJson: NxJsonConfiguration +) { + if (tree.exists(`${projectConfig.root}/.eslintrc.json`)) { + if (projectConfig.targets) { + const eslintTargets = Object.keys(projectConfig.targets || {}).filter( + (t) => projectConfig.targets[t].executor === '@nx/linter:eslint' + ); + for (const target of eslintTargets) { + // remove any obsolete `eslintConfig` options pointing to the old config file + if (projectConfig.targets[target].options?.eslintConfig) { + delete projectConfig.targets[target].options.eslintConfig; + } + updateProjectConfiguration(tree, project, projectConfig); + } + const nxHasLintTargets = Object.keys(nxJson.targetDefaults || {}).some( + (t) => + (t === '@nx/linter:eslint' || + nxJson.targetDefaults[t].executor === '@nx/linter:eslint') && + projectConfig.targets?.[t] + ); + if (nxHasLintTargets || eslintTargets.length > 0) { + convertConfigToFlatConfig( + tree, + projectConfig.root, + '.eslintrc.json', + 'eslint.config.js' + ); + } + } + } +} + +// update names of eslint files in nx.json +// and remove eslintignore +function updateNxJsonConfig(tree: Tree) { + if (tree.exists('nx.json')) { + updateJson(tree, 'nx.json', (json: NxJsonConfiguration) => { + if (json.targetDefaults?.lint?.inputs) { + const inputSet = new Set(json.targetDefaults.lint.inputs); + inputSet.add('{workspaceRoot}/eslint.config.js'); + json.targetDefaults.lint.inputs = Array.from(inputSet); + } + if (json.targetDefaults?.['@nx/linter:eslint']?.inputs) { + const inputSet = new Set( + json.targetDefaults['@nx/linter:eslint'].inputs + ); + inputSet.add('{workspaceRoot}/eslint.config.js'); + json.targetDefaults['@nx/linter:eslint'].inputs = Array.from(inputSet); + } + if (json.namedInputs?.production) { + const inputSet = new Set(json.namedInputs.production); + inputSet.add('!{projectRoot}/eslint.config.js'); + json.namedInputs.production = Array.from(inputSet); + } + return json; + }); + } +} + +function convertConfigToFlatConfig( + tree: Tree, + root: string, + source: string, + target: string +) { + convertEslintJsonToFlatConfig(tree, root, source, target); +} diff --git a/packages/linter/src/generators/convert-to-flat-config/schema.d.ts b/packages/linter/src/generators/convert-to-flat-config/schema.d.ts new file mode 100644 index 0000000000000..67eeb4ddadf42 --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/schema.d.ts @@ -0,0 +1,3 @@ +export interface ConvertToFlatConfigGeneratorSchema { + skipFormat?: boolean; +} diff --git a/packages/linter/src/generators/convert-to-flat-config/schema.json b/packages/linter/src/generators/convert-to-flat-config/schema.json new file mode 100644 index 0000000000000..55297951cf0de --- /dev/null +++ b/packages/linter/src/generators/convert-to-flat-config/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ConvertToFlatConfig", + "cli": "nx", + "description": "Convert an Nx workspace to a Flat ESLint config.", + "type": "object", + "properties": { + "skipFormat": { + "type": "boolean", + "description": "Skip formatting files.", + "default": false, + "x-priority": "internal" + } + }, + "additionalProperties": false, + "required": [] +} diff --git a/packages/linter/src/generators/init/init.spec.ts b/packages/linter/src/generators/init/init.spec.ts index 4f579e5bb734f..0b0c2aef641bf 100644 --- a/packages/linter/src/generators/init/init.spec.ts +++ b/packages/linter/src/generators/init/init.spec.ts @@ -34,6 +34,7 @@ describe('@nx/linter:init', () => { 'default', '{workspaceRoot}/.eslintrc.json', '{workspaceRoot}/.eslintignore', + '{workspaceRoot}/eslint.config.js', ], }); }); diff --git a/packages/linter/src/generators/init/init.ts b/packages/linter/src/generators/init/init.ts index d9023389f943a..03e889b71bd8e 100644 --- a/packages/linter/src/generators/init/init.ts +++ b/packages/linter/src/generators/init/init.ts @@ -32,6 +32,7 @@ function addTargetDefaults(tree: Tree) { if (productionFileSet) { // Remove .eslintrc.json productionFileSet.push('!{projectRoot}/.eslintrc.json'); + productionFileSet.push('!{projectRoot}/eslint.config.js'); // Dedupe and set nxJson.namedInputs.production = Array.from(new Set(productionFileSet)); } @@ -43,6 +44,7 @@ function addTargetDefaults(tree: Tree) { 'default', `{workspaceRoot}/.eslintrc.json`, `{workspaceRoot}/.eslintignore`, + `{workspaceRoot}/eslint.config.js`, ]; updateNxJson(tree, nxJson); } diff --git a/packages/linter/src/utils/versions.ts b/packages/linter/src/utils/versions.ts index 68a533f14b85f..a3c2bfcf995a2 100644 --- a/packages/linter/src/utils/versions.ts +++ b/packages/linter/src/utils/versions.ts @@ -1,6 +1,7 @@ export const nxVersion = require('../../package.json').version; export const eslintVersion = '~8.46.0'; +export const eslintrcVersion = '^2.1.1'; export const eslintConfigPrettierVersion = '8.1.0'; export const tslintToEslintConfigVersion = '^2.13.0'; export const typescriptESLintVersion = '^5.60.1'; diff --git a/packages/nx/src/command-line/init/implementation/angular/standalone-workspace.ts b/packages/nx/src/command-line/init/implementation/angular/standalone-workspace.ts index e861f084494e4..fbf9b8cbda4c2 100644 --- a/packages/nx/src/command-line/init/implementation/angular/standalone-workspace.ts +++ b/packages/nx/src/command-line/init/implementation/angular/standalone-workspace.ts @@ -90,7 +90,9 @@ function createNxJson( karmaProjectConfigFile ? '!{projectRoot}/karma.conf.js' : undefined, ].filter(Boolean) : []), - eslintProjectConfigFile ? '!{projectRoot}/.eslintrc.json' : undefined, + ...(eslintProjectConfigFile + ? ['!{projectRoot}/.eslintrc.json', '!{projectRoot}/eslint.config.js'] + : []), ].filter(Boolean), }; nxJson.targetDefaults = {}; @@ -115,6 +117,9 @@ function createNxJson( if (fileExists(join(repoRoot, '.eslintrc.json'))) { inputs.push('{workspaceRoot}/.eslintrc.json'); } + if (fileExists(join(repoRoot, 'eslint.config.js'))) { + inputs.push('{workspaceRoot}/eslint.config.js'); + } nxJson.targetDefaults.lint = { inputs }; } if (workspaceTargets.includes('e2e')) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 870d62fbc41d6..9f82d216a330f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + overrides: '@angular-devkit/core': ~16.2.0-rc.1 @@ -209,6 +213,12 @@ devDependencies: '@babel/runtime': specifier: ^7.22.6 version: 7.22.6 + '@eslint/eslintrc': + specifier: ^2.1.1 + version: 2.1.1 + '@eslint/js': + specifier: ^8.46.0 + version: 8.46.0 '@floating-ui/react': specifier: 0.19.2 version: 0.19.2(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) @@ -1106,8 +1116,8 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.18 - /@angular-devkit/architect@0.1601.8(chokidar@3.5.3): - resolution: {integrity: sha512-kOXVGwsQnZvtz2UZNefcEy64Jiwq0eSoQUeozvDXOaYRJABLjPKI2YaarvKC9/Z1SGLuje0o/eRJO4T8aRk9rQ==} + /@angular-devkit/architect@0.1601.0(chokidar@3.5.3): + resolution: {integrity: sha512-lrO++pcB+NFGXLZrFBhRMPbGCMpZuJyJEKSK8zknw9/7ipRz1MSlRaJFWUKEHRlVI/+hsBTWtBRUnR5WcgqvvA==} engines: {node: ^16.14.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} dependencies: '@angular-devkit/core': 16.2.0-rc.1(chokidar@3.5.3) @@ -1438,7 +1448,7 @@ packages: dependencies: '@angular/core': 16.2.0-rc.0(rxjs@7.8.1)(zone.js@0.13.1) rxjs: 7.8.1 - tslib: 2.6.0 + tslib: 2.5.3 dev: true /@angular/compiler-cli@16.2.0-rc.0(@angular/compiler@16.2.0-rc.0)(typescript@5.1.3): @@ -1456,7 +1466,7 @@ packages: convert-source-map: 1.9.0 reflect-metadata: 0.1.13 semver: 7.5.3 - tslib: 2.6.0 + tslib: 2.5.3 typescript: 5.1.3 yargs: 17.7.2 transitivePeerDependencies: @@ -1473,7 +1483,7 @@ packages: optional: true dependencies: '@angular/core': 16.2.0-rc.0(rxjs@7.8.1)(zone.js@0.13.1) - tslib: 2.6.0 + tslib: 2.5.3 dev: true /@angular/core@16.2.0-rc.0(rxjs@7.8.1)(zone.js@0.13.1): @@ -1484,7 +1494,7 @@ packages: zone.js: ~0.13.0 dependencies: rxjs: 7.8.1 - tslib: 2.6.0 + tslib: 2.5.3 zone.js: 0.13.1 dev: true @@ -1517,7 +1527,7 @@ packages: '@angular/core': 16.2.0-rc.0(rxjs@7.8.1)(zone.js@0.13.1) '@angular/platform-browser': 16.2.0-rc.0(@angular/common@16.2.0-rc.0)(@angular/core@16.2.0-rc.0) rxjs: 7.8.1 - tslib: 2.6.0 + tslib: 2.5.3 dev: true /@apidevtools/json-schema-ref-parser@9.0.9: @@ -1553,6 +1563,11 @@ packages: dependencies: '@babel/highlight': 7.22.5 + /@babel/compat-data@7.22.5: + resolution: {integrity: sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} @@ -2388,6 +2403,21 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: true + /@babel/plugin-transform-async-generator-functions@7.22.5(@babel/core@7.22.9): + resolution: {integrity: sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-transform-async-generator-functions@7.22.7(@babel/core@7.22.9): resolution: {integrity: sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==} engines: {node: '>=6.9.0'} @@ -2460,6 +2490,24 @@ packages: '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.9) dev: true + /@babel/plugin-transform-classes@7.22.5(@babel/core@7.22.9): + resolution: {integrity: sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.9(@babel/core@7.22.9) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + dev: true + /@babel/plugin-transform-classes@7.22.6(@babel/core@7.22.9): resolution: {integrity: sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==} engines: {node: '>=6.9.0'} @@ -2765,6 +2813,18 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.9) dev: true + /@babel/plugin-transform-optional-chaining@7.22.5(@babel/core@7.22.9): + resolution: {integrity: sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.9) + dev: true + /@babel/plugin-transform-optional-chaining@7.22.6(@babel/core@7.22.9): resolution: {integrity: sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==} engines: {node: '>=6.9.0'} @@ -3047,7 +3107,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.22.9 + '@babel/compat-data': 7.22.5 '@babel/core': 7.22.9 '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) '@babel/helper-plugin-utils': 7.22.5 @@ -3088,7 +3148,7 @@ packages: '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-block-scoping': 7.22.5(@babel/core@7.22.9) - '@babel/plugin-transform-classes': 7.22.6(@babel/core@7.22.9) + '@babel/plugin-transform-classes': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-destructuring': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.9) @@ -3121,7 +3181,98 @@ packages: babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.22.9) babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.22.9) babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.22.9) - core-js-compat: 3.31.1 + core-js-compat: 3.30.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-env@7.22.5(@babel/core@7.22.9): + resolution: {integrity: sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.22.5 + '@babel/core': 7.22.9 + '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.22.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.9) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.9) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.9) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.9) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.9) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.9) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.9) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.9) + '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-async-generator-functions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-block-scoping': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-class-static-block': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-classes': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-destructuring': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-dynamic-import': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-export-namespace-from': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-for-of': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-json-strings': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-logical-assignment-operators': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-modules-amd': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-modules-commonjs': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-modules-systemjs': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-numeric-separator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-object-rest-spread': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-optional-catch-binding': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-optional-chaining': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-private-property-in-object': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-regenerator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-escapes': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.9) + '@babel/preset-modules': 0.1.5(@babel/core@7.22.9) + '@babel/types': 7.22.5 + babel-plugin-polyfill-corejs2: 0.4.4(@babel/core@7.22.9) + babel-plugin-polyfill-corejs3: 0.8.2(@babel/core@7.22.9) + babel-plugin-polyfill-regenerator: 0.5.1(@babel/core@7.22.9) + core-js-compat: 3.30.2 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -4555,6 +4706,7 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.18 + dev: true /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} @@ -5222,11 +5374,11 @@ packages: peerDependencies: '@angular-devkit/build-angular': ^16.0.0 || ^16.1.0-next.0 dependencies: - '@angular-devkit/architect': 0.1601.8(chokidar@3.5.3) + '@angular-devkit/architect': 0.1601.0(chokidar@3.5.3) '@angular-devkit/build-angular': 16.2.0-rc.1(@angular/compiler-cli@16.2.0-rc.0)(@swc/core@1.3.51)(@types/node@18.16.9)(html-webpack-plugin@5.5.0)(jest-environment-jsdom@29.4.3)(jest@29.4.3)(ng-packagr@16.2.0-next.1)(stylus@0.59.0)(tailwindcss@3.2.4)(typescript@5.1.3) '@angular-devkit/core': 16.2.0-rc.1(chokidar@3.5.3) '@nguniversal/common': 16.2.0-rc.0(@angular/common@16.2.0-rc.0)(@angular/core@16.2.0-rc.0) - browser-sync: 2.29.3 + browser-sync: 2.27.11 express: 4.18.2 guess-parser: 0.4.22(typescript@5.1.3) http-proxy-middleware: 2.0.6(@types/express@4.17.14) @@ -5526,7 +5678,7 @@ packages: nx: 15.8.0(@swc-node/register@1.5.4)(@swc/core@1.3.51) semver: 7.3.4 tmp: 0.2.1 - tslib: 2.6.1 + tslib: 2.5.3 transitivePeerDependencies: - typescript dev: true @@ -5542,7 +5694,7 @@ packages: nx: 15.9.4(@swc-node/register@1.5.4)(@swc/core@1.3.51) semver: 7.3.4 tmp: 0.2.1 - tslib: 2.6.1 + tslib: 2.5.3 transitivePeerDependencies: - typescript dev: true @@ -5558,7 +5710,7 @@ packages: nx: 16.6.0-beta.8(@swc-node/register@1.5.4)(@swc/core@1.3.51) semver: 7.3.4 tmp: 0.2.1 - tslib: 2.6.1 + tslib: 2.5.3 transitivePeerDependencies: - typescript dev: true @@ -5617,7 +5769,7 @@ packages: '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.9) '@babel/plugin-proposal-decorators': 7.21.0(@babel/core@7.22.9) '@babel/plugin-transform-runtime': 7.22.9(@babel/core@7.22.9) - '@babel/preset-env': 7.22.9(@babel/core@7.22.9) + '@babel/preset-env': 7.22.5(@babel/core@7.22.9) '@babel/preset-typescript': 7.22.5(@babel/core@7.22.9) '@babel/runtime': 7.22.6 '@nrwl/devkit': 15.8.0(nx@16.6.0-beta.8)(typescript@5.1.3) @@ -5634,7 +5786,7 @@ packages: minimatch: 3.0.5 source-map-support: 0.5.19 tree-kill: 1.2.2 - tslib: 2.6.1 + tslib: 2.5.3 transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -5647,6 +5799,42 @@ packages: - typescript dev: true + /@nrwl/js@15.8.0(@swc-node/register@1.5.4)(@swc/core@1.3.51)(nx@15.8.0)(prettier@2.7.1)(typescript@5.1.3): + resolution: {integrity: sha512-l2Q7oFpzx6ul7G0nKpMkrvnIEaOY+X8fc2g2Db5WqpnnBdfkrtWXZPg/O4DQ1p9O6BXrZ+Q2AK9bfgnliiwyEg==} + dependencies: + '@babel/core': 7.22.9 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.9) + '@babel/plugin-proposal-decorators': 7.21.0(@babel/core@7.22.9) + '@babel/plugin-transform-runtime': 7.22.9(@babel/core@7.22.9) + '@babel/preset-env': 7.22.5(@babel/core@7.22.9) + '@babel/preset-typescript': 7.22.5(@babel/core@7.22.9) + '@babel/runtime': 7.22.6 + '@nrwl/devkit': 15.8.0(nx@15.8.0)(typescript@5.1.3) + '@nrwl/workspace': 15.8.0(@swc-node/register@1.5.4)(@swc/core@1.3.51)(eslint@8.46.0)(prettier@2.7.1)(typescript@5.1.3) + '@phenomnomnominal/tsquery': 4.1.1(typescript@5.1.3) + babel-plugin-const-enum: 1.2.0(@babel/core@7.22.9) + babel-plugin-macros: 2.8.0 + babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.22.9) + chalk: 4.1.2 + fast-glob: 3.2.7 + fs-extra: 11.1.1 + ignore: 5.2.0 + js-tokens: 4.0.0 + minimatch: 3.0.5 + source-map-support: 0.5.19 + tree-kill: 1.2.2 + tslib: 2.5.3 + transitivePeerDependencies: + - '@babel/traverse' + - '@swc-node/register' + - '@swc/core' + - debug + - nx + - prettier + - supports-color + - typescript + dev: true + /@nrwl/js@16.6.0-beta.8(@swc-node/register@1.5.4)(@swc/core@1.3.51)(@types/node@18.16.9)(nx@16.6.0-beta.8)(typescript@5.1.3)(verdaccio@5.15.4): resolution: {integrity: sha512-tRXayCZWPqXl0hxcsC3mg56IY6svE2GV4DWEYC4qo78ckhvd/TDmUZMvomB4VcR8pIxGR1I8T3B9jr/BxKZK7g==} dependencies: @@ -5673,7 +5861,7 @@ packages: optional: true dependencies: '@nrwl/devkit': 15.8.0(nx@15.8.0)(typescript@5.1.3) - '@nrwl/js': 15.8.0(@swc-node/register@1.5.4)(@swc/core@1.3.51)(eslint@8.46.0)(nx@16.6.0-beta.8)(prettier@2.7.1)(typescript@5.1.3) + '@nrwl/js': 15.8.0(@swc-node/register@1.5.4)(@swc/core@1.3.51)(nx@15.8.0)(prettier@2.7.1)(typescript@5.1.3) '@phenomnomnominal/tsquery': 4.1.1(typescript@5.1.3) eslint: 8.46.0 tmp: 0.2.1 @@ -7689,7 +7877,7 @@ packages: '@swc/core': 1.3.51(@swc/helpers@0.5.0) '@types/node': 16.18.36 '@types/semver': 7.5.0 - babel-loader: 9.1.3(@babel/core@7.22.9)(webpack@5.88.0) + babel-loader: 9.1.2(@babel/core@7.22.9)(webpack@5.88.0) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 @@ -8499,7 +8687,7 @@ packages: '@babel/core': 7.22.9 '@svgr/babel-preset': 8.0.0(@babel/core@7.22.9) camelcase: 6.3.0 - cosmiconfig: 8.2.0 + cosmiconfig: 8.1.3 snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -8535,7 +8723,7 @@ packages: '@svgr/core': '*' dependencies: '@svgr/core': 8.0.0 - cosmiconfig: 8.2.0 + cosmiconfig: 8.1.3 deepmerge: 4.3.1 svgo: 3.0.2 dev: true @@ -10451,6 +10639,11 @@ packages: hasBin: true dev: true + /ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -10464,6 +10657,11 @@ packages: resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==} dev: true + /ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -10566,7 +10764,7 @@ packages: dependencies: '@types/react': 18.2.14 react: 18.2.0 - tslib: 2.6.1 + tslib: 2.5.3 dev: true /aria-query@4.2.2: @@ -10897,19 +11095,6 @@ packages: webpack: 5.88.0(@swc/core@1.3.51)(esbuild@0.17.18) dev: true - /babel-loader@9.1.3(@babel/core@7.22.9)(webpack@5.88.0): - resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} - engines: {node: '>= 14.15.0'} - peerDependencies: - '@babel/core': ^7.12.0 - webpack: '>=5' - dependencies: - '@babel/core': 7.22.9 - find-cache-dir: 4.0.0 - schema-utils: 4.1.0 - webpack: 5.88.0(@swc/core@1.3.51)(esbuild@0.17.18) - dev: true - /babel-loader@9.1.3(@babel/core@7.22.9)(webpack@5.88.2): resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} engines: {node: '>= 14.15.0'} @@ -11382,24 +11567,25 @@ packages: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: true - /browser-sync-client@2.29.3: - resolution: {integrity: sha512-4tK5JKCl7v/3aLbmCBMzpufiYLsB1+UI+7tUXCCp5qF0AllHy/jAqYu6k7hUF3hYtlClKpxExWaR+rH+ny07wQ==} + /browser-sync-client@2.27.11: + resolution: {integrity: sha512-okMNfD2NasL/XD1/BclP3onXjhahisk3e/kTQ5HPDT/lLqdBqNDd6QFcjI5I1ak7na2hxKQSLjryql+7fp5gKQ==} engines: {node: '>=8.0.0'} dependencies: etag: 1.8.1 fresh: 0.5.2 mitt: 1.2.0 + rxjs: 5.5.12 + typescript: 4.9.5 dev: true - /browser-sync-ui@2.29.3: - resolution: {integrity: sha512-kBYOIQjU/D/3kYtUIJtj82e797Egk1FB2broqItkr3i4eF1qiHbFCG6srksu9gWhfmuM/TNG76jMfzAdxEPakg==} + /browser-sync-ui@2.27.11: + resolution: {integrity: sha512-1T/Y8Pp1R68aUL7zVSFq0nxtr258xWd/nTasCAHX2M6EsGaswVOFtXsw3bKqsr35z+J+LfVfOdz1HFLYKxdgrA==} dependencies: async-each-series: 0.1.1 - chalk: 4.1.2 connect-history-api-fallback: 1.6.0 immutable: 3.8.2 server-destroy: 1.0.1 - socket.io-client: 4.7.2 + socket.io-client: 4.5.4 stream-throttle: 0.1.3 transitivePeerDependencies: - bufferutil @@ -11407,21 +11593,21 @@ packages: - utf-8-validate dev: true - /browser-sync@2.29.3: - resolution: {integrity: sha512-NiM38O6XU84+MN+gzspVmXV2fTOoe+jBqIBx3IBdhZrdeURr6ZgznJr/p+hQ+KzkKEiGH/GcC4SQFSL0jV49bg==} + /browser-sync@2.27.11: + resolution: {integrity: sha512-U5f9u97OYJH66T0MGWWzG9rOQTW6ZmDMj97vsmtqwNS03JAwdLVES8eel2lD3rvAqQCNAFqaJ74NMacBI57vJg==} engines: {node: '>= 8.0.0'} hasBin: true dependencies: - browser-sync-client: 2.29.3 - browser-sync-ui: 2.29.3 + browser-sync-client: 2.27.11 + browser-sync-ui: 2.27.11 bs-recipes: 1.3.4 - chalk: 4.1.2 + bs-snippet-injector: 2.0.1 chokidar: 3.5.3 connect: 3.6.6 connect-history-api-fallback: 1.6.0 dev-ip: 1.0.1 easy-extender: 2.3.4 - eazy-logger: 4.0.1 + eazy-logger: 3.1.0 etag: 1.8.1 fresh: 0.5.2 fs-extra: 3.0.1 @@ -11431,6 +11617,7 @@ packages: micromatch: 4.0.5 opn: 5.3.0 portscanner: 2.2.0 + qs: 6.11.0 raw-body: 2.5.1 resp-modifier: 6.0.2 rx: 4.1.0 @@ -11438,8 +11625,8 @@ packages: serve-index: 1.9.1 serve-static: 1.13.2 server-destroy: 1.0.1 - socket.io: 4.7.2 - ua-parser-js: 1.0.35 + socket.io: 4.5.4 + ua-parser-js: 1.0.2 yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -11502,6 +11689,10 @@ packages: resolution: {integrity: sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==} dev: true + /bs-snippet-injector@2.0.1: + resolution: {integrity: sha512-4u8IgB+L9L+S5hknOj3ddNSb42436gsnGm1AuM15B7CdbkpQTyVWgIM5/JUBiKiRwGOR86uo0Lu/OsX+SAlJmw==} + dev: true + /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} dependencies: @@ -11522,6 +11713,7 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true /buffer-indexof-polyfill@1.0.2: resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} @@ -11803,6 +11995,17 @@ packages: traverse: 0.3.9 dev: true + /chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -12122,6 +12325,7 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -12545,6 +12749,12 @@ packages: webpack: 5.88.2(@swc/core@1.3.51)(esbuild@0.18.17) dev: true + /core-js-compat@3.30.2: + resolution: {integrity: sha512-nriW1nuJjUgvkEjIot1Spwakz52V9YkYHZAQG6A1eCgC8AA1p0zngrQEP9R0+V6hji5XilWKG1Bd0YRppmGimA==} + dependencies: + browserslist: 4.21.9 + dev: true + /core-js-compat@3.31.1: resolution: {integrity: sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA==} dependencies: @@ -12625,6 +12835,16 @@ packages: yaml: 1.10.2 dev: true + /cosmiconfig@8.1.3: + resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} + engines: {node: '>=14'} + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + dev: true + /cosmiconfig@8.2.0: resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} engines: {node: '>=14'} @@ -13687,11 +13907,11 @@ packages: lodash: 4.17.21 dev: true - /eazy-logger@4.0.1: - resolution: {integrity: sha512-2GSFtnnC6U4IEKhEI7+PvdxrmjJ04mdsj3wHZTFiw0tUtG4HCWzTr13ZYTk8XOGnA1xQMaDljoBOYlk3D/MMSw==} + /eazy-logger@3.1.0: + resolution: {integrity: sha512-/snsn2JqBtUSSstEl4R0RKjkisGHAhvYj89i7r3ytNUKW12y178KDZwXLXIgwDqLW6E/VRMT9qfld7wvFae8bQ==} engines: {node: '>= 0.8.0'} dependencies: - chalk: 4.1.2 + tfunk: 4.0.0 dev: true /ecc-jsbn@0.1.2: @@ -13772,13 +13992,13 @@ packages: objectorarray: 1.0.5 dev: true - /engine.io-client@6.5.2: - resolution: {integrity: sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==} + /engine.io-client@6.2.3: + resolution: {integrity: sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==} dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.4(supports-color@5.5.0) - engine.io-parser: 5.2.1 - ws: 8.11.0 + engine.io-parser: 5.0.4 + ws: 8.2.3 xmlhttprequest-ssl: 2.0.0 transitivePeerDependencies: - bufferutil @@ -13786,14 +14006,14 @@ packages: - utf-8-validate dev: true - /engine.io-parser@5.2.1: - resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==} + /engine.io-parser@5.0.4: + resolution: {integrity: sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==} engines: {node: '>=10.0.0'} dev: true - /engine.io@6.5.2: - resolution: {integrity: sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==} - engines: {node: '>=10.2.0'} + /engine.io@6.2.1: + resolution: {integrity: sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==} + engines: {node: '>=10.0.0'} dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.13 @@ -13803,8 +14023,8 @@ packages: cookie: 0.4.2 cors: 2.8.5 debug: 4.3.4(supports-color@5.5.0) - engine.io-parser: 5.2.1 - ws: 8.11.0 + engine.io-parser: 5.0.4 + ws: 8.2.3 transitivePeerDependencies: - bufferutil - supports-color @@ -14001,14 +14221,14 @@ packages: - supports-color dev: true - /esbuild-wasm@0.18.14: - resolution: {integrity: sha512-HKXsWTfBejkWApChQi+HTVuVuANwLWC33ebbWRJymvUizJt0TsiMDG2ilipEamj6f79TINR2byp7sULrWWUtPw==} + /esbuild-wasm@0.18.17: + resolution: {integrity: sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==} engines: {node: '>=12'} hasBin: true dev: true - /esbuild-wasm@0.18.17: - resolution: {integrity: sha512-9OHGcuRzy+I8ziF9FzjfKLWAPbvi0e/metACVg9k6bK+SI4FFxeV6PcZsz8RIVaMD4YNehw+qj6UMR3+qj/EuQ==} + /esbuild-wasm@0.18.20: + resolution: {integrity: sha512-xRXxH7q4FeC783rORSCyBPWQhcboleKXRPvt3Yl2YMe7jTtu/j7/zjWjqkVhO9BNVHSNVC6igG+XVTPWNQ+kRA==} engines: {node: '>=12'} hasBin: true dev: true @@ -14790,17 +15010,6 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 - /fast-glob@3.3.0: - resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - /fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} @@ -15709,7 +15918,7 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.2.12 ignore: 5.2.0 merge2: 1.4.1 slash: 3.0.0 @@ -15841,6 +16050,13 @@ packages: resolution: {integrity: sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==} dev: true + /has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: true + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true @@ -17574,7 +17790,7 @@ packages: http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.4 + nwsapi: 2.2.2 parse5: 7.1.2 saxes: 6.0.0 symbol-tree: 3.2.4 @@ -18907,7 +19123,7 @@ packages: '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-block-scoping': 7.22.5(@babel/core@7.22.9) - '@babel/plugin-transform-classes': 7.22.6(@babel/core@7.22.9) + '@babel/plugin-transform-classes': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-destructuring': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-flow-strip-types': 7.21.0(@babel/core@7.22.9) @@ -19760,8 +19976,8 @@ packages: commander: 11.0.0 convert-source-map: 2.0.0 dependency-graph: 0.11.0 - esbuild-wasm: 0.18.14 - fast-glob: 3.3.0 + esbuild-wasm: 0.18.20 + fast-glob: 3.2.12 find-cache-dir: 3.3.2 injection-js: 2.4.0 jsonc-parser: 3.2.0 @@ -20145,6 +20361,10 @@ packages: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} dev: true + /nwsapi@2.2.2: + resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} + dev: true + /nwsapi@2.2.4: resolution: {integrity: sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==} dev: true @@ -23441,6 +23661,13 @@ packages: resolution: {integrity: sha512-CiaiuN6gapkdl+cZUr67W6I8jquN4lkak3vtIsIWCl4XIPP8ffsoyN6/+PuGXnQy8Cu8W2y9Xxh31Rq4M6wUug==} dev: true + /rxjs@5.5.12: + resolution: {integrity: sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==} + engines: {npm: '>=2.0.0'} + dependencies: + symbol-observable: 1.0.1 + dev: true + /rxjs@6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} @@ -23554,6 +23781,7 @@ packages: chokidar: 3.5.3 immutable: 4.1.0 source-map-js: 1.0.2 + dev: true /sax@1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} @@ -24002,31 +24230,26 @@ packages: tslib: 2.6.1 dev: true - /socket.io-adapter@2.5.2: - resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} - dependencies: - ws: 8.11.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate + /socket.io-adapter@2.4.0: + resolution: {integrity: sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==} dev: true - /socket.io-client@4.7.2: - resolution: {integrity: sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==} + /socket.io-client@4.5.4: + resolution: {integrity: sha512-ZpKteoA06RzkD32IbqILZ+Cnst4xewU7ZYK12aS1mzHftFFjpoMz69IuhP/nL25pJfao/amoPI527KnuhFm01g==} engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.4(supports-color@5.5.0) - engine.io-client: 6.5.2 - socket.io-parser: 4.2.4 + engine.io-client: 6.2.3 + socket.io-parser: 4.2.1 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate dev: true - /socket.io-parser@4.2.4: - resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + /socket.io-parser@4.2.1: + resolution: {integrity: sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==} engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.0 @@ -24035,17 +24258,16 @@ packages: - supports-color dev: true - /socket.io@4.7.2: - resolution: {integrity: sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==} - engines: {node: '>=10.2.0'} + /socket.io@4.5.4: + resolution: {integrity: sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==} + engines: {node: '>=10.0.0'} dependencies: accepts: 1.3.8 base64id: 2.0.0 - cors: 2.8.5 debug: 4.3.4(supports-color@5.5.0) - engine.io: 6.5.2 - socket.io-adapter: 2.5.2 - socket.io-parser: 4.2.4 + engine.io: 6.2.1 + socket.io-adapter: 2.4.0 + socket.io-parser: 4.2.1 transitivePeerDependencies: - bufferutil - supports-color @@ -24154,6 +24376,7 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + dev: true /source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} @@ -24469,6 +24692,13 @@ packages: safe-buffer: 5.2.1 dev: true + /strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -24663,6 +24893,11 @@ packages: transitivePeerDependencies: - supports-color + /supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -24757,6 +24992,11 @@ packages: vue: 3.3.4 dev: true + /symbol-observable@1.0.1: + resolution: {integrity: sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw==} + engines: {node: '>=0.10.0'} + dev: true + /symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -24960,7 +25200,7 @@ packages: jest-worker: 27.5.1 schema-utils: 3.2.0 serialize-javascript: 6.0.1 - terser: 5.19.2 + terser: 5.18.0 webpack: 5.75.0(@swc/core@1.3.51)(esbuild@0.17.18) dev: true @@ -24986,7 +25226,7 @@ packages: jest-worker: 27.5.1 schema-utils: 3.2.0 serialize-javascript: 6.0.1 - terser: 5.19.2 + terser: 5.18.0 webpack: 5.88.0(@swc/core@1.3.51)(esbuild@0.17.18) dev: true @@ -25012,7 +25252,7 @@ packages: jest-worker: 27.5.1 schema-utils: 3.2.0 serialize-javascript: 6.0.1 - terser: 5.19.2 + terser: 5.18.0 webpack: 5.88.2(@swc/core@1.3.51)(esbuild@0.18.17) dev: true @@ -25027,6 +25267,17 @@ packages: source-map-support: 0.5.21 dev: true + /terser@5.18.0: + resolution: {integrity: sha512-pdL757Ig5a0I+owA42l6tIuEycRuM7FPY4n62h44mRLRfnOxJkkOHd6i89dOpwZlpF6JXBwaAHF6yWzFrt+QyA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.3 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + /terser@5.19.2: resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} engines: {node: '>=10'} @@ -25036,6 +25287,7 @@ packages: acorn: 8.10.0 commander: 2.20.3 source-map-support: 0.5.21 + dev: true /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -25055,6 +25307,13 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /tfunk@4.0.0: + resolution: {integrity: sha512-eJQ0dGfDIzWNiFNYFVjJ+Ezl/GmwHaFTBTjrtqNPW0S7cuVDBrZrmzUz6VkMeCR4DZFqhd4YtLwsw3i2wYHswQ==} + dependencies: + chalk: 1.1.3 + dlv: 1.1.3 + dev: true + /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -25413,10 +25672,6 @@ packages: /tslib@2.5.3: resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} - /tslib@2.6.0: - resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} - dev: true - /tslib@2.6.1: resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} @@ -25653,8 +25908,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - /ua-parser-js@1.0.35: - resolution: {integrity: sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==} + /ua-parser-js@1.0.2: + resolution: {integrity: sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==} dev: true /ufo@1.1.2: @@ -26210,7 +26465,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.4.7(@types/node@18.16.9)(less@4.1.3)(sass@1.64.1)(stylus@0.59.0)(terser@5.19.2) + vite: 4.4.7(@types/node@18.16.9)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) transitivePeerDependencies: - '@types/node' - less @@ -26257,6 +26512,45 @@ packages: optionalDependencies: fsevents: 2.3.2 + /vite@4.4.7(@types/node@18.16.9)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0): + resolution: {integrity: sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.16.9 + esbuild: 0.18.17 + less: 4.1.3 + postcss: 8.4.27 + rollup: 3.27.2 + sass: 1.55.0 + stylus: 0.59.0 + optionalDependencies: + fsevents: 2.3.2 + dev: false + /vite@4.4.7(@types/node@18.16.9)(less@4.1.3)(sass@1.64.1)(stylus@0.59.0)(terser@5.19.2): resolution: {integrity: sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -26295,6 +26589,7 @@ packages: terser: 5.19.2 optionalDependencies: fsevents: 2.3.2 + dev: true /vitest@0.32.0(less@4.1.3)(sass@1.55.0)(stylus@0.59.0): resolution: {integrity: sha512-SW83o629gCqnV3BqBnTxhB10DAwzwEx3z+rqYZESehUB+eWsJxwcBQx7CKy0otuGMJTYh7qCVuUX23HkftGl/Q==} @@ -26760,7 +27055,7 @@ packages: '@webassemblyjs/wasm-parser': 1.11.1 acorn: 8.10.0 acorn-import-assertions: 1.9.0(acorn@8.10.0) - browserslist: 4.21.9 + browserslist: 4.21.7 chrome-trace-event: 1.0.3 enhanced-resolve: 5.15.0 es-module-lexer: 0.9.3 @@ -27134,12 +27429,12 @@ packages: optional: true dev: true - /ws@8.11.0: - resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + /ws@8.12.0: + resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true @@ -27147,8 +27442,8 @@ packages: optional: true dev: true - /ws@8.12.0: - resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==} + /ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -27160,12 +27455,12 @@ packages: optional: true dev: true - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + /ws@8.2.3: + resolution: {integrity: sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + utf-8-validate: ^5.0.2 peerDependenciesMeta: bufferutil: optional: true @@ -27325,7 +27620,3 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: true - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false