@codyswann/lisa 1.47.0 → 1.48.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.
Files changed (216) hide show
  1. package/all/copy-overwrite/.claude/rules/lisa.md +23 -10
  2. package/all/copy-overwrite/.claude/settings.json +10 -230
  3. package/all/deletions.json +67 -1
  4. package/cdk/copy-overwrite/.claude/settings.json +80 -0
  5. package/cdk/create-only/.github/workflows/ci.yml +1 -1
  6. package/cdk/create-only/.github/workflows/deploy.yml +1 -1
  7. package/dist/core/lisa.d.ts +14 -0
  8. package/dist/core/lisa.d.ts.map +1 -1
  9. package/dist/core/lisa.js +47 -0
  10. package/dist/core/lisa.js.map +1 -1
  11. package/expo/copy-overwrite/.claude/settings.json +80 -0
  12. package/expo/copy-overwrite/eslint.expo.ts +2 -2
  13. package/expo/create-only/.github/workflows/ci.yml +1 -1
  14. package/expo/create-only/.github/workflows/deploy.yml +1 -1
  15. package/expo/deletions.json +33 -0
  16. package/expo/package-lisa/package.lisa.json +2 -2
  17. package/nestjs/copy-overwrite/.claude/settings.json +80 -0
  18. package/nestjs/create-only/.github/workflows/ci.yml +1 -1
  19. package/nestjs/create-only/.github/workflows/deploy.yml +1 -1
  20. package/nestjs/deletions.json +8 -0
  21. package/package.json +8 -4
  22. package/rails/copy-overwrite/.claude/settings.json +80 -0
  23. package/rails/create-only/.github/workflows/ci.yml +1 -1
  24. package/rails/deletions.json +11 -1
  25. package/typescript/copy-overwrite/.claude/settings.json +13 -231
  26. package/typescript/copy-overwrite/.github/workflows/claude-ci-auto-fix.yml +1 -0
  27. package/typescript/copy-overwrite/.github/workflows/claude-code-review-response.yml +11 -10
  28. package/typescript/copy-overwrite/.github/workflows/claude-deploy-auto-fix.yml +1 -0
  29. package/typescript/copy-overwrite/.github/workflows/claude-nightly-code-complexity.yml +1 -0
  30. package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-coverage.yml +1 -0
  31. package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-improvement.yml +2 -0
  32. package/typescript/copy-overwrite/.github/workflows/claude.yml +1 -0
  33. package/typescript/copy-overwrite/eslint.typescript.ts +1 -1
  34. package/typescript/create-only/.github/workflows/ci.yml +1 -1
  35. package/typescript/deletions.json +12 -1
  36. package/typescript/package-lisa/package.lisa.json +1 -1
  37. package/all/copy-overwrite/.claude/agents/agent-architect.md +0 -310
  38. package/all/copy-overwrite/.claude/agents/architecture-specialist.md +0 -53
  39. package/all/copy-overwrite/.claude/agents/debug-specialist.md +0 -204
  40. package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +0 -183
  41. package/all/copy-overwrite/.claude/agents/hooks-expert.md +0 -74
  42. package/all/copy-overwrite/.claude/agents/implementer.md +0 -54
  43. package/all/copy-overwrite/.claude/agents/learner.md +0 -44
  44. package/all/copy-overwrite/.claude/agents/performance-specialist.md +0 -95
  45. package/all/copy-overwrite/.claude/agents/product-specialist.md +0 -72
  46. package/all/copy-overwrite/.claude/agents/quality-specialist.md +0 -55
  47. package/all/copy-overwrite/.claude/agents/security-specialist.md +0 -58
  48. package/all/copy-overwrite/.claude/agents/skill-evaluator.md +0 -246
  49. package/all/copy-overwrite/.claude/agents/slash-command-architect.md +0 -87
  50. package/all/copy-overwrite/.claude/agents/test-specialist.md +0 -64
  51. package/all/copy-overwrite/.claude/agents/verification-specialist.md +0 -189
  52. package/all/copy-overwrite/.claude/agents/web-search-researcher.md +0 -112
  53. package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +0 -7
  54. package/all/copy-overwrite/.claude/commands/git/commit-submit-pr-and-verify.md +0 -7
  55. package/all/copy-overwrite/.claude/commands/git/commit-submit-pr-deploy-and-verify.md +0 -7
  56. package/all/copy-overwrite/.claude/commands/git/commit.md +0 -7
  57. package/all/copy-overwrite/.claude/commands/git/prune.md +0 -6
  58. package/all/copy-overwrite/.claude/commands/git/submit-pr.md +0 -7
  59. package/all/copy-overwrite/.claude/commands/jira/create.md +0 -7
  60. package/all/copy-overwrite/.claude/commands/jira/sync.md +0 -7
  61. package/all/copy-overwrite/.claude/commands/jira/verify.md +0 -7
  62. package/all/copy-overwrite/.claude/commands/lisa/review-implementation.md +0 -7
  63. package/all/copy-overwrite/.claude/commands/plan/add-test-coverage.md +0 -7
  64. package/all/copy-overwrite/.claude/commands/plan/create.md +0 -6
  65. package/all/copy-overwrite/.claude/commands/plan/execute.md +0 -7
  66. package/all/copy-overwrite/.claude/commands/plan/fix-linter-error.md +0 -7
  67. package/all/copy-overwrite/.claude/commands/plan/local-code-review.md +0 -6
  68. package/all/copy-overwrite/.claude/commands/plan/lower-code-complexity.md +0 -6
  69. package/all/copy-overwrite/.claude/commands/plan/reduce-max-lines-per-function.md +0 -7
  70. package/all/copy-overwrite/.claude/commands/plan/reduce-max-lines.md +0 -7
  71. package/all/copy-overwrite/.claude/commands/pull-request/review.md +0 -7
  72. package/all/copy-overwrite/.claude/commands/security/zap-scan.md +0 -6
  73. package/all/copy-overwrite/.claude/commands/sonarqube/check.md +0 -6
  74. package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +0 -6
  75. package/all/copy-overwrite/.claude/commands/tasks/load.md +0 -7
  76. package/all/copy-overwrite/.claude/commands/tasks/sync.md +0 -7
  77. package/all/copy-overwrite/.claude/hooks/check-tired-boss.sh +0 -61
  78. package/all/copy-overwrite/.claude/hooks/debug-hook.sh +0 -47
  79. package/all/copy-overwrite/.claude/hooks/enforce-plan-rules.sh +0 -15
  80. package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +0 -183
  81. package/all/copy-overwrite/.claude/hooks/setup-jira-cli.sh +0 -52
  82. package/all/copy-overwrite/.claude/hooks/sync-tasks.sh +0 -107
  83. package/all/copy-overwrite/.claude/hooks/ticket-sync-reminder.sh +0 -23
  84. package/all/copy-overwrite/.claude/hooks/track-plan-sessions.sh +0 -164
  85. package/all/copy-overwrite/.claude/rules/coding-philosophy.md +0 -428
  86. package/all/copy-overwrite/.claude/rules/verfication.md +0 -541
  87. package/all/copy-overwrite/.claude/skills/agent-design-best-practices/SKILL.md +0 -219
  88. package/all/copy-overwrite/.claude/skills/git-commit/SKILL.md +0 -48
  89. package/all/copy-overwrite/.claude/skills/git-commit-and-submit-pr/SKILL.md +0 -8
  90. package/all/copy-overwrite/.claude/skills/git-commit-submit-pr-and-verify/SKILL.md +0 -7
  91. package/all/copy-overwrite/.claude/skills/git-commit-submit-pr-deploy-and-verify/SKILL.md +0 -7
  92. package/all/copy-overwrite/.claude/skills/git-prune/SKILL.md +0 -35
  93. package/all/copy-overwrite/.claude/skills/git-submit-pr/SKILL.md +0 -44
  94. package/all/copy-overwrite/.claude/skills/jira-create/SKILL.md +0 -41
  95. package/all/copy-overwrite/.claude/skills/jira-sync/SKILL.md +0 -63
  96. package/all/copy-overwrite/.claude/skills/jira-verify/SKILL.md +0 -29
  97. package/all/copy-overwrite/.claude/skills/lisa-review-implementation/SKILL.md +0 -209
  98. package/all/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +0 -44
  99. package/all/copy-overwrite/.claude/skills/plan-execute/SKILL.md +0 -89
  100. package/all/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +0 -45
  101. package/all/copy-overwrite/.claude/skills/plan-local-code-review/SKILL.md +0 -88
  102. package/all/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +0 -44
  103. package/all/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +0 -45
  104. package/all/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +0 -46
  105. package/all/copy-overwrite/.claude/skills/pull-request-review/SKILL.md +0 -68
  106. package/all/copy-overwrite/.claude/skills/security-zap-scan/SKILL.md +0 -33
  107. package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +0 -202
  108. package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +0 -210
  109. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
  110. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +0 -305
  111. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +0 -112
  112. package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +0 -67
  113. package/all/copy-overwrite/.claude/skills/sonarqube-check/SKILL.md +0 -11
  114. package/all/copy-overwrite/.claude/skills/sonarqube-fix/SKILL.md +0 -8
  115. package/all/copy-overwrite/.claude/skills/tasks-load/SKILL.md +0 -88
  116. package/all/copy-overwrite/.claude/skills/tasks-sync/SKILL.md +0 -108
  117. package/eslint-plugin-code-organization/README.md +0 -149
  118. package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +0 -473
  119. package/eslint-plugin-code-organization/index.js +0 -28
  120. package/eslint-plugin-code-organization/package.json +0 -10
  121. package/eslint-plugin-code-organization/rules/enforce-statement-order.js +0 -162
  122. package/expo/copy-overwrite/.claude/agents/ops-specialist.md +0 -124
  123. package/expo/copy-overwrite/.claude/rules/expo-verification.md +0 -261
  124. package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +0 -238
  125. package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +0 -360
  126. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +0 -360
  127. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +0 -417
  128. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +0 -257
  129. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +0 -233
  130. package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +0 -329
  131. package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +0 -299
  132. package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +0 -749
  133. package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +0 -318
  134. package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +0 -200
  135. package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +0 -209
  136. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +0 -268
  137. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +0 -619
  138. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +0 -340
  139. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +0 -276
  140. package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +0 -416
  141. package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +0 -202
  142. package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +0 -445
  143. package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +0 -309
  144. package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +0 -417
  145. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +0 -431
  146. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +0 -290
  147. package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +0 -171
  148. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +0 -411
  149. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +0 -343
  150. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +0 -307
  151. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +0 -300
  152. package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +0 -315
  153. package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +0 -362
  154. package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +0 -505
  155. package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +0 -711
  156. package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +0 -446
  157. package/expo/copy-overwrite/.claude/skills/ops-browser-uat/SKILL.md +0 -124
  158. package/expo/copy-overwrite/.claude/skills/ops-check-logs/SKILL.md +0 -211
  159. package/expo/copy-overwrite/.claude/skills/ops-db-ops/SKILL.md +0 -119
  160. package/expo/copy-overwrite/.claude/skills/ops-deploy/SKILL.md +0 -119
  161. package/expo/copy-overwrite/.claude/skills/ops-monitor-errors/SKILL.md +0 -99
  162. package/expo/copy-overwrite/.claude/skills/ops-performance/SKILL.md +0 -165
  163. package/expo/copy-overwrite/.claude/skills/ops-run-local/SKILL.md +0 -166
  164. package/expo/copy-overwrite/.claude/skills/ops-verify-health/SKILL.md +0 -101
  165. package/expo/copy-overwrite/.claude/skills/owasp-zap/SKILL.md +0 -56
  166. package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +0 -223
  167. package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +0 -314
  168. package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +0 -420
  169. package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +0 -556
  170. package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +0 -590
  171. package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +0 -291
  172. package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +0 -234
  173. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +0 -89
  174. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +0 -201
  175. package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +0 -294
  176. package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +0 -37
  177. package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +0 -10
  178. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +0 -235
  179. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +0 -96
  180. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +0 -183
  181. package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +0 -243
  182. package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +0 -192
  183. package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +0 -31
  184. package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +0 -10
  185. package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +0 -56
  186. package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +0 -60
  187. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +0 -176
  188. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +0 -527
  189. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +0 -483
  190. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +0 -257
  191. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +0 -413
  192. package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +0 -513
  193. package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +0 -536
  194. package/nestjs/copy-overwrite/.claude/skills/security-zap-scan/SKILL.md +0 -33
  195. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +0 -275
  196. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +0 -487
  197. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +0 -450
  198. package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +0 -536
  199. package/rails/copy-overwrite/.claude/skills/action-controller-best-practices/SKILL.md +0 -374
  200. package/rails/copy-overwrite/.claude/skills/action-view-best-practices/SKILL.md +0 -335
  201. package/rails/copy-overwrite/.claude/skills/active-record-model-best-practices/SKILL.md +0 -166
  202. package/rails/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +0 -45
  203. package/rails/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +0 -45
  204. package/rails/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +0 -48
  205. package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +0 -46
  206. package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +0 -46
  207. package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +0 -76
  208. package/typescript/copy-overwrite/.claude/hooks/install-pkgs.sh +0 -64
  209. package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +0 -105
  210. package/typescript/copy-overwrite/.claude/hooks/sg-scan-on-edit.sh +0 -68
  211. package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +0 -432
  212. package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +0 -149
  213. package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +0 -473
  214. package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +0 -28
  215. package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +0 -10
  216. package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +0 -162
@@ -1,209 +0,0 @@
1
- #!/usr/bin/env python3
2
- # This file is managed by Lisa.
3
- # Do not edit directly — changes will be overwritten on the next `lisa` run.
4
- """
5
- Validation script for Container/View pattern components.
6
-
7
- This script validates that a component directory follows the Container/View pattern:
8
- - Has ComponentNameContainer.tsx
9
- - Has ComponentNameView.tsx
10
- - Has index.tsx with correct export
11
- - View uses memo() wrapper
12
- - View has displayName
13
- - View uses arrow function shorthand
14
-
15
- Usage:
16
- python3 validate_component.py <path-to-component-directory>
17
-
18
- Example:
19
- python3 validate_component.py features/player-kanban/components/AddColumnButton
20
- """
21
-
22
- import os
23
- import re
24
- import sys
25
- from pathlib import Path
26
-
27
-
28
- def validate_component(component_path: str) -> tuple[bool, list[str]]:
29
- """
30
- Validate a component directory follows Container/View pattern.
31
-
32
- Args:
33
- component_path: Path to the component directory
34
-
35
- Returns:
36
- Tuple of (is_valid, list of error messages)
37
- """
38
- errors = []
39
- component_dir = Path(component_path)
40
-
41
- if not component_dir.is_dir():
42
- return False, [f"Path is not a directory: {component_path}"]
43
-
44
- component_name = component_dir.name
45
-
46
- # Check required files exist
47
- container_file = component_dir / f"{component_name}Container.tsx"
48
- view_file = component_dir / f"{component_name}View.tsx"
49
- index_file = component_dir / "index.tsx"
50
-
51
- if not container_file.exists():
52
- # Check for .jsx variant
53
- container_jsx = component_dir / f"{component_name}Container.jsx"
54
- if not container_jsx.exists():
55
- errors.append(f"Missing Container file: {component_name}Container.tsx")
56
- else:
57
- container_file = container_jsx
58
-
59
- if not view_file.exists():
60
- # Check for .jsx variant
61
- view_jsx = component_dir / f"{component_name}View.jsx"
62
- if not view_jsx.exists():
63
- errors.append(f"Missing View file: {component_name}View.tsx")
64
- else:
65
- view_file = view_jsx
66
-
67
- if not index_file.exists():
68
- index_jsx = component_dir / "index.jsx"
69
- if not index_jsx.exists():
70
- errors.append("Missing index.tsx file")
71
- else:
72
- index_file = index_jsx
73
-
74
- # Validate index.tsx exports Container
75
- if index_file.exists():
76
- index_content = index_file.read_text()
77
- export_pattern = rf"export\s*{{\s*default\s*}}\s*from\s*['\"]\./{component_name}Container['\"]"
78
- if not re.search(export_pattern, index_content):
79
- errors.append(f"index.tsx should export {component_name}Container as default")
80
-
81
- # Validate View file
82
- if view_file.exists():
83
- view_content = view_file.read_text()
84
-
85
- # Check for memo wrapper
86
- memo_pattern = r"export\s+default\s+memo\s*\("
87
- if not re.search(memo_pattern, view_content):
88
- errors.append("View component should be wrapped with memo()")
89
-
90
- # Check for displayName
91
- display_name_pattern = rf"{component_name}View\.displayName\s*="
92
- if not re.search(display_name_pattern, view_content):
93
- errors.append(f"View should have displayName: {component_name}View.displayName = \"{component_name}View\"")
94
-
95
- # Check for block body (return statement) in main component
96
- # This is a simplified check - ESLint does the full validation
97
- block_body_pattern = rf"const\s+{component_name}View\s*=\s*\([^)]*\)\s*=>\s*{{"
98
- if re.search(block_body_pattern, view_content):
99
- errors.append("View should use arrow function shorthand: () => (...) instead of () => { return (...) }")
100
-
101
- # Check for hooks in View (they should be in Container)
102
- hook_patterns = [
103
- r"\buse[A-Z]\w+\s*\(", # General hook pattern
104
- r"\buseState\s*\(",
105
- r"\buseEffect\s*\(",
106
- r"\buseMemo\s*\(",
107
- r"\buseCallback\s*\(",
108
- r"\buseReducer\s*\(",
109
- r"\buseContext\s*\(",
110
- ]
111
-
112
- for hook_pattern in hook_patterns:
113
- # Exclude memo import check
114
- if hook_pattern == r"\buse[A-Z]\w+\s*\(":
115
- # More specific check to avoid false positives
116
- if re.search(r"\buseState\s*\(", view_content):
117
- errors.append("View should not contain useState - move to Container")
118
- break
119
- if re.search(r"\buseEffect\s*\(", view_content):
120
- errors.append("View should not contain useEffect - move to Container")
121
- break
122
- if re.search(r"\buseMemo\s*\(", view_content):
123
- errors.append("View should not contain useMemo - move to Container")
124
- break
125
- if re.search(r"\buseCallback\s*\(", view_content):
126
- errors.append("View should not contain useCallback - move to Container")
127
- break
128
-
129
- # Validate Container file
130
- if container_file.exists():
131
- container_content = container_file.read_text()
132
-
133
- # Check that Container imports View
134
- import_view_pattern = rf"import\s+{component_name}View\s+from\s*['\"]\./{component_name}View['\"]"
135
- if not re.search(import_view_pattern, container_content):
136
- errors.append(f"Container should import {component_name}View")
137
-
138
- # Check that Container returns View
139
- return_view_pattern = rf"<{component_name}View"
140
- if not re.search(return_view_pattern, container_content):
141
- errors.append(f"Container should return <{component_name}View />")
142
-
143
- # Check that Container ONLY renders View (no other JSX elements)
144
- # Find all JSX tags in Container (excluding the View)
145
- all_jsx_pattern = r"<([A-Z][a-zA-Z0-9]*)"
146
- jsx_matches = re.findall(all_jsx_pattern, container_content)
147
- other_components = [m for m in jsx_matches if m != f"{component_name}View"]
148
- if other_components:
149
- errors.append(
150
- f"Container should ONLY render {component_name}View, but found: {', '.join(set(other_components))}"
151
- )
152
-
153
- # Check for extra files
154
- allowed_files = {
155
- f"{component_name}Container.tsx",
156
- f"{component_name}Container.jsx",
157
- f"{component_name}View.tsx",
158
- f"{component_name}View.jsx",
159
- "index.tsx",
160
- "index.jsx",
161
- "index.ts",
162
- "__tests__", # Allow test directory
163
- }
164
-
165
- # Also allow platform-specific variants
166
- allowed_patterns = [
167
- rf"^{component_name}Container\.[^.]+\.(tsx|jsx)$",
168
- rf"^{component_name}View\.[^.]+\.(tsx|jsx)$",
169
- ]
170
-
171
- for item in component_dir.iterdir():
172
- if item.name not in allowed_files:
173
- is_allowed = False
174
- for pattern in allowed_patterns:
175
- if re.match(pattern, item.name):
176
- is_allowed = True
177
- break
178
- if not is_allowed and item.is_file():
179
- errors.append(f"Unexpected file in component directory: {item.name}")
180
-
181
- return len(errors) == 0, errors
182
-
183
-
184
- def main():
185
- """Main entry point for the validation script."""
186
- if len(sys.argv) < 2:
187
- print("Usage: python3 validate_component.py <path-to-component-directory>")
188
- print("Example: python3 validate_component.py features/player-kanban/components/AddColumnButton")
189
- sys.exit(1)
190
-
191
- component_path = sys.argv[1]
192
-
193
- print(f"Validating component: {component_path}")
194
- print("-" * 50)
195
-
196
- is_valid, errors = validate_component(component_path)
197
-
198
- if is_valid:
199
- print("Component follows Container/View pattern")
200
- sys.exit(0)
201
- else:
202
- print("Validation errors found:")
203
- for error in errors:
204
- print(f" - {error}")
205
- sys.exit(1)
206
-
207
-
208
- if __name__ == "__main__":
209
- main()
@@ -1,268 +0,0 @@
1
- ---
2
- name: cross-platform-compatibility
3
- description: This skill enforces cross-platform compatibility best practices for Expo apps targeting iOS, Android, and web. It should be used when creating new features, components, or screens to ensure they work correctly on all platforms. Use this skill when writing platform-specific code, using Platform.OS checks, creating platform-specific files (.web.tsx, .native.tsx, .ios.tsx, .android.tsx), or reviewing code for cross-platform issues.
4
- ---
5
-
6
- # Cross-Platform Compatibility
7
-
8
- This skill provides guidance for writing code that works correctly on iOS, Android, and web platforms in Expo applications.
9
-
10
- ## Core Principle
11
-
12
- Every feature must work on **all three platforms** (iOS, Android, web) unless explicitly documented otherwise. Test on all platforms before considering a feature complete.
13
-
14
- ## Platform-Specific Approaches
15
-
16
- There are two primary ways to handle platform differences:
17
-
18
- ### 1. Platform Module (Runtime Checks)
19
-
20
- Use `Platform.OS` for small, inline differences within a single component.
21
-
22
- ```tsx
23
- import { Platform } from "react-native";
24
-
25
- // Simple conditional
26
- if (Platform.OS === "web") {
27
- // Web-specific code
28
- }
29
-
30
- // Platform.select for multiple platforms
31
- const styles = StyleSheet.create({
32
- container: {
33
- ...Platform.select({
34
- ios: { shadowColor: "#000" },
35
- android: { elevation: 4 },
36
- web: { boxShadow: "0 2px 4px rgba(0,0,0,0.1)" },
37
- }),
38
- },
39
- });
40
- ```
41
-
42
- ### 2. Platform-Specific File Extensions
43
-
44
- Use file extensions when entire components or modules differ significantly between platforms.
45
-
46
- | Extension | Platforms | Use Case |
47
- | -------------- | ------------- | ------------------------------- |
48
- | `.web.tsx` | Web only | Web-specific implementation |
49
- | `.native.tsx` | iOS + Android | Shared native implementation |
50
- | `.ios.tsx` | iOS only | iOS-specific implementation |
51
- | `.android.tsx` | Android only | Android-specific implementation |
52
-
53
- **Resolution Priority**: Metro bundler resolves in this order:
54
-
55
- 1. `.ios.tsx` / `.android.tsx` (most specific)
56
- 2. `.native.tsx` (native platforms)
57
- 3. `.web.tsx` (web platform)
58
- 4. `.tsx` (universal fallback)
59
-
60
- ## Decision Tree: When to Use Each Approach
61
-
62
- ```
63
- Need platform-specific behavior?
64
- ├── Small differences (styles, one-liner logic)?
65
- │ └── Use Platform.OS or Platform.select()
66
- ├── Moderate differences (conditional rendering blocks)?
67
- │ └── Use Platform.OS with clear separation
68
- └── Significant differences (entire component logic)?
69
- └── Use platform-specific file extensions
70
- ```
71
-
72
- ### Use Platform.OS When:
73
-
74
- - Differences are 1-5 lines of code
75
- - Only styles differ between platforms
76
- - Logic is mostly shared with minor variations
77
- - You need to check platform at runtime dynamically
78
-
79
- ### Use File Extensions When:
80
-
81
- - Components have fundamentally different implementations
82
- - Different libraries are needed per platform (e.g., `dom-to-image` for web vs `react-native-view-shot` for native)
83
- - Layout structure differs significantly
84
- - You want cleaner separation of concerns
85
-
86
- ## File Extension Rules
87
-
88
- ### Within `app/` Directory (Expo Router)
89
-
90
- Platform-specific extensions in the `app/` directory **require a base version** for route universality:
91
-
92
- ```
93
- app/
94
- ├── _layout.tsx # Required base version
95
- ├── _layout.web.tsx # Optional web override
96
- ├── index.tsx # Required base version
97
- ├── about.tsx # Required base version
98
- └── about.web.tsx # Optional web override
99
- ```
100
-
101
- ### Outside `app/` Directory
102
-
103
- Platform-specific files outside `app/` do not require a base version:
104
-
105
- ```
106
- components/
107
- ├── DatePicker/
108
- │ ├── DatePickerContainer.tsx # Container (shared logic)
109
- │ ├── DatePickerView.tsx # Default view
110
- │ ├── DatePickerView.web.tsx # Web-specific view
111
- │ └── index.tsx # Exports container
112
- ```
113
-
114
- ### Re-exporting Pattern
115
-
116
- To use platform-specific components in routes:
117
-
118
- ```tsx
119
- // components/about/index.tsx (or about.native.tsx + about.web.tsx)
120
- // Platform-specific implementations
121
-
122
- // app/about.tsx
123
- export { default } from "../components/about";
124
- ```
125
-
126
- ## Common Cross-Platform Issues
127
-
128
- ### 1. Web-Incompatible APIs
129
-
130
- These APIs require Platform.OS checks or alternatives on web:
131
-
132
- | API | Issue on Web | Solution |
133
- | --------------------------------- | ----------------- | -------------------------------- |
134
- | `MediaLibrary.saveToLibraryAsync` | Not supported | Use download link on web |
135
- | `Share.share()` | Limited support | Use Web Share API or clipboard |
136
- | `Haptics.*` | Not supported | Skip or use CSS animations |
137
- | `captureRef()` | Not supported | Use `dom-to-image` on web |
138
- | `Linking.openURL()` | Works but differs | Consider `window.open()` for web |
139
-
140
- ### 2. Style Differences
141
-
142
- ```tsx
143
- // Platform-specific shadows
144
- const shadowStyles = Platform.select({
145
- ios: {
146
- shadowColor: "#000",
147
- shadowOffset: { width: 0, height: 2 },
148
- shadowOpacity: 0.25,
149
- shadowRadius: 3.84,
150
- },
151
- android: {
152
- elevation: 5,
153
- },
154
- web: {
155
- boxShadow: "0 2px 4px rgba(0,0,0,0.25)",
156
- },
157
- });
158
- ```
159
-
160
- ### 3. Layout Differences
161
-
162
- - Bottom tabs work differently on web vs native
163
- - Drawer navigation may need different treatment
164
- - Touch vs mouse interactions differ
165
-
166
- ### 4. Gesture Handling
167
-
168
- ```tsx
169
- // Web may need different gesture handlers
170
- const gestureConfig = Platform.select({
171
- web: { enabled: false }, // Disable on web if using mouse
172
- default: { enabled: true },
173
- });
174
- ```
175
-
176
- ## Implementation Patterns
177
-
178
- ### Pattern 1: Platform-Specific Hook
179
-
180
- ```tsx
181
- // hooks/useSaveImage.ts
182
- import { Platform } from "react-native";
183
-
184
- /**
185
- * Hook for saving images with platform-specific implementations.
186
- */
187
- export const useSaveImage = () => {
188
- const saveImage = useCallback(async (imageRef: React.RefObject<View>) => {
189
- if (Platform.OS === "web") {
190
- // Web implementation using dom-to-image
191
- const dataUrl = await domtoimage.toJpeg(imageRef.current);
192
- const link = document.createElement("a");
193
- link.download = "image.jpeg";
194
- link.href = dataUrl;
195
- link.click();
196
- } else {
197
- // Native implementation using view-shot
198
- const uri = await captureRef(imageRef);
199
- await MediaLibrary.saveToLibraryAsync(uri);
200
- }
201
- }, []);
202
-
203
- return { saveImage };
204
- };
205
- ```
206
-
207
- ### Pattern 2: Platform-Specific Component Files
208
-
209
- ```tsx
210
- // components/Modal/ModalView.native.tsx
211
- import { Modal as RNModal } from "react-native";
212
-
213
- const ModalView = ({ visible, children }: ModalViewProps) => (
214
- <RNModal visible={visible} animationType="slide">
215
- {children}
216
- </RNModal>
217
- );
218
-
219
- // components/Modal/ModalView.web.tsx
220
- const ModalView = ({ visible, children }: ModalViewProps) =>
221
- visible ? (
222
- <div className="modal-overlay">
223
- <div className="modal-content">{children}</div>
224
- </div>
225
- ) : null;
226
- ```
227
-
228
- ### Pattern 3: Conditional Feature Loading
229
-
230
- ```tsx
231
- // Only import heavy libraries on platforms that need them
232
- const loadPlatformModule = async () => {
233
- if (Platform.OS === "web") {
234
- return await import("dom-to-image");
235
- }
236
- return await import("react-native-view-shot");
237
- };
238
- ```
239
-
240
- ## Validation Checklist
241
-
242
- Before submitting code, verify:
243
-
244
- - [ ] Component renders correctly on iOS
245
- - [ ] Component renders correctly on Android
246
- - [ ] Component renders correctly on web
247
- - [ ] Platform-specific files in `app/` have base versions
248
- - [ ] All Platform.OS checks handle all three platforms (or use `default`)
249
- - [ ] No web-incompatible APIs are called without Platform checks
250
- - [ ] Styles work on all platforms (shadows, layouts)
251
- - [ ] Touch/gesture handlers work on all platforms
252
- - [ ] No hardcoded platform assumptions
253
-
254
- ## Running Validation
255
-
256
- To validate cross-platform compliance:
257
-
258
- ```bash
259
- python3 .claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py [path]
260
- ```
261
-
262
- ## Reference Documentation
263
-
264
- For detailed patterns and examples:
265
-
266
- - `references/platform-api.md` - Platform module API reference
267
- - `references/file-extensions.md` - File extension patterns and resolution
268
- - `references/common-issues.md` - Platform-specific issues and solutions