qwen-code/eslint.config.js
易良 db8897d567
fix(export): shrink the exported transcript renderer to what a read-only transcript needs (#11038)
* fix(export): stop inlining the interactive Web Shell runtime in exported HTML

/export html builds document-main.tsx with esbuild bundle:true and inlines
the result into every exported file. The entry imported WebShellTranscript
from the @qwen-code/web-shell package root, whose facade also reaches App,
the daemon providers, the editor/terminal chrome and the full injected
component stylesheet, so each export carried 19,523,259 runtime bytes
(62x the legacy renderer) even for an empty session (#11031).

Add a transcript-only subpath entry (@qwen-code/web-shell/transcript,
mirroring the existing ./daemon-react-sdk subpath and the SDK's
./daemon/transcript pattern) that exports only the read-only transcript
renderer, and point document-main.tsx at it. The entry is built in its own
rollup run so it carries only the stylesheet reachable from transcript
rendering instead of the whole component sheet. Exports stay fully
self-contained: CSP, nonce handling and offline rendering are unchanged.

Also add a hard size budget on the inlined document runtime in the
template build, mirroring the MAX_*_BROWSER_BUNDLE_BYTES assertions in
packages/sdk-typescript/scripts/build.js. The limit sits below the
regression value so a repeat fails the build instead of landing silently.

Measured on the generated document template (empty session):
- before: 19,525,807 bytes raw / 4,775,943 gzip (runtime 19,523,259)
- after:  17,966,485 bytes raw / 4,512,650 gzip (runtime 17,963,937)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-issue-patrol/jmtn7fhrmj3

* fix(export): drop dead Shiki and CodeMirror from the export runtime

The transcript-only entry stopped the interactive shell from reaching the
inlined document runtime, but two large graphs still did, and the size
budget could not see either of them.

- Shiki (~9.7 MB of pre-minify inputs, the single largest) is unreachable
  in an export: `CodeBlock` returns before touching the highlighter when
  `renderMode === 'document'` and always renders a plain `<pre>`. It is a
  static import of `codeHighlighter.ts`, so esbuild cannot drop it. The
  document build now resolves `shiki` / `@shikijs/*` to a stub. Its
  Oniguruma WASM engine could not have started under the export CSP
  (`script-src 'nonce-…'`, no `'wasm-unsafe-eval'`) in any case.
- CodeMirror (~1 MB) still reached the transcript entry: `UserMessage`
  imported three composer-tag string getters from `hooks/useComposerCore.ts`,
  which pulls the whole editor at top level. The getters move to
  `utils/composerTag.ts` (editor-free, and already imported by
  `UserMessage`); `useComposerCore` re-exports them for existing callers.

Replace the byte-cap-only ratchet with a structural one: the document build
now emits a metafile and fails when a forbidden module graph appears in the
inputs (Shiki, the web-shell package root, CodeMirror), naming the reason.
The byte cap stays as a coarse backstop and still needs re-measuring.

Also fix a latent collision introduced by building the transcript entry in
its own rollup run: both entries injected their stylesheet under the same
`data-qwen-web-shell="component"` key, so a host importing both would keep
whichever loaded first and silently lose the other's rules. Injection is now
keyed per entry, and shadow-root style adoption concatenates every match.

Refs #11031

* docs(verification): add the export-html runtime size verification plan

The change to the inlined `/export html` runtime rests on measurements that
cannot be taken on the machine that wrote it. Rather than leave that as a
caveat in the PR description, commit the plan to the branch so any
build-capable machine gets it by cloning: exact commands, the reference
numbers to compare against and whose machine they came from, the premise the
Shiki removal rests on plus a way to falsify it independently, the two budget
constants that are knowingly stale, and what to report back.

Follows the docs/verification/abort-controller-refactor layout; results belong
next to it as results.md.

Refs #11031

* test(web-shell): scope the transcript entry guard to its JS graph

The not.toContain('vaul') guard ran against the whole bundle, but
injectCssModules prepends the Tailwind-generated stylesheet as a
single-line __qwenWebShellCss constant, and Tailwind v4 compiles
classes from every scanned source file regardless of the entry's
module graph — so drawer.tsx's data-[vaul-drawer-direction=…] variant
selectors land in the transcript entry's CSS even though no transcript
JS imports vaul (verified: 64 'vaul' occurrences in the injected CSS
line, 0 in the JS remainder, no from"vaul" import specifier).

Strip the injected CSS line before the graph guards. If the injection
shape ever changes, the replace() is a no-op and the checks fail
loudly rather than passing falsely.

* fix(export): drop the dead echarts runtime from the export bundle

CI measured the merged branch at 8,456,076 runtime bytes, and named the
inputs: `echarts 3841596` and `zrender 624992` are still the largest single
block in it.

They arrive the same way mermaid does. `@datafe-open/markdown-chart-echarts`
ends `createEChartsRenderer` with

    const loadECharts = options.loadECharts ?? (async () => await import('echarts'));

and this repository never takes that default: `MarkdownChartRenderer` always
passes a `loadECharts`, because `adaptLegacyRuntimeLoader` returns a function
that throws 'Chart runtime is unavailable.' when no `loadEcharts` prop was
supplied, and no call site in `packages/web-shell/client/` supplies one. So the
fallback is dead in this codebase — but a bundler cannot prove that, and the
export build is esbuild `format: 'iife'` with a single outfile, which cannot
code-split, so the dynamic import is flattened straight into the renderer.

Resolves `echarts` to a stub on exactly the reasoning the Shiki stub already
uses in this file — unreachable in document mode — and adds echarts/zrender to
FORBIDDEN_DOCUMENT_INPUTS so it cannot come back unnoticed. Chart blocks in an
exported transcript already could not render; they threw
'Chart runtime is unavailable.' before this change and do the same after.
Whether exports *should* render charts and diagrams is #11091, and this does
not prejudge it: giving the renderer a real runtime stays a deliberate act.

Also lowers the runtime budget from 19,000,000 to 8,700,000 using the CI
measurement above. It is still loose, because the echarts stub in this same
commit lowers the real number again — tighten it from the next green run
rather than from a guess. The structural guard is the load-bearing check.

* fix(web-shell): make the transcript entry's "no daemon providers" claim true

Review found the entry docblock over-claiming. `WebShellTranscript.tsx`
value-imported `transcriptBlocksToLocalizedMessages` from `hooks/useMessages`,
and that module value-imports `useConnection` / `useTranscriptBlocks` /
`useWorkspace` from the `daemon-react-sdk` barrel — so `dist/transcript.js`
still carried the provider guards, including
`useDaemonActions must be used within DaemonSessionProvider`.

Gives that helper the same leaf-module treatment as the composer tags: the
pure projection (and the `Translator` type it needs) moves to
`adapters/localizedMessages.ts`, which imports nothing from the daemon SDK
barrel, and `useMessages.ts` re-exports both so existing callers and its own
test are unaffected. `build-artifact.test.ts` now asserts `dist/transcript.js`
contains neither `DaemonSessionProvider` nor `DaemonWorkspaceProvider`, so the
docblock's claim is pinned rather than asserted in prose.

Also fixes the read-only recipe in `packages/web-shell/README.md`, which still
taught the root import this PR makes wrong — a host following it would ship
the interactive shell, which the reviewer measured as landing a document at
~8.8 MB, past the new cap. Same for the example in the read-only transcript
design doc.

Tightens the runtime budget to 7,400,000 / 7,300,000 warning, from the
reviewer's local measurement of 7,275,173 bytes with the echarts stub in place
(CI's 8,456,076 predates it).

* fix(web-shell): drop the now-unused adapter import from useMessages

The projection that used transcriptBlocksToDaemonMessages moved to
adapters/localizedMessages.ts in 1d94060f5, leaving the import behind.
Lint & Static caught it:

  14:10  error  'transcriptBlocksToDaemonMessages' is defined but never used

* fix(web-shell): assert what the transcript entry delivers, not what it doesn't

The guard added in 1d94060f5 was red against a clean build. Moving
`transcriptBlocksToLocalizedMessages` out of `hooks/useMessages` was correct
but it was one of several paths into the daemon barrel, and not the load-
bearing one: review's static walk of the entry's value-import graph found
three more, through components the transcript genuinely renders —
`useArtifactWorkspaceTarget.ts` (`useWorkspace`, `useWorkspaceActions`),
`McpStatusMessage.tsx` (`useMcp`) and `TasksStatusMessage.tsx` (`useActions`).
Every one of those barrel aliases resolves to a strict hook, so the provider
guards ship no matter which module the import names. Consistent with that,
`dist/transcript.js` came out 90 bytes larger after the extraction, not
smaller.

Asserting `DaemonSessionProvider` is absent therefore asserted something this
entry does not deliver. Replaced with a bound on the transcript JS remainder —
1,140,948 measured bytes against 7,021,715 for `dist/index.js`, ceiling
1,300,000 — which pins the property the entry actually exists for.

The entry docblock now says the same thing: no `App`, no composer, no
editor/terminal chrome, and the daemon hook runtime named as a known residual
with #11100 as its home. That issue also carries the question this raised —
`TasksStatusMessage` calls `useActions()` unconditionally and
`WebShellTranscript` mounts no provider, so whether an export containing a
tasks-status block renders or throws depends on what the document projector
filters, and nobody has checked.

* fix(web-shell): preserve KaTeX cascade in transcript bundle

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: yiliang114 <jinjing.zzj@gmail.com>
2026-09-06 06:15:42 +00:00

610 lines
18 KiB
JavaScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettierConfig from 'eslint-config-prettier';
import importPlugin from 'eslint-plugin-import';
import vitest from '@vitest/eslint-plugin';
import globals from 'globals';
import checkFile from 'eslint-plugin-check-file';
import noCoreRootBarrelImport from './eslint-rules/no-core-root-barrel-import.js';
import noUtilsUpwardImport from './eslint-rules/no-utils-upward-import.js';
import noCoreUtilsUpwardImport from './eslint-rules/no-core-utils-upward-import.js';
import { legacyFilenames } from './eslint.legacy-filenames.mjs';
import noConfigObjectCreate from './eslint-rules/no-config-object-create.js';
// General syntax restrictions applied to every TS/TSX source file. Hoisted so
// surface-specific overrides (flat config keeps only the last
// no-restricted-syntax setting per file) can repeat them without drift.
const generalRestrictedSyntaxSelectors = [
{
selector: 'CallExpression[callee.name="require"]',
message: 'Avoid using require(). Use ES6 imports instead.',
},
{
selector: 'ThrowStatement > Literal:not([value=/^\\w+Error:/])',
message:
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
},
];
export default tseslint.config(
{
// Global ignores
ignores: [
'node_modules/*',
'packages/**/dist/**',
'packages/web-templates/src/generated/**',
'integrations/**/dist/**',
'bundle/**',
'package/bundle/**',
'.integration-tests/**',
'packages/**/.integration-test/**',
'dist/**',
'demo/**/dist/**',
'docs-site/.next/**',
'docs-site/out/**',
'.qwen/**',
'scripts/codemod/fixtures/**', // codemod test data; intentionally non-idiomatic ink input/output
'packages/desktop-shell/runtime/**',
'packages/desktop-shell/src-tauri/target/**',
'packages/live-host/**', // standalone Electron app with its own Node test conventions
'packages/cua-driver/**', // vendored trycua/cua driver (Rust + scripts); not qwen-code TS
'packages/mobile-mcp/**', // vendored mobile-next/mobile-mcp; has own eslint config
],
},
eslint.configs.recommended,
...tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'], // Add this if you are using React 17+
{
// Settings for eslint-plugin-react
settings: {
react: {
version: 'detect',
},
},
},
{
// Import specific config
files: ['packages/cli/src/**/*.{ts,tsx}'], // Target only TS/TSX in the cli package
plugins: {
import: importPlugin,
},
settings: {
'import/resolver': {
node: true,
},
},
rules: {
...importPlugin.configs.recommended.rules,
...importPlugin.configs.typescript.rules,
'import/no-default-export': 'warn',
'import/no-unresolved': 'off', // Disable for now, can be noisy with monorepos/paths
'import/namespace': 'off', // Disabled due to https://github.com/import-js/eslint-plugin-import/issues/2866
},
},
{
// ACP integration and the daemon are separate runtime surfaces that happen
// to share a package directory. ACP may consume neutral contracts under
// `runtime/`, but never `serve/` implementation modules — see #8084.
files: ['packages/cli/src/acp-integration/**/*.{ts,tsx,js}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['**/serve', '**/serve/**'],
message:
'acp-integration must not import serve/ internals. Put shared, lifecycle-free logic in packages/cli/src/runtime/ instead (#8084).',
},
],
},
],
},
},
{
// `utils/` is the leaf layer that every other directory imports, so it
// must not import back up into a domain directory. Type-only imports are
// exempt: they are erased at compile time and cannot create a runtime
// cycle. See #9146.
files: ['packages/cli/src/utils/**/*.{ts,tsx}'],
plugins: {
architecture: {
rules: {
'no-utils-upward-import': noUtilsUpwardImport,
},
},
},
rules: {
'architecture/no-utils-upward-import': 'error',
},
},
{
// General overrides and rules for the project (TS/TSX files)
files: [
'packages/**/src/**/*.{ts,tsx}',
'integrations/**/src/**/*.{ts,tsx}',
],
plugins: {
import: importPlugin,
},
settings: {
'import/resolver': {
node: true,
},
},
languageOptions: {
globals: {
...globals.node,
...globals.es2021,
},
},
rules: {
// We use TypeScript for React components; prop-types are unnecessary
'react/prop-types': 'off',
// General Best Practice Rules (subset adapted for flat config)
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'arrow-body-style': ['error', 'as-needed'],
curly: ['error', 'multi-line'],
eqeqeq: ['error', 'always', { null: 'ignore' }],
'@typescript-eslint/consistent-type-assertions': [
'error',
{ assertionStyle: 'as' },
],
'@typescript-eslint/explicit-member-accessibility': [
'error',
{ accessibility: 'no-public' },
],
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-inferrable-types': [
'error',
{ ignoreParameters: true, ignoreProperties: true },
],
'@typescript-eslint/consistent-type-imports': [
'error',
{ disallowTypeAnnotations: false },
],
'@typescript-eslint/no-namespace': ['error', { allowDeclarations: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'import/no-internal-modules': [
'error',
{
allow: [
'react-dom/test-utils',
'react-dom/client',
'memfs/lib/volume.js',
'mime/lite',
'yargs/**',
'msw/node',
'**/generated/**',
'./styles/tailwind.css',
'./styles/App.css',
'./styles/style.css'
],
},
],
'import/no-relative-packages': 'error',
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'no-restricted-syntax': ['error', ...generalRestrictedSyntaxSelectors],
'no-unsafe-finally': 'error',
'no-console': 'error',
'no-unused-expressions': 'off', // Disable base rule
'@typescript-eslint/no-unused-expressions': [
// Enable TS version
'error',
{ allowShortCircuit: true, allowTernary: true },
],
'no-var': 'error',
'object-shorthand': 'error',
'one-var': ['error', 'never'],
'prefer-arrow-callback': 'error',
'prefer-const': ['error', { destructuring: 'all' }],
radix: 'error',
'default-case': 'error',
},
},
{
// The rule itself exempts tests, __tests__, and fixtures; repeating that
// here would give the exemption two sources of truth. The utils-upward
// rule self-scopes to packages/core/src/utils production files, so it can
// share this block without redefining the architecture plugin.
files: ['packages/core/src/**/*.{ts,tsx}'],
plugins: {
architecture: {
rules: {
'no-core-root-barrel-import': noCoreRootBarrelImport,
'no-core-utils-upward-import': noCoreUtilsUpwardImport,
},
},
},
rules: {
'architecture/no-core-root-barrel-import': 'error',
'architecture/no-core-utils-upward-import': 'error',
},
},
{
// no-restricted-imports only sees static import/export declarations, so a
// dynamic `await import('../serve/...')` would slip past the #8084 guard
// above. Kept after the general TS block because flat config applies only
// the last no-restricted-syntax setting per file, hence the repeated
// general selectors.
files: ['packages/cli/src/acp-integration/**/*.{ts,tsx,js}'],
rules: {
'no-restricted-syntax': [
'error',
...generalRestrictedSyntaxSelectors,
{
// \x2f is '/' — esquery selector regexes cannot contain a literal '/'.
selector: "ImportExpression[source.value=/(^|\\x2f)serve(\\x2f|$)/i]",
message:
'acp-integration must not dynamically import serve/ internals. Put shared, lifecycle-free logic in packages/cli/src/runtime/ instead (#8084).',
},
],
},
},
{
files: [
'packages/web-shell/client/**/*.{ts,tsx}',
'packages/web-shell/*.config.ts',
],
plugins: {
import: importPlugin,
},
settings: {
'import/resolver': {
node: true,
},
},
languageOptions: {
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
},
},
rules: {
'react/prop-types': 'off',
'@typescript-eslint/consistent-type-imports': [
'error',
{ disallowTypeAnnotations: false },
],
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'no-console': ['error', { allow: ['warn', 'error'] }],
'no-debugger': 'error',
'object-shorthand': 'error',
'prefer-const': ['error', { destructuring: 'all' }],
},
},
{
files: ['packages/web-shell/client/daemon/**/*.{ts,tsx}'],
rules: {
'no-console': ['error', { allow: ['debug', 'warn', 'error'] }],
},
},
{
files: [
'packages/web-shell/client/**/*.test.{ts,tsx}',
'packages/web-shell/client/test/**/*.{ts,tsx}',
],
plugins: {
vitest,
},
languageOptions: {
globals: {
...globals.browser,
...globals.es2021,
...globals.vitest,
},
},
rules: {
...vitest.configs.recommended.rules,
'vitest/expect-expect': 'off',
'vitest/no-commented-out-tests': 'off',
'no-console': 'off',
},
},
{
files: ['packages/web-shell/client/e2e/**/*.{ts,tsx}'],
languageOptions: {
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
},
},
rules: {
'no-console': 'off',
},
},
{
files: ['packages/core/src/**/*.ts'],
ignores: [
'packages/core/src/config/config.ts',
'**/*.test.ts',
'**/*.spec.ts',
'**/__tests__/**',
'**/generated/**',
'**/*.generated.ts',
],
plugins: {
'qwen-code': {
rules: {
'no-config-object-create': noConfigObjectCreate,
},
},
},
rules: {
'qwen-code/no-config-object-create': 'error',
},
},
{
// Enforce kebab-case filenames
files: ['packages/core/src/**/*.ts', 'packages/cli/src/**/*.ts'],
ignores: legacyFilenames.flatMap((name) => [
`**/${name}.ts`,
`**/${name}.*.ts`,
]),
plugins: {
'check-file': checkFile,
},
rules: {
'check-file/filename-naming-convention': [
'error',
{ '**/*.ts': 'KEBAB_CASE' },
{ ignoreMiddleExtensions: true },
],
},
},
{
files: [
'packages/*/src/**/*.test.{ts,tsx}',
'packages/**/test/**/*.test.{ts,tsx}',
'integrations/**/src/**/*.test.{ts,tsx}',
],
plugins: {
vitest,
},
languageOptions: {
globals: {
...globals.vitest,
},
},
rules: {
...vitest.configs.recommended.rules,
'vitest/expect-expect': 'off',
'vitest/no-commented-out-tests': 'off',
'no-console': 'off', // Allow console in tests
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
// extra settings for scripts that we run directly with node
{
files: [
'./scripts/**/*.js',
'./scripts/**/*.mjs',
'esbuild.config.js',
'packages/*/scripts/**/*.js',
'packages/*/scripts/**/*.mjs',
'packages/*/build.mjs',
// web-templates' export-html template build scripts also run with `node`.
'packages/*/src/export-html/*.mjs',
// Verification reproducer scripts under docs/ also run with `node`.
'docs/**/*.mjs',
// Plan C CDP-tunnel acceptance harness (issue #5626) runs with `node`.
'packages/cli/src/serve/cdp-tunnel/acceptance/**/*.mjs',
// Desktop-shell skill helper scripts also run with `node`.
'packages/desktop-shell/.agents/skills/**/scripts/**/*.mjs',
],
languageOptions: {
globals: {
...globals.node,
...globals.browser,
process: 'readonly',
console: 'readonly',
},
},
rules: {
'no-console': 'off', // Allow console in scripts
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
{
files: ['**/*.cjs'],
languageOptions: {
globals: {
...globals.node,
module: 'readonly',
require: 'readonly',
},
},
rules: {
'@typescript-eslint/no-require-imports': 'off',
'no-undef': 'off',
},
},
{
files: ['.github/scripts/**/*.{js,mjs,cjs}'],
languageOptions: {
globals: {
...globals.node,
},
},
},
{
files: ['packages/desktop-shell/bootstrap/**/*.js'],
languageOptions: {
globals: {
...globals.browser,
},
},
},
// The VS Code companion renders through @qwen-code/web-shell; the legacy
// @qwen-code/webui surface must not re-enter the extension bundle.
{
files: ['packages/vscode-ide-companion/src/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['@qwen-code/webui', '@qwen-code/webui/*'],
message:
'vscode-ide-companion must render through @qwen-code/web-shell; do not re-introduce @qwen-code/webui.',
},
],
},
],
},
},
// ==================== no-console allowlist ====================
// The following files/packages are allowed to use console.*
// VS Code IDE companion - out of scope for no-console rule
{
files: ['packages/vscode-ide-companion/**/*.ts', 'packages/vscode-ide-companion/**/*.tsx', 'packages/vscode-ide-companion/**/*.js'],
rules: { 'no-console': 'off' },
},
// Chrome extension (chrome-extension) - the MV3 background service
// worker and content scripts run in the browser with no stdio; console is
// the only logging / debugging channel available there.
{
files: ['packages/chrome-extension/**/*.ts', 'packages/chrome-extension/**/*.tsx'],
rules: { 'no-console': 'off' },
},
// Specific CLI files that intentionally wrap console usage
{
files: [
'packages/cli/src/acp-integration/acpAgent.ts', // console infrastructure for ACP mode
'packages/cli/src/utils/stdioHelpers.ts', // wraps console.clear()
],
rules: { 'no-console': 'off' },
},
// Specific esbuild configs not covered by scripts pattern
{
files: ['packages/vscode-ide-companion/esbuild.js'],
languageOptions: {
globals: {
...globals.node,
process: 'readonly',
console: 'readonly',
},
},
rules: {
'no-restricted-syntax': 'off',
'@typescript-eslint/no-require-imports': 'off',
'no-console': 'off',
},
},
// Settings for web-templates assets
{
files: [
'packages/web-templates/src/**/*.{js,jsx,ts,tsx}',
'packages/web-templates/*.mjs',
],
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'no-console': 'off',
'no-undef': 'off',
},
},
// Prettier config must be last
prettierConfig,
// extra settings for scripts that we run directly with node
{
files: ['./integration-tests/**/*.{js,ts,tsx}'],
languageOptions: {
globals: {
...globals.node,
process: 'readonly',
console: 'readonly',
},
},
rules: {
'no-console': 'off', // Allow console in integration tests
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
// Settings for docs-site directory
{
files: ['docs-site/**/*.{js,jsx}'],
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
// Allow relaxed rules for documentation site
'@typescript-eslint/no-unused-vars': 'off',
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
},
},
);