diff --git a/.circleci/config.yml b/.circleci/config.yml index b392f5c30..a61e98d50 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -452,8 +452,8 @@ jobs: working_directory: 'packages/server' - run: - name: 'Lint with TypeScript Compiler' - command: yarn lint:tsc + name: 'Lint' + command: yarn lint:ci working_directory: 'packages/server' - run: @@ -516,7 +516,7 @@ jobs: - run: name: Lint everything - command: yarn lint + command: yarn lint:ci working_directory: 'packages/frontend-2' test-viewer: @@ -550,7 +550,7 @@ jobs: - run: name: Lint everything - command: yarn lint + command: yarn lint:ci working_directory: 'packages/viewer' - run: @@ -588,17 +588,17 @@ jobs: - run: name: Lint tailwind theme - command: yarn lint + command: yarn lint:ci working_directory: 'packages/tailwind-theme' - run: name: Lint ui components - command: yarn lint + command: yarn lint:ci working_directory: 'packages/ui-components' - run: name: Lint component nuxt package - command: yarn lint + command: yarn lint:ci working_directory: 'packages/ui-components-nuxt' - run: @@ -1018,7 +1018,7 @@ jobs: command: yarn build:public - run: name: Lint viewer-sandbox - command: yarn lint + command: yarn lint:ci working_directory: 'packages/viewer-sandbox' - run: name: Build viewer-sandbox diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 716ac3a54..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,47 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -const config = { - root: true, - parserOptions: { - ecmaVersion: 2022 - }, - env: { - es2022: true, - node: true, - commonjs: true - }, - extends: ['eslint:recommended', 'prettier'], - rules: { - camelcase: [ - 1, - { - properties: 'always' - } - ], - 'no-var': 'error', - 'no-alert': 'error', - eqeqeq: 'error', - 'prefer-const': 'warn', - 'object-shorthand': 'warn' - }, - overrides: [ - { - files: '*.mjs', - parserOptions: { - sourceType: 'module' - } - } - ], - ignorePatterns: [ - 'node_modules', - 'dist', - 'dist-*', - 'public', - 'events.json', - '.*.{ts,js,vue,tsx,jsx}', - 'generated/**/*', - '.nuxt', - '.output' - ] -} - -module.exports = config diff --git a/.husky/pre-commit b/.husky/pre-commit index 9c3e8a14d..655ecfb61 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -5,7 +5,7 @@ set -e if [ -n "$CI" ] then echo "running eslint" - yarn lint + yarn eslint:projectwide echo "...eslint done" echo "running prettier" yarn prettier:check diff --git a/.prettierignore b/.prettierignore index 511e294a8..fe7c119be 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,6 +15,7 @@ packages/viewer/example/speckleviewer.web.js **/nuxt-modules/**/templates/*.js packages/frontend-2/lib/common/generated/**/* packages/dui3/lib/common/generated/**/* +packages/server/introspected-schema.graphql package-lock.json yarn.lock diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..be14e44d2 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,112 @@ +import globals from 'globals' +import js from '@eslint/js' +import prettierConfig from 'eslint-config-prettier' +import { fileURLToPath } from 'url' +import { dirname } from 'path' + +/** + * TODO: + * - Check speed (inspect ignored files, that we're not processing junk) + * - Fix lint-staged + */ + +/** + * Feed in import.meta.url in your .mjs module to get the equivalent of __dirname + * @param {string} importMetaUrl + */ +export const getESMDirname = (importMetaUrl) => { + return dirname(fileURLToPath(importMetaUrl)) +} + +/** + * Configs that should only apply to repo root (shouldn't be inherited in subdirectories) + * @type {Array} + */ +const rootConfigs = [ + { + ignores: [ + 'packages/**/*', + '.circleci', + '.devcontainer', + '.github', + '.husky', + '.vscode', + '.yarn', + 'docker', + 'node_modules', + 'test-queries', + 'setup' + ] + }, + { + files: ['*.{js,mjs,cjs}', '.*.{js,mjs,cjs}', 'utils/*.{js,mjs,cjs}'], + languageOptions: { + sourceType: 'commonjs', + globals: { + ...globals.node + } + } + }, + { + files: ['*.mjs', '.*.mjs', 'utils/*.mjs'], + languageOptions: { + sourceType: 'module' + } + } +] + +/** + * Base configs that should be inherited in all packages as well + * @type {Array} + */ +export const baseConfigs = [ + { + ignores: [ + '**/node_modules/**', + '**/dist/**', + '**/dist-*/**', + '**/public/**', + '**/events.json', + '**/generated/**/*', + '**/.nuxt/**', + '**/.output/**' + ] + }, + { + files: ['**/*.mjs'], + languageOptions: { + sourceType: 'module' + } + }, + { + files: ['**/*.cjs'], + languageOptions: { + sourceType: 'commonjs' + } + }, + { + files: ['**/*.{js,mjs,cjs}', '**/.*.{js,mjs,cjs}'], + ...js.configs.recommended + }, + prettierConfig, + { + rules: { + camelcase: [ + 1, + { + properties: 'always' + } + ], + 'no-var': 'error', + 'no-alert': 'error', + eqeqeq: 'error', + 'prefer-const': 'warn', + 'object-shorthand': 'warn' + } + } +] + +const configs = [...baseConfigs, ...rootConfigs] + +export { globals, prettierConfig } +export default configs diff --git a/lint-staged.config.js b/lint-staged.config.js index dc0068565..d605b883f 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,22 +1,4 @@ -const micromatch = require('micromatch') - -const extList = ['ts', 'js', 'vue', 'tsx', 'jsx', 'json'].join(',') module.exports = { - '*.{js,ts,vue}': (files) => { - const finalFiles = micromatch.not(files, [ - // Filter out files that start with a period, since they're ignored by default - `**/.*.{${extList}}`, - // Filter out generated folder files - `**/generated/**/*`, - // Filter out types in object loader - '**/packages/objectloader/types/**/*', - // Filter out nuxt plugin templates - '**/templates/plugin.js', - // ui-components ignore - '**/packages/ui-components/utils/tailwind-configure.d.ts' - ]) - - return 'eslint --cache --max-warnings=0 ' + finalFiles.join(' ') - }, + '*.{js,ts,vue,cjs,mjs,cts,mts}': 'yarn eslint:projectwide', '*.**': 'prettier --check --ignore-unknown' } diff --git a/package.json b/package.json index 8af86b2c3..1b6beb1c4 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "build:public": "yarn workspaces foreach -ptv --no-private run build", "build:tailwind-deps": "yarn workspaces foreach -iv -j unlimited --include '{@speckle/shared,@speckle/tailwind-theme,@speckle/ui-components}' run build", "ensure:tailwind-deps": "node ./utils/ensure-tailwind-deps.mjs", - "lint": "node --max-old-space-size=4096 ./node_modules/eslint/bin/eslint.js . --ext .js,.ts,.vue --max-warnings=0", "helm:readme:generate": "./utils/helm/update-schema-json.sh", "prettier:check": "prettier --check .", "prettier:fix": "prettier --write .", @@ -37,38 +36,47 @@ "dev:shared": "yarn workspace @speckle/shared dev", "prepare": "husky install", "postinstall": "husky install", - "cm": "cz" + "cm": "cz", + "eslint:inspect": "eslint-config-inspector", + "eslint:projectwide": "node ./utils/eslint-projectwide.mjs" }, "devDependencies": { + "@eslint/config-inspector": "^0.4.10", + "@eslint/js": "^9.4.0", "@rollup/plugin-typescript": "^11.1.0", "@swc/core": "^1.2.222", - "@types/eslint": "^8.4.1", + "@types/eslint": "^8.56.10", + "@types/eslint__js": "^8.42.3", "@types/lockfile": "^1.0.2", "commitizen": "^4.2.5", "cross-env": "^7.0.3", "cz-conventional-changelog": "^3.3.0", - "eslint": "^8.11.0", - "eslint-config-prettier": "^8.5.0", + "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", + "eslint-flat-config-utils": "^0.2.5", + "globals": "^15.4.0", "husky": "^7.0.4", "lint-staged": "^12.3.7", "lockfile": "^1.0.4", "pino-pretty": "^9.1.1", "prettier": "^2.5.1", "ts-node": "^10.9.1", - "tsconfig-paths": "^4.0.0" + "tsconfig-paths": "^4.0.0", + "zx": "^8.1.2" }, "resolutions": { "@babel/traverse": ">=7.23.2", "@microsoft/api-extractor/semver": "^7.5.4", "@rushstack/node-core-library/semver": "^7.5.4", - "@typescript-eslint/eslint-plugin": "^6.4.1", - "@typescript-eslint/parser": "^6.4.1", + "@typescript-eslint/eslint-plugin": "^7.12.0", + "@typescript-eslint/parser": "^7.12.0", + "typescript-eslint": "^7.12.0", "@types/react": "file:./packages/frontend-2/type-augmentations/stubs/types__react", "axios": ">=1.6.0", "core-js": "3.22.4", "core-js-compat/semver": "^7.5.4", - "eslint": "^8.11.0", - "eslint-config-prettier": "^8.5.0", + "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", "express": ">=4.19.2", "fast-xml-parser": ">=4.2.5", "graphql": "^15.3.0", diff --git a/packages/dui3/.eslintrc.js b/packages/dui3/.eslintrc.js deleted file mode 100644 index dbc33e71c..000000000 --- a/packages/dui3/.eslintrc.js +++ /dev/null @@ -1,119 +0,0 @@ -const mainExtends = [ - 'plugin:nuxt/recommended', - 'plugin:vue/vue3-recommended', - 'prettier' -] - -/** @type {import('eslint').Linter.Config} */ -const config = { - env: { - node: true - }, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - parser: '@typescript-eslint/parser', - tsconfigRootDir: __dirname, - project: ['./tsconfig.eslint.json'], - extraFileExtensions: ['.vue'] - }, - extends: [...mainExtends], - plugins: ['@typescript-eslint'], - ignorePatterns: [ - '**/templates/*', - 'coverage', - 'lib/common/generated/**/*', - 'storybook-static', - '!.storybook', - '.nuxt', - '.output' - ], - rules: { - camelcase: [ - 'error', - { - properties: 'always', - allow: ['^[\\w]+_[\\w]+Fragment$'] - } - ], - 'no-alert': 'error', - eqeqeq: ['error', 'always', { null: 'always' }], - 'no-console': 'off', - 'no-var': 'error' - }, - overrides: [ - { - files: '*.test.{ts,js}', - env: { - jest: true - } - }, - { - files: './{components|pages|store|lib}/*.{js,ts,vue}', - env: { - node: false, - browser: true - } - }, - { - files: '*.{ts,tsx,vue}', - extends: ['plugin:@typescript-eslint/recommended', ...mainExtends], - rules: { - '@typescript-eslint/no-explicit-any': ['error'], - '@typescript-eslint/no-unsafe-argument': ['error'], - '@typescript-eslint/no-unsafe-assignment': 'error', - '@typescript-eslint/no-unsafe-call': 'error', - '@typescript-eslint/no-unsafe-member-access': 'error', - '@typescript-eslint/no-unsafe-return': 'error', - '@typescript-eslint/no-for-in-array': ['error'], - '@typescript-eslint/restrict-template-expressions': ['error'], - '@typescript-eslint/restrict-plus-operands': ['error'], - '@typescript-eslint/await-thenable': ['warn'], - '@typescript-eslint/ban-types': ['warn'], - 'require-await': 'off', - '@typescript-eslint/require-await': 'error', - 'no-undef': 'off' - } - }, - { - files: '*.vue', - plugins: ['vuejs-accessibility'], - extends: [ - 'plugin:@typescript-eslint/recommended', - ...mainExtends, - 'plugin:vuejs-accessibility/recommended' - ], - rules: { - 'vue/component-tags-order': [ - 'error', - { order: ['docs', 'template', 'script', 'style'] } - ], - 'vue/require-default-prop': 'off', - 'vue/multi-word-component-names': 'off', - 'vue/component-name-in-template-casing': [ - 'error', - 'PascalCase', - { registeredComponentsOnly: false } - ], - 'vuejs-accessibility/label-has-for': [ - 'error', - { - required: { - some: ['nesting', 'id'] - } - } - ] - } - }, - { - files: '*.d.ts', - rules: { - 'no-var': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-types': 'off' - } - } - ] -} - -module.exports = config diff --git a/packages/dui3/components/header/UserAccount.vue b/packages/dui3/components/header/UserAccount.vue index 9e0608bfb..d66d50b05 100644 --- a/packages/dui3/components/header/UserAccount.vue +++ b/packages/dui3/components/header/UserAccount.vue @@ -26,7 +26,7 @@ diff --git a/packages/frontend-2/components/form/MarkdownEditor.vue b/packages/frontend-2/components/form/MarkdownEditor.vue index 36d78fa95..72c4e0f1b 100644 --- a/packages/frontend-2/components/form/MarkdownEditor.vue +++ b/packages/frontend-2/components/form/MarkdownEditor.vue @@ -63,7 +63,7 @@ const props = withDefaults( defineModel() const { value } = useField(props.name, props.rules) -const body = computed(() => (process.client ? document.body : undefined)) +const body = computed(() => (import.meta.client ? document.body : undefined)) const isEditing = ref(true) const isPreviewDisabled = computed(() => !(value.value || '').trim().length) diff --git a/packages/frontend-2/components/form/json/ArrayListRenderer.vue b/packages/frontend-2/components/form/json/ArrayListRenderer.vue index 0bdb37954..330756e28 100644 --- a/packages/frontend-2/components/form/json/ArrayListRenderer.vue +++ b/packages/frontend-2/components/form/json/ArrayListRenderer.vue @@ -128,7 +128,6 @@ const onAdd = () => { const path = control.value.path const val = createDefaultValue(control.value.schema, props.schema) - // eslint-disable-next-line @typescript-eslint/unbound-method const addItem = baseControl.addItem if (!addItem) return diff --git a/packages/frontend-2/components/form/json/DateTimeControlRenderer.vue b/packages/frontend-2/components/form/json/DateTimeControlRenderer.vue index 9c25d1b36..a09cbc167 100644 --- a/packages/frontend-2/components/form/json/DateTimeControlRenderer.vue +++ b/packages/frontend-2/components/form/json/DateTimeControlRenderer.vue @@ -43,7 +43,6 @@ const { onChangeValueConverter: (val) => toISOString(val as string) }) -// eslint-disable-next-line @typescript-eslint/restrict-template-expressions const modelValue = computed(() => control.value.data ? (control.value.data as string).replace(zuluTimeSuffix, '') diff --git a/packages/frontend-2/components/form/json/EnumOneOfControlRenderer.vue b/packages/frontend-2/components/form/json/EnumOneOfControlRenderer.vue index 1f8c4512f..3d8d8af9b 100644 --- a/packages/frontend-2/components/form/json/EnumOneOfControlRenderer.vue +++ b/packages/frontend-2/components/form/json/EnumOneOfControlRenderer.vue @@ -13,6 +13,5 @@ const props = defineProps({ ...rendererProps() }) -// eslint-disable-next-line @typescript-eslint/unbound-method const controlOverrides = useJsonFormsOneOfEnumControl(props) diff --git a/packages/frontend-2/components/header/NavShare.vue b/packages/frontend-2/components/header/NavShare.vue index 79aa7fef9..7c7b84241 100644 --- a/packages/frontend-2/components/header/NavShare.vue +++ b/packages/frontend-2/components/header/NavShare.vue @@ -1,3 +1,4 @@ +