import storybook from "eslint-plugin-storybook"; import betterTailwindcss from "eslint-plugin-better-tailwindcss"; import prettier from "eslint-config-prettier"; import path from "node:path"; import js from "@eslint/js"; import svelte from "eslint-plugin-svelte"; import { defineConfig, includeIgnoreFile } from "eslint/config"; import globals from "globals"; import ts from "typescript-eslint"; const gitignorePath = path.resolve(import.meta.dirname, ".gitignore"); const fixtures = { group: ["$fixtures", "$fixtures/*", "**/src/fixtures", "**/src/fixtures/*"], message: "fixtures are storybook input: import them from a *.stories.svelte file." }; const relative = { group: ["./*", "../*"], message: "import through $lib, not a relative path." }; const relativeRoute = { group: ["./*", "../*", "!./$types", "!./+*", "!../app.css"], message: "import through $lib or $routes, not a relative path." }; export default defineConfig( { ignores: ["src/lib/api/lexicons/"] }, includeIgnoreFile(gitignorePath), js.configs.recommended, ts.configs.recommended, svelte.configs.recommended, storybook.configs["flat/recommended"], prettier, svelte.configs.prettier, { languageOptions: { globals: { ...globals.browser, ...globals.node } }, rules: { // typescript owns undefined-name checks. "no-undef": "off", "@typescript-eslint/no-unused-vars": [ "error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_" } ] } }, { files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"], languageOptions: { parserOptions: { projectService: { allowDefaultProject: [ ".storybook/MockAuth.svelte", ".storybook/MockNotifications.svelte", ".storybook/BoneCaptureDecorator.svelte", ".storybook/WorkflowRunReplay.svelte" ] }, extraFileExtensions: [".svelte"], parser: ts.parser } } }, { files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js", "**/*.ts", "**/*.js"], plugins: { "better-tailwindcss": betterTailwindcss }, settings: { "better-tailwindcss": { entryPoint: "src/app.css", // without this the rule silently skips px -> spacing-scale rewrites. rootFontSize: 16 } }, rules: { "better-tailwindcss/enforce-canonical-classes": "warn", "better-tailwindcss/no-deprecated-classes": "warn" } }, { // fixtures feed stories and nothing else. without this the app can import // them and ship sample data, which is how the notifications page got its // mock feed files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js", "**/*.ts", "**/*.js"], ignores: ["**/*.stories.svelte", "src/lib/**", "src/routes/**"], rules: { "no-restricted-imports": ["error", { patterns: [fixtures] }] } }, { files: ["src/routes/**"], ignores: ["**/*.stories.svelte"], rules: { "no-restricted-imports": ["error", { patterns: [fixtures, relativeRoute] }] } }, { files: ["src/routes/**/*.stories.svelte"], rules: { "no-restricted-imports": ["error", { patterns: [relativeRoute] }] } }, { files: ["src/lib/**"], ignores: ["**/*.stories.svelte"], rules: { "no-restricted-imports": ["error", { patterns: [fixtures, relative] }] } }, { files: ["src/lib/**/*.stories.svelte"], rules: { "no-restricted-imports": ["error", { patterns: [relative] }] } } );