@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,300 @@
|
|
|
1
|
+
# Spacing Scale Reference
|
|
2
|
+
|
|
3
|
+
This reference provides the complete spacing scale for NativeWind/Tailwind CSS. Use only these values for consistent, maintainable layouts.
|
|
4
|
+
|
|
5
|
+
## Standard Spacing Scale
|
|
6
|
+
|
|
7
|
+
| Class Suffix | Pixels | Rem | Usage |
|
|
8
|
+
| ------------ | ------ | -------- | -------------------------------- |
|
|
9
|
+
| `0` | 0px | 0rem | Reset spacing |
|
|
10
|
+
| `px` | 1px | - | Hairline borders, minimal offset |
|
|
11
|
+
| `0.5` | 2px | 0.125rem | Micro spacing |
|
|
12
|
+
| `1` | 4px | 0.25rem | Tight spacing |
|
|
13
|
+
| `1.5` | 6px | 0.375rem | Compact spacing |
|
|
14
|
+
| `2` | 8px | 0.5rem | Small spacing |
|
|
15
|
+
| `2.5` | 10px | 0.625rem | Small-medium spacing |
|
|
16
|
+
| `3` | 12px | 0.75rem | Medium-small spacing |
|
|
17
|
+
| `3.5` | 14px | 0.875rem | Medium spacing |
|
|
18
|
+
| `4` | 16px | 1rem | **Default** - standard spacing |
|
|
19
|
+
| `5` | 20px | 1.25rem | Medium-large spacing |
|
|
20
|
+
| `6` | 24px | 1.5rem | Large spacing |
|
|
21
|
+
| `7` | 28px | 1.75rem | Large+ spacing |
|
|
22
|
+
| `8` | 32px | 2rem | Extra large spacing |
|
|
23
|
+
| `9` | 36px | 2.25rem | XL spacing |
|
|
24
|
+
| `10` | 40px | 2.5rem | XXL spacing |
|
|
25
|
+
| `11` | 44px | 2.75rem | Touch target minimum |
|
|
26
|
+
| `12` | 48px | 3rem | Section spacing |
|
|
27
|
+
| `14` | 56px | 3.5rem | Large section spacing |
|
|
28
|
+
| `16` | 64px | 4rem | Major section spacing |
|
|
29
|
+
| `20` | 80px | 5rem | Page section spacing |
|
|
30
|
+
| `24` | 96px | 6rem | Hero spacing |
|
|
31
|
+
| `28` | 112px | 7rem | Extra hero spacing |
|
|
32
|
+
| `32` | 128px | 8rem | Maximum spacing |
|
|
33
|
+
| `36` | 144px | 9rem | Oversized spacing |
|
|
34
|
+
| `40` | 160px | 10rem | Oversized spacing |
|
|
35
|
+
| `44` | 176px | 11rem | Oversized spacing |
|
|
36
|
+
| `48` | 192px | 12rem | Oversized spacing |
|
|
37
|
+
| `52` | 208px | 13rem | Oversized spacing |
|
|
38
|
+
| `56` | 224px | 14rem | Oversized spacing |
|
|
39
|
+
| `60` | 240px | 15rem | Oversized spacing |
|
|
40
|
+
| `64` | 256px | 16rem | Oversized spacing |
|
|
41
|
+
| `72` | 288px | 18rem | Oversized spacing |
|
|
42
|
+
| `80` | 320px | 20rem | Oversized spacing |
|
|
43
|
+
| `96` | 384px | 24rem | Maximum oversized |
|
|
44
|
+
|
|
45
|
+
## Spacing Properties
|
|
46
|
+
|
|
47
|
+
### Padding
|
|
48
|
+
|
|
49
|
+
| Property | Classes |
|
|
50
|
+
| ----------------- | ------------ |
|
|
51
|
+
| All sides | `p-{scale}` |
|
|
52
|
+
| Horizontal | `px-{scale}` |
|
|
53
|
+
| Vertical | `py-{scale}` |
|
|
54
|
+
| Top | `pt-{scale}` |
|
|
55
|
+
| Right | `pr-{scale}` |
|
|
56
|
+
| Bottom | `pb-{scale}` |
|
|
57
|
+
| Left | `pl-{scale}` |
|
|
58
|
+
| Start (RTL-aware) | `ps-{scale}` |
|
|
59
|
+
| End (RTL-aware) | `pe-{scale}` |
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// Uniform padding
|
|
63
|
+
<Box className="p-4" /> // 16px all sides
|
|
64
|
+
|
|
65
|
+
// Horizontal and vertical
|
|
66
|
+
<Box className="px-6 py-4" /> // 24px horizontal, 16px vertical
|
|
67
|
+
|
|
68
|
+
// Individual sides
|
|
69
|
+
<Box className="pt-2 pr-4 pb-6 pl-4" />
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Margin
|
|
73
|
+
|
|
74
|
+
| Property | Classes |
|
|
75
|
+
| ----------------- | ------------------------------------ |
|
|
76
|
+
| All sides | `m-{scale}` |
|
|
77
|
+
| Horizontal | `mx-{scale}` |
|
|
78
|
+
| Vertical | `my-{scale}` |
|
|
79
|
+
| Top | `mt-{scale}` |
|
|
80
|
+
| Right | `mr-{scale}` |
|
|
81
|
+
| Bottom | `mb-{scale}` |
|
|
82
|
+
| Left | `ml-{scale}` |
|
|
83
|
+
| Start (RTL-aware) | `ms-{scale}` |
|
|
84
|
+
| End (RTL-aware) | `me-{scale}` |
|
|
85
|
+
| Auto | `m-auto`, `mx-auto`, `my-auto`, etc. |
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
// Centered horizontally
|
|
89
|
+
<Box className="mx-auto" />
|
|
90
|
+
|
|
91
|
+
// Stack spacing
|
|
92
|
+
<Box className="mb-4" /> // 16px bottom margin
|
|
93
|
+
|
|
94
|
+
// Negative margin (use sparingly)
|
|
95
|
+
<Box className="-mt-2" /> // -8px top margin
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Gap (Flexbox/Grid)
|
|
99
|
+
|
|
100
|
+
| Property | Classes |
|
|
101
|
+
| ---------- | --------------- |
|
|
102
|
+
| Both axes | `gap-{scale}` |
|
|
103
|
+
| Row gap | `gap-y-{scale}` |
|
|
104
|
+
| Column gap | `gap-x-{scale}` |
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// Uniform gap in flex container
|
|
108
|
+
<Box className="flex flex-row gap-4">
|
|
109
|
+
<Item />
|
|
110
|
+
<Item />
|
|
111
|
+
<Item />
|
|
112
|
+
</Box>
|
|
113
|
+
|
|
114
|
+
// Grid with different gaps
|
|
115
|
+
<Box className="grid grid-cols-3 gap-x-6 gap-y-4">
|
|
116
|
+
<Item />
|
|
117
|
+
<Item />
|
|
118
|
+
<Item />
|
|
119
|
+
</Box>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Space Between (Legacy Alternative)
|
|
123
|
+
|
|
124
|
+
Use `gap-*` instead when possible, but `space-*` is available:
|
|
125
|
+
|
|
126
|
+
| Property | Classes |
|
|
127
|
+
| ---------- | ----------------- |
|
|
128
|
+
| Horizontal | `space-x-{scale}` |
|
|
129
|
+
| Vertical | `space-y-{scale}` |
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// Vertical stack with space between
|
|
133
|
+
<Box className="flex flex-col space-y-4">
|
|
134
|
+
<Item />
|
|
135
|
+
<Item />
|
|
136
|
+
</Box>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Common Spacing Patterns
|
|
140
|
+
|
|
141
|
+
### Card Padding
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
// Compact card
|
|
145
|
+
<Box className="p-3" /> // 12px
|
|
146
|
+
|
|
147
|
+
// Standard card
|
|
148
|
+
<Box className="p-4" /> // 16px
|
|
149
|
+
|
|
150
|
+
// Spacious card
|
|
151
|
+
<Box className="p-6" /> // 24px
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### List Item Spacing
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
// Tight list
|
|
158
|
+
<Box className="py-2 px-3" /> // 8px vertical, 12px horizontal
|
|
159
|
+
|
|
160
|
+
// Standard list
|
|
161
|
+
<Box className="py-3 px-4" /> // 12px vertical, 16px horizontal
|
|
162
|
+
|
|
163
|
+
// Spacious list
|
|
164
|
+
<Box className="py-4 px-6" /> // 16px vertical, 24px horizontal
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Section Spacing
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
// Between sections
|
|
171
|
+
<Box className="my-8" /> // 32px vertical margin
|
|
172
|
+
|
|
173
|
+
// Page sections
|
|
174
|
+
<Box className="py-12" /> // 48px vertical padding
|
|
175
|
+
|
|
176
|
+
// Hero sections
|
|
177
|
+
<Box className="py-16" /> // 64px vertical padding
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Button Padding
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
// Small button
|
|
184
|
+
<Button className="px-3 py-1.5" /> // 12px horizontal, 6px vertical
|
|
185
|
+
|
|
186
|
+
// Medium button
|
|
187
|
+
<Button className="px-4 py-2" /> // 16px horizontal, 8px vertical
|
|
188
|
+
|
|
189
|
+
// Large button
|
|
190
|
+
<Button className="px-6 py-3" /> // 24px horizontal, 12px vertical
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Form Field Spacing
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
// Form field group
|
|
197
|
+
<Box className="space-y-4"> // 16px between fields
|
|
198
|
+
<Input />
|
|
199
|
+
<Input />
|
|
200
|
+
<Button />
|
|
201
|
+
</Box>
|
|
202
|
+
|
|
203
|
+
// Form section
|
|
204
|
+
<Box className="space-y-6"> // 24px between sections
|
|
205
|
+
<FormSection />
|
|
206
|
+
<FormSection />
|
|
207
|
+
</Box>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Touch Targets
|
|
211
|
+
|
|
212
|
+
Minimum touch target size is 44x44px (11 spacing units):
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
// Icon button with minimum touch target
|
|
216
|
+
<Pressable className="h-11 w-11 items-center justify-center">
|
|
217
|
+
<Icon />
|
|
218
|
+
</Pressable>
|
|
219
|
+
|
|
220
|
+
// Touch target with padding
|
|
221
|
+
<Pressable className="p-3"> // At least 12px padding
|
|
222
|
+
<Text>Tappable</Text>
|
|
223
|
+
</Pressable>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Prohibited Patterns
|
|
227
|
+
|
|
228
|
+
### Arbitrary Values
|
|
229
|
+
|
|
230
|
+
Never use bracket notation for spacing:
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
// WRONG
|
|
234
|
+
<Box className="p-[13px]" />
|
|
235
|
+
<Box className="m-[27px]" />
|
|
236
|
+
<Box className="gap-[15px]" />
|
|
237
|
+
|
|
238
|
+
// CORRECT - use nearest scale value
|
|
239
|
+
<Box className="p-3" /> // 12px instead of 13px
|
|
240
|
+
<Box className="m-7" /> // 28px instead of 27px
|
|
241
|
+
<Box className="gap-4" /> // 16px instead of 15px
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Inline Style Spacing
|
|
245
|
+
|
|
246
|
+
Never use inline styles for spacing:
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
// WRONG
|
|
250
|
+
<Box style={{ padding: 13 }} />
|
|
251
|
+
<Box style={{ marginTop: 27 }} />
|
|
252
|
+
|
|
253
|
+
// CORRECT
|
|
254
|
+
<Box className="p-3" />
|
|
255
|
+
<Box className="mt-7" />
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Non-Scale Decimals
|
|
259
|
+
|
|
260
|
+
Only use defined decimal values:
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
// WRONG
|
|
264
|
+
<Box className="p-2.7" />
|
|
265
|
+
<Box className="m-4.3" />
|
|
266
|
+
|
|
267
|
+
// CORRECT - allowed decimals: 0.5, 1.5, 2.5, 3.5
|
|
268
|
+
<Box className="p-2.5" />
|
|
269
|
+
<Box className="m-4" />
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Responsive Spacing
|
|
273
|
+
|
|
274
|
+
Apply different spacing at breakpoints:
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
// Smaller padding on mobile, larger on desktop
|
|
278
|
+
<Box className="p-4 md:p-6 lg:p-8" />
|
|
279
|
+
|
|
280
|
+
// Responsive gap
|
|
281
|
+
<Box className="gap-2 md:gap-4 lg:gap-6" />
|
|
282
|
+
|
|
283
|
+
// Responsive margin
|
|
284
|
+
<Box className="mt-4 md:mt-8 lg:mt-12" />
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Spacing Decision Guide
|
|
288
|
+
|
|
289
|
+
| Context | Recommended Values |
|
|
290
|
+
| ----------------- | -------------------------------- |
|
|
291
|
+
| Icon spacing | `1`, `1.5`, `2` |
|
|
292
|
+
| Text line spacing | `1`, `2`, `3` |
|
|
293
|
+
| Button padding | `2-3` vertical, `3-6` horizontal |
|
|
294
|
+
| Card padding | `3`, `4`, `6` |
|
|
295
|
+
| List item padding | `2-4` vertical, `3-4` horizontal |
|
|
296
|
+
| Section spacing | `6`, `8`, `12`, `16` |
|
|
297
|
+
| Page margins | `4`, `6`, `8` |
|
|
298
|
+
| Modal padding | `4`, `6` |
|
|
299
|
+
| Form field gap | `3`, `4` |
|
|
300
|
+
| Touch targets | minimum `11` (44px) |
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validates Gluestack UI v3 and NativeWind v4 styling patterns.
|
|
4
|
+
|
|
5
|
+
This script detects common styling violations:
|
|
6
|
+
1. Direct React Native imports with Gluestack equivalents
|
|
7
|
+
2. Raw color values without semantic tokens
|
|
8
|
+
3. Inline style objects where className could be used
|
|
9
|
+
4. Arbitrary bracket notation values
|
|
10
|
+
5. Non-scale spacing values
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python3 validate_styling.py [path]
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
path Optional path to validate. Defaults to current directory.
|
|
17
|
+
Can be a file or directory.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import sys
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class Violation:
|
|
30
|
+
"""Represents a styling violation."""
|
|
31
|
+
file: str
|
|
32
|
+
line: int
|
|
33
|
+
rule: str
|
|
34
|
+
message: str
|
|
35
|
+
severity: str = "error"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# React Native components that have Gluestack equivalents
|
|
39
|
+
RN_TO_GLUESTACK_MAP = {
|
|
40
|
+
"View": "Box",
|
|
41
|
+
"Text": "Text (from @/components/ui/text)",
|
|
42
|
+
"TouchableOpacity": "Pressable",
|
|
43
|
+
"TouchableHighlight": "Pressable",
|
|
44
|
+
"TouchableWithoutFeedback": "Pressable",
|
|
45
|
+
"Image": "Image (from @/components/ui/image)",
|
|
46
|
+
"ScrollView": "ScrollView (from @/components/ui/scroll-view)",
|
|
47
|
+
"TextInput": "Input + InputField",
|
|
48
|
+
"FlatList": "FlashList",
|
|
49
|
+
"SectionList": "FlashList",
|
|
50
|
+
"ActivityIndicator": "Spinner",
|
|
51
|
+
"Modal": "Modal (from @/components/ui/modal)",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Raw colors that should be semantic tokens
|
|
55
|
+
RAW_COLOR_PATTERNS = [
|
|
56
|
+
# Tailwind raw colors (red, green, blue, yellow, gray, etc.)
|
|
57
|
+
r'\b(text|bg|border|ring|fill|stroke)-(red|green|blue|yellow|orange|purple|pink|indigo|cyan|teal|emerald|lime|amber|violet|fuchsia|rose|sky|slate|gray|zinc|neutral|stone)-\d{2,3}\b',
|
|
58
|
+
# White/black that should be typography-0 or typography-950
|
|
59
|
+
r'\btext-white\b',
|
|
60
|
+
r'\btext-black\b',
|
|
61
|
+
r'\bbg-white\b',
|
|
62
|
+
r'\bbg-black\b',
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
# Semantic tokens that ARE allowed
|
|
66
|
+
ALLOWED_SEMANTIC_PATTERNS = [
|
|
67
|
+
r'\b(text|bg|border|ring)-(primary|secondary|tertiary|error|success|warning|info|typography|outline|background|indicator)-',
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
# Arbitrary value patterns (bracket notation)
|
|
71
|
+
ARBITRARY_VALUE_PATTERNS = [
|
|
72
|
+
r'\b[a-z]+-\[\d+px\]', # p-[13px], m-[27px]
|
|
73
|
+
r'\b[a-z]+-\[\d+rem\]', # p-[1.3rem]
|
|
74
|
+
r'\b[a-z]+-\[\d+%\]', # w-[50%] (sometimes acceptable)
|
|
75
|
+
r'\bgap-\[\d+', # gap-[15px]
|
|
76
|
+
r'\bspace-[xy]-\[\d+', # space-x-[10px]
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
# Non-standard spacing values (not in Tailwind scale)
|
|
80
|
+
# Valid values: 0, px, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96
|
|
81
|
+
VALID_SPACING_VALUES = {
|
|
82
|
+
"0", "px", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "5", "6",
|
|
83
|
+
"7", "8", "9", "10", "11", "12", "14", "16", "20", "24", "28", "32",
|
|
84
|
+
"36", "40", "44", "48", "52", "56", "60", "64", "72", "80", "96"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Inline style patterns that could be className
|
|
88
|
+
INLINE_STYLE_PATTERNS = [
|
|
89
|
+
r'style=\{\{[^}]*backgroundColor\s*:',
|
|
90
|
+
r'style=\{\{[^}]*color\s*:',
|
|
91
|
+
r'style=\{\{[^}]*padding\s*:',
|
|
92
|
+
r'style=\{\{[^}]*margin\s*:',
|
|
93
|
+
r'style=\{\{[^}]*borderRadius\s*:',
|
|
94
|
+
r'style=\{\{[^}]*borderColor\s*:',
|
|
95
|
+
r'style=\{\{[^}]*borderWidth\s*:',
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
# Exceptions - files/patterns to skip
|
|
99
|
+
SKIP_PATTERNS = [
|
|
100
|
+
r'node_modules',
|
|
101
|
+
r'\.test\.',
|
|
102
|
+
r'\.spec\.',
|
|
103
|
+
r'__tests__',
|
|
104
|
+
r'components/ui/', # UI primitives are allowed to use any styling
|
|
105
|
+
r'\.d\.ts$',
|
|
106
|
+
r'tailwind\.config',
|
|
107
|
+
r'\.config\.',
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def should_skip_file(file_path: str) -> bool:
|
|
112
|
+
"""Check if file should be skipped."""
|
|
113
|
+
for pattern in SKIP_PATTERNS:
|
|
114
|
+
if re.search(pattern, file_path):
|
|
115
|
+
return True
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def is_semantic_color(match: str) -> bool:
|
|
120
|
+
"""Check if a color class uses semantic tokens."""
|
|
121
|
+
for pattern in ALLOWED_SEMANTIC_PATTERNS:
|
|
122
|
+
if re.search(pattern, match):
|
|
123
|
+
return True
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def check_rn_imports(content: str, file_path: str) -> list[Violation]:
|
|
128
|
+
"""Check for React Native imports that should be Gluestack."""
|
|
129
|
+
violations = []
|
|
130
|
+
lines = content.split('\n')
|
|
131
|
+
|
|
132
|
+
for i, line in enumerate(lines, 1):
|
|
133
|
+
# Check for import from react-native
|
|
134
|
+
if 'from "react-native"' in line or "from 'react-native'" in line:
|
|
135
|
+
for rn_component, gluestack_equiv in RN_TO_GLUESTACK_MAP.items():
|
|
136
|
+
# Check if component is imported
|
|
137
|
+
if re.search(rf'\b{rn_component}\b', line):
|
|
138
|
+
violations.append(Violation(
|
|
139
|
+
file=file_path,
|
|
140
|
+
line=i,
|
|
141
|
+
rule="gluestack-components",
|
|
142
|
+
message=f"Use Gluestack '{gluestack_equiv}' instead of React Native '{rn_component}'",
|
|
143
|
+
))
|
|
144
|
+
|
|
145
|
+
return violations
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def check_raw_colors(content: str, file_path: str) -> list[Violation]:
|
|
149
|
+
"""Check for raw color values instead of semantic tokens."""
|
|
150
|
+
violations = []
|
|
151
|
+
lines = content.split('\n')
|
|
152
|
+
|
|
153
|
+
for i, line in enumerate(lines, 1):
|
|
154
|
+
# Skip comments
|
|
155
|
+
if line.strip().startswith('//') or line.strip().startswith('*'):
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
for pattern in RAW_COLOR_PATTERNS:
|
|
159
|
+
matches = re.findall(pattern, line)
|
|
160
|
+
for match in matches:
|
|
161
|
+
if isinstance(match, tuple):
|
|
162
|
+
match = '-'.join(match)
|
|
163
|
+
if not is_semantic_color(match):
|
|
164
|
+
violations.append(Violation(
|
|
165
|
+
file=file_path,
|
|
166
|
+
line=i,
|
|
167
|
+
rule="semantic-tokens",
|
|
168
|
+
message=f"Use semantic color token instead of raw color '{match}'",
|
|
169
|
+
))
|
|
170
|
+
|
|
171
|
+
return violations
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def check_arbitrary_values(content: str, file_path: str) -> list[Violation]:
|
|
175
|
+
"""Check for arbitrary bracket notation values."""
|
|
176
|
+
violations = []
|
|
177
|
+
lines = content.split('\n')
|
|
178
|
+
|
|
179
|
+
for i, line in enumerate(lines, 1):
|
|
180
|
+
# Skip comments
|
|
181
|
+
if line.strip().startswith('//') or line.strip().startswith('*'):
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
for pattern in ARBITRARY_VALUE_PATTERNS:
|
|
185
|
+
matches = re.findall(pattern, line)
|
|
186
|
+
for match in matches:
|
|
187
|
+
violations.append(Violation(
|
|
188
|
+
file=file_path,
|
|
189
|
+
line=i,
|
|
190
|
+
rule="no-arbitrary-values",
|
|
191
|
+
message=f"Avoid arbitrary values '{match}'. Use spacing scale instead.",
|
|
192
|
+
severity="warning",
|
|
193
|
+
))
|
|
194
|
+
|
|
195
|
+
return violations
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def check_inline_styles(content: str, file_path: str) -> list[Violation]:
|
|
199
|
+
"""Check for inline styles that could be className."""
|
|
200
|
+
violations = []
|
|
201
|
+
lines = content.split('\n')
|
|
202
|
+
|
|
203
|
+
for i, line in enumerate(lines, 1):
|
|
204
|
+
# Skip comments
|
|
205
|
+
if line.strip().startswith('//') or line.strip().startswith('*'):
|
|
206
|
+
continue
|
|
207
|
+
|
|
208
|
+
for pattern in INLINE_STYLE_PATTERNS:
|
|
209
|
+
if re.search(pattern, line):
|
|
210
|
+
# Check for exceptions (dynamic values, animations)
|
|
211
|
+
if 'bottomInset' in line or 'Animated' in line or 'animatedValue' in line:
|
|
212
|
+
continue
|
|
213
|
+
if 'Platform.select' in line or 'Platform.OS' in line:
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
violations.append(Violation(
|
|
217
|
+
file=file_path,
|
|
218
|
+
line=i,
|
|
219
|
+
rule="no-inline-styles",
|
|
220
|
+
message="Prefer className over inline style for static styling",
|
|
221
|
+
severity="warning",
|
|
222
|
+
))
|
|
223
|
+
|
|
224
|
+
return violations
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_non_scale_spacing(content: str, file_path: str) -> list[Violation]:
|
|
228
|
+
"""Check for spacing values not in the standard scale."""
|
|
229
|
+
violations = []
|
|
230
|
+
lines = content.split('\n')
|
|
231
|
+
|
|
232
|
+
# Pattern to match spacing classes: p-X, m-X, gap-X, etc.
|
|
233
|
+
spacing_pattern = r'\b(p|px|py|pt|pr|pb|pl|ps|pe|m|mx|my|mt|mr|mb|ml|ms|me|gap|gap-x|gap-y|space-x|space-y)-(\d+\.?\d*)\b'
|
|
234
|
+
|
|
235
|
+
for i, line in enumerate(lines, 1):
|
|
236
|
+
# Skip comments
|
|
237
|
+
if line.strip().startswith('//') or line.strip().startswith('*'):
|
|
238
|
+
continue
|
|
239
|
+
|
|
240
|
+
matches = re.findall(spacing_pattern, line)
|
|
241
|
+
for prefix, value in matches:
|
|
242
|
+
if value not in VALID_SPACING_VALUES:
|
|
243
|
+
violations.append(Violation(
|
|
244
|
+
file=file_path,
|
|
245
|
+
line=i,
|
|
246
|
+
rule="spacing-scale",
|
|
247
|
+
message=f"Spacing value '{value}' is not in the standard scale. Use a valid value: {', '.join(sorted(VALID_SPACING_VALUES, key=lambda x: float(x) if x != 'px' else 0.1))}",
|
|
248
|
+
severity="warning",
|
|
249
|
+
))
|
|
250
|
+
|
|
251
|
+
return violations
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def validate_file(file_path: str) -> list[Violation]:
|
|
255
|
+
"""Validate a single file for styling violations."""
|
|
256
|
+
if should_skip_file(file_path):
|
|
257
|
+
return []
|
|
258
|
+
|
|
259
|
+
# Only check TypeScript/JavaScript files
|
|
260
|
+
if not file_path.endswith(('.tsx', '.ts', '.jsx', '.js')):
|
|
261
|
+
return []
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
265
|
+
content = f.read()
|
|
266
|
+
except (IOError, UnicodeDecodeError):
|
|
267
|
+
return []
|
|
268
|
+
|
|
269
|
+
violations = []
|
|
270
|
+
violations.extend(check_rn_imports(content, file_path))
|
|
271
|
+
violations.extend(check_raw_colors(content, file_path))
|
|
272
|
+
violations.extend(check_arbitrary_values(content, file_path))
|
|
273
|
+
violations.extend(check_inline_styles(content, file_path))
|
|
274
|
+
violations.extend(check_non_scale_spacing(content, file_path))
|
|
275
|
+
|
|
276
|
+
return violations
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def validate_directory(directory: str) -> list[Violation]:
|
|
280
|
+
"""Validate all files in a directory recursively."""
|
|
281
|
+
violations = []
|
|
282
|
+
|
|
283
|
+
for root, dirs, files in os.walk(directory):
|
|
284
|
+
# Skip node_modules and other excluded directories
|
|
285
|
+
dirs[:] = [d for d in dirs if not should_skip_file(os.path.join(root, d))]
|
|
286
|
+
|
|
287
|
+
for file in files:
|
|
288
|
+
file_path = os.path.join(root, file)
|
|
289
|
+
violations.extend(validate_file(file_path))
|
|
290
|
+
|
|
291
|
+
return violations
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def format_violation(violation: Violation) -> str:
|
|
295
|
+
"""Format a violation for display."""
|
|
296
|
+
severity_icon = "ā" if violation.severity == "error" else "ā ļø"
|
|
297
|
+
return f"{severity_icon} {violation.file}:{violation.line} [{violation.rule}] {violation.message}"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def main():
|
|
301
|
+
"""Main entry point."""
|
|
302
|
+
# Get path from command line or use current directory
|
|
303
|
+
path = sys.argv[1] if len(sys.argv) > 1 else "."
|
|
304
|
+
|
|
305
|
+
# Resolve to absolute path
|
|
306
|
+
path = os.path.abspath(path)
|
|
307
|
+
|
|
308
|
+
if not os.path.exists(path):
|
|
309
|
+
print(f"ā Path not found: {path}")
|
|
310
|
+
sys.exit(1)
|
|
311
|
+
|
|
312
|
+
print(f"š Validating styling patterns in: {path}\n")
|
|
313
|
+
|
|
314
|
+
# Validate
|
|
315
|
+
if os.path.isfile(path):
|
|
316
|
+
violations = validate_file(path)
|
|
317
|
+
else:
|
|
318
|
+
violations = validate_directory(path)
|
|
319
|
+
|
|
320
|
+
# Report results
|
|
321
|
+
if not violations:
|
|
322
|
+
print("ā
No styling violations found!")
|
|
323
|
+
sys.exit(0)
|
|
324
|
+
|
|
325
|
+
# Group by file
|
|
326
|
+
by_file: dict[str, list[Violation]] = {}
|
|
327
|
+
for v in violations:
|
|
328
|
+
if v.file not in by_file:
|
|
329
|
+
by_file[v.file] = []
|
|
330
|
+
by_file[v.file].append(v)
|
|
331
|
+
|
|
332
|
+
# Print violations
|
|
333
|
+
error_count = 0
|
|
334
|
+
warning_count = 0
|
|
335
|
+
|
|
336
|
+
for file_path, file_violations in sorted(by_file.items()):
|
|
337
|
+
print(f"\nš {file_path}")
|
|
338
|
+
for v in sorted(file_violations, key=lambda x: x.line):
|
|
339
|
+
print(f" {format_violation(v)}")
|
|
340
|
+
if v.severity == "error":
|
|
341
|
+
error_count += 1
|
|
342
|
+
else:
|
|
343
|
+
warning_count += 1
|
|
344
|
+
|
|
345
|
+
print(f"\nš Summary: {error_count} errors, {warning_count} warnings")
|
|
346
|
+
|
|
347
|
+
# Exit with error if there are errors
|
|
348
|
+
if error_count > 0:
|
|
349
|
+
sys.exit(1)
|
|
350
|
+
sys.exit(0)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
if __name__ == "__main__":
|
|
354
|
+
main()
|