@codyswann/lisa 1.0.0
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/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Query Priority Guide
|
|
2
|
+
|
|
3
|
+
This reference provides detailed guidance on selecting the appropriate query for each testing scenario.
|
|
4
|
+
|
|
5
|
+
## Priority Order
|
|
6
|
+
|
|
7
|
+
The Testing Library team recommends queries in this priority order, based on how accessible they are to users and assistive technologies.
|
|
8
|
+
|
|
9
|
+
### Priority 1: getByRole
|
|
10
|
+
|
|
11
|
+
`getByRole` queries elements by their ARIA role, which is the primary way screen readers identify elements. This should be the default query for almost everything.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// Buttons
|
|
15
|
+
screen.getByRole("button", { name: "Submit" });
|
|
16
|
+
screen.getByRole("button", { name: /save/i }); // Case-insensitive regex
|
|
17
|
+
|
|
18
|
+
// Headings
|
|
19
|
+
screen.getByRole("heading", { name: "Welcome" });
|
|
20
|
+
screen.getByRole("heading", { level: 1 }); // h1
|
|
21
|
+
screen.getByRole("heading", { level: 2, name: "Details" }); // h2 with name
|
|
22
|
+
|
|
23
|
+
// Links
|
|
24
|
+
screen.getByRole("link", { name: "View Profile" });
|
|
25
|
+
|
|
26
|
+
// Form elements
|
|
27
|
+
screen.getByRole("textbox"); // Input without specific type
|
|
28
|
+
screen.getByRole("textbox", { name: "Email" }); // With accessible name
|
|
29
|
+
screen.getByRole("checkbox", { name: "Accept terms" });
|
|
30
|
+
screen.getByRole("radio", { name: "Option A" });
|
|
31
|
+
screen.getByRole("combobox"); // Select/dropdown
|
|
32
|
+
screen.getByRole("switch"); // Toggle switch
|
|
33
|
+
|
|
34
|
+
// Status elements
|
|
35
|
+
screen.getByRole("alert"); // Alert messages
|
|
36
|
+
screen.getByRole("progressbar"); // Loading indicators
|
|
37
|
+
screen.getByRole("status"); // Status updates
|
|
38
|
+
|
|
39
|
+
// Navigation
|
|
40
|
+
screen.getByRole("navigation");
|
|
41
|
+
screen.getByRole("menu");
|
|
42
|
+
screen.getByRole("menuitem", { name: "Settings" });
|
|
43
|
+
|
|
44
|
+
// Tables
|
|
45
|
+
screen.getByRole("table");
|
|
46
|
+
screen.getByRole("row");
|
|
47
|
+
screen.getByRole("cell", { name: "John Doe" });
|
|
48
|
+
|
|
49
|
+
// Dialogs
|
|
50
|
+
screen.getByRole("dialog");
|
|
51
|
+
screen.getByRole("alertdialog");
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Role Options
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Filter by state
|
|
58
|
+
screen.getByRole("button", { name: "Submit", disabled: true });
|
|
59
|
+
screen.getByRole("checkbox", { checked: true });
|
|
60
|
+
screen.getByRole("option", { selected: true });
|
|
61
|
+
screen.getByRole("textbox", { busy: true });
|
|
62
|
+
|
|
63
|
+
// Filter by expanded state (accordion, dropdown)
|
|
64
|
+
screen.getByRole("button", { expanded: true });
|
|
65
|
+
screen.getByRole("button", { expanded: false });
|
|
66
|
+
|
|
67
|
+
// Filter by pressed state (toggle buttons)
|
|
68
|
+
screen.getByRole("button", { pressed: true });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### When getByRole Works with Split Text
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Component with split text:
|
|
75
|
+
// <Button><Icon /> Submit Form</Button>
|
|
76
|
+
|
|
77
|
+
// This fails - text is split by Icon
|
|
78
|
+
screen.getByText("Submit Form"); // Fails!
|
|
79
|
+
|
|
80
|
+
// This works - queries by accessible name
|
|
81
|
+
screen.getByRole("button", { name: /submit form/i }); // Works!
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Priority 2: getByLabelText
|
|
85
|
+
|
|
86
|
+
Use for form fields that have associated labels. This is how users identify form inputs.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// Standard label association
|
|
90
|
+
// <label htmlFor="email">Email Address</label>
|
|
91
|
+
// <input id="email" />
|
|
92
|
+
screen.getByLabelText("Email Address");
|
|
93
|
+
|
|
94
|
+
// Aria-labelledby
|
|
95
|
+
// <span id="label-1">Username</span>
|
|
96
|
+
// <input aria-labelledby="label-1" />
|
|
97
|
+
screen.getByLabelText("Username");
|
|
98
|
+
|
|
99
|
+
// Aria-label
|
|
100
|
+
// <input aria-label="Search" />
|
|
101
|
+
screen.getByLabelText("Search");
|
|
102
|
+
|
|
103
|
+
// Case-insensitive matching
|
|
104
|
+
screen.getByLabelText(/email/i);
|
|
105
|
+
|
|
106
|
+
// Exact match
|
|
107
|
+
screen.getByLabelText("Email", { exact: true });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Priority 3: getByPlaceholderText
|
|
111
|
+
|
|
112
|
+
Use when a form field has placeholder text but no visible label. Note: Placeholders are not a substitute for labels.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// <input placeholder="Enter your email" />
|
|
116
|
+
screen.getByPlaceholderText("Enter your email");
|
|
117
|
+
screen.getByPlaceholderText(/email/i);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Priority 4: getByText
|
|
121
|
+
|
|
122
|
+
Use for non-interactive content like paragraphs, spans, and div text.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// Static text content
|
|
126
|
+
screen.getByText("Welcome to our app");
|
|
127
|
+
screen.getByText(/welcome/i); // Case-insensitive
|
|
128
|
+
|
|
129
|
+
// Partial matching
|
|
130
|
+
screen.getByText("Welcome", { exact: false });
|
|
131
|
+
|
|
132
|
+
// Custom normalizer (for whitespace issues)
|
|
133
|
+
screen.getByText("Hello World", {
|
|
134
|
+
normalizer: str => str.replace(/\s+/g, " ").trim(),
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Priority 5: getByDisplayValue
|
|
139
|
+
|
|
140
|
+
Use for inputs with visible values (like filled form fields).
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// <input value="john@example.com" />
|
|
144
|
+
screen.getByDisplayValue("john@example.com");
|
|
145
|
+
|
|
146
|
+
// Select with selected option
|
|
147
|
+
screen.getByDisplayValue("United States");
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Priority 6: getByAltText
|
|
151
|
+
|
|
152
|
+
Use for images and elements with alt text.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// <img alt="User avatar" src="..." />
|
|
156
|
+
screen.getByAltText("User avatar");
|
|
157
|
+
screen.getByAltText(/avatar/i);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Priority 7: getByTitle
|
|
161
|
+
|
|
162
|
+
Use for elements with title attribute. Less common in React Native.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// <span title="Close">X</span>
|
|
166
|
+
screen.getByTitle("Close");
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Priority 8: getByTestId (Last Resort)
|
|
170
|
+
|
|
171
|
+
Use only when semantic queries are not possible. Adding unnecessary test IDs clutters components.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// <View testID="custom-component">...</View>
|
|
175
|
+
screen.getByTestId("custom-component");
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Valid Use Cases for getByTestId
|
|
179
|
+
|
|
180
|
+
1. Dynamic content that changes frequently
|
|
181
|
+
2. Elements without semantic meaning
|
|
182
|
+
3. Container elements that group other elements
|
|
183
|
+
4. Canvas or custom drawing components
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Valid: Dynamic chart container
|
|
187
|
+
screen.getByTestId("chart-container");
|
|
188
|
+
|
|
189
|
+
// Valid: Animation container
|
|
190
|
+
screen.getByTestId("animation-wrapper");
|
|
191
|
+
|
|
192
|
+
// Invalid: Button (use getByRole)
|
|
193
|
+
screen.getByTestId("submit-button"); // Don't do this
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## React Native Specific Roles
|
|
197
|
+
|
|
198
|
+
React Native components map to accessibility roles:
|
|
199
|
+
|
|
200
|
+
| Component | Accessible Role | Query Example |
|
|
201
|
+
| ------------------ | ------------------ | -------------------------------------- |
|
|
202
|
+
| `Button` | `button` | `getByRole("button")` |
|
|
203
|
+
| `Text` | `text` | `getByRole("text")` |
|
|
204
|
+
| `TextInput` | `textbox` | `getByRole("textbox")` |
|
|
205
|
+
| `Switch` | `switch` | `getByRole("switch")` |
|
|
206
|
+
| `Image` | `image` | `getByRole("image")` or `getByAltText` |
|
|
207
|
+
| `Pressable` | Depends on content | Set `accessibilityRole` explicitly |
|
|
208
|
+
| `TouchableOpacity` | Depends on content | Set `accessibilityRole` explicitly |
|
|
209
|
+
|
|
210
|
+
### Setting Explicit Roles
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
// Pressable as a button
|
|
214
|
+
<Pressable accessibilityRole="button" accessibilityLabel="Save">
|
|
215
|
+
<Text>Save</Text>
|
|
216
|
+
</Pressable>
|
|
217
|
+
|
|
218
|
+
// Custom checkbox
|
|
219
|
+
<Pressable
|
|
220
|
+
accessibilityRole="checkbox"
|
|
221
|
+
accessibilityState={{ checked: isChecked }}
|
|
222
|
+
accessibilityLabel="Accept terms"
|
|
223
|
+
>
|
|
224
|
+
<CheckIcon />
|
|
225
|
+
</Pressable>
|
|
226
|
+
|
|
227
|
+
// Link
|
|
228
|
+
<Pressable accessibilityRole="link" accessibilityLabel="View profile">
|
|
229
|
+
<Text>Profile</Text>
|
|
230
|
+
</Pressable>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Common Mistakes
|
|
234
|
+
|
|
235
|
+
### Using getByTestId When Semantic Query Works
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Wrong
|
|
239
|
+
screen.getByTestId("login-button");
|
|
240
|
+
|
|
241
|
+
// Correct
|
|
242
|
+
screen.getByRole("button", { name: "Login" });
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Using getByText for Interactive Elements
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Wrong - getByText works but doesn't verify accessibility
|
|
249
|
+
screen.getByText("Submit");
|
|
250
|
+
|
|
251
|
+
// Correct - verifies element is actually a button
|
|
252
|
+
screen.getByRole("button", { name: "Submit" });
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Case Sensitivity Issues
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// May fail if case doesn't match
|
|
259
|
+
screen.getByText("Submit");
|
|
260
|
+
|
|
261
|
+
// More robust - case insensitive
|
|
262
|
+
screen.getByRole("button", { name: /submit/i });
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Querying Hidden Elements
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// By default, queries ignore hidden elements
|
|
269
|
+
screen.getByRole("button", { name: "Submit" });
|
|
270
|
+
|
|
271
|
+
// To include hidden elements
|
|
272
|
+
screen.getByRole("button", { name: "Submit", hidden: true });
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Query Decision Tree
|
|
276
|
+
|
|
277
|
+
1. Is it an interactive element (button, link, input)?
|
|
278
|
+
- Yes → Use `getByRole`
|
|
279
|
+
2. Is it a form field with a label?
|
|
280
|
+
- Yes → Use `getByLabelText`
|
|
281
|
+
3. Is it a form field with only placeholder?
|
|
282
|
+
- Yes → Use `getByPlaceholderText`
|
|
283
|
+
4. Is it static text content?
|
|
284
|
+
- Yes → Use `getByText`
|
|
285
|
+
5. Is it an image?
|
|
286
|
+
- Yes → Use `getByAltText`
|
|
287
|
+
6. Does it have a value?
|
|
288
|
+
- Yes → Use `getByDisplayValue`
|
|
289
|
+
7. None of the above?
|
|
290
|
+
- Consider if the component is accessible
|
|
291
|
+
- If not fixable, use `getByTestId` as last resort
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"expo-docs": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": ["expo-local-docs-mcp"]
|
|
6
|
+
},
|
|
7
|
+
"sonarqube": {
|
|
8
|
+
"command": "docker",
|
|
9
|
+
"args": [
|
|
10
|
+
"run",
|
|
11
|
+
"-i",
|
|
12
|
+
"--rm",
|
|
13
|
+
"-e",
|
|
14
|
+
"SONARQUBE_TOKEN",
|
|
15
|
+
"-e",
|
|
16
|
+
"SONARQUBE_ORG",
|
|
17
|
+
"mcp/sonarqube"
|
|
18
|
+
],
|
|
19
|
+
"env": {
|
|
20
|
+
"SONARQUBE_TOKEN": "${SONAR_TOKEN}",
|
|
21
|
+
"SONARQUBE_ORG": "${SONAR_ORG}"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"atlassian": {
|
|
25
|
+
"type": "sse",
|
|
26
|
+
"url": "https://mcp.atlassian.com/v1/sse"
|
|
27
|
+
},
|
|
28
|
+
"playwright": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["@playwright/mcp@latest"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# ESLint Plugin: Component Structure
|
|
2
|
+
|
|
3
|
+
Custom ESLint rules for enforcing component structure standards in the frontend.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
### enforce-component-structure
|
|
8
|
+
|
|
9
|
+
Enforces the Container/View pattern for React components by ensuring component directories contain exactly three files: `*Container.tsx`, `*View.tsx`, and `index.tsx`.
|
|
10
|
+
|
|
11
|
+
This rule helps maintain consistent component organization and separation of concerns throughout the codebase.
|
|
12
|
+
|
|
13
|
+
#### Rule Details
|
|
14
|
+
|
|
15
|
+
This rule checks component directories to ensure they follow the standard three-file structure:
|
|
16
|
+
|
|
17
|
+
- `ComponentNameContainer.tsx` - Contains logic, state, and data fetching
|
|
18
|
+
- `ComponentNameView.tsx` - Pure UI presentation receiving props only
|
|
19
|
+
- `index.tsx` - Default export of the Container
|
|
20
|
+
|
|
21
|
+
**Where does this rule apply?**
|
|
22
|
+
|
|
23
|
+
- Files in `features/**/components/` directories
|
|
24
|
+
- Files in `components/` directory
|
|
25
|
+
- **Excludes**: `components/ui/`, `components/shared/`, `components/icons/`
|
|
26
|
+
|
|
27
|
+
#### Configuration
|
|
28
|
+
|
|
29
|
+
In `.eslintrc.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"rules": {
|
|
34
|
+
"component-structure/enforce-component-structure": "error"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### no-return-in-view
|
|
42
|
+
|
|
43
|
+
Prevents early returns and conditional logic in View components to maintain pure presentation components.
|
|
44
|
+
|
|
45
|
+
#### Rule Details
|
|
46
|
+
|
|
47
|
+
View components should only contain JSX presentation logic. Any conditional rendering or early returns should be handled in the Container component or passed as props.
|
|
48
|
+
|
|
49
|
+
**Where does this rule apply?**
|
|
50
|
+
|
|
51
|
+
- Files matching `*View.tsx`, `*View.jsx`
|
|
52
|
+
|
|
53
|
+
#### Configuration
|
|
54
|
+
|
|
55
|
+
In `.eslintrc.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"rules": {
|
|
60
|
+
"component-structure/no-return-in-view": "error"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### require-memo-in-view
|
|
68
|
+
|
|
69
|
+
Enforces the use of `React.memo()` for View components to optimize rendering performance.
|
|
70
|
+
|
|
71
|
+
#### Rule Details
|
|
72
|
+
|
|
73
|
+
All View components should be wrapped with `React.memo()` to prevent unnecessary re-renders when props haven't changed.
|
|
74
|
+
|
|
75
|
+
**Where does this rule apply?**
|
|
76
|
+
|
|
77
|
+
- Files matching `*View.tsx`, `*View.jsx`
|
|
78
|
+
- **Excludes**: `components/ui/` directory
|
|
79
|
+
|
|
80
|
+
#### Configuration
|
|
81
|
+
|
|
82
|
+
In `.eslintrc.json`:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"rules": {
|
|
87
|
+
"component-structure/require-memo-in-view": "error"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### single-component-per-file
|
|
95
|
+
|
|
96
|
+
Enforces one React component per file to improve code organization and maintainability.
|
|
97
|
+
|
|
98
|
+
#### Rule Details
|
|
99
|
+
|
|
100
|
+
This rule ensures that each file contains exactly one React component. Multiple components in a single file make code harder to navigate, test, and maintain.
|
|
101
|
+
|
|
102
|
+
**What is considered a React component?**
|
|
103
|
+
|
|
104
|
+
- Any function with PascalCase naming that returns JSX
|
|
105
|
+
- This includes components wrapped with `memo()` or `React.memo()`
|
|
106
|
+
- Both arrow functions and function declarations
|
|
107
|
+
|
|
108
|
+
**Where does this rule apply?**
|
|
109
|
+
|
|
110
|
+
- Files matching `*View.tsx`, `*View.jsx`, `*Container.tsx`, `*Container.jsx`
|
|
111
|
+
- In `features/**/components/` directories
|
|
112
|
+
- In `components/` directory
|
|
113
|
+
- **Excludes**: `components/ui/`, `components/shared/`, `components/icons/`
|
|
114
|
+
|
|
115
|
+
#### Examples
|
|
116
|
+
|
|
117
|
+
❌ **Incorrect** (multiple components):
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// MessageListView.tsx
|
|
121
|
+
const MessageItem = ({ item }) => <div>{item}</div>;
|
|
122
|
+
|
|
123
|
+
const MessageListView = ({ messages }) => (
|
|
124
|
+
<div>
|
|
125
|
+
{messages.map(msg => <MessageItem item={msg} />)}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
export default MessageListView;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
✅ **Correct** (one component per file):
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// MessageItem.tsx
|
|
136
|
+
const MessageItem = ({ item }) => <div>{item}</div>;
|
|
137
|
+
export default MessageItem;
|
|
138
|
+
|
|
139
|
+
// MessageListView.tsx
|
|
140
|
+
import MessageItem from "./MessageItem";
|
|
141
|
+
|
|
142
|
+
const MessageListView = ({ messages }) => (
|
|
143
|
+
<div>
|
|
144
|
+
{messages.map(msg => <MessageItem item={msg} />)}
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
export default MessageListView;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Configuration
|
|
152
|
+
|
|
153
|
+
In `.eslintrc.json`:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"rules": {
|
|
158
|
+
"component-structure/single-component-per-file": "error"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### When to Disable
|
|
164
|
+
|
|
165
|
+
This rule should rarely be disabled. If you have a valid use case, use an inline comment:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
/* eslint-disable component-structure/single-component-per-file --
|
|
169
|
+
Reason: These components are tightly coupled and only used together
|
|
170
|
+
*/
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Installation
|
|
174
|
+
|
|
175
|
+
This plugin is installed locally as a file dependency:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"devDependencies": {
|
|
180
|
+
"eslint-plugin-component-structure": "file:./eslint-plugin-component-structure"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Usage
|
|
186
|
+
|
|
187
|
+
### ESLint 9 Flat Config (Recommended)
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// eslint.config.mjs
|
|
191
|
+
import componentStructurePlugin from './eslint-plugin-component-structure/index.js';
|
|
192
|
+
|
|
193
|
+
export default [
|
|
194
|
+
{
|
|
195
|
+
plugins: {
|
|
196
|
+
'component-structure': componentStructurePlugin,
|
|
197
|
+
},
|
|
198
|
+
rules: {
|
|
199
|
+
'component-structure/enforce-component-structure': 'error',
|
|
200
|
+
'component-structure/no-return-in-view': 'error',
|
|
201
|
+
'component-structure/require-memo-in-view': 'error',
|
|
202
|
+
'component-structure/single-component-per-file': 'error',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
];
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Legacy Config (.eslintrc.json)
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"plugins": ["component-structure"],
|
|
213
|
+
"rules": {
|
|
214
|
+
"component-structure/enforce-component-structure": "error",
|
|
215
|
+
"component-structure/no-return-in-view": "error",
|
|
216
|
+
"component-structure/require-memo-in-view": "error",
|
|
217
|
+
"component-structure/single-component-per-file": "error"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Version
|
|
223
|
+
|
|
224
|
+
1.0.0
|
|
225
|
+
|
|
226
|
+
## Contributing
|
|
227
|
+
|
|
228
|
+
When adding new rules to this plugin:
|
|
229
|
+
|
|
230
|
+
1. Create the rule implementation in `rules/`
|
|
231
|
+
2. Add comprehensive tests in `__tests__/`
|
|
232
|
+
3. Export the rule in `index.js`
|
|
233
|
+
4. Update this README with rule documentation
|
|
234
|
+
5. Add the rule to `.eslintrc.json` configuration
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the plugin index
|
|
3
|
+
*
|
|
4
|
+
* Verifies that all rules are properly registered and exported from the plugin.
|
|
5
|
+
* Also verifies that the plugin has proper ESLint 9 flat config metadata.
|
|
6
|
+
* @module eslint-plugin-component-structure/tests/plugin-index
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const plugin = require("../index");
|
|
10
|
+
|
|
11
|
+
describe("eslint-plugin-component-structure", () => {
|
|
12
|
+
describe("plugin meta (ESLint 9 flat config)", () => {
|
|
13
|
+
it("should export a meta object", () => {
|
|
14
|
+
expect(plugin).toHaveProperty("meta");
|
|
15
|
+
expect(typeof plugin.meta).toBe("object");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should have name property in meta", () => {
|
|
19
|
+
expect(plugin.meta).toHaveProperty("name");
|
|
20
|
+
expect(plugin.meta.name).toBe("eslint-plugin-component-structure");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should have version property in meta", () => {
|
|
24
|
+
expect(plugin.meta).toHaveProperty("version");
|
|
25
|
+
expect(plugin.meta.version).toBe("1.0.0");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("plugin exports", () => {
|
|
30
|
+
it("should export a rules object", () => {
|
|
31
|
+
expect(plugin).toHaveProperty("rules");
|
|
32
|
+
expect(typeof plugin.rules).toBe("object");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should export enforce-component-structure rule", () => {
|
|
36
|
+
expect(plugin.rules).toHaveProperty("enforce-component-structure");
|
|
37
|
+
expect(typeof plugin.rules["enforce-component-structure"]).toBe("object");
|
|
38
|
+
expect(plugin.rules["enforce-component-structure"]).toHaveProperty(
|
|
39
|
+
"create"
|
|
40
|
+
);
|
|
41
|
+
expect(plugin.rules["enforce-component-structure"]).toHaveProperty(
|
|
42
|
+
"meta"
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should export no-return-in-view rule", () => {
|
|
47
|
+
expect(plugin.rules).toHaveProperty("no-return-in-view");
|
|
48
|
+
expect(typeof plugin.rules["no-return-in-view"]).toBe("object");
|
|
49
|
+
expect(plugin.rules["no-return-in-view"]).toHaveProperty("create");
|
|
50
|
+
expect(plugin.rules["no-return-in-view"]).toHaveProperty("meta");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should export require-memo-in-view rule", () => {
|
|
54
|
+
expect(plugin.rules).toHaveProperty("require-memo-in-view");
|
|
55
|
+
expect(typeof plugin.rules["require-memo-in-view"]).toBe("object");
|
|
56
|
+
expect(plugin.rules["require-memo-in-view"]).toHaveProperty("create");
|
|
57
|
+
expect(plugin.rules["require-memo-in-view"]).toHaveProperty("meta");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should export single-component-per-file rule", () => {
|
|
61
|
+
expect(plugin.rules).toHaveProperty("single-component-per-file");
|
|
62
|
+
expect(typeof plugin.rules["single-component-per-file"]).toBe("object");
|
|
63
|
+
expect(plugin.rules["single-component-per-file"]).toHaveProperty(
|
|
64
|
+
"create"
|
|
65
|
+
);
|
|
66
|
+
expect(plugin.rules["single-component-per-file"]).toHaveProperty("meta");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should have correct number of rules", () => {
|
|
70
|
+
const ruleCount = Object.keys(plugin.rules).length;
|
|
71
|
+
expect(ruleCount).toBe(4);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("rule metadata", () => {
|
|
76
|
+
it("single-component-per-file should have correct metadata", () => {
|
|
77
|
+
const rule = plugin.rules["single-component-per-file"];
|
|
78
|
+
expect(rule.meta.type).toBe("problem");
|
|
79
|
+
expect(rule.meta.docs).toHaveProperty("description");
|
|
80
|
+
expect(rule.meta.docs.description).toContain("one React component");
|
|
81
|
+
expect(rule.meta.messages).toHaveProperty("multipleComponents");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|