@elliemae/pui-cli 9.0.0-alpha.10 → 9.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/build/docs/404.html +2 -2
- package/build/docs/api/functions/loadRoutes/index.html +2 -2
- package/build/docs/api/index.html +2 -2
- package/build/docs/api/type-aliases/LIB_NAME/index.html +2 -2
- package/build/docs/api/variables/babelConfig/index.html +2 -2
- package/build/docs/api/variables/commitlintConfig/index.html +2 -2
- package/build/docs/api/variables/eslintBaseConfig/index.html +2 -2
- package/build/docs/api/variables/eslintConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatBaseConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatBaseConfigStrict/index.html +2 -2
- package/build/docs/api/variables/eslintFlatConfig/index.html +2 -2
- package/build/docs/api/variables/eslintFlatConfigStrict/index.html +2 -2
- package/build/docs/api/variables/jestConfig/index.html +2 -2
- package/build/docs/api/variables/jestNodeConfig/index.html +2 -2
- package/build/docs/api/variables/lintStagedConfig/index.html +2 -2
- package/build/docs/api/variables/prettierConfig/index.html +2 -2
- package/build/docs/api/variables/stylelintConfig/index.html +2 -2
- package/build/docs/api/variables/vitestConfig/index.html +2 -2
- package/build/docs/assets/js/04ee7372.2852111b.js +1 -0
- package/build/docs/assets/js/13097d8d.7877421c.js +1 -0
- package/build/docs/assets/js/4fb6949f.69e375e4.js +1 -0
- package/build/docs/assets/js/{main.00e13c37.js → main.d5acb4ca.js} +2 -2
- package/build/docs/assets/js/{runtime~main.cb214d1a.js → runtime~main.4f7cd700.js} +1 -1
- package/build/docs/eslint-rules-migration/index.html +6 -6
- package/build/docs/index.html +2 -2
- package/build/docs/pui-cli-9-migration/index.html +93 -6
- package/build/docs/ssl-certificate-setup/index.html +2 -2
- package/build/docs/stylelint-migration/index.html +2 -2
- package/build/docs/usage-guide/index.html +4 -4
- package/dist/cjs/commands/storybook.js +33 -4
- package/dist/cjs/lint-config/eslint/flat/compat.mjs +5 -5
- package/dist/cjs/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/dist/cjs/skills/migrate-to-pui-cli-9/SKILL.md +131 -18
- package/dist/cjs/testing/jest.config.cjs +5 -1
- package/dist/cjs/testing/setup-textencoder.cjs +4 -0
- package/dist/cjs/webpack/webpack.storybook.js +62 -0
- package/dist/esm/commands/storybook.js +22 -4
- package/dist/esm/lint-config/eslint/flat/compat.mjs +5 -5
- package/dist/esm/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/dist/esm/skills/migrate-to-pui-cli-9/SKILL.md +131 -18
- package/dist/esm/testing/jest.config.cjs +5 -1
- package/dist/esm/testing/setup-textencoder.cjs +4 -0
- package/dist/esm/webpack/webpack.storybook.js +61 -0
- package/dist/types/lib/commands/storybook.d.ts +1 -0
- package/dist/types/lib/lint-config/eslint/flat/compat.d.mts +1 -1
- package/dist/types/lib/testing/setup-textencoder.d.cts +1 -0
- package/dist/types/lib/webpack/webpack.storybook.d.ts +2 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/lib/lint-config/eslint/flat/compat.mjs +5 -5
- package/lib/skills/migrate-storybook-out-of-cjs/SKILL.md +188 -0
- package/lib/skills/migrate-to-pui-cli-9/SKILL.md +131 -18
- package/package.json +18 -25
- package/build/docs/assets/js/04ee7372.eaa386ed.js +0 -1
- package/build/docs/assets/js/13097d8d.c1821d28.js +0 -1
- package/build/docs/assets/js/4fb6949f.369cc1b9.js +0 -1
- /package/build/docs/assets/js/{main.00e13c37.js.LICENSE.txt → main.d5acb4ca.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(globalThis.webpackChunk_elliemae_pui_cli=globalThis.webpackChunk_elliemae_pui_cli||[]).push([[5455],{2668(e,n,s){s.r(n),s.d(n,{assets:()=>t,contentTitle:()=>d,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"pui-cli-9-migration","title":"pui-cli 9 migration guide","description":"This guide helps PUI consumers upgrade apps and libraries from pui-cli 8 to pui-cli 9.","source":"@site/docs/pui-cli-9-migration.md","sourceDirName":".","slug":"/pui-cli-9-migration","permalink":"/cli/pui-cli-9-migration","draft":false,"unlisted":false,"editUrl":"https://git.elliemae.io/platform-ui/pui-cli.git/docs/pui-cli-9-migration.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docsSidebar","previous":{"title":"PUI CLI Documentation","permalink":"/cli/"},"next":{"title":"Trust SSL Certificate Guide","permalink":"/cli/ssl-certificate-setup"}}');var l=s(6070),r=s(6607);const c={},d="pui-cli 9 migration guide",t={},o=[{value:"At a glance",id:"at-a-glance",level:2},{value:"Recommended rollout",id:"recommended-rollout",level:2},{value:"Step-by-step",id:"step-by-step",level:2},{value:"1. Upgrade toolchain",id:"1-upgrade-toolchain",level:3},{value:"1b. Migrate pnpm hoisting to <code>pnpm-workspace.yaml</code> (pnpm 11)",id:"1b-migrate-pnpm-hoisting-to-pnpm-workspaceyaml-pnpm-11",level:3},{value:"Why",id:"why",level:4},{value:"Settings to move",id:"settings-to-move",level:4},{value:"Single-package app or library",id:"single-package-app-or-library",level:4},{value:"Monorepo (<code>libs/*</code>, <code>apps/*</code>)",id:"monorepo-libs-apps",level:4},{value:"Reinstall and verify",id:"reinstall-and-verify",level:4},{value:"Common failures",id:"common-failures",level:4},{value:"2. Upgrade pui-cli",id:"2-upgrade-pui-cli",level:3},{value:"3. Add flat ESLint config",id:"3-add-flat-eslint-config",level:3},{value:"4. Update Stylelint config",id:"4-update-stylelint-config",level:3},{value:"5. Fix lint",id:"5-fix-lint",level:3},{value:"6. Install the migration skill (optional)",id:"6-install-the-migration-skill-optional",level:3},{value:"Temporary overrides",id:"temporary-overrides",level:2},{value:"Strict config (after cleanup)",id:"strict-config-after-cleanup",level:2},{value:"Husky 9",id:"husky-9",level:2},{value:"Jest (<code>pui-cli test</code>)",id:"jest-pui-cli-test",level:2},{value:"Vitest 4",id:"vitest-4",level:2},{value:"semantic-release 25",id:"semantic-release-25",level:2},{value:"1. Upgrade semantic-release (if pinned locally)",id:"1-upgrade-semantic-release-if-pinned-locally",level:3},{value:"2. Migrate release config to ESM",id:"2-migrate-release-config-to-esm",level:3},{value:"3. Custom plugins or overrides",id:"3-custom-plugins-or-overrides",level:3},{value:"4. Verify locally",id:"4-verify-locally",level:3},{value:"Agent-assisted migration",id:"agent-assisted-migration",level:3},{value:"Lerna 9 and Nx 22 (monorepos only)",id:"lerna-9-and-nx-22-monorepos-only",level:2},{value:"1. Remove legacy Nx package pins",id:"1-remove-legacy-nx-package-pins",level:3},{value:"2. Migrate <code>nx.json</code>",id:"2-migrate-nxjson",level:3},{value:"3. Lerna 9 notes",id:"3-lerna-9-notes",level:3},{value:"4. Verify monorepo workflows",id:"4-verify-monorepo-workflows",level:3},{value:"Storybook 10 (pui-cli 9)",id:"storybook-10-pui-cli-9",level:2},{value:"What changed",id:"what-changed",level:3},{value:"Consumer migration",id:"consumer-migration",level:3},{value:"Verify",id:"verify",level:3},{value:"CI checklist",id:"ci-checklist",level:2},{value:"Getting help",id:"getting-help",level:2}];function a(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",hr:"hr",input:"input",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.header,{children:(0,l.jsx)(n.h1,{id:"pui-cli-9-migration-guide",children:"pui-cli 9 migration guide"})}),"\n",(0,l.jsxs)(n.p,{children:["This guide helps PUI consumers upgrade apps and libraries from ",(0,l.jsx)(n.strong,{children:"pui-cli 8"})," to ",(0,l.jsx)(n.strong,{children:"pui-cli 9"}),".\nFor ESLint rule-level detail, see ",(0,l.jsx)(n.a,{href:"/cli/eslint-rules-migration",children:"ESLint rules migration guide"}),"."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"at-a-glance",children:"At a glance"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Topic"}),(0,l.jsx)(n.th,{children:"pui-cli 8"}),(0,l.jsx)(n.th,{children:"pui-cli 9"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Node.js"}),(0,l.jsx)(n.td,{children:"20"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.strong,{children:"24"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"pnpm"}),(0,l.jsx)(n.td,{children:"8\u201310"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"11"})," (hoist settings in ",(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})}),", not ",(0,l.jsx)(n.code,{children:".npmrc"}),")"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"App/library bundler"}),(0,l.jsx)(n.td,{children:"Webpack"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"Webpack"})," (unchanged)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"ESLint"}),(0,l.jsxs)(n.td,{children:["8.x + ",(0,l.jsx)(n.code,{children:".eslintrc.cjs"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"10.x"})," + ",(0,l.jsx)(n.code,{children:"eslint.config.mjs"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Stylelint"}),(0,l.jsxs)(n.td,{children:["15.x + ",(0,l.jsx)(n.code,{children:"stylelint-config-styled-components"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"17.x"})," + ",(0,l.jsx)(n.code,{children:"postcss-styled-syntax"})," (styled-components rules inlined)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:["Vitest (via ",(0,l.jsx)(n.code,{children:"pui-cli vitest"}),")"]}),(0,l.jsx)(n.td,{children:"1.x"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"4.x"})," (uses Vite internally; not the app bundler)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"TypeScript lint"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"@typescript-eslint"})," v5"]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"typescript-eslint"})," v8"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Exported tsconfig"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'moduleResolution: "node"'})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:'moduleResolution: "bundler"'})})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Shared config import"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"require('@elliemae/pui-cli').eslintConfig"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"import { eslintFlatConfig } from '@elliemae/pui-cli/eslint'"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Stylelint import"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"require('@elliemae/pui-cli').stylelintConfig"})}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"import { stylelintConfig } from '@elliemae/pui-cli/stylelint'"})," (or keep CJS re-export)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"semantic-release"}),(0,l.jsxs)(n.td,{children:["21.x + ",(0,l.jsx)(n.code,{children:"release.config.cjs"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"25.x"})," + ",(0,l.jsx)(n.code,{children:"release.config.mjs"})," (ESM ",(0,l.jsx)(n.code,{children:"extends"})," for shareable config)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Husky"}),(0,l.jsx)(n.td,{children:"8.x"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.strong,{children:"9.x"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Lerna (monorepos)"}),(0,l.jsx)(n.td,{children:"6.x"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"9.x"})," (via pui-cli; ",(0,l.jsx)(n.code,{children:"bootstrap"}),"/",(0,l.jsx)(n.code,{children:"add"}),"/",(0,l.jsx)(n.code,{children:"link"})," removed)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Nx (monorepos)"}),(0,l.jsxs)(n.td,{children:["15.x (",(0,l.jsx)(n.code,{children:"@nrwl/*"}),")"]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.strong,{children:"22.x"})," (",(0,l.jsx)(n.code,{children:"nx"})," + ",(0,l.jsx)(n.code,{children:"@nx/workspace"}),"; modern ",(0,l.jsx)(n.code,{children:"nx.json"}),")"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Cursor skill"}),(0,l.jsx)(n.td,{children:"\u2014"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"pui-cli skills install migrate-to-pui-cli-9 --target all"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Storybook CJS \u2192 ESM skill"}),(0,l.jsx)(n.td,{children:"\u2014"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"pui-cli skills install migrate-storybook-out-of-cjs --target all"})})]})]})]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"recommended-rollout",children:"Recommended rollout"}),"\n",(0,l.jsxs)(n.p,{children:["Ship in ",(0,l.jsx)(n.strong,{children:"small PRs"})," to reduce regression risk:"]}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Toolchain"})," \u2014 Node 24 + pnpm 11 + CI image updates + ",(0,l.jsxs)(n.strong,{children:["hoisting in ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})]})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Dependency bump"})," \u2014 ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli@9"})," without ESLint config change"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"ESLint flat config"})," \u2014 add ",(0,l.jsx)(n.code,{children:"eslint.config.mjs"}),", delete legacy ESLint files, fix lint"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Stylelint 17"})," \u2014 simplify ",(0,l.jsx)(n.code,{children:"stylelint.config.cjs"})," (remove ",(0,l.jsx)(n.code,{children:"stylelint-config-styled-components"})," overrides); optional ",(0,l.jsx)(n.code,{children:"stylelint.config.mjs"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Husky 9"})," \u2014 update ",(0,l.jsx)(n.code,{children:"prepare"})," script and hook files (if ",(0,l.jsx)(n.code,{children:".husky/"})," exists)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Vitest 4"})," \u2014 only if the repo uses ",(0,l.jsx)(n.code,{children:"pui-cli vitest"})," (see below)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"semantic-release 25"})," \u2014 migrate ",(0,l.jsx)(n.code,{children:"release.config.cjs"})," \u2192 ",(0,l.jsx)(n.code,{children:"release.config.mjs"})," (libraries that publish to npm)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Lerna 9 + Nx 22"})," \u2014 monorepos only: update ",(0,l.jsx)(n.code,{children:"nx.json"}),", remove ",(0,l.jsx)(n.code,{children:"@nrwl/*"})," pins, verify ",(0,l.jsx)(n.code,{children:"pui-cli version"})," / ",(0,l.jsx)(n.code,{children:"nx run-many"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Debt (optional)"})," \u2014 remove temporary rule overrides, adopt strict config"]}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:["Each PR should pass: ",(0,l.jsx)(n.code,{children:"lint"}),", ",(0,l.jsx)(n.code,{children:"tscheck"}),", ",(0,l.jsx)(n.code,{children:"test"}),", ",(0,l.jsx)(n.code,{children:"build"}),"."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"step-by-step",children:"Step-by-step"}),"\n",(0,l.jsx)(n.h3,{id:"1-upgrade-toolchain",children:"1. Upgrade toolchain"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"# .node-version\n24\n"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'// package.json (root)\n"engines": {\n "pnpm": ">=11",\n "node": ">=24"\n}\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Do ",(0,l.jsx)(n.strong,{children:"not"})," pin an exact pnpm version in ",(0,l.jsx)(n.code,{children:"packageManager"})," \u2014 Corepack requires an exact semver there, which forces every customer onto the same patch. Use ",(0,l.jsx)(n.code,{children:"engines.pnpm"})," so teams can run any pnpm 11 minor or patch. Omit ",(0,l.jsx)(n.code,{children:"packageManager"})," unless you intentionally want Corepack to lock one version for your own CI."]}),"\n",(0,l.jsx)(n.p,{children:"Update Jenkins/docker Node images before merging."}),"\n",(0,l.jsxs)(n.h3,{id:"1b-migrate-pnpm-hoisting-to-pnpm-workspaceyaml-pnpm-11",children:["1b. Migrate pnpm hoisting to ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})," (pnpm 11)"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Do this in every repo"})," that upgrades to pnpm 11 \u2014 single-package apps, libraries, and monorepos."]}),"\n",(0,l.jsx)(n.h4,{id:"why",children:"Why"}),"\n",(0,l.jsxs)(n.p,{children:["pnpm 11 only reads ",(0,l.jsx)(n.strong,{children:"auth and registry"})," from ",(0,l.jsx)(n.code,{children:".npmrc"}),". Every other pnpm setting \u2014 including hoisting \u2014 must live in ",(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})})," (camelCase keys). See ",(0,l.jsx)(n.a,{href:"https://pnpm.io/next/migration",children:"pnpm v11 migration"}),"."]}),"\n",(0,l.jsxs)(n.p,{children:["If hoisting stays only in ",(0,l.jsx)(n.code,{children:".npmrc"}),", pnpm ",(0,l.jsx)(n.strong,{children:"silently ignores it"}),". Symptom: ",(0,l.jsx)(n.code,{children:"node_modules/.modules.yaml"})," shows ",(0,l.jsx)(n.code,{children:'"publicHoistPattern": []'})," even when ",(0,l.jsx)(n.code,{children:".npmrc"})," has ",(0,l.jsx)(n.code,{children:"shamefully-hoist=true"}),". Webpack builds then fail with ",(0,l.jsx)(n.code,{children:"Can't resolve 'esbuild-loader'"}),", ",(0,l.jsx)(n.code,{children:"styled-components"}),", or ",(0,l.jsx)(n.code,{children:"@elliemae/pui-theme"})," because ",(0,l.jsx)(n.strong,{children:"pui-cli webpack aliases"})," resolve packages from the ",(0,l.jsx)(n.strong,{children:"repo root"})," ",(0,l.jsx)(n.code,{children:"node_modules/"}),"."]}),"\n",(0,l.jsxs)(n.p,{children:["PUI org policy keeps ",(0,l.jsx)(n.strong,{children:(0,l.jsx)(n.code,{children:"shamefullyHoist: true"})})," (same as pnpm 8 ",(0,l.jsx)(n.code,{children:"shamefully-hoist=true"}),") for compatibility with ",(0,l.jsx)(n.code,{children:"@elliemae/app-react-dependencies"})," and pui-cli tooling. ",(0,l.jsx)(n.strong,{children:"Do not remove hoisting"})," during the cli 9 migration."]}),"\n",(0,l.jsx)(n.h4,{id:"settings-to-move",children:"Settings to move"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.th,{children:["pnpm 8\u201310 (",(0,l.jsx)(n.code,{children:".npmrc"})," or ",(0,l.jsx)(n.code,{children:"package.json#pnpm"}),")"]}),(0,l.jsxs)(n.th,{children:["pnpm 11 (",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"}),")"]})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"shamefully-hoist=true"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"shamefullyHoist: true"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"public-hoist-pattern[]=\u2026"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'publicHoistPattern: [ "\u2026" ]'})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"strict-peer-dependencies=false"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"strictPeerDependencies: false"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"auto-install-peers=false"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"autoInstallPeers: false"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"git-checks=false"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"gitChecks: false"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"enable-pre-post-scripts=true"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"enablePrePostScripts: true"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"package.json"})," \u2192 ",(0,l.jsx)(n.code,{children:'"pnpm": { "overrides": \u2026 }'})]}),(0,l.jsxs)(n.td,{children:["top-level ",(0,l.jsx)(n.code,{children:"overrides:"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"onlyBuiltDependencies"})," / ",(0,l.jsx)(n.code,{children:"neverBuiltDependencies"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"allowBuilds:"})," (",(0,l.jsx)(n.code,{children:"true"})," / ",(0,l.jsx)(n.code,{children:"false"})," per package)"]})]})]})]}),"\n",(0,l.jsxs)(n.p,{children:["Leave ",(0,l.jsx)(n.strong,{children:"only"})," auth/registry lines in ",(0,l.jsx)(n.code,{children:".npmrc"})," (for example ",(0,l.jsx)(n.code,{children:"legacy-peer-deps=true"})," if your registry workflow needs it)."]}),"\n",(0,l.jsx)(n.h4,{id:"single-package-app-or-library",children:"Single-package app or library"}),"\n",(0,l.jsxs)(n.p,{children:["Create or update ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})," at the repo root:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:"packages:\n - '.'\n\nshamefullyHoist: true\nstrictPeerDependencies: false\nautoInstallPeers: false\n\nallowBuilds:\n '@swc/core': true\n esbuild: true\n nx: true\n # \u2026approve other packages that run install scripts (see pnpm approve-builds)\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Reference: ",(0,l.jsx)(n.code,{children:"pui-react-boilerplate/pnpm-workspace.yaml"}),", ",(0,l.jsx)(n.code,{children:"pui-lib-boilerplate/pnpm-workspace.yaml"}),"."]}),"\n",(0,l.jsxs)(n.h4,{id:"monorepo-libs-apps",children:["Monorepo (",(0,l.jsx)(n.code,{children:"libs/*"}),", ",(0,l.jsx)(n.code,{children:"apps/*"}),")"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-yaml",children:'packages:\n - "libs/*"\n - "apps/*"\n\nshamefullyHoist: true\n# Optional explicit patterns (shamefullyHoist already hoists all deps to root)\npublicHoistPattern:\n - "esbuild-loader"\n - "@elliemae/*"\n - "styled-components"\n - "history"\n - "lodash"\nstrictPeerDependencies: false\nautoInstallPeers: false\ngitChecks: false\nenablePrePostScripts: true\n\noverrides:\n esbuild-loader: "4.4.3" # if webpack hits esbuild-loader@3.x useSourceMap crash\n\nallowBuilds:\n \'@swc/core\': true\n esbuild: true\n nx: true\n # \u2026set true for each package that must run postinstall scripts\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Reference: ",(0,l.jsx)(n.code,{children:"pui-microfe/pnpm-workspace.yaml"}),", ",(0,l.jsx)(n.code,{children:"pui-mono-repo-boilerplate/pnpm-workspace.yaml"}),"."]}),"\n",(0,l.jsxs)(n.p,{children:["Move any ",(0,l.jsx)(n.code,{children:"package.json"})," ",(0,l.jsx)(n.code,{children:'"pnpm": { "overrides": \u2026 }'})," block into this file and delete the ",(0,l.jsx)(n.code,{children:"pnpm"})," key from ",(0,l.jsx)(n.code,{children:"package.json"}),"."]}),"\n",(0,l.jsx)(n.h4,{id:"reinstall-and-verify",children:"Reinstall and verify"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"rm -rf node_modules libs/*/node_modules # monorepos; apps/libs only if present\nSKIP_POST_INSTALL_BUILD=1 pnpm install --no-frozen-lockfile\n"})}),"\n",(0,l.jsx)(n.p,{children:"Check hoisting took effect:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'# Should list patterns (shamefullyHoist => ["*"]) \u2014 not []\ngrep publicHoistPattern node_modules/.modules.yaml\n\n# Webpack / pui-cli alias targets should exist at repo root\nls node_modules/esbuild-loader node_modules/styled-components 2>/dev/null\npnpm run build\n'})}),"\n",(0,l.jsx)(n.h4,{id:"common-failures",children:"Common failures"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Symptom"}),(0,l.jsx)(n.th,{children:"Fix"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"Can't resolve 'esbuild-loader'"})," during ",(0,l.jsx)(n.code,{children:"pui-cli pack"})," / webpack"]}),(0,l.jsxs)(n.td,{children:["Add ",(0,l.jsx)(n.code,{children:"shamefullyHoist: true"})," to ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"}),"; clean reinstall"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"Can't resolve '@elliemae/pui-theme'"})," or ",(0,l.jsx)(n.code,{children:"styled-components"})]}),(0,l.jsxs)(n.td,{children:["Same \u2014 hoisting must be in workspace yaml, not ",(0,l.jsx)(n.code,{children:".npmrc"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"husky: command not found"})," on ",(0,l.jsx)(n.code,{children:"pnpm prepare"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"shamefullyHoist"})," + optional ",(0,l.jsx)(n.code,{children:"publicHoistPattern: [husky]"}),"; or keep ",(0,l.jsx)(n.code,{children:"husky"})," as a direct root ",(0,l.jsx)(n.code,{children:"devDependency"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"ERR_PNPM_IGNORED_BUILDS"})}),(0,l.jsxs)(n.td,{children:["Replace placeholder ",(0,l.jsx)(n.code,{children:"allowBuilds"})," values with ",(0,l.jsx)(n.code,{children:"true"})," or run ",(0,l.jsx)(n.code,{children:"pnpm approve-builds"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"publicHoistPattern: []"})," in ",(0,l.jsx)(n.code,{children:".modules.yaml"})]}),(0,l.jsxs)(n.td,{children:["Hoist settings still in ",(0,l.jsx)(n.code,{children:".npmrc"})," only \u2014 migrate to ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})]})]})]})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Long-term platform fix:"})," pui-cli should resolve webpack loaders from its own install path and make ",(0,l.jsx)(n.code,{children:"getAlias()"})," fall back beyond root ",(0,l.jsx)(n.code,{children:"node_modules"}),". Until then, hoisting in ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"})," is required for pnpm 11 consumers."]}),"\n",(0,l.jsx)(n.h3,{id:"2-upgrade-pui-cli",children:"2. Upgrade pui-cli"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm add -D @elliemae/pui-cli@9\n"})}),"\n",(0,l.jsx)(n.h3,{id:"3-add-flat-eslint-config",children:"3. Add flat ESLint config"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"React app or library:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-js",children:"// eslint.config.mjs\nimport { eslintFlatConfig } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatConfig;\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Node / TS service:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-js",children:"// eslint.config.mjs\nimport { eslintFlatBaseConfig } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatBaseConfig;\n"})}),"\n",(0,l.jsx)(n.p,{children:"Remove:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:".eslintrc.cjs"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:".eslintignore"})}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"4-update-stylelint-config",children:"4. Update Stylelint config"}),"\n",(0,l.jsxs)(n.p,{children:["pui-cli 9 ships ",(0,l.jsx)(n.strong,{children:"Stylelint 17"})," with ",(0,l.jsx)(n.code,{children:"stylelint-config-recommended@18"})," and ",(0,l.jsx)(n.code,{children:"postcss-styled-syntax"}),". The unmaintained ",(0,l.jsx)(n.code,{children:"stylelint-config-styled-components"})," package is removed; its rules are inlined in the shared config."]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Minimal (CJS \u2014 still supported):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"// stylelint.config.cjs\nconst { stylelintConfig } = require('@elliemae/pui-cli');\nmodule.exports = stylelintConfig;\n"})}),"\n",(0,l.jsxs)(n.p,{children:["If your repo previously filtered out ",(0,l.jsx)(n.code,{children:"stylelint-config-styled-components"})," from ",(0,l.jsx)(n.code,{children:"extends"}),", delete that workaround \u2014 the base config no longer extends it."]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Recommended (ESM):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"// stylelint.config.mjs\nimport { stylelintConfig } from '@elliemae/pui-cli/stylelint';\n\nexport default stylelintConfig;\n"})}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.code,{children:"pui-cli lint"})," prefers ",(0,l.jsx)(n.code,{children:"stylelint.config.mjs"})," when present, otherwise falls back to ",(0,l.jsx)(n.code,{children:"stylelint.config.cjs"}),"."]}),"\n",(0,l.jsxs)(n.p,{children:["See ",(0,l.jsx)(n.a,{href:"/cli/stylelint-migration",children:"Stylelint migration guide"})," for version and rule changes."]}),"\n",(0,l.jsx)(n.h3,{id:"5-fix-lint",children:"5. Fix lint"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli lint --fix\npnpm exec pui-cli lint\npnpm exec pui-cli tscheck --files\npnpm test\npnpm run build\n"})}),"\n",(0,l.jsx)(n.h3,{id:"6-install-the-migration-skill-optional",children:"6. Install the migration skill (optional)"}),"\n",(0,l.jsx)(n.p,{children:"Gives Cursor, Claude Code, and GitHub Copilot agents a step-by-step playbook in the repo:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli skills list\npnpm exec pui-cli skills install migrate-to-pui-cli-9 --target all\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Skills are copied to ",(0,l.jsx)(n.code,{children:".cursor/skills/"}),", ",(0,l.jsx)(n.code,{children:".claude/skills/"}),", and ",(0,l.jsx)(n.code,{children:".github/skills/"})," (commit them if you want the whole team to share the same agent guidance)."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"temporary-overrides",children:"Temporary overrides"}),"\n",(0,l.jsxs)(n.p,{children:["Large repos may have pre-existing ",(0,l.jsx)(n.code,{children:"any"})," usage. Legacy ESLint reported these as ",(0,l.jsx)(n.strong,{children:"warnings"}),"; flat config defaults them to ",(0,l.jsx)(n.strong,{children:"error"}),"."]}),"\n",(0,l.jsx)(n.p,{children:"Short-term override (remove in a follow-up):"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-js",children:"import { eslintFlatConfig } from '@elliemae/pui-cli/eslint';\n\nexport default [\n ...eslintFlatConfig,\n {\n rules: {\n '@typescript-eslint/no-explicit-any': 'warn',\n },\n },\n];\n"})}),"\n",(0,l.jsx)(n.p,{children:"Libraries with heavy decorator/micro-frontend typings may need additional one-off overrides \u2014 keep them minimal and tracked."}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"strict-config-after-cleanup",children:"Strict config (after cleanup)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-js",children:"import { eslintFlatConfigStrict } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatConfigStrict;\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Strict mode elevates ",(0,l.jsx)(n.code,{children:"no-unsafe-*"})," and ",(0,l.jsx)(n.code,{children:"exhaustive-deps"})," to error."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"husky-9",children:"Husky 9"}),"\n",(0,l.jsx)(n.p,{children:"If your repo uses Husky 8 hooks from pui-cli boilerplate:"}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:["Upgrade: ",(0,l.jsx)(n.code,{children:"pnpm add -D husky@9"})]}),"\n",(0,l.jsxs)(n.li,{children:["Update ",(0,l.jsx)(n.code,{children:"package.json"}),":","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-diff",children:'- "prepare": "[ -n \\"$CI\\" ] || husky install"\n+ "prepare": "[ -n \\"$CI\\" ] || husky"\n'})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Remove the shebang and ",(0,l.jsx)(n.code,{children:"husky.sh"})," source from each hook in ",(0,l.jsx)(n.code,{children:".husky/"}),":","\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-diff",children:'- #!/bin/sh\n- . "$(dirname "$0")/_/husky.sh"\n\npnpm -s dlx lint-staged\n'})}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:["Delete ",(0,l.jsx)(n.code,{children:".husky/.gitignore"})," if present (v9 regenerates ",(0,l.jsx)(n.code,{children:".husky/_"})," on install)."]}),"\n",(0,l.jsxs)(n.li,{children:["Remove ",(0,l.jsx)(n.code,{children:"husky-init"})," from devDependencies (use ",(0,l.jsx)(n.code,{children:"pnpm exec husky init"})," for new projects)."]}),"\n",(0,l.jsxs)(n.li,{children:["Run ",(0,l.jsx)(n.code,{children:"pnpm prepare"})," and verify with a test commit."]}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Environment variable changes:"})," ",(0,l.jsx)(n.code,{children:"HUSKY_SKIP_HOOKS"})," / ",(0,l.jsx)(n.code,{children:"HUSKY_SKIP_INSTALL"})," \u2192 ",(0,l.jsx)(n.code,{children:"HUSKY=0"}),"; ",(0,l.jsx)(n.code,{children:"HUSKY_GIT_PARAMS"})," \u2192 use ",(0,l.jsx)(n.code,{children:"$1"})," in hook scripts."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsxs)(n.h2,{id:"jest-pui-cli-test",children:["Jest (",(0,l.jsx)(n.code,{children:"pui-cli test"}),")"]}),"\n",(0,l.jsxs)(n.p,{children:["pui-cli's default ",(0,l.jsx)(n.code,{children:"jestConfig"})," runs ",(0,l.jsx)(n.code,{children:"lib/testing/setup-textencoder.cjs"})," before other ",(0,l.jsx)(n.code,{children:"setupFiles"}),". It polyfills ",(0,l.jsx)(n.code,{children:"TextEncoder"})," / ",(0,l.jsx)(n.code,{children:"TextDecoder"})," on ",(0,l.jsx)(n.code,{children:"globalThis"})," from ",(0,l.jsx)(n.code,{children:"node:util"})," so ",(0,l.jsx)(n.strong,{children:"jsdom"})," tests can import packages (for example ",(0,l.jsx)(n.code,{children:"@elliemae/pui-diagnostics"})," HTTP transport) that expect those APIs at module load time."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsxs)(n.strong,{children:["Repos do not need a local ",(0,l.jsx)(n.code,{children:"jest-textencoder-setup.cjs"}),"."]})," Delete it if you added one during migration."]}),"\n",(0,l.jsxs)(n.p,{children:["Typical ",(0,l.jsx)(n.code,{children:"jest.config.cjs"})," when testing against the real diagnostics package (not the pui-cli mock):"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"const { jestConfig } = require('@elliemae/pui-cli');\n\ndelete jestConfig.moduleNameMapper['@elliemae/pui-diagnostics'];\n\nmodule.exports = jestConfig;\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Do ",(0,l.jsx)(n.strong,{children:"not"})," replace ",(0,l.jsx)(n.code,{children:"setupFiles"})," unless you must prepend repo-specific setup; spread the defaults instead:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"jestConfig.setupFiles = [\n path.resolve(__dirname, './my-extra-setup.cjs'),\n ...(jestConfig.setupFiles || []),\n];\n"})}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"vitest-4",children:"Vitest 4"}),"\n",(0,l.jsxs)(n.p,{children:["Skip this section if the repo uses Jest (",(0,l.jsx)(n.code,{children:"pui-cli test"}),") only. ",(0,l.jsx)(n.strong,{children:"pui-cli 9 still builds apps and libraries with Webpack"}),"; Vite is used by Vitest (and optional ",(0,l.jsx)(n.code,{children:"pui-cli buildCDN"}),"), not for production bundling."]}),"\n",(0,l.jsxs)(n.p,{children:["After bumping ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli@9"}),", align local test dependencies with the versions pui-cli ships:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm add -D vitest@4 @vitest/coverage-v8@4 vite@8 @vitejs/plugin-react@6 vite-tsconfig-paths@6\npnpm remove @vitest/coverage-c8 @types/uuid # if present; uuid 14+ includes types\n"})}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Extend the shared config"})," (recommended):"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-typescript",children:"// vitest.config.ts\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { vitestConfig } from '@elliemae/pui-cli/vitest';\n\nexport default mergeConfig(vitestConfig, defineConfig({\n test: {\n // repo-specific overrides\n },\n}));\n"})}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsxs)(n.strong,{children:["If you spread ",(0,l.jsx)(n.code,{children:"vitestConfig"})," manually"]}),", update any Vitest 1.x options:"]}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"pui-cli 8 / Vitest 1"}),(0,l.jsx)(n.th,{children:"pui-cli 9 / Vitest 4"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"test.deps.optimizer.web"})}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"test.deps.optimizer.client"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"@vitest/coverage-c8"})}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"@vitest/coverage-v8"})," (coverage provider ",(0,l.jsx)(n.code,{children:"v8"}),")"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"import { PluginOption } from 'vite'"})}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"import type { PluginOption } from 'vite'"})," (Vite 8)"]})]})]})]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"TypeScript:"})," exported ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli/app.tsconfig.json"})," and ",(0,l.jsx)(n.code,{children:"library.tsconfig.json"})," use ",(0,l.jsx)(n.code,{children:'moduleResolution: "bundler"'}),". If your ",(0,l.jsx)(n.code,{children:"tsconfig.json"})," extends them, reinstall pui-cli and re-run ",(0,l.jsx)(n.code,{children:"tscheck"}),". Custom tsconfigs that import ",(0,l.jsx)(n.code,{children:"vitest/config"})," or ",(0,l.jsx)(n.code,{children:"vite"})," may need the same setting."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Vitest config import:"})," use ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli/vitest"})," (not the package root). pui-cli 9 publishes ",(0,l.jsx)(n.code,{children:"types"})," on each ",(0,l.jsx)(n.code,{children:"package.json"})," ",(0,l.jsx)(n.code,{children:"exports"})," entry so ",(0,l.jsx)(n.code,{children:"tsc"})," resolves declarations under ",(0,l.jsx)(n.code,{children:'moduleResolution: "bundler"'})," \u2014 no ",(0,l.jsx)(n.code,{children:"tsconfig"})," ",(0,l.jsx)(n.code,{children:"paths"})," workaround."]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli vitest --passWithNoTests\npnpm exec pui-cli tscheck --files\n"})}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"semantic-release-25",children:"semantic-release 25"}),"\n",(0,l.jsxs)(n.p,{children:["pui-cli 9 ships ",(0,l.jsx)(n.strong,{children:"semantic-release 25"})," with an ESM shareable config at ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli/releaseConfig"}),". semantic-release 22+ loads ESM ",(0,l.jsx)(n.code,{children:"extends"})," targets via dynamic ",(0,l.jsx)(n.code,{children:"import()"})," \u2014 the old ",(0,l.jsx)(n.code,{children:"release.config.cjs"})," + ",(0,l.jsx)(n.code,{children:"require()"})," path no longer works for the shared config."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsxs)(n.strong,{children:["Libraries that run ",(0,l.jsx)(n.code,{children:"semantic-release"})," in CI"]})," should migrate in the same PR as the pui-cli 9 bump (or immediately after)."]}),"\n",(0,l.jsx)(n.h3,{id:"1-upgrade-semantic-release-if-pinned-locally",children:"1. Upgrade semantic-release (if pinned locally)"}),"\n",(0,l.jsxs)(n.p,{children:["Most PUI libraries inherit semantic-release from ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli"}),". If your ",(0,l.jsx)(n.code,{children:"package.json"})," pins ",(0,l.jsx)(n.code,{children:"semantic-release"})," or ",(0,l.jsx)(n.code,{children:"@semantic-release/*"})," plugins directly, align with pui-cli 9:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm add -D semantic-release@25 @semantic-release/changelog@6 @semantic-release/exec@7 @semantic-release/git@10\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Remove explicit pins if the repo only uses ",(0,l.jsx)(n.code,{children:"pnpm release"})," and relies on pui-cli's dependency tree."]}),"\n",(0,l.jsx)(n.h3,{id:"2-migrate-release-config-to-esm",children:"2. Migrate release config to ESM"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Before:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"// release.config.cjs\nmodule.exports = {\n extends: '@elliemae/pui-cli/releaseConfig',\n};\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"After:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"// release.config.mjs\n/** @type {import('semantic-release').GlobalConfig} */\nexport default {\n extends: '@elliemae/pui-cli/releaseConfig',\n};\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Delete ",(0,l.jsx)(n.code,{children:"release.config.cjs"})," after adding ",(0,l.jsx)(n.code,{children:"release.config.mjs"}),"."]}),"\n",(0,l.jsx)(n.h3,{id:"3-custom-plugins-or-overrides",children:"3. Custom plugins or overrides"}),"\n",(0,l.jsxs)(n.p,{children:["Keep repo-specific plugins as relative paths from the config file. ESM plugins use ",(0,l.jsx)(n.code,{children:"export default"}),":"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"// release.config.mjs\nexport default {\n extends: '@elliemae/pui-cli/releaseConfig',\n plugins: [\n '@semantic-release/commit-analyzer',\n // ...other plugins from the shared config if replacing extends entirely\n './my-custom-plugin.mjs',\n ],\n};\n"})}),"\n",(0,l.jsxs)(n.p,{children:["CJS plugins (",(0,l.jsx)(n.code,{children:".cjs"}),") still work when referenced by path."]}),"\n",(0,l.jsx)(n.h3,{id:"4-verify-locally",children:"4. Verify locally"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec semantic-release --dry-run\n"})}),"\n",(0,l.jsx)(n.h3,{id:"agent-assisted-migration",children:"Agent-assisted migration"}),"\n",(0,l.jsx)(n.p,{children:"Install the pui-cli 9 skill so Cursor / Copilot agents follow the full config migration playbook (ESLint, Stylelint, Vitest, Husky, and semantic-release):"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli skills install migrate-to-pui-cli-9 --target all\n"})}),"\n",(0,l.jsx)(n.p,{children:"Then ask the agent to migrate configuration files for pui-cli 9."}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"lerna-9-and-nx-22-monorepos-only",children:"Lerna 9 and Nx 22 (monorepos only)"}),"\n",(0,l.jsxs)(n.p,{children:["Skip this section for single-package apps and libraries. PUI monorepos (for example ",(0,l.jsx)(n.code,{children:"pui-microfe"}),", ",(0,l.jsx)(n.code,{children:"pui-websocket"}),", ",(0,l.jsx)(n.code,{children:"pui-mono-repo-boilerplate"}),") use ",(0,l.jsx)(n.strong,{children:"Nx"})," for task orchestration and ",(0,l.jsx)(n.strong,{children:"Lerna"})," (via ",(0,l.jsx)(n.code,{children:"pui-cli version"}),") for independent package versioning."]}),"\n",(0,l.jsxs)(n.p,{children:["pui-cli 9 ships ",(0,l.jsx)(n.strong,{children:"lerna 9"})," and ",(0,l.jsx)(n.strong,{children:"nx 22"})," (",(0,l.jsx)(n.code,{children:"nx"})," + ",(0,l.jsx)(n.code,{children:"@nx/workspace"}),"). After bumping ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli@9"}),", reinstall so the workspace picks up the new CLIs:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm install\npnpm exec nx --version # expect 22.x\npnpm exec lerna --version # expect 9.x\n"})}),"\n",(0,l.jsx)(n.h3,{id:"1-remove-legacy-nx-package-pins",children:"1. Remove legacy Nx package pins"}),"\n",(0,l.jsxs)(n.p,{children:["Most monorepos inherit Nx and Lerna from pui-cli and do ",(0,l.jsx)(n.strong,{children:"not"})," pin them locally. If your root ",(0,l.jsx)(n.code,{children:"package.json"})," still lists ",(0,l.jsx)(n.code,{children:"@nrwl/cli"}),", ",(0,l.jsx)(n.code,{children:"@nrwl/tao"}),", or ",(0,l.jsx)(n.code,{children:"@nrwl/workspace"}),", remove those entries and any direct ",(0,l.jsx)(n.code,{children:"lerna"})," / ",(0,l.jsx)(n.code,{children:"nx"})," pins \u2014 pui-cli 9 provides them."]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm remove @nrwl/cli @nrwl/tao @nrwl/workspace lerna nx # only if explicitly pinned\npnpm install\n"})}),"\n",(0,l.jsxs)(n.h3,{id:"2-migrate-nxjson",children:["2. Migrate ",(0,l.jsx)(n.code,{children:"nx.json"})]}),"\n",(0,l.jsxs)(n.p,{children:["Nx 15 configs use deprecated ",(0,l.jsx)(n.code,{children:"@nrwl/workspace"})," presets, ",(0,l.jsx)(n.code,{children:"tasksRunnerOptions"}),", and ",(0,l.jsx)(n.code,{children:"targetDependencies"}),". Nx 22 uses ",(0,l.jsx)(n.code,{children:"nx/presets/npm.json"})," (or ",(0,l.jsx)(n.code,{children:"@nx/workspace/presets/npm.json"}),") and ",(0,l.jsx)(n.code,{children:"targetDefaults.dependsOn"}),"."]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Before (pui-cli 8 / Nx 15):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'{\n "extends": "@nrwl/workspace/presets/npm.json",\n "tasksRunnerOptions": {\n "default": {\n "runner": "@nrwl/workspace/tasks-runners/default",\n "options": {\n "cacheableOperations": ["build", "test", "lint"]\n }\n }\n },\n "targetDependencies": {\n "build": [{ "target": "build", "projects": "dependencies" }],\n "test": [{ "target": "build", "projects": "dependencies" }]\n }\n}\n'})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"After (pui-cli 9 / Nx 22):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'{\n "$schema": "./node_modules/nx/schemas/nx-schema.json",\n "extends": "nx/presets/npm.json",\n "targetDefaults": {\n "build": {\n "dependsOn": ["^build"],\n "cache": true\n },\n "test": {\n "dependsOn": ["^build"],\n "cache": true\n },\n "dts": {\n "dependsOn": ["^dts"],\n "cache": true\n },\n "lint": {\n "dependsOn": ["^dts"],\n "cache": true\n },\n "dev": {\n "dependsOn": ["^dev"],\n "cache": true\n },\n "storybook:start": {\n "dependsOn": ["^build"],\n "cache": true\n },\n "storybook:build": {\n "dependsOn": ["^build"],\n "cache": true\n },\n "prepare": {\n "dependsOn": ["^prepare"],\n "cache": true\n },\n "package": {\n "dependsOn": ["^package"],\n "cache": true\n },\n "postinstall": {\n "cache": true\n },\n "compile:scss": {\n "cache": true\n }\n }\n}\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Map each legacy ",(0,l.jsx)(n.code,{children:"targetDependencies"})," entry to ",(0,l.jsx)(n.code,{children:'"dependsOn": ["^<target>"]'})," on the same target name. Targets that were only listed under ",(0,l.jsx)(n.code,{children:"cacheableOperations"})," get ",(0,l.jsx)(n.code,{children:'"cache": true'})," in ",(0,l.jsx)(n.code,{children:"targetDefaults"}),"."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Automated migration (optional):"})," from the monorepo root after installing pui-cli 9:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec nx migrate latest\npnpm exec nx migrate --run-migrations\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Review the generated migrations; they may simplify ",(0,l.jsx)(n.code,{children:"nx.json"})," further. Commit the result with your pui-cli 9 bump."]}),"\n",(0,l.jsx)(n.h3,{id:"3-lerna-9-notes",children:"3. Lerna 9 notes"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Removed commands:"})," ",(0,l.jsx)(n.code,{children:"lerna bootstrap"}),", ",(0,l.jsx)(n.code,{children:"lerna add"}),", and ",(0,l.jsx)(n.code,{children:"lerna link"})," are gone. Use pnpm workspaces (",(0,l.jsx)(n.code,{children:"pnpm add <pkg> --filter <lib>"}),") for linking and dependency management."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsxs)(n.strong,{children:[(0,l.jsx)(n.code,{children:"lerna.json"}),":"]})," existing PUI repos can keep ",(0,l.jsx)(n.code,{children:'npmClient: "pnpm"'})," and ",(0,l.jsx)(n.code,{children:"useWorkspaces: true"}),". No change required unless you relied on removed commands."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsxs)(n.strong,{children:[(0,l.jsx)(n.code,{children:"pui-cli version"}),":"]})," unchanged \u2014 still wraps ",(0,l.jsx)(n.code,{children:"lerna version --conventional-commits --exact --create-release github --force-publish --yes"}),"."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Dry-run override:"})," ",(0,l.jsx)(n.code,{children:"semantic-version:dryrun:override"})," scripts that call ",(0,l.jsx)(n.code,{children:"lerna version"})," directly continue to work with lerna 9."]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"4-verify-monorepo-workflows",children:"4. Verify monorepo workflows"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec nx run-many --target=build --all --parallel\npnpm exec nx affected --target=test --uncommitted\npnpm exec pui-cli lint\npnpm exec pui-cli version --help # confirms pui-cli can invoke lerna 9\n"})}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"storybook-10-pui-cli-9",children:"Storybook 10 (pui-cli 9)"}),"\n",(0,l.jsxs)(n.p,{children:["Applies to repos that run ",(0,l.jsx)(n.code,{children:"pui-cli storybook"}),". Upgrade ",(0,l.jsx)(n.strong,{children:"pui-cli 9"})," and ",(0,l.jsx)(n.strong,{children:"pui-app-sdk"})," together \u2014 shared Storybook config lives in pui-app-sdk."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Agent skill:"})," install the bundled playbook for CJS \u2192 ESM migration:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli skills install migrate-storybook-out-of-cjs --target all\n"})}),"\n",(0,l.jsx)(n.h3,{id:"what-changed",children:"What changed"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Topic"}),(0,l.jsx)(n.th,{children:"Before (Storybook 6)"}),(0,l.jsx)(n.th,{children:"After (Storybook 10)"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"CLI"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"start-storybook"})," / ",(0,l.jsx)(n.code,{children:"build-storybook"})]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"storybook dev"})," / ",(0,l.jsx)(n.code,{children:"storybook build"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Config format"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:".storybook/main.js"})," (CJS)"]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:".storybook/main.mjs"})," (ESM, required)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Shared config import"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"@elliemae/pui-app-sdk/storybook/cjs/main"})," (removed)"]}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"@elliemae/pui-app-sdk/storybook/main"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Framework"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"@storybook/react"})," + ",(0,l.jsx)(n.code,{children:"core.builder: webpack5"})]}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"@storybook/react-webpack5"})})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Default port"}),(0,l.jsx)(n.td,{children:"11000 (pui-cli)"}),(0,l.jsx)(n.td,{children:"11000 (unchanged)"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Story globs"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"../lib"})," only (webpack)"]}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"../lib"})," and ",(0,l.jsx)(n.code,{children:"../app"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"API middleware"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".storybook/middleware.js"})}),(0,l.jsxs)(n.td,{children:["Built into pui-cli ",(0,l.jsx)(n.code,{children:"webpackFinal"})," dev server"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Removed addons"}),(0,l.jsx)(n.td,{children:"\u2014"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"addon-essentials"}),", ",(0,l.jsx)(n.code,{children:"addon-interactions"}),", ",(0,l.jsx)(n.code,{children:"addon-links"})," (moved into Storybook core in v9+), ",(0,l.jsx)(n.code,{children:"addon-events"}),", ",(0,l.jsx)(n.code,{children:"addon-storysource"}),", ",(0,l.jsx)(n.code,{children:"storybook-addon-turbo-build"}),", ",(0,l.jsx)(n.code,{children:"storybook-react-router"})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"JS compiler"}),(0,l.jsx)(n.td,{children:"SWC (default in some setups)"}),(0,l.jsxs)(n.td,{children:[(0,l.jsx)(n.code,{children:"@storybook/addon-webpack5-compiler-babel"})," (bundled in pui-cli; resolves via pui-app-sdk)"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Lib-only packages"}),(0,l.jsx)(n.td,{children:"N/A"}),(0,l.jsxs)(n.td,{children:["Story globs skip ",(0,l.jsx)(n.code,{children:"../app/**"})," when no ",(0,l.jsx)(n.code,{children:"app/"})," directory exists"]})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"consumer-migration",children:"Consumer migration"}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:["Bump ",(0,l.jsx)(n.code,{children:"@elliemae/pui-cli@9"})," and ",(0,l.jsx)(n.code,{children:"@elliemae/pui-app-sdk@*"})," (same release train)."]}),"\n",(0,l.jsxs)(n.li,{children:["Rename ",(0,l.jsx)(n.code,{children:".storybook/main.js"})," \u2192 ",(0,l.jsx)(n.code,{children:".storybook/main.mjs"}),":"]}),"\n"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-javascript",children:"import { getStorybookConfig } from '@elliemae/pui-app-sdk/storybook/main';\n\nexport default getStorybookConfig();\n"})}),"\n",(0,l.jsxs)(n.ol,{start:"3",children:["\n",(0,l.jsxs)(n.li,{children:["Convert other ",(0,l.jsx)(n.code,{children:".storybook/*.js"})," wrappers to ",(0,l.jsx)(n.code,{children:".mjs"})," where they use ",(0,l.jsx)(n.code,{children:"import"}),"/",(0,l.jsx)(n.code,{children:"export"})," (e.g. ",(0,l.jsx)(n.code,{children:"preview.mjs"}),", ",(0,l.jsx)(n.code,{children:"manager.js"})," can stay if ESM)."]}),"\n",(0,l.jsxs)(n.li,{children:["Delete ",(0,l.jsx)(n.code,{children:".storybook/middleware.js"})," \u2014 mock API routes are registered by pui-cli during ",(0,l.jsx)(n.code,{children:"storybook dev"}),". Legacy middleware is still exported as ",(0,l.jsx)(n.code,{children:"@elliemae/pui-app-sdk/storybook/middleware"})," (deprecated) for repos not yet on pui-cli 9 Storybook."]}),"\n",(0,l.jsxs)(n.li,{children:["Update story imports to CSF3 / ",(0,l.jsx)(n.code,{children:"@storybook/react-webpack5"})," as needed (CSF2 may still work for simple stories)."]}),"\n",(0,l.jsx)(n.li,{children:"Remove Storybook 6 webpack alias workarounds (MDX pinning, react-select hacks) unless a specific component still fails after upgrade."}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"verify",children:"Verify"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"pnpm exec pui-cli storybook # dev on port 11000\npnpm exec pui-cli storybook -b # static build to demo/\npnpm exec pui-cli storybook -b --docs # docs build\npnpm exec pui-cli lint # stories + .storybook/\n"})}),"\n",(0,l.jsxs)(n.p,{children:["Pilot reference: ",(0,l.jsx)(n.code,{children:"pui-mono-repo-boilerplate/libs/foo"}),", ",(0,l.jsx)(n.code,{children:"pui-react-boilerplate"}),"."]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"ci-checklist",children:"CI checklist"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Node 24 in pipeline"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","pnpm 11 in pipeline"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"shamefullyHoist"})," (and related settings) in ",(0,l.jsx)(n.code,{children:"pnpm-workspace.yaml"}),", not ",(0,l.jsx)(n.code,{children:".npmrc"})]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"pnpm run build"})," after clean install (webpack resolves hoisted deps)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"pui-cli lint"})," (0 errors)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"pui-cli tscheck --files"})]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Unit tests"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Production build"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","lint-staged / husky hooks pass locally"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"semantic-release --dry-run"})," (libraries that publish to npm)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"nx run-many --target=build --all"})," (monorepos)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ",(0,l.jsx)(n.code,{children:"pui-cli version --help"})," or dry-run versioning (monorepos that publish packages)"]}),"\n"]}),"\n",(0,l.jsx)(n.hr,{}),"\n",(0,l.jsx)(n.h2,{id:"getting-help",children:"Getting help"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Rule changes:"})," ",(0,l.jsx)(n.a,{href:"/cli/eslint-rules-migration",children:"eslint-rules-migration.md"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Stylelint changes:"})," ",(0,l.jsx)(n.a,{href:"/cli/stylelint-migration",children:"stylelint-migration.md"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Commands:"})," ",(0,l.jsx)(n.a,{href:"/cli/usage-guide",children:"usage guide"})]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Platform team:"})," ",(0,l.jsx)(n.code,{children:"#pui-platform"})," or your team's platform-ui channel"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(a,{...e})}):a(e)}},6607(e,n,s){s.d(n,{R:()=>c,x:()=>d});var i=s(758);const l={},r=i.createContext(l);function c(e){const n=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:c(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(globalThis.webpackChunk_elliemae_pui_cli=globalThis.webpackChunk_elliemae_pui_cli||[]).push([[1019],{176(e,s,n){n.r(s),n.d(s,{assets:()=>l,contentTitle:()=>t,default:()=>x,frontMatter:()=>c,metadata:()=>r,toc:()=>o});const r=JSON.parse('{"id":"eslint-rules-migration","title":"ESLint rules migration guide (legacy \u2192 ESLint 10 flat config)","description":"This document compares the previous @elliemae/pui-cli ESLint setup (ESLint 8 + .eslintrc.cjs + Airbnb) with the current setup (ESLint 10 + eslint.config.mjs + typescript-eslint v8 flat config).","source":"@site/docs/eslint-rules-migration.md","sourceDirName":".","slug":"/eslint-rules-migration","permalink":"/cli/eslint-rules-migration","draft":false,"unlisted":false,"editUrl":"https://git.elliemae.io/platform-ui/pui-cli.git/docs/eslint-rules-migration.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docsSidebar","previous":{"title":"vitestConfig","permalink":"/cli/api/variables/vitestConfig"},"next":{"title":"PUI CLI Documentation","permalink":"/cli/"}}');var i=n(6070),d=n(6607);const c={},t="ESLint rules migration guide (legacy \u2192 ESLint 10 flat config)",l={},o=[{value:"At a glance",id:"at-a-glance",level:2},{value:"How to upgrade a repo",id:"how-to-upgrade-a-repo",level:2},{value:"Presets: what was removed vs added",id:"presets-what-was-removed-vs-added",level:2},{value:"Removed (no longer extended)",id:"removed-no-longer-extended",level:3},{value:"Still included (equivalent or better)",id:"still-included-equivalent-or-better",level:3},{value:"Optional (not enabled by default)",id:"optional-not-enabled-by-default",level:3},{value:"PUI custom rules \u2014 unchanged",id:"pui-custom-rules--unchanged",level:2},{value:"TypeScript (explicit, same as before)",id:"typescript-explicit-same-as-before",level:3},{value:"React (explicit, same as before)",id:"react-explicit-same-as-before",level:3},{value:"E2E specs (unchanged)",id:"e2e-specs-unchanged",level:3},{value:"Import rules: <code>import/*</code> \u2192 <code>import-x/*</code>",id:"import-rules-import--import-x",level:2},{value:"Still off (same as legacy PUI config)",id:"still-off-same-as-legacy-pui-config",level:3},{value:"Still on",id:"still-on",level:3},{value:"Formatting: removed from ESLint",id:"formatting-removed-from-eslint",level:2},{value:"New rules you may see after upgrade",id:"new-rules-you-may-see-after-upgrade",level:2},{value:"TypeScript \u2014 newly explicit in PUI config",id:"typescript--newly-explicit-in-pui-config",level:3},{value:"TypeScript \u2014 from <code>recommendedTypeChecked</code> (v8 bundle)",id:"typescript--from-recommendedtypechecked-v8-bundle",level:3},{value:"React \u2014 new in pui-cli shared config",id:"react--new-in-pui-cli-shared-config",level:3},{value:"Unused variables",id:"unused-variables",level:3},{value:"Airbnb removal \u2014 practical impact",id:"airbnb-removal--practical-impact",level:2},{value:"File-type overrides (flat config only)",id:"file-type-overrides-flat-config-only",level:2},{value:"Ignore patterns",id:"ignore-patterns",level:2},{value:"TypeScript project resolution",id:"typescript-project-resolution",level:2},{value:"Quick fix cheat sheet",id:"quick-fix-cheat-sheet",level:2},{value:"Config entry points (reference)",id:"config-entry-points-reference",level:2},{value:"Post-migration tune-ups (alpha flat config)",id:"post-migration-tune-ups-alpha-flat-config",level:2},{value:"ESLint 10 plugin compatibility",id:"eslint-10-plugin-compatibility",level:3},{value:"Config performance notes",id:"config-performance-notes",level:3},{value:"Strict exports",id:"strict-exports",level:3},{value:"Questions?",id:"questions",level:2}];function h(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(s.header,{children:(0,i.jsx)(s.h1,{id:"eslint-rules-migration-guide-legacy--eslint-10-flat-config",children:"ESLint rules migration guide (legacy \u2192 ESLint 10 flat config)"})}),"\n",(0,i.jsxs)(s.p,{children:["This document compares the ",(0,i.jsx)(s.strong,{children:"previous"})," ",(0,i.jsx)(s.code,{children:"@elliemae/pui-cli"})," ESLint setup (ESLint 8 + ",(0,i.jsx)(s.code,{children:".eslintrc.cjs"})," + Airbnb) with the ",(0,i.jsx)(s.strong,{children:"current"})," setup (ESLint 10 + ",(0,i.jsx)(s.code,{children:"eslint.config.mjs"})," + ",(0,i.jsx)(s.code,{children:"typescript-eslint"})," v8 flat config)."]}),"\n",(0,i.jsxs)(s.p,{children:["For the full pui-cli 9 upgrade path (Node 24, pnpm 11, CI, Cursor skills), see ",(0,i.jsx)(s.a,{href:"/cli/pui-cli-9-migration",children:"pui-cli 9 migration guide"}),"."]}),"\n",(0,i.jsx)(s.p,{children:"Use it when upgrading apps/libraries and explaining new lint failures to your team."}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"at-a-glance",children:"At a glance"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Topic"}),(0,i.jsx)(s.th,{children:"Before (legacy)"}),(0,i.jsx)(s.th,{children:"After (flat config)"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Config format"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:".eslintrc.cjs"})," + ",(0,i.jsx)(s.code,{children:".eslintignore"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint.config.mjs"})," (ignores built-in)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"ESLint"}),(0,i.jsx)(s.td,{children:"8.x"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"10.x"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"TypeScript lint"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@typescript-eslint"})," v5, ",(0,i.jsx)(s.code,{children:"project: true"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"typescript-eslint"})," v8, ",(0,i.jsx)(s.code,{children:"projectService: true"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"JS parser"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@babel/eslint-parser"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@eslint/js"})," recommended (no Babel parser for lint)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Style presets"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"Airbnb"})," + ",(0,i.jsx)(s.strong,{children:"airbnb-typescript"})]}),(0,i.jsx)(s.td,{children:"Removed \u2014 rules re-expressed explicitly"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Import plugin"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-import"})," (",(0,i.jsx)(s.code,{children:"import/*"}),")"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-import-x"})," (",(0,i.jsx)(s.code,{children:"import-x/*"}),")"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Prettier in ESLint"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"prettier/prettier"})," ",(0,i.jsx)(s.strong,{children:"error"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"Not enforced in ESLint"})," \u2014 use Prettier in ",(0,i.jsx)(s.code,{children:"lint-staged"})," / CI"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Indent in ESLint"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"indent"})," ",(0,i.jsx)(s.strong,{children:"error"})]}),(0,i.jsx)(s.td,{children:"Removed \u2014 Prettier owns formatting"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Type-aware TS"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"recommended-requiring-type-checking"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"recommendedTypeChecked"})," (v8 equivalent)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Consumer import"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"require('@elliemae/pui-cli').eslintConfig"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import { eslintFlatConfig } from '@elliemae/pui-cli/eslint'"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Strict import"}),(0,i.jsx)(s.td,{children:"\u2014"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslintFlatConfigStrict"})," / ",(0,i.jsx)(s.code,{children:"eslintFlatBaseConfigStrict"})]})]})]})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"how-to-upgrade-a-repo",children:"How to upgrade a repo"}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-js",children:"// eslint.config.mjs \u2014 React apps / libraries\nimport { eslintFlatConfig } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatConfig;\n"})}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-js",children:"// eslint.config.mjs \u2014 Node / TS services (non-React)\nimport { eslintFlatBaseConfig } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatBaseConfig;\n"})}),"\n",(0,i.jsxs)(s.ol,{children:["\n",(0,i.jsxs)(s.li,{children:["Upgrade ",(0,i.jsx)(s.code,{children:"@elliemae/pui-cli"})," to the alpha release that ships flat config."]}),"\n",(0,i.jsxs)(s.li,{children:["Add ",(0,i.jsx)(s.code,{children:"eslint.config.mjs"})," as above."]}),"\n",(0,i.jsxs)(s.li,{children:["Delete ",(0,i.jsx)(s.code,{children:".eslintrc.cjs"})," and ",(0,i.jsx)(s.code,{children:".eslintignore"}),"."]}),"\n",(0,i.jsxs)(s.li,{children:["Run ",(0,i.jsx)(s.code,{children:"pui-cli lint"})," and ",(0,i.jsx)(s.code,{children:"pui-cli lint --fix"}),"."]}),"\n"]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"presets-what-was-removed-vs-added",children:"Presets: what was removed vs added"}),"\n",(0,i.jsx)(s.h3,{id:"removed-no-longer-extended",children:"Removed (no longer extended)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Legacy extend"}),(0,i.jsx)(s.th,{children:"Impact"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"airbnb"})," / ",(0,i.jsx)(s.code,{children:"airbnb/hooks"})]}),(0,i.jsxs)(s.td,{children:["React style rules from Airbnb (e.g. ",(0,i.jsx)(s.code,{children:"react/jsx-props-no-spreading"}),", ",(0,i.jsx)(s.code,{children:"react/no-array-index-key"}),", stricter JSX patterns) are ",(0,i.jsx)(s.strong,{children:"gone"})," unless we set them explicitly in PUI config."]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"airbnb-base"})}),(0,i.jsx)(s.td,{children:"Same for non-React JS."})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"airbnb-typescript"})," / ",(0,i.jsx)(s.code,{children:"airbnb-typescript/base"})]}),(0,i.jsx)(s.td,{children:"Airbnb + TypeScript combo rules removed."})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:prettier/recommended"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"prettier/prettier"})," is no longer an ESLint error."]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:import/recommended"})}),(0,i.jsxs)(s.td,{children:["Replaced by ",(0,i.jsx)(s.code,{children:"eslint-plugin-import-x"})," flat recommended."]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:mdx/recommended"})}),(0,i.jsx)(s.td,{children:"MDX-specific ESLint block removed from shared React config (Storybook flat config remains)."})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"still-included-equivalent-or-better",children:"Still included (equivalent or better)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Area"}),(0,i.jsx)(s.th,{children:"Legacy"}),(0,i.jsx)(s.th,{children:"Flat config"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Core JS"}),(0,i.jsx)(s.td,{children:"ESLint recommended (via Airbnb + plugins)"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@eslint/js"})," ",(0,i.jsx)(s.strong,{children:"recommended"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"TypeScript"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@typescript-eslint/recommended"})," + ",(0,i.jsx)(s.strong,{children:"recommended-requiring-type-checking"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"typescript-eslint"})," ",(0,i.jsx)(s.strong,{children:"recommendedTypeChecked"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"React"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"plugin:react/recommended"})," (via Airbnb)"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-react"})," ",(0,i.jsx)(s.strong,{children:"recommended"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Hooks"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"react-hooks/rules-of-hooks"})," (explicit); ",(0,i.jsx)(s.strong,{children:"no"})," ",(0,i.jsx)(s.code,{children:"exhaustive-deps"})," in old pui-cli"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"rules-of-hooks"})," ",(0,i.jsx)(s.strong,{children:"error"})," + ",(0,i.jsxs)(s.strong,{children:[(0,i.jsx)(s.code,{children:"exhaustive-deps"})," warn"]})," (new)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"a11y"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:jsx-a11y/recommended"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-jsx-a11y"})," flat ",(0,i.jsx)(s.strong,{children:"recommended"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Jest"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:jest/recommended"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-jest"})," ",(0,i.jsx)(s.strong,{children:"recommended"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Testing Library"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:testing-library/dom"})}),(0,i.jsxs)(s.td,{children:["Same (",(0,i.jsx)(s.strong,{children:"dom"})," rules only)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"WDIO"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:wdio/recommended"})}),(0,i.jsx)(s.td,{children:"Same"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Redux Saga"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:redux-saga/recommended"})}),(0,i.jsx)(s.td,{children:"Same"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Storybook"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"plugin:storybook/recommended"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-storybook"})," flat ",(0,i.jsx)(s.strong,{children:"recommended"})," (v10, Storybook 10\u2013compatible)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Prettier conflict"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-config-prettier"})," via ",(0,i.jsx)(s.code,{children:"plugin:prettier/recommended"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslint-config-prettier"})," only (disables conflicting ESLint style rules)"]})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"optional-not-enabled-by-default",children:"Optional (not enabled by default)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Preset"}),(0,i.jsx)(s.th,{children:"Status"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"typescript-eslint/strictTypeChecked"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"Not"})," enabled \u2014 optional stricter tier for a later rollout"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"typescript-eslint/stylistic*"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"Not"})," enabled \u2014 Prettier is the source of truth for formatting"]})]})]})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"pui-custom-rules--unchanged",children:"PUI custom rules \u2014 unchanged"}),"\n",(0,i.jsxs)(s.p,{children:["These explicit PUI rules are ",(0,i.jsx)(s.strong,{children:"the same"})," in spirit (same limits and overrides):"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsxs)(s.th,{children:["JS (",(0,i.jsx)(s.code,{children:".js"}),")"]}),(0,i.jsxs)(s.th,{children:["TS (",(0,i.jsx)(s.code,{children:".ts"}),"/",(0,i.jsx)(s.code,{children:".tsx"}),")"]})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"complexity"})}),(0,i.jsx)(s.td,{children:"max 10"}),(0,i.jsx)(s.td,{children:"max 10"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"max-depth"})}),(0,i.jsx)(s.td,{children:"max 4"}),(0,i.jsx)(s.td,{children:"max 4"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"max-nested-callbacks"})}),(0,i.jsx)(s.td,{children:"max 3"}),(0,i.jsx)(s.td,{children:"max 3"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"max-params"})}),(0,i.jsx)(s.td,{children:"max 3"}),(0,i.jsx)(s.td,{children:"max 3"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"max-statements"})}),(0,i.jsx)(s.td,{children:"max 20"}),(0,i.jsx)(s.td,{children:"max 20"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"max-lines"})}),(0,i.jsx)(s.td,{children:"120"}),(0,i.jsx)(s.td,{children:"200"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"no-console"})}),(0,i.jsx)(s.td,{children:"warn"}),(0,i.jsx)(s.td,{children:"warn"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"no-param-reassign"})}),(0,i.jsx)(s.td,{children:"props: false"}),(0,i.jsx)(s.td,{children:"props: false"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"arrow-body-style"})}),(0,i.jsx)(s.td,{children:"as-needed"}),(0,i.jsx)(s.td,{children:"as-needed"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"prefer-template"})}),(0,i.jsx)(s.td,{children:"error"}),(0,i.jsx)(s.td,{children:"error"})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"typescript-explicit-same-as-before",children:"TypeScript (explicit, same as before)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Setting"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-floating-promises"})}),(0,i.jsxs)(s.td,{children:["error, ",(0,i.jsx)(s.code,{children:"ignoreIIFE: true"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/unbound-method"})}),(0,i.jsxs)(s.td,{children:["error, ",(0,i.jsx)(s.code,{children:"ignoreStatic: true"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-use-before-define"})}),(0,i.jsx)(s.td,{children:"functions: false, classes/variables/typedefs: true"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/explicit-module-boundary-types"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/explicit-function-return-type"})}),(0,i.jsx)(s.td,{children:"off"})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"react-explicit-same-as-before",children:"React (explicit, same as before)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Setting"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react/function-component-definition"})}),(0,i.jsx)(s.td,{children:"named components: arrow-function"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react/react-in-jsx-scope"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react/prop-types"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"jsx-a11y/heading-has-content"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"jsx-a11y/label-has-associated-control"})}),(0,i.jsxs)(s.td,{children:["on, ",(0,i.jsx)(s.code,{children:"controlComponents: ['Input']"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"redux-saga/no-yield-in-race"})}),(0,i.jsx)(s.td,{children:"error"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"redux-saga/yield-effects"})}),(0,i.jsx)(s.td,{children:"error"})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"e2e-specs-unchanged",children:"E2E specs (unchanged)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Files"}),(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Setting"})]})}),(0,i.jsx)(s.tbody,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"*.func.spec.js"}),", ",(0,i.jsx)(s.code,{children:"*.visual.spec.js"})]}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"jest/valid-expect"})}),(0,i.jsx)(s.td,{children:"off"})]})})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsxs)(s.h2,{id:"import-rules-import--import-x",children:["Import rules: ",(0,i.jsx)(s.code,{children:"import/*"})," \u2192 ",(0,i.jsx)(s.code,{children:"import-x/*"})]}),"\n",(0,i.jsxs)(s.p,{children:["Update ",(0,i.jsx)(s.strong,{children:"eslint-disable"})," comments when you touch files:"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Legacy rule name"}),(0,i.jsx)(s.th,{children:"New rule name"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import/no-unresolved"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-unresolved"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import/extensions"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/extensions"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import/no-named-as-default"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-named-as-default"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"\u2026"}),(0,i.jsxs)(s.td,{children:["Prefix ",(0,i.jsx)(s.code,{children:"import/"})," \u2192 ",(0,i.jsx)(s.code,{children:"import-x/"})]})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"still-off-same-as-legacy-pui-config",children:"Still off (same as legacy PUI config)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Status"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/imports-first"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/newline-after-import"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-dynamic-require"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-extraneous-dependencies"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-named-as-default"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-webpack-loader-syntax"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/prefer-default-export"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/default"})}),(0,i.jsx)(s.td,{children:"off"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/namespace"})}),(0,i.jsx)(s.td,{children:"off"})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"still-on",children:"Still on"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Setting"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-unresolved"})}),(0,i.jsx)(s.td,{children:"error, strict casing"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/extensions"})}),(0,i.jsx)(s.td,{children:"never (json/js ignorePackages)"})]})]})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"formatting-removed-from-eslint",children:"Formatting: removed from ESLint"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Legacy"}),(0,i.jsx)(s.th,{children:"Flat config"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"prettier/prettier"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"error"})," (via ",(0,i.jsx)(s.code,{children:"plugin:prettier/recommended"}),")"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"off"})," \u2014 run Prettier separately"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"indent"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"error"})," (2 spaces, SwitchCase: 1)"]}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"removed"})})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.strong,{children:"Action:"})," Rely on ",(0,i.jsx)(s.code,{children:"prettier --write"})," / ",(0,i.jsx)(s.code,{children:"lint-staged"})," for formatting. Do not expect ESLint to fail on quote/semicolon/indent issues."]}),"\n",(0,i.jsxs)(s.p,{children:["Legacy ",(0,i.jsx)(s.code,{children:"eslint-disable prettier/prettier"})," comments still work (no-op rule registered as off)."]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"new-rules-you-may-see-after-upgrade",children:"New rules you may see after upgrade"}),"\n",(0,i.jsxs)(s.p,{children:["These are the main ",(0,i.jsx)(s.strong,{children:"new or stricter"})," checks teams notice beyond \u201csame PUI rules as before.\u201d"]}),"\n",(0,i.jsx)(s.h3,{id:"typescript--newly-explicit-in-pui-config",children:"TypeScript \u2014 newly explicit in PUI config"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Severity"}),(0,i.jsx)(s.th,{children:"What it catches"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/consistent-type-imports"})}),(0,i.jsx)(s.td,{children:"error"}),(0,i.jsxs)(s.td,{children:["Use ",(0,i.jsx)(s.code,{children:"import type { Foo }"})," for type-only imports"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-import-type-side-effects"})}),(0,i.jsx)(s.td,{children:"error"}),(0,i.jsxs)(s.td,{children:["TS 5+ ",(0,i.jsx)(s.code,{children:"import type"})," side-effect hygiene"]})]})]})]}),"\n",(0,i.jsxs)(s.h3,{id:"typescript--from-recommendedtypechecked-v8-bundle",children:["TypeScript \u2014 from ",(0,i.jsx)(s.code,{children:"recommendedTypeChecked"})," (v8 bundle)"]}),"\n",(0,i.jsxs)(s.p,{children:["Already largely covered by legacy ",(0,i.jsx)(s.code,{children:"recommended-requiring-type-checking"}),", but stricter defaults / renames may surface more issues, including:"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Typical issue"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-misused-promises"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"async"})," handler passed where ",(0,i.jsx)(s.code,{children:"void"})," is expected (e.g. some callbacks)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-assignment"})}),(0,i.jsxs)(s.td,{children:["Assigning ",(0,i.jsx)(s.code,{children:"any"})," to a typed variable"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-member-access"})}),(0,i.jsxs)(s.td,{children:["Property access on ",(0,i.jsx)(s.code,{children:"any"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-call"})}),(0,i.jsxs)(s.td,{children:["Calling an ",(0,i.jsx)(s.code,{children:"any"})," value"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-argument"})}),(0,i.jsxs)(s.td,{children:["Passing ",(0,i.jsx)(s.code,{children:"any"})," into a typed parameter"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-return"})}),(0,i.jsxs)(s.td,{children:["Returning ",(0,i.jsx)(s.code,{children:"any"})," from a typed function"]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.strong,{children:"Note:"})," Test files (",(0,i.jsx)(s.code,{children:"**/*.{test,spec}.*"}),") disable the ",(0,i.jsx)(s.code,{children:"no-unsafe-*"})," and ",(0,i.jsx)(s.code,{children:"unbound-method"})," rules in the shared config to reduce noise."]}),"\n",(0,i.jsx)(s.h3,{id:"react--new-in-pui-cli-shared-config",children:"React \u2014 new in pui-cli shared config"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Severity"}),(0,i.jsx)(s.th,{children:"Notes"})]})}),(0,i.jsx)(s.tbody,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react-hooks/exhaustive-deps"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"warn"})}),(0,i.jsxs)(s.td,{children:["Missing deps in ",(0,i.jsx)(s.code,{children:"useEffect"})," / ",(0,i.jsx)(s.code,{children:"useCallback"})," / ",(0,i.jsx)(s.code,{children:"useMemo"})," \u2014 was not in legacy pui-cli (only ",(0,i.jsx)(s.code,{children:"rules-of-hooks"}),")"]})]})})]}),"\n",(0,i.jsx)(s.h3,{id:"unused-variables",children:"Unused variables"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Legacy"}),(0,i.jsx)(s.th,{children:"Flat config"})]})}),(0,i.jsx)(s.tbody,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"no-unused-vars"})," on TS files"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unused-vars"})," with ",(0,i.jsx)(s.code,{children:"ignoreRestSiblings"}),", ",(0,i.jsx)(s.code,{children:"argsIgnorePattern: '^_'"})]})]})})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"airbnb-removal--practical-impact",children:"Airbnb removal \u2014 practical impact"}),"\n",(0,i.jsxs)(s.p,{children:["We no longer extend Airbnb. You should ",(0,i.jsx)(s.strong,{children:"not"})," expect every Airbnb rule to have a 1:1 replacement. Common behavioral changes:"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"You might have relied on (Airbnb)"}),(0,i.jsx)(s.th,{children:"After migration"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Stricter React patterns (e.g. some JSX prop rules)"}),(0,i.jsxs)(s.td,{children:["Only if still in ",(0,i.jsx)(s.code,{children:"eslint-plugin-react"})," recommended or our explicit ",(0,i.jsx)(s.code,{children:"reactRules"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import/prefer-default-export"})}),(0,i.jsxs)(s.td,{children:["Still ",(0,i.jsx)(s.strong,{children:"off"})," in PUI config"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react/jsx-props-no-spreading"})}),(0,i.jsxs)(s.td,{children:["Still ",(0,i.jsx)(s.strong,{children:"off"})," in PUI config"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Many opinionated React/a11y defaults from Airbnb"}),(0,i.jsxs)(s.td,{children:["Replaced by ",(0,i.jsx)(s.strong,{children:"plugin recommended"})," sets + PUI overrides above"]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["If lint gets ",(0,i.jsx)(s.strong,{children:"looser"})," in some areas, that is expected. If it gets ",(0,i.jsx)(s.strong,{children:"stricter"}),", it is usually from ",(0,i.jsx)(s.strong,{children:"type-checked TypeScript"})," or ",(0,i.jsx)(s.strong,{children:(0,i.jsx)(s.code,{children:"consistent-type-imports"})}),", not from Airbnb."]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"file-type-overrides-flat-config-only",children:"File-type overrides (flat config only)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Files"}),(0,i.jsx)(s.th,{children:"Rules relaxed"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"**/*.d.ts"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"@typescript-eslint/no-explicit-any"}),", ",(0,i.jsx)(s.code,{children:"@typescript-eslint/no-empty-object-type"})," off"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"**/*.{test,spec}.{js,jsx,ts,tsx}"}),", ",(0,i.jsx)(s.code,{children:"**/__tests__/**"}),", ",(0,i.jsx)(s.code,{children:"lib/**/tests/**"}),", ",(0,i.jsx)(s.code,{children:"app/**/tests/**"}),", etc."]}),(0,i.jsxs)(s.td,{children:["Jest + Testing Library; ",(0,i.jsx)(s.code,{children:"no-unsafe-*"})," off; ",(0,i.jsx)(s.code,{children:"no-unsafe-declaration-merging"}),", ",(0,i.jsx)(s.code,{children:"no-unsafe-enum-comparison"}),", ",(0,i.jsx)(s.code,{children:"await-thenable"}),", ",(0,i.jsx)(s.code,{children:"prefer-promise-reject-errors"}),", ",(0,i.jsx)(s.code,{children:"prefer-const"}),", etc. off in tests"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"**/*.checksum*.js"}),", ",(0,i.jsx)(s.code,{children:"**/*.endpoint.js"}),", versioned ",(0,i.jsx)(s.code,{children:"tests/**/latest"})," and ",(0,i.jsx)(s.code,{children:"tests/**/X.Y"})," assets"]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"no-unused-vars"}),", ",(0,i.jsx)(s.code,{children:"no-console"}),", ",(0,i.jsx)(s.code,{children:"max-lines"}),", ",(0,i.jsx)(s.code,{children:"max-statements"}),", ",(0,i.jsx)(s.code,{children:"complexity"})," off (fixture JS only)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"**/lint-config/**"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"max-lines"})," off; some ",(0,i.jsx)(s.code,{children:"import-x"})," rules off"]})]})]})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"ignore-patterns",children:"Ignore patterns"}),"\n",(0,i.jsxs)(s.p,{children:["Legacy ",(0,i.jsx)(s.code,{children:".eslintignore"})," entries are merged into the shared flat config ",(0,i.jsx)(s.code,{children:"ignores"}),", including:"]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"build"}),", ",(0,i.jsx)(s.code,{children:"node_modules"}),", ",(0,i.jsx)(s.code,{children:"dist"}),", ",(0,i.jsx)(s.code,{children:"reports"}),", ",(0,i.jsx)(s.code,{children:"coverage"}),", ",(0,i.jsx)(s.code,{children:"demo"}),", ",(0,i.jsx)(s.code,{children:"docs"}),", ",(0,i.jsx)(s.code,{children:"temp"}),", ",(0,i.jsx)(s.code,{children:".tmp"}),", ",(0,i.jsx)(s.code,{children:"public"}),", ",(0,i.jsx)(s.code,{children:"webroot"}),", ",(0,i.jsx)(s.code,{children:"cdn"}),", ",(0,i.jsx)(s.code,{children:".docusaurus"}),", ",(0,i.jsx)(s.code,{children:"vendor/*.js"}),", ",(0,i.jsx)(s.code,{children:".nx"}),", ",(0,i.jsx)(s.code,{children:"pnpm-lock.yaml"}),", ",(0,i.jsx)(s.code,{children:".scannerwork"}),", ",(0,i.jsx)(s.code,{children:"stats.json"}),", ",(0,i.jsx)(s.code,{children:"jsconfig.json"}),", ",(0,i.jsx)(s.code,{children:"allure-report"}),", ",(0,i.jsx)(s.code,{children:"docs/api"})]}),"\n",(0,i.jsxs)(s.p,{children:["Repo-specific paths should still be added in ",(0,i.jsx)(s.strong,{children:"your"})," ",(0,i.jsx)(s.code,{children:"eslint.config.mjs"})," if needed:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-js",children:"import { eslintFlatConfig } from '@elliemae/pui-cli/eslint';\n\nexport default [\n ...eslintFlatConfig,\n { ignores: ['my-generated-folder/**'] },\n];\n"})}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"typescript-project-resolution",children:"TypeScript project resolution"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{}),(0,i.jsx)(s.th,{children:"Legacy"}),(0,i.jsx)(s.th,{children:"Flat config"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Option"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"parserOptions.project: true"})}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"parserOptions.projectService: true"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Root"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"tsconfigRootDir: process.cwd()"})}),(0,i.jsxs)(s.td,{children:["Same (",(0,i.jsx)(s.code,{children:"process.cwd()"})," when lint runs)"]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Monorepo packages: run lint from each package root (or ensure ",(0,i.jsx)(s.code,{children:"tsconfig"})," is discoverable). Same guidance as before, but ",(0,i.jsx)(s.code,{children:"projectService"})," is faster and less brittle than ",(0,i.jsx)(s.code,{children:"project: true"}),"."]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"quick-fix-cheat-sheet",children:"Quick fix cheat sheet"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Lint message / area"}),(0,i.jsx)(s.th,{children:"What to do"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"import/..."})," rule id in comment"]}),(0,i.jsxs)(s.td,{children:["Rename to ",(0,i.jsx)(s.code,{children:"import-x/..."})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"consistent-type-imports"})}),(0,i.jsxs)(s.td,{children:["Change to ",(0,i.jsx)(s.code,{children:"import type { X }"})," or inline ",(0,i.jsx)(s.code,{children:"import { type X }"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"no-floating-promises"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"void fn()"}),", ",(0,i.jsx)(s.code,{children:".catch()"}),", or ",(0,i.jsx)(s.code,{children:"await"})," in async context"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"no-misused-promises"})}),(0,i.jsxs)(s.td,{children:["Usually fixed by shared config (",(0,i.jsx)(s.code,{children:"attributes: false"}),"); otherwise wrap handler or fix callback type"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"exhaustive-deps"})," warning"]}),(0,i.jsx)(s.td,{children:"Fix dependency array or document intentional omission"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Formatting (quotes, indent)"}),(0,i.jsx)(s.td,{children:"Run Prettier \u2014 not ESLint"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"prettier/prettier"})," in disable comment"]}),(0,i.jsx)(s.td,{children:"Harmless; rule is off in ESLint"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"no-extraneous-dependencies"})," on app or ",(0,i.jsx)(s.code,{children:".babelrc.cjs"})]}),(0,i.jsxs)(s.td,{children:["Rule is ",(0,i.jsx)(s.strong,{children:"off"})," (legacy parity; ",(0,i.jsx)(s.code,{children:"app-react-dependencies"})," meta-package)"]})]})]})]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"config-entry-points-reference",children:"Config entry points (reference)"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"App type"}),(0,i.jsx)(s.th,{children:"Legacy export"}),(0,i.jsx)(s.th,{children:"Flat export"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"React + TS"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslintConfig"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslintFlatConfig"})," / ",(0,i.jsx)(s.code,{children:"eslintFlatConfigStrict"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Non-React TS"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslintBaseConfig"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"eslintFlatBaseConfig"})," / ",(0,i.jsx)(s.code,{children:"eslintFlatBaseConfigStrict"})]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Legacy ",(0,i.jsx)(s.code,{children:".eslintrc.cjs"})," exports remain in the package for one transition release but are ",(0,i.jsx)(s.strong,{children:"deprecated"}),"."]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"post-migration-tune-ups-alpha-flat-config",children:"Post-migration tune-ups (alpha flat config)"}),"\n",(0,i.jsx)(s.p,{children:"The shared flat config includes pragmatic defaults to reduce migration noise while keeping high-value checks."}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Change"}),(0,i.jsx)(s.th,{children:"Behavior"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-misused-promises"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"checksVoidReturn.attributes: false"})," \u2014 async ",(0,i.jsx)(s.code,{children:"onClick"})," / JSX handlers allowed"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-*"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"warn"})," in app code (not error); ",(0,i.jsx)(s.strong,{children:"off"})," in test globs (",(0,i.jsx)(s.code,{children:"*.{test,spec}.*"}),", ",(0,i.jsx)(s.code,{children:"lib/**/tests/**"}),", etc.)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"import-x/no-extraneous-dependencies"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"off"})," (legacy parity; apps use ",(0,i.jsx)(s.code,{children:"@elliemae/app-react-dependencies"}),")"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"JSDoc"}),(0,i.jsxs)(s.td,{children:["Full ",(0,i.jsx)(s.code,{children:"jsdoc/recommended"})," ",(0,i.jsx)(s.strong,{children:"removed"}),"; only legacy ",(0,i.jsx)(s.code,{children:"require-jsdoc: off"})," + noisy rules explicitly off"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Testing Library"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"dom"})," rules on test files; ",(0,i.jsx)(s.strong,{children:"react"})," rules on ",(0,i.jsx)(s.code,{children:"*.{test,spec}.{tsx,jsx}"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"WDIO"}),(0,i.jsxs)(s.td,{children:["Globals + rules on ",(0,i.jsx)(s.code,{children:"*.func.spec.js"}),", ",(0,i.jsx)(s.code,{children:"*.visual.spec.js"}),", ",(0,i.jsx)(s.code,{children:"*e2e*"}),", and ",(0,i.jsx)(s.code,{children:"**/e2e/**"})," (page-objects, etc.)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Storybook"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"react/jsx-props-no-spreading"})," off (React config); ",(0,i.jsx)(s.code,{children:"eslint-plugin-storybook@10"})," flat preset (no compat shim)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslint.config.*"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"import-x/no-unresolved"})," off"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"scripts/**"}),", ",(0,i.jsx)(s.code,{children:"ci_cd/**"})]}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"no-console"}),", ",(0,i.jsx)(s.code,{children:"max-lines"}),", ",(0,i.jsx)(s.code,{children:"complexity"})," off"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react-hooks/exhaustive-deps"})}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"warn"})," (not error) until repos are clean"]})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"eslint-10-plugin-compatibility",children:"ESLint 10 plugin compatibility"}),"\n",(0,i.jsxs)(s.p,{children:["Only plugins that still call removed ",(0,i.jsx)(s.code,{children:"context.getFilename()"})," / ",(0,i.jsx)(s.code,{children:"getScope()"})," APIs are wrapped via ",(0,i.jsx)(s.code,{children:"@eslint/compat"})," v2 ",(0,i.jsx)(s.code,{children:"fixupPluginRules"})," in ",(0,i.jsx)(s.code,{children:"lib/lint-config/eslint/flat/compat.mjs"}),":"]}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Plugin"}),(0,i.jsx)(s.th,{children:"Wrapped?"}),(0,i.jsx)(s.th,{children:"Reason"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslint-plugin-react"})}),(0,i.jsx)(s.td,{children:"Yes"}),(0,i.jsxs)(s.td,{children:["Uses legacy context APIs (",(0,i.jsx)(s.code,{children:"display-name"}),", etc.)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslint-plugin-redux-saga"})}),(0,i.jsx)(s.td,{children:"Yes"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"no-yield-in-race"})," uses ",(0,i.jsx)(s.code,{children:"getScope()"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslint-plugin-storybook"})}),(0,i.jsx)(s.td,{children:"No"}),(0,i.jsx)(s.td,{children:"v10 flat preset is ESLint 10\u2013compatible"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslint-plugin-wdio"})}),(0,i.jsx)(s.td,{children:"No"}),(0,i.jsxs)(s.td,{children:["Use nested plugin from ",(0,i.jsx)(s.code,{children:"flat/recommended"})," (see ",(0,i.jsx)(s.code,{children:"presets.mjs"}),")"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.code,{children:"typescript-eslint"}),", ",(0,i.jsx)(s.code,{children:"import-x"}),", ",(0,i.jsx)(s.code,{children:"jest"}),", ",(0,i.jsx)(s.code,{children:"react-hooks"}),", ",(0,i.jsx)(s.code,{children:"jsx-a11y"}),", ",(0,i.jsx)(s.code,{children:"testing-library"})]}),(0,i.jsx)(s.td,{children:"No"}),(0,i.jsx)(s.td,{children:"ESLint 10\u2013compatible; no shim overhead"})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Use ",(0,i.jsx)(s.code,{children:"@eslint/compat"})," ",(0,i.jsx)(s.strong,{children:"v2+"})," with ESLint 10. v1 ",(0,i.jsx)(s.code,{children:"fixupPluginRules"})," lacks ESLint 10 context patches."]}),"\n",(0,i.jsx)(s.h3,{id:"config-performance-notes",children:"Config performance notes"}),"\n",(0,i.jsx)(s.p,{children:"The shared flat config is structured for faster lint runs:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:["Preset rule spreads are computed once in ",(0,i.jsx)(s.code,{children:"presets.mjs"})," (not per factory call)."]}),"\n",(0,i.jsx)(s.li,{children:"Jest and Testing Library plugins apply only to test-like file globs (not all source files)."}),"\n",(0,i.jsx)(s.li,{children:"WDIO plugin applies only to e2e / visual / func spec files."}),"\n",(0,i.jsxs)(s.li,{children:["Unused ",(0,i.jsx)(s.code,{children:"eslint-plugin-prettier"})," and ",(0,i.jsx)(s.code,{children:"eslint-plugin-jsdoc"})," were removed (Prettier stays in ",(0,i.jsx)(s.code,{children:"lint-staged"}),"; no JSDoc rules enforced)."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"eslint-plugin-eslint-comments"})," was removed (incompatible with ESLint 10; rules were low-value)."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Lint toolchain (pui-cli 9 alpha):"})," ESLint 10, Prettier 3, Stylelint 17, ",(0,i.jsx)(s.code,{children:"eslint-plugin-react-hooks"})," 7, ",(0,i.jsx)(s.code,{children:"typescript-eslint"})," 8.56+, Commitlint 21, lint-staged 17."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"createBaseFlatConfigs()"})," caches the two variants (default + strict)."]}),"\n"]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h3,{id:"strict-exports",children:"Strict exports"}),"\n",(0,i.jsx)(s.p,{children:"Use when the default config is clean and you want full type-safety enforcement:"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"App type"}),(0,i.jsx)(s.th,{children:"Export"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"React + TS"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslintFlatConfigStrict"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Non-React TS"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"eslintFlatBaseConfigStrict"})})]})]})]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-js",children:"import { eslintFlatConfigStrict } from '@elliemae/pui-cli/eslint';\n\nexport default eslintFlatConfigStrict;\n"})}),"\n",(0,i.jsx)(s.p,{children:"Compared to the default flat config, strict mode:"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Rule"}),(0,i.jsx)(s.th,{children:"Default"}),(0,i.jsx)(s.th,{children:"Strict"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"@typescript-eslint/no-unsafe-*"})}),(0,i.jsx)(s.td,{children:"warn in app code"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"error"})})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"react-hooks/exhaustive-deps"})}),(0,i.jsx)(s.td,{children:"warn"}),(0,i.jsxs)(s.td,{children:[(0,i.jsx)(s.strong,{children:"error"})," (React config only)"]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Tests, Storybook, and other file overrides are unchanged. Strict does ",(0,i.jsx)(s.strong,{children:"not"})," enable ",(0,i.jsx)(s.code,{children:"typescript-eslint/strictTypeChecked"})," (can be added per-repo later)."]}),"\n",(0,i.jsx)(s.hr,{}),"\n",(0,i.jsx)(s.h2,{id:"questions",children:"Questions?"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Channel:"})," ui-platform-chat"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Source of truth in repo:"})," ",(0,i.jsx)(s.code,{children:"lib/lint-config/eslint/flat/"})]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Legacy reference:"})," ",(0,i.jsx)(s.code,{children:"lib/lint-config/eslint/*.cjs"})," (frozen snapshot of old behavior)"]}),"\n"]})]})}function x(e={}){const{wrapper:s}={...(0,d.R)(),...e.components};return s?(0,i.jsx)(s,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},6607(e,s,n){n.d(s,{R:()=>c,x:()=>t});var r=n(758);const i={},d=r.createContext(i);function c(e){const s=r.useContext(d);return r.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function t(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),r.createElement(d.Provider,{value:s},e.children)}}}]);
|