2026-05-13 07:49:49 +00:00
|
|
|
import obsidianmd from "eslint-plugin-obsidianmd";
|
|
|
|
|
import reactPlugin from "eslint-plugin-react";
|
|
|
|
|
import reactHooks from "eslint-plugin-react-hooks";
|
|
|
|
|
import tailwind from "eslint-plugin-tailwindcss";
|
|
|
|
|
import globals from "globals";
|
|
|
|
|
|
|
|
|
|
export default [
|
|
|
|
|
{
|
|
|
|
|
ignores: [
|
|
|
|
|
"node_modules/**",
|
|
|
|
|
"main.js",
|
|
|
|
|
"styles.css",
|
|
|
|
|
"data.json",
|
|
|
|
|
"designdocs/**",
|
|
|
|
|
"docs/**",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// obsidianmd recommended brings:
|
|
|
|
|
// - eslint:recommended
|
|
|
|
|
// - typescript-eslint recommendedTypeChecked on .ts/.tsx (recommended on .js/.jsx)
|
|
|
|
|
// - obsidianmd plugin + all obsidianmd-namespaced rules
|
|
|
|
|
// - import / @microsoft/sdl / depend / no-unsanitized
|
|
|
|
|
// - Obsidian-injected globals (activeDocument, createDiv, etc.)
|
|
|
|
|
...obsidianmd.configs.recommended,
|
|
|
|
|
|
|
|
|
|
// React + tailwind plugins ship flat configs with no `files` filter, so
|
|
|
|
|
// they'd cascade onto package.json (which uses the JSON parser) and crash.
|
|
|
|
|
// Constrain them to JS/TS sources.
|
|
|
|
|
{
|
|
|
|
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
|
|
|
...reactPlugin.configs.flat.recommended,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
|
|
|
plugins: { "react-hooks": reactHooks },
|
|
|
|
|
rules: {
|
|
|
|
|
"react-hooks/rules-of-hooks": "error",
|
|
|
|
|
"react-hooks/exhaustive-deps": "error",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
...tailwind.configs["flat/recommended"].map((cfg) => ({
|
|
|
|
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
|
|
|
...cfg,
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
|
|
|
languageOptions: {
|
|
|
|
|
globals: {
|
|
|
|
|
// Obsidian plugin runtime injects `app` as a global (see CLAUDE.md).
|
|
|
|
|
app: "readonly",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
settings: {
|
|
|
|
|
react: { version: "detect" },
|
|
|
|
|
tailwindcss: {
|
|
|
|
|
callees: ["classnames", "clsx", "ctl", "cn", "cva"],
|
|
|
|
|
config: "./tailwind.config.js",
|
|
|
|
|
cssFiles: ["**/*.css", "!**/node_modules", "!**/.*", "!**/dist", "!**/build"],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
rules: {
|
|
|
|
|
// Carry-over from legacy .eslintrc
|
|
|
|
|
"no-prototype-builtins": "off",
|
|
|
|
|
"react/prop-types": "off",
|
|
|
|
|
"tailwindcss/classnames-order": "error",
|
|
|
|
|
"tailwindcss/enforces-negative-arbitrary-values": "error",
|
|
|
|
|
"tailwindcss/enforces-shorthand": "error",
|
|
|
|
|
"tailwindcss/migration-from-tailwind-2": "error",
|
|
|
|
|
"tailwindcss/no-arbitrary-value": "off",
|
|
|
|
|
"tailwindcss/no-custom-classname": "error",
|
|
|
|
|
"tailwindcss/no-contradicting-classname": "error",
|
|
|
|
|
|
|
|
|
|
// obsidianmd: defer to follow-up PRs
|
|
|
|
|
"obsidianmd/ui/sentence-case": "off",
|
|
|
|
|
|
|
|
|
|
// obsidianmd: disabled intentionally — Platform.isMacOS branching is on-purpose
|
|
|
|
|
"obsidianmd/platform": "off",
|
|
|
|
|
|
|
|
|
|
// Bundled by obsidianmd/recommended via tseslint.configs.recommendedTypeChecked.
|
|
|
|
|
// Disabled here because the codebase intentionally uses `any` / dynamic typing
|
|
|
|
|
// around Obsidian's untyped APIs and LangChain message shapes — flipping these
|
|
|
|
|
// on would require refactoring thousands of call sites with no functional gain.
|
2026-05-13 08:52:09 +00:00
|
|
|
//
|
|
|
|
|
// Violation counts (src/**/*.{ts,tsx}) are noted inline. Rules with low counts
|
|
|
|
|
// are candidates to enable in small follow-up PRs.
|
|
|
|
|
|
|
|
|
|
// --- Heavy: any-flow through Obsidian/LangChain APIs ---
|
|
|
|
|
"@typescript-eslint/no-unsafe-member-access": "off", // 2040 violations
|
|
|
|
|
"@typescript-eslint/no-unsafe-assignment": "off", // 879 violations
|
|
|
|
|
"@typescript-eslint/no-unsafe-call": "off", // 679 violations
|
|
|
|
|
"@typescript-eslint/no-unsafe-return": "off", // 187 violations
|
|
|
|
|
|
|
|
|
|
// --- Medium: promise / method ergonomics ---
|
|
|
|
|
"@typescript-eslint/unbound-method": "off", // 68 violations
|
2026-05-14 04:45:35 +00:00
|
|
|
// Enabled in the TS-only block below.
|
2026-05-13 08:52:09 +00:00
|
|
|
|
2026-05-13 07:49:49 +00:00
|
|
|
// no-deprecated: defer — surface the warnings, but don't fail CI yet
|
|
|
|
|
"@typescript-eslint/no-deprecated": "off",
|
|
|
|
|
|
|
|
|
|
// SDL / import / no-unsanitized / depend: defer — review separately
|
|
|
|
|
"no-restricted-globals": "off",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Test files need Jest globals
|
|
|
|
|
{
|
|
|
|
|
files: ["**/*.test.{js,jsx,ts,tsx}", "jest.setup.js", "__mocks__/**"],
|
|
|
|
|
languageOptions: {
|
|
|
|
|
globals: {
|
|
|
|
|
...globals.jest,
|
|
|
|
|
...globals.node,
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-05-13 09:01:32 +00:00
|
|
|
rules: {
|
|
|
|
|
"import/no-nodejs-modules": "off",
|
|
|
|
|
},
|
2026-05-13 07:49:49 +00:00
|
|
|
},
|
|
|
|
|
|
2026-05-13 09:13:27 +00:00
|
|
|
// Integration tests bootstrap jsdom fetch via `node-fetch` polyfill —
|
|
|
|
|
// allow the otherwise-banned import here only.
|
|
|
|
|
{
|
|
|
|
|
files: ["src/integration_tests/**"],
|
|
|
|
|
rules: {
|
|
|
|
|
"no-restricted-imports": "off",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
2026-05-13 07:49:49 +00:00
|
|
|
// Node-context files (build configs, scripts)
|
|
|
|
|
{
|
|
|
|
|
files: [
|
|
|
|
|
"*.{js,mjs,cjs}",
|
|
|
|
|
"scripts/**",
|
|
|
|
|
"esbuild.config.mjs",
|
|
|
|
|
"version-bump.mjs",
|
|
|
|
|
"wasmPlugin.mjs",
|
|
|
|
|
"nodeModuleShim.mjs",
|
|
|
|
|
"jest.config.js",
|
|
|
|
|
"tailwind.config.js",
|
|
|
|
|
],
|
|
|
|
|
languageOptions: {
|
|
|
|
|
globals: {
|
|
|
|
|
...globals.node,
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-05-13 09:01:32 +00:00
|
|
|
rules: {
|
|
|
|
|
"import/no-nodejs-modules": "off",
|
|
|
|
|
},
|
2026-05-13 07:49:49 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// TypeScript-specific overrides (the @typescript-eslint plugin is registered
|
|
|
|
|
// by obsidianmd's recommended config only for .ts/.tsx files).
|
|
|
|
|
{
|
|
|
|
|
files: ["**/*.ts", "**/*.tsx"],
|
|
|
|
|
languageOptions: {
|
|
|
|
|
parserOptions: {
|
|
|
|
|
project: "./tsconfig.json",
|
|
|
|
|
tsconfigRootDir: import.meta.dirname,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
rules: {
|
|
|
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
|
|
|
"@typescript-eslint/no-empty-function": "off",
|
|
|
|
|
"@typescript-eslint/ban-ts-comment": "off",
|
|
|
|
|
"@typescript-eslint/no-unused-vars": ["error", { args: "none" }],
|
2026-05-14 04:27:35 +00:00
|
|
|
// checksVoidReturn relaxed for:
|
|
|
|
|
// - attributes: async event handlers in JSX (onClick={async () => ...}) are
|
|
|
|
|
// the standard React pattern; React already handles them correctly.
|
|
|
|
|
// - inheritedMethods: Obsidian's Plugin.onload/onunload are commonly async.
|
|
|
|
|
"@typescript-eslint/no-misused-promises": [
|
|
|
|
|
"error",
|
|
|
|
|
{ checksVoidReturn: { attributes: false, inheritedMethods: false } },
|
|
|
|
|
],
|
2026-05-14 04:45:35 +00:00
|
|
|
"@typescript-eslint/no-floating-promises": "error",
|
2026-05-13 07:49:49 +00:00
|
|
|
// TypeScript handles undefined-identifier detection (and does so cross-realm
|
|
|
|
|
// correctly); per typescript-eslint's own guidance, disable no-undef on TS.
|
|
|
|
|
"no-undef": "off",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Non-TS files aren't in tsconfig.json — disable type-aware rules that
|
2026-05-14 05:01:00 +00:00
|
|
|
// obsidianmd's recommended config enables globally. Most typed obsidianmd
|
|
|
|
|
// rules are already gated to **/*.ts(x); only no-plugin-as-component leaks
|
|
|
|
|
// out via recommendedPluginRulesConfig, and @typescript-eslint/no-deprecated
|
|
|
|
|
// is enabled globally.
|
2026-05-13 07:49:49 +00:00
|
|
|
{
|
|
|
|
|
files: ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.jsx", "**/package.json"],
|
|
|
|
|
rules: {
|
|
|
|
|
"@typescript-eslint/no-deprecated": "off",
|
|
|
|
|
"obsidianmd/no-plugin-as-component": "off",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
2026-05-13 09:07:28 +00:00
|
|
|
// package.json: keep depend/ban-dependencies enabled (from obsidianmd
|
|
|
|
|
// recommended) but allow the deps we deliberately keep.
|
2026-05-13 07:49:49 +00:00
|
|
|
{
|
|
|
|
|
files: ["**/package.json"],
|
|
|
|
|
rules: {
|
2026-05-13 09:07:28 +00:00
|
|
|
"depend/ban-dependencies": [
|
|
|
|
|
"error",
|
|
|
|
|
{
|
|
|
|
|
presets: ["native", "microutilities", "preferred"],
|
|
|
|
|
allowed: [
|
|
|
|
|
"crypto-js",
|
|
|
|
|
"dotenv",
|
|
|
|
|
"js-yaml",
|
|
|
|
|
"lodash.debounce",
|
|
|
|
|
"eslint-plugin-react",
|
|
|
|
|
"lint-staged",
|
|
|
|
|
"npm-run-all",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
2026-05-13 07:49:49 +00:00
|
|
|
},
|
|
|
|
|
},
|
2026-05-13 08:39:35 +00:00
|
|
|
|
|
|
|
|
// logger.ts is the central logging utility and must call console.* directly.
|
|
|
|
|
// scripts/** are CLI tools that print to stdout.
|
|
|
|
|
{
|
|
|
|
|
files: ["src/logger.ts", "scripts/**"],
|
|
|
|
|
rules: {
|
|
|
|
|
"obsidianmd/rule-custom-message": "off",
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-05-13 07:49:49 +00:00
|
|
|
];
|