diff --git a/.changeset/lazy-sheep-pay.md b/.changeset/lazy-sheep-pay.md new file mode 100644 index 000000000..08b8c1cf9 --- /dev/null +++ b/.changeset/lazy-sheep-pay.md @@ -0,0 +1,7 @@ +--- +"@ilo-org/prettier-config": major +--- + +### Prettier 3 Upgrade + +We've upgraded to Prettier 3. This is a breaking change because Prettier 3 introduces several updates and deprecations that might impact your current formatting setup. diff --git a/.changeset/tidy-kiwis-mate.md b/.changeset/tidy-kiwis-mate.md new file mode 100644 index 000000000..156e7fdf4 --- /dev/null +++ b/.changeset/tidy-kiwis-mate.md @@ -0,0 +1,5 @@ +--- +"@ilo-org/typescript-config": major +--- + +Typescript package no longer exports lib with `["dom", "dom.iterable"]`, so it's more generic and can be used in more projects. This is a breaking change because it might impact your current TypeScript setup. diff --git a/.changeset/wicked-ads-worry.md b/.changeset/wicked-ads-worry.md new file mode 100644 index 000000000..5ee7fcdcb --- /dev/null +++ b/.changeset/wicked-ads-worry.md @@ -0,0 +1,19 @@ +--- +"@ilo-org/eslint-config": major +--- + +### ESLint 9 Upgrade + +We've upgraded to ESLint 9! 🚀 This is a breaking change because ESLint 9 introduces several updates and deprecations that might impact your current linting setup. + +The `@ilo-org/eslint-config` package now uses ESLint 9 and exports only flat configuration objects. + +Here are the available configs: + +| Config Name | Description | Internal Extends | +| ----------- | -------------------------------- | ---------------- | +| js | Base JavaScript config | ⛔ | +| recommended | Recommended one with `js` + `ts` | `js` | +| react | React config | `ts` -> `js` | + +Make sure to check out the [ESLint 9 migration guide](https://eslint.org/docs/latest/use/migrate-to-9.0.0) for details on updating your configuration. diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 468b47dc3..000000000 --- a/.eslintignore +++ /dev/null @@ -1,33 +0,0 @@ -node_modules/ -.next/ -dist/ -pages/ -lib/ - -brand-assets/dist/ -brand-assets/node_modules/ - -icon-builder-helpers/node_modules/ - -icons/es/ -icons/lib/ -icons/node_modules/ -icons/svg/ -icons/umd/ - -icons-react/es/ -icons-react/lib/ -icons-react/next/ -icons-react/node_modules/ -icons-react/umd/ - -react/lib/ -react/node_modules/ -react/storybook-static/ - -styles/build/ -styles/node_modules/ - -themes/build/ -themes/node_modules/ - diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 33328d11d..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,27 +0,0 @@ -const baseConfig = require("./config/eslint-config"); -const tsConfig = require("./config/eslint-config/typescript"); - -module.exports = { - /* =============== */ - /* Global Settings */ - /* =============== */ - root: true, - extends: [baseConfig], - // Extend the default config and add any specific settings for this project - ignorePatterns: ["node_modules/", "lib/", "dist/"], - overrides: [ - /* =================== */ - /* TypeScript Settings */ - /* =================== */ - { - // Which files the override will apply to relative to the package root - files: ["**/*.{ts,tsx}"], - extends: [tsConfig], - // The typescript parser options for this package, which will be different - // from other packages - parserOptions: { - project: ["./tsconfig.json"], - }, - }, - ], -}; diff --git a/.husky/install.js b/.husky/install.js new file mode 100644 index 000000000..bea3de510 --- /dev/null +++ b/.husky/install.js @@ -0,0 +1,16 @@ +/** + * This optionally loads husky except in CI environments + * like Github Actions where the lint-staged pre-commit hook + * seems to break. CI is always set to true in Github Actions + * so there's no need to set it manually. + */ + +if (process.env.CI === "true") { + process.stdout.write("CI detected, skipping husky install \n"); + process.exit(0); +} + +const husky = await import("husky"); +process.stdout.write("husky - Installing Git hooks \n"); + +husky.default.install(); diff --git a/config/eslint-config/README.md b/config/eslint-config/README.md index 147c6c115..4a90cec5b 100644 --- a/config/eslint-config/README.md +++ b/config/eslint-config/README.md @@ -10,42 +10,59 @@ npm install -D @ilo-org/eslint-config ## Usage -You can use `@ilo-org/eslint-config` in your project by extending it in your -`eslint` configuration. For example, if we had an `.eslintrc` file: +`@ilo-org/eslint-config` provides a list of ESLint flat configurations: -```json -{ - "extends": ["@ilo-org/eslint-config"] -} +| Config Name | Description | Internal Extends | +| ----------- | ------------------------------------- | ---------------- | +| js | Base JavaScript config | ⛔ | +| recommended | Recommended configuration `js` + `ts` | `js` | +| react | React Typescript config | `ts` -> `js` | + +You can use any configuration you like by simply including it inside your eslint config + +Just export it + +```js +import configs from "@ilo-org/eslint-config"; + +export default configs.recommended; ``` -## TypeScript - -To use this configuration in a project with Typescript, you can add an `overrides` property to your `.eslintrc`. Here's an example: - -```cjs -// .eslintrc.cjs - -module.exports = { - extends: ["@ilo-org/eslint-config"], - ignorePatterns: ["node_modules/"], - overrides: [ - /* =================== */ - /* TypeScript Settings */ - /* =================== */ - { - // Which files the override will apply to relative to the package root - files: ["**/*.{ts,tsx}"], - extends: ["@ilo-org/eslint-config/typescript"], - // Your typescript parser options - parserOptions: { - project: ["./tsconfig.json"], - }, +or extend and add your own + +```js +import configs from "@ilo-org/eslint-config"; + +export default [ + ...configs.recommended, + { + rules: { + "no-console": "warn", }, - ], -}; + }, +]; ``` +## Opinionated rules + +🚨 - Displayed as an error +🚧 - Displayed as a warning +✅ - Allowed + +| Rule | Severity | Description | +| ------------------------------------------------- | -------- | --------------------------------------------------------------- | +| "prettier/prettier" | 🚨 | Is strong about formatting | +| "no-console" | 🚧 | Prevents the use of `console.log` but allows `warn` and `error` | +| "no-duplicate-imports" | 🚧 | Prevents duplicate imports | +| "no-await-in-loop" | 🚧 | Prevents `await` inside loops | +| "no-unused-vars" | 🚧 | Prevents unused variables but allows `_` to be ignored | +| "@typescript-eslint/class-literal-property-style" | 🚧 | Normalizes class literal properties | +| "@typescript-eslint/no-duplicate-enum-values" | 🚧 | | +| "@typescript-eslint/prefer-for-of" | 🚧 | Enforces the use of `for-of` | +| "@typescript-eslint/consistent-type-definitions" | 🚧 | `interface` is preferred | +| "@typescript-eslint/ban-ts-comments" | ✅ | | +| "@typescript-eslint/ban-ts-ignores" | ✅ | | + ## 📝 License Licensed under the [Apache 2.0 License](/LICENSE). diff --git a/config/eslint-config/base.js b/config/eslint-config/base.js deleted file mode 100644 index 7f06e673c..000000000 --- a/config/eslint-config/base.js +++ /dev/null @@ -1,52 +0,0 @@ -/* Base Eslint Settings for JS/JSX */ - -module.exports = { - env: { - browser: true, - es6: true, - jest: true, - node: true, - }, - globals: { - React: "writable", - }, - ignorePatterns: ["node_modules/"], - settings: { - react: { - version: "detect", - }, - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, - }, - plugins: ["jsx-a11y", "prettier"], - extends: [ - "eslint:recommended", - "plugin:jsx-a11y/recommended", - "plugin:react-hooks/recommended", - "plugin:storybook/recommended", - "plugin:prettier/recommended", - ], - rules: { - "jsx-a11y/label-has-associated-control": [ - "error", - { - assert: "either", - controlComponents: [], - depth: 25, - labelAttributes: [], - labelComponents: [], - }, - ], - "jsx-a11y/click-events-have-key-events": "off", - "jsx-a11y/media-has-caption": "off", - "jsx-a11y/no-noninteractive-element-interactions": "off", - "react/prop-types": "off", - "react/react-in-jsx-scope": "off", - "prettier/prettier": "error", - }, -}; diff --git a/config/eslint-config/index.js b/config/eslint-config/index.js index 2358ad4d9..cbd59ffef 100644 --- a/config/eslint-config/index.js +++ b/config/eslint-config/index.js @@ -1,5 +1,11 @@ -"use strict"; +import js from "./variants/base-js.config.js"; +import ts from "./variants/base-ts.config.js"; +import react from "./variants/react.config.js"; -module.exports = { - extends: [require.resolve("./base")], +const configs = { + js, + recommended: ts, + react, }; + +export default configs; diff --git a/config/eslint-config/package.json b/config/eslint-config/package.json index a1e57dc52..488cb15f3 100644 --- a/config/eslint-config/package.json +++ b/config/eslint-config/package.json @@ -11,6 +11,7 @@ "files": [ "*.{js,ts,json}" ], + "type": "module", "publishConfig": { "access": "public" }, @@ -25,16 +26,17 @@ }, "homepage": "https://github.com/international-labour-organization/designsystem#readme", "dependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.7", - "@typescript-eslint/parser": "^5.59.7", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-storybook": "^0.6.12" + "@types/eslint__js": "^8.42.3", + "eslint-config-prettier": "^9.1.0", + "eslint-config-turbo": "^2.1.1", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.36.0", + "eslint-plugin-react-hooks": "5.1.0-rc-d6cb4e77-20240911", + "globals": "^15.9.0", + "typescript-eslint": "^8.5.0" }, "peerDependencies": { - "eslint": ">= 8" + "eslint": "9.x" } } diff --git a/config/eslint-config/typescript.js b/config/eslint-config/typescript.js deleted file mode 100644 index f5c082773..000000000 --- a/config/eslint-config/typescript.js +++ /dev/null @@ -1,20 +0,0 @@ -/* Eslint Settings for TS/TSX */ - -module.exports = { - parser: "@typescript-eslint/parser", - globals: { - React: "writable", - }, - extends: [ - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - ], - plugins: ["@typescript-eslint"], - rules: { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/ban-ts-ignore": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-empty-function": "off", - }, -}; diff --git a/config/eslint-config/variants/base-js.config.js b/config/eslint-config/variants/base-js.config.js new file mode 100644 index 000000000..d671708d5 --- /dev/null +++ b/config/eslint-config/variants/base-js.config.js @@ -0,0 +1,30 @@ +import js from "@eslint/js"; +import prettier from "eslint-plugin-prettier/recommended"; +import globals from "globals"; +import { IgnoreConfig } from "./ignores.config.js"; + +/** @type {import("eslint").Linter.Config} */ +const BaseJSConfig = { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + rules: { + "no-console": ["warn", { allow: ["warn", "error"] }], + "prettier/prettier": "error", + "no-duplicate-imports": "warn", + "no-await-in-loop": "warn", + "no-unused-vars": [ + "warn", + { + ignoreRestSiblings: true, + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + }, +}; + +export default [js.configs.recommended, prettier, BaseJSConfig, IgnoreConfig]; diff --git a/config/eslint-config/variants/base-ts.config.js b/config/eslint-config/variants/base-ts.config.js new file mode 100644 index 000000000..b4b2ef63b --- /dev/null +++ b/config/eslint-config/variants/base-ts.config.js @@ -0,0 +1,59 @@ +import BaseJSConfig from "./base-js.config.js"; +import ts from "typescript-eslint"; +import { resolve } from "path"; + +const tsconfigPath = resolve(process.cwd(), "tsconfig.json"); + +const RecommendedTSConfig = ts.configs.recommendedTypeChecked.map((config) => ({ + ...config, + files: ["**/*.ts", "**/*.tsx"], + languageOptions: { + ...config.languageOptions, + parserOptions: { + project: tsconfigPath, + }, + }, +})); + +/** @type {import("eslint").Linter.Config} */ +const BaseTSConfig = { + files: ["**/*.ts"], + plugins: { + "@typescript-eslint": ts.plugin, + }, + languageOptions: { + parser: ts.parser, + parserOptions: { + sourceType: "module", + project: tsconfigPath, + }, + }, + rules: { + "@typescript-eslint/class-literal-property-style": "warn", + "@typescript-eslint/no-duplicate-enum-values": "warn", + "@typescript-eslint/prefer-for-of": "warn", + "@typescript-eslint/consistent-type-definitions": ["error", "interface"], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + ignoreRestSiblings: true, + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + // Migrated from old typescript-eslint config + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/ban-ts-ignore": "off", + }, +}; + +export default ts.config( + ...BaseJSConfig, + ...RecommendedTSConfig, + { + // disable type-aware linting on JS files + files: ["**/*.js"], + ...ts.configs.disableTypeChecked, + }, + BaseTSConfig +); diff --git a/config/eslint-config/variants/ignores.config.js b/config/eslint-config/variants/ignores.config.js new file mode 100644 index 000000000..a20d5e621 --- /dev/null +++ b/config/eslint-config/variants/ignores.config.js @@ -0,0 +1,14 @@ +/** @type {import("eslint").Linter.Config} */ +const IgnoreConfig = { + ignores: [ + "**/*.config.{js,mjs,ts}", + "**/*.setup.{js,mjs,ts}", + "lib/", + "dist/", + "build/", + ".storybook/", + "storybook-static/", + ], +}; + +export { IgnoreConfig }; diff --git a/config/eslint-config/variants/react.config.js b/config/eslint-config/variants/react.config.js new file mode 100644 index 000000000..097ea8663 --- /dev/null +++ b/config/eslint-config/variants/react.config.js @@ -0,0 +1,57 @@ +import baseTsConfig from "./base-ts.config.js"; +import react from "eslint-plugin-react"; +import a11y from "eslint-plugin-jsx-a11y"; +import hooks from "eslint-plugin-react-hooks"; + +/** @type {import("eslint").Linter.Config} */ +const ReactConfig = { + files: ["**/*.{tsx,jsx}"], + settings: { + react: { + version: "18", + }, + }, + plugins: { + "react-hooks": hooks, + }, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + rules: { + // Migrated from old react config + "jsx-a11y/label-has-associated-control": [ + "error", + { + assert: "either", + controlComponents: [], + depth: 25, + labelAttributes: [], + labelComponents: [], + }, + ], + "jsx-a11y/click-events-have-key-events": "off", + "jsx-a11y/media-has-caption": "off", + "jsx-a11y/no-noninteractive-element-interactions": "off", + "react/prop-types": "off", + "react/display-name": "off", + }, +}; + +export default [ + ...baseTsConfig, + { + ...react.configs.flat.recommended, + settings: { + react: { + version: "18", + }, + }, + }, + react.configs.flat["jsx-runtime"], + a11y.flatConfigs.recommended, + ReactConfig, +]; diff --git a/config/prettier-config/README.md b/config/prettier-config/README.md index f01cb3722..a378d374c 100644 --- a/config/prettier-config/README.md +++ b/config/prettier-config/README.md @@ -14,10 +14,9 @@ You can use this prettier configuration by creating a `prettier.config.js` file in the root of project and using this package in the following way: ```js -"use strict"; +import prettierConfig from "@ilo-org/prettier-config"; -const prettierConfig = require("@ilo-org/prettier-config"); -module.exports = prettierConfig; +export default prettierConfig; ``` ## 📝 License diff --git a/config/prettier-config/index.js b/config/prettier-config/index.js index 67a214cf0..0fb5b627b 100644 --- a/config/prettier-config/index.js +++ b/config/prettier-config/index.js @@ -1,9 +1,12 @@ -"use strict"; - -module.exports = { +/** + * @type {import("prettier").Config} + */ +const config = { endOfLine: "lf", singleQuote: false, tabWidth: 2, trailingComma: "es5", printWidth: 80, }; + +export default config; diff --git a/config/prettier-config/package.json b/config/prettier-config/package.json index 1449c2944..f7e3e4f92 100644 --- a/config/prettier-config/package.json +++ b/config/prettier-config/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "Prettier config for ILO Design System", "main": "index.js", + "type": "module", "repository": { "type": "git", "url": "git+https://github.com/international-labour-organization/designsystem.git", @@ -24,6 +25,6 @@ "access": "public" }, "peerDependencies": { - "prettier": ">=2" + "prettier": "3.x" } } diff --git a/config/typescript-config/tsconfig.json b/config/typescript-config/tsconfig.json index 6d17d87ab..1050cf944 100644 --- a/config/typescript-config/tsconfig.json +++ b/config/typescript-config/tsconfig.json @@ -6,7 +6,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "jsx": "react-jsx", - "lib": ["dom", "dom.iterable", "es2017"], + "lib": ["es2017"], "module": "esnext", "moduleResolution": "node", "noFallthroughCasesInSwitch": true, diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..0af50146a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,3 @@ +import configs from "./config/eslint-config/index.js" + +export default configs.js; \ No newline at end of file diff --git a/package.json b/package.json index d63b6859d..221d06f28 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "A design system for the International Labour Organization", "license": "Apache-2.0", - "main": "index.js", + "type": "module", "packageManager": "pnpm@8.6.0", "contributors": [ { @@ -43,13 +43,12 @@ "clean:test": "rimraf summarize.js", "format": "pnpm turbo run format:fix", "lint": "pnpm turbo run lint:fix", - "prepare": "node ./prepare.js", + "prepare": "node .husky/install.js", "react:build:docs": "pnpm turbo run build:docs --filter=@ilo-org/react...", "react:build:lib": "pnpm turbo run build:lib --filter react... ", "react:dev:docs": "pnpm --filter react storybook", "test:all": "pnpm turbo run test", - "fix:pnpm-filter": "pnpm config set dedupe-peer-dependents=false", - "twig:build:docs": "pnpm fix:pnpm-filter && pnpm turbo run build:docs --filter twig...", + "twig:build:docs": "pnpm turbo run build:docs --filter twig...", "twig:build:lib": "pnpm turbo run build:lib --filter twig... ", "twig:dev:docs": "pnpm --filter twig storybook" }, @@ -74,10 +73,10 @@ "dependencies": { "@changesets/cli": "^2.25.0", "@manypkg/cli": "^0.19.2", - "eslint": "^8.41.0", + "eslint": "^9.0.0", "husky": "^7.0.4", "lint-staged": "^13.1.0", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "rimraf": "^3.0.2", "rollup": "^3.23.0", "turbo": "1.7.4", diff --git a/packages/brand-assets/eslint.config.mjs b/packages/brand-assets/eslint.config.mjs new file mode 100644 index 000000000..e24434875 --- /dev/null +++ b/packages/brand-assets/eslint.config.mjs @@ -0,0 +1,3 @@ +import configs from "@ilo-org/eslint-config" + +export default configs.recommended; \ No newline at end of file diff --git a/packages/brand-assets/package.json b/packages/brand-assets/package.json index 933b2e0f2..caa8cf7dd 100644 --- a/packages/brand-assets/package.json +++ b/packages/brand-assets/package.json @@ -53,10 +53,8 @@ "build": "rollup -c", "build:lib": "pnpm build", "build:docs": "pnpm build", - "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", - "lint": "eslint --ext .js,.ts,.tsx", - "lint:fix": "eslint --ext .js,.ts,.tsx --fix" + "lint": "eslint .", + "lint:fix": "eslint --fix" }, "devDependencies": { "@ilo-org/eslint-config": "workspace:*", diff --git a/packages/fonts/font-css/fonts-ar.css b/packages/fonts/font-css/fonts-ar.css index 79f503b7e..68d680841 100644 --- a/packages/fonts/font-css/fonts-ar.css +++ b/packages/fonts/font-css/fonts-ar.css @@ -8,7 +8,8 @@ font-family: "Noto Sans"; src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.ttf") format("truetype"); - src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.eot?#iefix") + src: + url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.eot?#iefix") format("embedded-opentype"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.woff2") format("woff2"), @@ -25,7 +26,8 @@ font-family: "Noto Sans"; src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.ttf") format("truetype"); - src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.eot?#iefix") + src: + url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.eot?#iefix") format("embedded-opentype"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Regular.woff2") format("woff2"), @@ -43,7 +45,8 @@ font-family: "Noto Sans"; src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.ttf") format("truetype"); - src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.eot?#iefix") + src: + url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.eot?#iefix") format("embedded-opentype"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.woff2") format("woff2"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.woff") format("woff"), @@ -58,7 +61,8 @@ font-family: "Noto Sans"; src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.ttf") format("truetype"); - src: url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.eot?#iefix") + src: + url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.eot?#iefix") format("embedded-opentype"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.woff2") format("woff2"), url("../assets/Noto_Sans_Arabic/NotoSansArabic-Bold.woff") format("woff"), diff --git a/packages/fonts/font-css/fonts.css b/packages/fonts/font-css/fonts.css index fd136776e..79c94e4f5 100644 --- a/packages/fonts/font-css/fonts.css +++ b/packages/fonts/font-css/fonts.css @@ -62,7 +62,8 @@ @font-face { font-family: "Noto Sans"; src: url("../assets/NotoSans.eot"); - src: url("../assets/NotoSans.eot?#iefix") format("embedded-opentype"), + src: + url("../assets/NotoSans.eot?#iefix") format("embedded-opentype"), url("../assets/NotoSans.woff2") format("woff2"), url("../assets/NotoSans.woff") format("woff"), url("../assets/NotoSans.ttf") format("truetype"); @@ -74,7 +75,8 @@ @font-face { font-family: "Noto Sans"; src: url("../assets/NotoSans-Italic.eot"); - src: url("../assets/NotoSans-Italic.eot?#iefix") format("embedded-opentype"), + src: + url("../assets/NotoSans-Italic.eot?#iefix") format("embedded-opentype"), url("../assets/NotoSans-Italic.woff2") format("woff2"), url("../assets/NotoSans-Italic.woff") format("woff"), url("../assets/NotoSans-Italic.ttf") format("truetype"); @@ -88,7 +90,8 @@ @font-face { font-family: "Noto Sans"; src: url("../assets/NotoSans-Bold.eot"); - src: url("../assets/NotoSans-Bold.eot?#iefix") format("embedded-opentype"), + src: + url("../assets/NotoSans-Bold.eot?#iefix") format("embedded-opentype"), url("../assets/NotoSans-Bold.woff2") format("woff2"), url("../assets/NotoSans-Bold.woff") format("woff"), url("../assets/NotoSans-Bold.ttf") format("truetype"); @@ -100,8 +103,8 @@ @font-face { font-family: "Noto Sans"; src: url("../assets/NotoSans-BoldItalic.eot"); - src: url("../assets/NotoSans-BoldItalic.eot?#iefix") - format("embedded-opentype"), + src: + url("../assets/NotoSans-BoldItalic.eot?#iefix") format("embedded-opentype"), url("../assets/NotoSans-BoldItalic.woff2") format("woff2"), url("../assets/NotoSans-BoldItalic.woff") format("woff"), url("../assets/NotoSans-BoldItalic.ttf") format("truetype"); diff --git a/packages/fonts/index.scss b/packages/fonts/index.scss index c222d1fee..886217519 100644 --- a/packages/fonts/index.scss +++ b/packages/fonts/index.scss @@ -64,7 +64,8 @@ @font-face { font-family: "Noto Sans"; src: url("~@ilo-org/fonts/assets/NotoSans.eot"); - src: url("~@ilo-org/fonts/assets/NotoSans.eot?#iefix") + src: + url("~@ilo-org/fonts/assets/NotoSans.eot?#iefix") format("embedded-opentype"), url("~@ilo-org/fonts/assets/NotoSans.woff2") format("woff2"), url("~@ilo-org/fonts/assets/NotoSans.woff") format("woff"), @@ -77,7 +78,8 @@ @font-face { font-family: "Noto Sans"; src: url("~@ilo-org/fonts/assets/NotoSans-Italic.eot"); - src: url("~@ilo-org/fonts/assets/NotoSans-Italic.eot?#iefix") + src: + url("~@ilo-org/fonts/assets/NotoSans-Italic.eot?#iefix") format("embedded-opentype"), url("~@ilo-org/fonts/assets/NotoSans-Italic.woff2") format("woff2"), url("~@ilo-org/fonts/assets/NotoSans-Italic.woff") format("woff"), @@ -92,7 +94,8 @@ @font-face { font-family: "Noto Sans"; src: url("~@ilo-org/fonts/assets/NotoSans-Bold.eot"); - src: url("~@ilo-org/fonts/assets/NotoSans-Bold.eot?#iefix") + src: + url("~@ilo-org/fonts/assets/NotoSans-Bold.eot?#iefix") format("embedded-opentype"), url("~@ilo-org/fonts/assets/NotoSans-Bold.woff2") format("woff2"), url("~@ilo-org/fonts/assets/NotoSans-Bold.woff") format("woff"), @@ -105,7 +108,8 @@ @font-face { font-family: "Noto Sans"; src: url("~@ilo-org/fonts/assets/NotoSans-BoldItalic.eot"); - src: url("~@ilo-org/fonts/assets/NotoSans-BoldItalic.eot?#iefix") + src: + url("~@ilo-org/fonts/assets/NotoSans-BoldItalic.eot?#iefix") format("embedded-opentype"), url("~@ilo-org/fonts/assets/NotoSans-BoldItalic.woff2") format("woff2"), url("~@ilo-org/fonts/assets/NotoSans-BoldItalic.woff") format("woff"), diff --git a/packages/fonts/package.json b/packages/fonts/package.json index 2d8079ece..d32b59551 100644 --- a/packages/fonts/package.json +++ b/packages/fonts/package.json @@ -15,9 +15,7 @@ }, "scripts": { "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", - "lint": "eslint --ext .js,.ts,.tsx", - "lint:fix": "eslint --ext .js,.ts,.tsx --fix" + "format:fix": "prettier --write . --ignore-path ../../.prettierignore" }, "repository": { "type": "git", diff --git a/packages/icon-build-helpers/eslint.config.mjs b/packages/icon-build-helpers/eslint.config.mjs new file mode 100644 index 000000000..96d58af34 --- /dev/null +++ b/packages/icon-build-helpers/eslint.config.mjs @@ -0,0 +1,15 @@ +import configs from "@ilo-org/eslint-config"; + +/** @type {import("eslint").Linter.Config} */ +const IconBuildHelpersConfig = { + rules: { + "no-await-in-loop": "off", // This package needs refactoring to remove this rule + "no-console": "off", + }, +}; + +export default [ + ...configs.js, + IconBuildHelpersConfig, + { ignores: ["**/__tests__/"] }, +]; diff --git a/packages/icon-build-helpers/package.json b/packages/icon-build-helpers/package.json index b2b382c8d..c240ac465 100644 --- a/packages/icon-build-helpers/package.json +++ b/packages/icon-build-helpers/package.json @@ -43,12 +43,11 @@ "access": "public" }, "scripts": { - "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", - "lint": "eslint --ext .js,.ts,.tsx", - "lint:fix": "eslint --ext .js,.ts,.tsx --fix" + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "devDependencies": { + "@ilo-org/eslint-config": "workspace:*", "@babel/generator": "^7.21.9", "@babel/preset-env": "^7.21.5", "@babel/preset-react": "^7.18.6", @@ -81,4 +80,4 @@ "react": ">16", "react-dom": ">16" } -} +} \ No newline at end of file diff --git a/packages/icon-build-helpers/src/builders/react/next/babel.js b/packages/icon-build-helpers/src/builders/react/next/babel.js index 9b593b94a..5935f6704 100644 --- a/packages/icon-build-helpers/src/builders/react/next/babel.js +++ b/packages/icon-build-helpers/src/builders/react/next/babel.js @@ -5,27 +5,27 @@ * LICENSE file in the root directory of this source tree. */ -'use strict'; +"use strict"; const babelConfig = { babelrc: false, exclude: /node_modules/, presets: [ [ - '@babel/preset-env', + "@babel/preset-env", { targets: { - browsers: ['extends browserslist-config-carbon'], + browsers: ["extends browserslist-config-carbon"], }, }, ], - '@babel/preset-react', + "@babel/preset-react", ], plugins: [ - '@babel/plugin-transform-react-constant-elements', - 'babel-plugin-dev-expression', + "@babel/plugin-transform-react-constant-elements", + "babel-plugin-dev-expression", ], - babelHelpers: 'bundled', + babelHelpers: "bundled", }; module.exports = { diff --git a/packages/icon-build-helpers/src/builders/react/next/convert.js b/packages/icon-build-helpers/src/builders/react/next/convert.js index 8a196c2a9..7232642b7 100644 --- a/packages/icon-build-helpers/src/builders/react/next/convert.js +++ b/packages/icon-build-helpers/src/builders/react/next/convert.js @@ -5,21 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -'use strict'; +"use strict"; -const t = require('@babel/types'); -const convertStylesStringToObject = require('./stylesStringToObject'); +const t = require("@babel/types"); +const convertStylesStringToObject = require("./stylesStringToObject"); function jsToAST(value) { - if (typeof value === 'string') { + if (typeof value === "string") { return t.stringLiteral(value); } - if (typeof value === 'number') { + if (typeof value === "number") { return t.numericLiteral(value); } - if (typeof value === 'boolean') { + if (typeof value === "boolean") { return t.booleanLiteral(value); } @@ -28,14 +28,14 @@ function jsToAST(value) { } if (value === undefined) { - return t.identifier('undefined'); + return t.identifier("undefined"); } if (Array.isArray(value)) { return t.arrayExpression(value.map(jsToAST)); } - if (typeof value === 'object') { + if (typeof value === "object") { return t.objectExpression( Object.entries(value).map(([key, value]) => { return t.objectProperty(t.identifier(key), jsToAST(value)); @@ -47,8 +47,8 @@ function jsToAST(value) { } function svgToJSX(node) { - if (node.type === 'element') { - if (node.tagName === 'svg') { + if (node.type === "element") { + if (node.tagName === "svg") { return { svgProps: node.attributes, children: node.children.map(svgToJSX), @@ -56,8 +56,8 @@ function svgToJSX(node) { } const { tagName } = node; - const attributeAllowlist = new Set(['data-icon-path']); - const attributeDenylist = ['data', 'aria']; + const attributeAllowlist = new Set(["data-icon-path"]); + const attributeDenylist = ["data", "aria"]; const attributes = Object.entries(node.attributes) .filter(([key]) => { if (attributeAllowlist.has(key)) { @@ -66,13 +66,13 @@ function svgToJSX(node) { return attributeDenylist.every((prefix) => !key.startsWith(prefix)); }) .map(([key, value]) => { - if (t.jSXIdentifier(key).name === 'style') { + if (t.jSXIdentifier(key).name === "style") { return t.jSXAttribute( t.jSXIdentifier(key), t.jSXExpressionContainer(convertStylesStringToObject(value)) ); } - if (typeof value === 'string') { + if (typeof value === "string") { return t.jSXAttribute(t.jSXIdentifier(key), t.stringLiteral(value)); } return t.jSXAttribute( diff --git a/packages/icon-build-helpers/src/builders/react/next/stylesStringToObject.js b/packages/icon-build-helpers/src/builders/react/next/stylesStringToObject.js index 8112584a0..27e47f884 100644 --- a/packages/icon-build-helpers/src/builders/react/next/stylesStringToObject.js +++ b/packages/icon-build-helpers/src/builders/react/next/stylesStringToObject.js @@ -1,7 +1,7 @@ const convertStylesStringToObject = (stringStyles) => - typeof stringStyles === 'string' - ? stringStyles.split(';').reduce((acc, style) => { - const colonPosition = style.indexOf(':'); + typeof stringStyles === "string" + ? stringStyles.split(";").reduce((acc, style) => { + const colonPosition = style.indexOf(":"); if (colonPosition === -1) { return acc; @@ -10,7 +10,7 @@ const convertStylesStringToObject = (stringStyles) => const camelCaseProperty = style .substr(0, colonPosition) .trim() - .replace(/^-ms-/, 'ms-') + .replace(/^-ms-/, "ms-") .replace(/-./g, (c) => c.substr(1).toUpperCase()), value = style.substr(colonPosition + 1).trim(); diff --git a/packages/icon-build-helpers/src/builders/react/next/templates.js b/packages/icon-build-helpers/src/builders/react/next/templates.js index bb81dbe07..ff06d5476 100644 --- a/packages/icon-build-helpers/src/builders/react/next/templates.js +++ b/packages/icon-build-helpers/src/builders/react/next/templates.js @@ -5,9 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -'use strict'; +"use strict"; -const { default: template } = require('@babel/template'); +const { default: template } = require("@babel/template"); const banner = `/** * @@ -25,7 +25,7 @@ const jsx = template.expression( ) `, { - plugins: ['jsx'], + plugins: ["jsx"], } ); @@ -40,7 +40,7 @@ const component = template( %%moduleName%%.propTypes = iconPropTypes; `, { - plugins: ['jsx'], + plugins: ["jsx"], } ); diff --git a/packages/icon-build-helpers/src/builders/vanilla.js b/packages/icon-build-helpers/src/builders/vanilla.js index 07966aa5e..a0c601921 100644 --- a/packages/icon-build-helpers/src/builders/vanilla.js +++ b/packages/icon-build-helpers/src/builders/vanilla.js @@ -55,9 +55,8 @@ async function builder(metadata, { output }) { for (const m of modules) { files[m.filepath] = m.source; input[m.filepath] = m.filepath; - files[ - "index.js" - ] += `\nexport { default as ${m.moduleName} } from '${m.filepath}';`; + files["index.js"] += + `\nexport { default as ${m.moduleName} } from '${m.filepath}';`; } const bundle = await rollup({ diff --git a/packages/icon-build-helpers/src/builders/vue/builder.js b/packages/icon-build-helpers/src/builders/vue/builder.js index 747ab5d37..7a8473c21 100644 --- a/packages/icon-build-helpers/src/builders/vue/builder.js +++ b/packages/icon-build-helpers/src/builders/vue/builder.js @@ -73,9 +73,8 @@ async function builder(metadata, { output }) { for (const m of modules) { files[m.filepath] = m.source; input[m.filepath] = m.filepath; - files[ - "index.js" - ] += `\nexport { default as ${m.moduleName} } from '${m.filepath}';`; + files["index.js"] += + `\nexport { default as ${m.moduleName} } from '${m.filepath}';`; } const bundle = await rollup({ diff --git a/packages/icon-build-helpers/src/metadata/extensions/output/index.js b/packages/icon-build-helpers/src/metadata/extensions/output/index.js index b827048b0..fb4f49f54 100644 --- a/packages/icon-build-helpers/src/metadata/extensions/output/index.js +++ b/packages/icon-build-helpers/src/metadata/extensions/output/index.js @@ -129,7 +129,7 @@ const output = (options = defaultOptions) => { * @param {string} [original] * @returns {object} */ -async function createDescriptor(name, data, size, original) { +async function createDescriptor(name, data, size, _original) { const info = await parse(data, name); const { attrs } = info; const descriptor = { @@ -180,9 +180,7 @@ async function parse(svg, name) { try { return convert(root.content[0]); } catch (error) { - // eslint-disable-next-line no-console console.log(error); - // eslint-disable-next-line no-console console.log(`Error parsing icon with name: ${name}`); } } diff --git a/packages/icons-react/eslint.config.mjs b/packages/icons-react/eslint.config.mjs new file mode 100644 index 000000000..581907b8b --- /dev/null +++ b/packages/icons-react/eslint.config.mjs @@ -0,0 +1,8 @@ +import configs from "@ilo-org/eslint-config"; + +/** @type {import("eslint").Linter.Config} */ +const IconsReactConfig = { + ignores: ["es/", "lib/", "next/", "umd/"], +}; + +export default [...configs.js, IconsReactConfig]; diff --git a/packages/icons-react/package.json b/packages/icons-react/package.json index b5f578908..af3a94941 100644 --- a/packages/icons-react/package.json +++ b/packages/icons-react/package.json @@ -51,10 +51,8 @@ "build:lib": "pnpm build", "build:docs": "pnpm build", "clean": "rimraf es lib umd next", - "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", - "lint": "eslint --ext .js,.ts,.tsx", - "lint:fix": "eslint --ext .js,.ts,.tsx --fix", + "lint": "eslint .", + "lint:fix": "eslint . --fix", "postinstall": "carbon-telemetry collect --install" }, "peerDependencies": { @@ -69,14 +67,15 @@ "@ilo-org/icons": "workspace:*" }, "devDependencies": { + "@ilo-org/eslint-config": "workspace:*", "@babel/plugin-transform-react-constant-elements": "^7.17.6", "@babel/preset-env": "^7.21.5", "@babel/preset-react": "^7.18.6", "babel-plugin-dev-expression": "^0.2.3", "browserslist-config-carbon": "^10.6.1", "prop-types": "^15.7.2", - "react": "17.0.2", + "react": "17.0.0", "rimraf": "^3.0.2" }, "sideEffects": false -} +} \ No newline at end of file diff --git a/packages/icons/eslint.config.mjs b/packages/icons/eslint.config.mjs new file mode 100644 index 000000000..805bb2445 --- /dev/null +++ b/packages/icons/eslint.config.mjs @@ -0,0 +1,8 @@ +import configs from "@ilo-org/eslint-config"; + +/** @type {import("eslint").Linter.Config} */ +const IconsConfig = { + ignores: ["es/", "lib/", "svg/", "build/", "umd/"], +}; + +export default [...configs.js, IconsConfig]; diff --git a/packages/icons/package.json b/packages/icons/package.json index f71491302..b35f167c3 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -52,19 +52,18 @@ "download-figma": "pnpm run clean && node tasks/download.js", "ci-check": "node tasks/ci-check.js", "clean": "rimraf es lib build-info.json metadata.json", - "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", - "lint": "eslint --ext .js,.ts,.tsx", - "lint:fix": "eslint --ext .js,.ts,.tsx --fix", + "lint": "eslint .", + "lint:fix": "eslint . --fix", "prepublishOnly": "pnpm run build" }, "dependencies": { "@ilo-org/icon-build-helpers": "workspace:*" }, "devDependencies": { + "@ilo-org/eslint-config": "workspace:*", "@babel/preset-env": "^7.21.5", "@un/figma-connect": "^0.0.7", "browserslist-config-carbon": "^10.6.1", "rimraf": "^3.0.2" } -} +} \ No newline at end of file diff --git a/packages/icons/tasks/build.js b/packages/icons/tasks/build.js index 26091a52a..564f4b5a2 100644 --- a/packages/icons/tasks/build.js +++ b/packages/icons/tasks/build.js @@ -28,6 +28,6 @@ async function build() { } build().catch((error) => { - console.log(error); + console.error(error); process.exit(1); }); diff --git a/packages/icons/tasks/ci-check.js b/packages/icons/tasks/ci-check.js index 883cb5add..9a07afde7 100644 --- a/packages/icons/tasks/ci-check.js +++ b/packages/icons/tasks/ci-check.js @@ -26,6 +26,6 @@ async function check() { } check().catch((error) => { - console.log(error); + console.error(error); process.exit(1); }); diff --git a/packages/icons/tasks/download.js b/packages/icons/tasks/download.js index f128d34f6..3cf36987f 100644 --- a/packages/icons/tasks/download.js +++ b/packages/icons/tasks/download.js @@ -8,9 +8,6 @@ "use strict"; const { svgExporter } = require("@un/figma-connect"); -const path = require("path"); -const rimraf = require("rimraf"); -const fs = require("fs"); async function build() { /*rimraf.sync('./src'); @@ -19,6 +16,6 @@ async function build() { } build().catch((error) => { - console.log(error); + console.error(error); process.exit(1); }); diff --git a/packages/icons/tasks/scaffold.js b/packages/icons/tasks/scaffold.js index ff5d12659..70d958701 100644 --- a/packages/icons/tasks/scaffold.js +++ b/packages/icons/tasks/scaffold.js @@ -21,6 +21,6 @@ async function scaffold() { } scaffold().catch((error) => { - console.log(error); + console.error(error); process.exit(1); }); diff --git a/packages/maestro/.eslintrc b/packages/maestro/.eslintrc deleted file mode 100644 index 6e911fbbd..000000000 --- a/packages/maestro/.eslintrc +++ /dev/null @@ -1,46 +0,0 @@ -{ - "root": true, - "extends": [ - "eslint:recommended", - "plugin:import/typescript", - "plugin:@typescript-eslint/recommended" - ], - "plugins": ["@typescript-eslint/eslint-plugin", "import", "prettier"], - "parser": "@typescript-eslint/parser", - "env": { - "node": true - }, - "settings": { - "import/resolver": { - "typescript": { - "project": "./tsconfig.json" - } - }, - "import/parser": { - "@typescript-eslint/parser": [".ts"] - } - }, - "rules": { - "no-console": "warn", - "prettier/prettier": "warn", - "no-await-in-loop": "warn", - "@typescript-eslint/class-literal-property-style": "warn", - "@typescript-eslint/no-duplicate-enum-values": "warn", - "@typescript-eslint/prefer-for-of": "warn", - "@typescript-eslint/consistent-type-definitions": ["error", "type"], - "import/order": [ - "error", - { - "newlines-between": "always" - } - ], - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "ignoreRestSiblings": true, - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_" - } - ] - } -} diff --git a/packages/maestro/eslint.config.mjs b/packages/maestro/eslint.config.mjs new file mode 100644 index 000000000..10cd34fce --- /dev/null +++ b/packages/maestro/eslint.config.mjs @@ -0,0 +1,3 @@ +import configs from "@ilo-org/eslint-config"; + +export default configs.recommended; diff --git a/packages/maestro/package.json b/packages/maestro/package.json index fa710e647..de27882b4 100644 --- a/packages/maestro/package.json +++ b/packages/maestro/package.json @@ -33,7 +33,8 @@ "build": "tsc && vite build", "build:lib": "pnpm build", "build:docs": "pnpm build", - "lint": "eslint --ext .ts lib" + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "dependencies": { "@modyfi/vite-plugin-yaml": "^1.1.0", @@ -44,14 +45,9 @@ "zod": "^3.23.8" }, "devDependencies": { + "@ilo-org/eslint-config": "workspace:*", "@storybook/html": "^8.1.9", - "@types/node": "^17.0.45", - "@typescript-eslint/eslint-plugin": "^7.1.0", - "@typescript-eslint/parser": "^7.1.0", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prettier": "^5.1.3", + "@types/node": "^20.16.0", "typescript": "^4.9.3", "vite": "^5.3.1", "vite-plugin-dts": "^3.9.1" diff --git a/packages/maestro/src/generator/index.ts b/packages/maestro/src/generator/index.ts index c91721012..87966e403 100644 --- a/packages/maestro/src/generator/index.ts +++ b/packages/maestro/src/generator/index.ts @@ -4,17 +4,17 @@ import { create } from "./create"; export type MaestroComponent = (props: Record) => string; export type MaestroPattern = Record; -export type MaestroStory = { +export interface MaestroStory { meta: Meta; stories: StoryObj[]; -}; +} -type MaestroType = { +interface MaestroType { create: ( component: MaestroComponent, pattern: MaestroPattern ) => MaestroStory; -}; +} const Maestro: MaestroType = { create, diff --git a/packages/maestro/src/generator/schema.ts b/packages/maestro/src/generator/schema.ts index 29e33bb84..6c0f4dfdc 100644 --- a/packages/maestro/src/generator/schema.ts +++ b/packages/maestro/src/generator/schema.ts @@ -16,7 +16,7 @@ const field = z.object({ label: z.string(), description: z.string(), required: z.boolean().optional(), - preview: z.any(), + preview: z.unknown(), options: z .union([z.record(z.string()).optional(), z.record(z.number()).optional()]) .optional(), diff --git a/packages/maestro/src/plugin/twig.d.ts b/packages/maestro/src/plugin/twig.d.ts index e59f9c484..3da6bb991 100644 --- a/packages/maestro/src/plugin/twig.d.ts +++ b/packages/maestro/src/plugin/twig.d.ts @@ -1,9 +1,9 @@ -type PluginParams = { +interface PluginParams { namespaces: Record; functions?: Record; globalContext?: Record; dynamics?: string[]; -}; +} function twig(args: PluginParams): PluginOption; export default twig; diff --git a/packages/maestro/src/plugin/twig.js b/packages/maestro/src/plugin/twig.js index 532cf2aef..a92d3eea4 100644 --- a/packages/maestro/src/plugin/twig.js +++ b/packages/maestro/src/plugin/twig.js @@ -219,7 +219,7 @@ const plugin = (options = {}) => { if (!seen.includes(template)) { includePromises.push( // eslint-disable-next-line no-async-promise-executor - new Promise(async (resolve, reject) => { + new Promise(async (resolve, _reject) => { const { includes, code } = await compileTemplate( template, file, diff --git a/packages/maestro/src/storybook/behavior.ts b/packages/maestro/src/storybook/behavior.ts index c404b3f58..d51f6aefe 100644 --- a/packages/maestro/src/storybook/behavior.ts +++ b/packages/maestro/src/storybook/behavior.ts @@ -1,5 +1,4 @@ declare global { - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface Window { Drupal: { behaviors: Record void }>; diff --git a/packages/maestro/src/vite.ts b/packages/maestro/src/vite.ts index df564c52c..9ade584e5 100644 --- a/packages/maestro/src/vite.ts +++ b/packages/maestro/src/vite.ts @@ -1,16 +1,18 @@ import Twig from "twig"; import yaml from "@modyfi/vite-plugin-yaml"; +import type { Plugin } from "vite"; import twig from "./plugin/twig"; -type Options = { +interface Options { namespaces: Record; globals?: Record; dynamics?: string[]; -}; +} -function UIPatterns(options: Options) { - return [ +function UIPatterns(options: Options): Plugin[] { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const plugins: Plugin[] = [ yaml(), twig({ namespaces: options.namespaces, @@ -18,13 +20,15 @@ function UIPatterns(options: Options) { dynamics: options.dynamics, functions: { boolval: (instance: typeof Twig) => - //@ts-expect-error typedefintions are wrong + // @ts-expect-error - twig preprocessor wants it to be a function instance.extendFilter("boolval", (value: string) => value === "false" ? false : !!value ), }, }), ]; + + return plugins; } export { UIPatterns }; diff --git a/packages/react/.eslintrc.cjs b/packages/react/.eslintrc.cjs deleted file mode 100644 index 571aa8de8..000000000 --- a/packages/react/.eslintrc.cjs +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Package-level eslint config extends the global config and applies - * customizations relative to the local project. In this example we - * are lintinting both js and ts files, so we combine two configs - * and set the TypeScript settings as an override - */ -module.exports = { - /* =============== */ - /* Global Settings */ - /* =============== */ - root: true, - extends: ["@ilo-org/eslint-config"], - // Extend the default config and add any specific settings for this project - ignorePatterns: [ - "storybook-static/", - "node_modules/", - "lib/", - "src/stories/", - //@TODO: Remove this once type errors in tests and args files are fixed - "src/__tests__", - "src/components/**/*.args.ts", - "vite.config.ts", - "vitest.setup.ts", - ], - - overrides: [ - /* =================== */ - /* TypeScript Settings */ - /* =================== */ - { - // Which files the override will apply to relative to the package root - files: ["{src,tests}/**/*.{ts,tsx}"], - extends: ["@ilo-org/eslint-config/typescript"], - // The typescript parser options for this package, which will be different - // from other packages - parserOptions: { - project: ["./tsconfig.json"], - }, - }, - ], -}; diff --git a/packages/react/.storybook/preview.tsx b/packages/react/.storybook/preview.tsx index 0124f63a4..f1d3527c7 100644 --- a/packages/react/.storybook/preview.tsx +++ b/packages/react/.storybook/preview.tsx @@ -4,6 +4,7 @@ import { Preview } from "@storybook/react"; import theme from "./theme"; import "./styles.scss"; import { brand } from "@ilo-org/themes/tokens/brand/base.json"; +import React from "react"; const preview: Preview = { decorators: [ diff --git a/packages/react/eslint.config.mjs b/packages/react/eslint.config.mjs new file mode 100644 index 000000000..76b9c43ba --- /dev/null +++ b/packages/react/eslint.config.mjs @@ -0,0 +1,8 @@ +import configs from "@ilo-org/eslint-config"; + +/** @type {import("eslint").Linter.Config} */ +const ReactConfigOverrides = { + ignores: ["**/*.args.ts", "**/*.stories.tsx"], +}; + +export default [...configs.react, ReactConfigOverrides]; diff --git a/packages/react/package.json b/packages/react/package.json index 335db53e0..e104eeb43 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -57,8 +57,6 @@ "build:docs": "storybook build", "check": "tsc --noEmit --p tsconfig.build.json", "dev:lib": "vite build --watch", - "format": "prettier --check . --ignore-path ../../.prettierignore", - "format:fix": "prettier --write . --ignore-path ../../.prettierignore", "lint": "eslint .", "lint:fix": "eslint . --fix", "storybook": "storybook dev -p 6006", diff --git a/packages/react/src/components/Accordion/Accordion.props.ts b/packages/react/src/components/Accordion/Accordion.props.ts index 02962b569..6cc339a46 100644 --- a/packages/react/src/components/Accordion/Accordion.props.ts +++ b/packages/react/src/components/Accordion/Accordion.props.ts @@ -14,7 +14,7 @@ export interface AccordionProps { /** * Callback to onButtonClick event; */ - onButtonClick?: (e: MouseEvent, i: any) => void; + onButtonClick?: (e: MouseEvent, i: unknown) => void; /** * Allow multiple accordions to be expanded at once, default value is false @@ -37,5 +37,5 @@ export interface AccordionContextProps { getUpdatedItems: typeof getUpdatedItems; setActiveItems: Dispatch>; allowMultipleExpanded: boolean; - onButtonClick?: (e: MouseEvent, i: any) => void; + onButtonClick?: (e: MouseEvent, i: unknown) => void; } diff --git a/packages/react/src/components/Accordion/Accordion.tsx b/packages/react/src/components/Accordion/Accordion.tsx index 69e050fad..9cd3f32ac 100755 --- a/packages/react/src/components/Accordion/Accordion.tsx +++ b/packages/react/src/components/Accordion/Accordion.tsx @@ -29,14 +29,15 @@ const Accordion: FC = ({ const expandedOnLoad = allowMultipleExpanded ? defaultAccordionsExpanded : defaultAccordionsExpanded.length > 0 - ? [defaultAccordionsExpanded[0]] - : defaultAccordionsExpanded; + ? [defaultAccordionsExpanded[0]] + : defaultAccordionsExpanded; setActiveItems(expandedOnLoad); - }, [defaultAccordionsExpandedString, allowMultipleExpanded]); //eslint-disable-line react-hooks/exhaustive-deps + }, [defaultAccordionsExpandedString, allowMultipleExpanded]); if (children) { const ids: string[] = []; Children.forEach(children, (child: ReactElement) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access ids.push(child.props.id); }); if (checkArrayDuplicates(ids)) { diff --git a/packages/react/src/components/Accordion/AccordionPanel.tsx b/packages/react/src/components/Accordion/AccordionPanel.tsx index 1877240f2..1df6ed060 100644 --- a/packages/react/src/components/Accordion/AccordionPanel.tsx +++ b/packages/react/src/components/Accordion/AccordionPanel.tsx @@ -22,10 +22,12 @@ const AccordionPanel: FC = ({ [`${baseClass}--open`]: open, }); - const ref = useRef(); + const ref = useRef(null); useLayoutEffect(() => { - ref.current && setPanelHeight(ref.current.scrollHeight); + if (ref.current) { + setPanelHeight(ref.current.scrollHeight); + } }); return ( @@ -34,8 +36,8 @@ const AccordionPanel: FC = ({ id={`panel-${id}`} aria-labelledby={`button-${id}`} role="region" - ref={ref as any} - style={{ ["--height" as any]: `${panelHeight}px` }} + ref={ref} + style={{ ["--height" as string]: `${panelHeight}px` }} {...rest} >
{children}
diff --git a/packages/react/src/components/Breadcrumb/Breadcrumb.tsx b/packages/react/src/components/Breadcrumb/Breadcrumb.tsx index c104722f7..cec61e9a2 100644 --- a/packages/react/src/components/Breadcrumb/Breadcrumb.tsx +++ b/packages/react/src/components/Breadcrumb/Breadcrumb.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-has-content */ /* This is a good rule in general, but disabling here because the link has an aria-label */ import { diff --git a/packages/react/src/components/Button/Button.props.ts b/packages/react/src/components/Button/Button.props.ts index e11480640..396955b3f 100644 --- a/packages/react/src/components/Button/Button.props.ts +++ b/packages/react/src/components/Button/Button.props.ts @@ -10,7 +10,7 @@ export interface ButtonProps { /** * Specify the callback of your Button. */ - callback?: (e: React.MouseEvent) => any; + callback?: (e: React.MouseEvent) => unknown; /** * Specify the content of your Button. diff --git a/packages/react/src/components/Cards/CardGroup/CardGroup.tsx b/packages/react/src/components/Cards/CardGroup/CardGroup.tsx index c2a5f9128..18df131ea 100644 --- a/packages/react/src/components/Cards/CardGroup/CardGroup.tsx +++ b/packages/react/src/components/Cards/CardGroup/CardGroup.tsx @@ -1,3 +1,5 @@ +/* @ESLINT-DEBT During new eslint refactoring this file was omitted because of heavy type refactoring */ +/* eslint-disable */ import { FC } from "react"; import classnames from "classnames"; import useGlobalSettings from "../../../hooks/useGlobalSettings"; diff --git a/packages/react/src/components/Cards/DataCard/DataCard.props.ts b/packages/react/src/components/Cards/DataCard/DataCard.props.ts index c46adc2cc..038ae317d 100644 --- a/packages/react/src/components/Cards/DataCard/DataCard.props.ts +++ b/packages/react/src/components/Cards/DataCard/DataCard.props.ts @@ -1,7 +1,7 @@ import { CardSize } from "../../../types"; import { LinkProps } from "../../LinkList/LinkList.props"; -export type DataCardProps = { +export interface DataCardProps { /** * A line of text that appears as a small heading at the top of the card */ @@ -26,7 +26,7 @@ export type DataCardProps = { * Make the content appear in one or two columns. Only applies when the size is set to `wide` or `fluid` */ columns?: string; -}; +} interface CardDataset { content?: DataContent; diff --git a/packages/react/src/components/Cards/DataCard/DataCard.tsx b/packages/react/src/components/Cards/DataCard/DataCard.tsx index 883f2d1c8..b1d5eed02 100644 --- a/packages/react/src/components/Cards/DataCard/DataCard.tsx +++ b/packages/react/src/components/Cards/DataCard/DataCard.tsx @@ -16,7 +16,7 @@ const DataCard: FC = ({ const baseClass = `${prefix}--card`; const cardClasses = classnames(baseClass, `${baseClass}__type__data`, { - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, [`${baseClass}__type__data__columns__${columns}`]: columns, }); @@ -40,7 +40,7 @@ const DataCard: FC = ({ dataset.content && dataset.content.items && dataset.content.items.map((item) => ( -
+

{item.label}

@@ -60,6 +60,7 @@ const DataCard: FC = ({ className={`${baseClass}--data--file ${prefix}--button ${prefix}--button--primary ${prefix}--button--small`} href={item.url} download + key={item.url} > {item.label} @@ -77,6 +78,7 @@ const DataCard: FC = ({ {item.label} diff --git a/packages/react/src/components/Cards/DetailCard/DetailCard.props.ts b/packages/react/src/components/Cards/DetailCard/DetailCard.props.ts index 2019390dd..57eb7938e 100644 --- a/packages/react/src/components/Cards/DetailCard/DetailCard.props.ts +++ b/packages/react/src/components/Cards/DetailCard/DetailCard.props.ts @@ -1,6 +1,6 @@ import { CardSize, EventDate, HeadingTypes } from "../../../types"; -export type DetailCardProps = { +export interface DetailCardProps { /** * A line of text that appears as a small heading above the title of the card */ @@ -45,4 +45,4 @@ export type DetailCardProps = { * How big should the card be */ size?: Omit; -}; +} diff --git a/packages/react/src/components/Cards/DetailCard/DetailCard.tsx b/packages/react/src/components/Cards/DetailCard/DetailCard.tsx index dafa68f47..347c32037 100644 --- a/packages/react/src/components/Cards/DetailCard/DetailCard.tsx +++ b/packages/react/src/components/Cards/DetailCard/DetailCard.tsx @@ -19,7 +19,7 @@ const DetailCard: FC = ({ const cardClasses = classnames(baseClass, `${baseClass}__type__detail`, { [`${baseClass}__action`]: link, - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, }); return ( diff --git a/packages/react/src/components/Cards/FactlistCard/FactListCard.props.ts b/packages/react/src/components/Cards/FactlistCard/FactListCard.props.ts index 4e5bcce00..86109dab6 100644 --- a/packages/react/src/components/Cards/FactlistCard/FactListCard.props.ts +++ b/packages/react/src/components/Cards/FactlistCard/FactListCard.props.ts @@ -1,6 +1,6 @@ import { ThemeTypes, CardSize, HeadingTypes } from "../../../types"; -export type FactlistCardProps = { +export interface FactlistCardProps { /** * The title of the card */ @@ -21,4 +21,4 @@ export type FactlistCardProps = { */ size?: Omit; list?: string[]; -}; +} diff --git a/packages/react/src/components/Cards/FactlistCard/FactListCard.tsx b/packages/react/src/components/Cards/FactlistCard/FactListCard.tsx index e5335eda7..182b47f94 100644 --- a/packages/react/src/components/Cards/FactlistCard/FactListCard.tsx +++ b/packages/react/src/components/Cards/FactlistCard/FactListCard.tsx @@ -16,7 +16,7 @@ const FactlistCard: FC = ({ const baseClass = `${prefix}--card`; const cardClasses = classnames(baseClass, `${baseClass}__type__factlist`, { - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, [`${baseClass}__theme__${theme}`]: theme, }); @@ -34,7 +34,7 @@ const FactlistCard: FC = ({ {list && ( {list.map((item, index) => ( - +

{item}

))} diff --git a/packages/react/src/components/Cards/FeatureCard/FeatureCard.props.ts b/packages/react/src/components/Cards/FeatureCard/FeatureCard.props.ts index 16c1aa769..9ec97d0cf 100644 --- a/packages/react/src/components/Cards/FeatureCard/FeatureCard.props.ts +++ b/packages/react/src/components/Cards/FeatureCard/FeatureCard.props.ts @@ -1,7 +1,8 @@ import { ThemeTypes, CardSize, EventDate, HeadingTypes } from "../../../types"; import { LinkListProps } from "../../LinkList/LinkList.props"; -export type FeatureCardProps = { + +export interface FeatureCardProps { isvideo?: boolean; /** @@ -40,4 +41,4 @@ export type FeatureCardProps = { * The image to show in the card */ image?: string; -}; +} diff --git a/packages/react/src/components/Cards/FeatureCard/FeatureCard.tsx b/packages/react/src/components/Cards/FeatureCard/FeatureCard.tsx index b1ba4dd31..853bd159a 100644 --- a/packages/react/src/components/Cards/FeatureCard/FeatureCard.tsx +++ b/packages/react/src/components/Cards/FeatureCard/FeatureCard.tsx @@ -22,7 +22,7 @@ const FeatureCard: FC = ({ const cardClasses = classnames(baseClass, `${baseClass}__type__feature`, { [`${baseClass}__action`]: link, - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, [`${baseClass}__isvideo`]: isvideo, [`${baseClass}__linklist`]: linklist, [`${baseClass}__theme__${theme}`]: theme, diff --git a/packages/react/src/components/Cards/MultilinkCard/MultilinkCard.props.ts b/packages/react/src/components/Cards/MultilinkCard/MultilinkCard.props.ts index 61c81c8ce..2cb6dd43b 100644 --- a/packages/react/src/components/Cards/MultilinkCard/MultilinkCard.props.ts +++ b/packages/react/src/components/Cards/MultilinkCard/MultilinkCard.props.ts @@ -1,7 +1,7 @@ import { CardAlignment, CardSize, HeadingTypes } from "../../../types"; import { LinkListProps } from "../../LinkList/LinkList.props"; -export type MultilinkCardProps = { +export interface MultilinkCardProps { isvideo?: boolean; /** @@ -32,4 +32,4 @@ export type MultilinkCardProps = { * The image to show in the card */ image?: string; -}; +} diff --git a/packages/react/src/components/Cards/PromoCard/PromoCard.props.ts b/packages/react/src/components/Cards/PromoCard/PromoCard.props.ts index b552744c2..1bf954d29 100644 --- a/packages/react/src/components/Cards/PromoCard/PromoCard.props.ts +++ b/packages/react/src/components/Cards/PromoCard/PromoCard.props.ts @@ -6,7 +6,7 @@ import { } from "../../../types"; import { LinkProps } from "../../LinkList/LinkList.props"; -export type PromoCardProps = { +export interface PromoCardProps { /** * A line of text that appears as a small heading above the title of the card */ @@ -43,4 +43,4 @@ export type PromoCardProps = { intro?: string; link?: string; cta?: LinkProps; -}; +} diff --git a/packages/react/src/components/Cards/StatCard/StatCard.props.ts b/packages/react/src/components/Cards/StatCard/StatCard.props.ts index d63b27e4d..c77fa7c64 100644 --- a/packages/react/src/components/Cards/StatCard/StatCard.props.ts +++ b/packages/react/src/components/Cards/StatCard/StatCard.props.ts @@ -1,7 +1,7 @@ import { CardColor, CardSize, HeadingTypes } from "../../../types"; import { LinkProps } from "../../LinkList/LinkList.props"; -export type StatCardProps = { +export interface StatCardProps { /** * The title of the card */ @@ -28,4 +28,4 @@ export type StatCardProps = { */ intro?: string; source?: LinkProps; -}; +} diff --git a/packages/react/src/components/Cards/StatCard/StatCard.tsx b/packages/react/src/components/Cards/StatCard/StatCard.tsx index 39adc28ab..8cf22b248 100644 --- a/packages/react/src/components/Cards/StatCard/StatCard.tsx +++ b/packages/react/src/components/Cards/StatCard/StatCard.tsx @@ -18,7 +18,7 @@ const StatCard: FC = ({ const cardClasses = classnames(baseClass, `${baseClass}__type__stat`, { [`${baseClass}__color__${color}`]: color, - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, }); return ( diff --git a/packages/react/src/components/Cards/TextCard/TextCard.props.ts b/packages/react/src/components/Cards/TextCard/TextCard.props.ts index 97f55c622..46a25da71 100644 --- a/packages/react/src/components/Cards/TextCard/TextCard.props.ts +++ b/packages/react/src/components/Cards/TextCard/TextCard.props.ts @@ -2,7 +2,7 @@ import { ThemeTypes, CardSize, EventDate, HeadingTypes } from "../../../types"; import { ProfileProps } from "../../Profile/Profile.props"; -export type TextCardProps = { +export interface TextCardProps { /** * A line of text that appears as a small heading above the title of the card */ @@ -34,4 +34,4 @@ export type TextCardProps = { date?: EventDate; profile: ProfileProps; link?: string; -}; +} diff --git a/packages/react/src/components/Cards/TextCard/TextCard.tsx b/packages/react/src/components/Cards/TextCard/TextCard.tsx index 955fd106e..a1116dd2b 100644 --- a/packages/react/src/components/Cards/TextCard/TextCard.tsx +++ b/packages/react/src/components/Cards/TextCard/TextCard.tsx @@ -22,7 +22,7 @@ const TextCard: FC = ({ const cardClasses = classnames(baseClass, `${baseClass}__type__text`, { [`${baseClass}__action`]: link, - [`${baseClass}__size__${size}`]: size, + [`${baseClass}__size__${size as string}`]: size, [`${baseClass}__theme__${theme}`]: theme, }); diff --git a/packages/react/src/components/Checkbox/Checkbox.props.ts b/packages/react/src/components/Checkbox/Checkbox.props.ts index d29613e33..574efceb1 100644 --- a/packages/react/src/components/Checkbox/Checkbox.props.ts +++ b/packages/react/src/components/Checkbox/Checkbox.props.ts @@ -1,5 +1,5 @@ -import { ChoiceFieldProps } from "../../types"; -import { LabelledFormFieldProps } from "../../types"; +import { ChoiceFieldProps, LabelledFormFieldProps } from "../../types"; + export type CheckboxProps = ChoiceFieldProps; export type LabelledCheckboxProps = LabelledFormFieldProps; diff --git a/packages/react/src/components/Collapse/Collapse.tsx b/packages/react/src/components/Collapse/Collapse.tsx index 66cd2a05f..2fc9d47be 100644 --- a/packages/react/src/components/Collapse/Collapse.tsx +++ b/packages/react/src/components/Collapse/Collapse.tsx @@ -1,3 +1,6 @@ +/* @ESLINT-DEBT During new eslint refactoring this file was omitted because of heavy type refactoring */ +/* eslint-disable */ + import classNames from "classnames"; import { cloneElement, forwardRef, useMemo } from "react"; import Transition, { diff --git a/packages/react/src/components/DatePicker/DatePicker.props.ts b/packages/react/src/components/DatePicker/DatePicker.props.ts index 3cc6b2f75..9225c63cb 100644 --- a/packages/react/src/components/DatePicker/DatePicker.props.ts +++ b/packages/react/src/components/DatePicker/DatePicker.props.ts @@ -1,5 +1,4 @@ -import { FormFieldProps } from "../../types"; -import { LabelledFormFieldProps } from "../../types"; +import { FormFieldProps, LabelledFormFieldProps } from "../../types"; export interface DatePickerProps extends FormFieldProps { /** diff --git a/packages/react/src/components/Dropdown/Dropdown.props.ts b/packages/react/src/components/Dropdown/Dropdown.props.ts index 3e073a495..4db82f8f7 100644 --- a/packages/react/src/components/Dropdown/Dropdown.props.ts +++ b/packages/react/src/components/Dropdown/Dropdown.props.ts @@ -1,5 +1,4 @@ -import { FormFieldProps } from "../../types"; -import { LabelledFormFieldProps } from "../../types"; +import { FormFieldProps, LabelledFormFieldProps } from "../../types"; export interface OptionProps { /** diff --git a/packages/react/src/components/FileUpload/FileUpload.props.ts b/packages/react/src/components/FileUpload/FileUpload.props.ts index 12a7afb9f..6f90eda53 100644 --- a/packages/react/src/components/FileUpload/FileUpload.props.ts +++ b/packages/react/src/components/FileUpload/FileUpload.props.ts @@ -1,5 +1,4 @@ -import { FormFieldProps } from "../../types"; -import { LabelledFormFieldProps } from "../../types"; +import { FormFieldProps, LabelledFormFieldProps } from "../../types"; export interface FileUploadProps extends FormFieldProps { /** diff --git a/packages/react/src/components/FileUpload/FileUpload.tsx b/packages/react/src/components/FileUpload/FileUpload.tsx index ff80ae5dc..c9f7434df 100644 --- a/packages/react/src/components/FileUpload/FileUpload.tsx +++ b/packages/react/src/components/FileUpload/FileUpload.tsx @@ -70,7 +70,7 @@ const FileUpload = React.forwardRef( disabled={disabled} multiple={multiple} placeholder={placeholder} - required={required as any} + required={required} type="file" data-label={placeholder} aria-describedby={ariaDescribedBy} diff --git a/packages/react/src/components/Footer/Footer.props.ts b/packages/react/src/components/Footer/Footer.props.ts index 55e1fa2b8..5a1d1e0ba 100644 --- a/packages/react/src/components/Footer/Footer.props.ts +++ b/packages/react/src/components/Footer/Footer.props.ts @@ -1,5 +1,4 @@ -import { LinkGroupProps } from "../LinkList/LinkList.props"; -import { LinkProps } from "../LinkList/LinkList.props"; +import { LinkGroupProps, LinkProps } from "../LinkList/LinkList.props"; import { SocialMediaProps } from "../SocialMedia"; export interface FooterProps { diff --git a/packages/react/src/components/Footer/Footer.tsx b/packages/react/src/components/Footer/Footer.tsx index 2e70fb458..6c462ca2f 100644 --- a/packages/react/src/components/Footer/Footer.tsx +++ b/packages/react/src/components/Footer/Footer.tsx @@ -72,13 +72,9 @@ const Footer: FC = ({ {secondarylinks && (
diff --git a/packages/react/src/components/SocialMedia/SocialMedia.tsx b/packages/react/src/components/SocialMedia/SocialMedia.tsx index e13874b1b..7f24ecd38 100644 --- a/packages/react/src/components/SocialMedia/SocialMedia.tsx +++ b/packages/react/src/components/SocialMedia/SocialMedia.tsx @@ -30,7 +30,7 @@ const SocialMedia: React.FC = ({ {headline &&
{headline}
}