@lyse-labs/lyse 0.1.0-alpha.2
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 +45 -0
- package/PRIVACY.md +181 -0
- package/README.md +34 -0
- package/SECURITY.md +43 -0
- package/dist/bench/evidence-pack/anti-dummy.d.ts +11 -0
- package/dist/bench/evidence-pack/anti-dummy.js +20 -0
- package/dist/bench/evidence-pack/anti-dummy.js.map +1 -0
- package/dist/bench/evidence-pack/builder.d.ts +14 -0
- package/dist/bench/evidence-pack/builder.js +77 -0
- package/dist/bench/evidence-pack/builder.js.map +1 -0
- package/dist/bench/evidence-pack/histograms.d.ts +2 -0
- package/dist/bench/evidence-pack/histograms.js +131 -0
- package/dist/bench/evidence-pack/histograms.js.map +1 -0
- package/dist/bench/evidence-pack/manifest-detector.d.ts +2 -0
- package/dist/bench/evidence-pack/manifest-detector.js +65 -0
- package/dist/bench/evidence-pack/manifest-detector.js.map +1 -0
- package/dist/bench/evidence-pack/package-json-digest.d.ts +2 -0
- package/dist/bench/evidence-pack/package-json-digest.js +51 -0
- package/dist/bench/evidence-pack/package-json-digest.js.map +1 -0
- package/dist/bench/evidence-pack/sampler.d.ts +2 -0
- package/dist/bench/evidence-pack/sampler.js +140 -0
- package/dist/bench/evidence-pack/sampler.js.map +1 -0
- package/dist/bench/evidence-pack/types.d.ts +127 -0
- package/dist/bench/evidence-pack/types.js +2 -0
- package/dist/bench/evidence-pack/types.js.map +1 -0
- package/dist/bench/evidence-pack/verifier-corpus.d.ts +5 -0
- package/dist/bench/evidence-pack/verifier-corpus.js +13 -0
- package/dist/bench/evidence-pack/verifier-corpus.js.map +1 -0
- package/dist/bench/taxonomy-loader.d.ts +20 -0
- package/dist/bench/taxonomy-loader.js +28 -0
- package/dist/bench/taxonomy-loader.js.map +1 -0
- package/dist/bench/taxonomy.v3.json +20 -0
- package/dist/cli/__tests__/version-migration.test.d.ts +1 -0
- package/dist/cli/__tests__/version-migration.test.js +69 -0
- package/dist/cli/__tests__/version-migration.test.js.map +1 -0
- package/dist/cli/output/__tests__/eslint-style.test.d.ts +1 -0
- package/dist/cli/output/__tests__/eslint-style.test.js +205 -0
- package/dist/cli/output/__tests__/eslint-style.test.js.map +1 -0
- package/dist/cli/output/__tests__/limit.test.d.ts +1 -0
- package/dist/cli/output/__tests__/limit.test.js +65 -0
- package/dist/cli/output/__tests__/limit.test.js.map +1 -0
- package/dist/cli/output/eslint-style.d.ts +18 -0
- package/dist/cli/output/eslint-style.js +42 -0
- package/dist/cli/output/eslint-style.js.map +1 -0
- package/dist/cli/output/limit.d.ts +5 -0
- package/dist/cli/output/limit.js +32 -0
- package/dist/cli/output/limit.js.map +1 -0
- package/dist/cli/output/score-gauge.d.ts +4 -0
- package/dist/cli/output/score-gauge.js +15 -0
- package/dist/cli/output/score-gauge.js.map +1 -0
- package/dist/cli/version-migration.d.ts +18 -0
- package/dist/cli/version-migration.js +49 -0
- package/dist/cli/version-migration.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +856 -0
- package/dist/cli.js.map +1 -0
- package/dist/codemods/diff.d.ts +17 -0
- package/dist/codemods/diff.js +77 -0
- package/dist/codemods/diff.js.map +1 -0
- package/dist/codemods/git-helpers.d.ts +10 -0
- package/dist/codemods/git-helpers.js +75 -0
- package/dist/codemods/git-helpers.js.map +1 -0
- package/dist/codemods/index.d.ts +27 -0
- package/dist/codemods/index.js +40 -0
- package/dist/codemods/index.js.map +1 -0
- package/dist/codemods/naming-component-pascalcase.d.ts +13 -0
- package/dist/codemods/naming-component-pascalcase.js +106 -0
- package/dist/codemods/naming-component-pascalcase.js.map +1 -0
- package/dist/codemods/naming-hook-prefix.d.ts +13 -0
- package/dist/codemods/naming-hook-prefix.js +86 -0
- package/dist/codemods/naming-hook-prefix.js.map +1 -0
- package/dist/codemods/safety.d.ts +50 -0
- package/dist/codemods/safety.js +109 -0
- package/dist/codemods/safety.js.map +1 -0
- package/dist/codemods/safety.test.d.ts +1 -0
- package/dist/codemods/safety.test.js +154 -0
- package/dist/codemods/safety.test.js.map +1 -0
- package/dist/codemods/shadow-native.d.ts +2 -0
- package/dist/codemods/shadow-native.js +103 -0
- package/dist/codemods/shadow-native.js.map +1 -0
- package/dist/codemods/tokens-color.d.ts +2 -0
- package/dist/codemods/tokens-color.js +69 -0
- package/dist/codemods/tokens-color.js.map +1 -0
- package/dist/codemods/tokens-spacing.d.ts +2 -0
- package/dist/codemods/tokens-spacing.js +66 -0
- package/dist/codemods/tokens-spacing.js.map +1 -0
- package/dist/commands/__tests__/email-prompt.test.d.ts +1 -0
- package/dist/commands/__tests__/email-prompt.test.js +126 -0
- package/dist/commands/__tests__/email-prompt.test.js.map +1 -0
- package/dist/commands/__tests__/explain-score.test.d.ts +1 -0
- package/dist/commands/__tests__/explain-score.test.js +88 -0
- package/dist/commands/__tests__/explain-score.test.js.map +1 -0
- package/dist/commands/__tests__/feedback.test.d.ts +1 -0
- package/dist/commands/__tests__/feedback.test.js +186 -0
- package/dist/commands/__tests__/feedback.test.js.map +1 -0
- package/dist/commands/audit-flags.d.ts +49 -0
- package/dist/commands/audit-flags.js +17 -0
- package/dist/commands/audit-flags.js.map +1 -0
- package/dist/commands/audit-pipeline.d.ts +31 -0
- package/dist/commands/audit-pipeline.js +342 -0
- package/dist/commands/audit-pipeline.js.map +1 -0
- package/dist/commands/bench-pack.d.ts +5 -0
- package/dist/commands/bench-pack.js +61 -0
- package/dist/commands/bench-pack.js.map +1 -0
- package/dist/commands/ci-setup.d.ts +9 -0
- package/dist/commands/ci-setup.js +42 -0
- package/dist/commands/ci-setup.js.map +1 -0
- package/dist/commands/email-prompt.d.ts +36 -0
- package/dist/commands/email-prompt.js +160 -0
- package/dist/commands/email-prompt.js.map +1 -0
- package/dist/commands/explain-score.d.ts +35 -0
- package/dist/commands/explain-score.js +137 -0
- package/dist/commands/explain-score.js.map +1 -0
- package/dist/commands/explain.d.ts +6 -0
- package/dist/commands/explain.js +93 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/feedback.d.ts +31 -0
- package/dist/commands/feedback.js +155 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/fix.d.ts +48 -0
- package/dist/commands/fix.js +191 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/init-detect.d.ts +20 -0
- package/dist/commands/init-detect.js +124 -0
- package/dist/commands/init-detect.js.map +1 -0
- package/dist/commands/init-write-agents-md.d.ts +14 -0
- package/dist/commands/init-write-agents-md.js +71 -0
- package/dist/commands/init-write-agents-md.js.map +1 -0
- package/dist/commands/init-write-lyse-md.d.ts +14 -0
- package/dist/commands/init-write-lyse-md.js +253 -0
- package/dist/commands/init-write-lyse-md.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +147 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp-entry.d.ts +33 -0
- package/dist/commands/mcp-entry.js +47 -0
- package/dist/commands/mcp-entry.js.map +1 -0
- package/dist/commands/mcp-setup.d.ts +10 -0
- package/dist/commands/mcp-setup.js +74 -0
- package/dist/commands/mcp-setup.js.map +1 -0
- package/dist/commands/share.d.ts +4 -0
- package/dist/commands/share.js +60 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/telemetry.d.ts +4 -0
- package/dist/commands/telemetry.js +27 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/templates/lyse-workflow.yml.template +30 -0
- package/dist/config/schema.d.ts +158 -0
- package/dist/config/schema.js +136 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/credentials/keychain.d.ts +20 -0
- package/dist/credentials/keychain.js +35 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/keychain.test.d.ts +1 -0
- package/dist/credentials/keychain.test.js +32 -0
- package/dist/credentials/keychain.test.js.map +1 -0
- package/dist/credentials/paths.d.ts +1 -0
- package/dist/credentials/paths.js +6 -0
- package/dist/credentials/paths.js.map +1 -0
- package/dist/credentials/store.d.ts +17 -0
- package/dist/credentials/store.js +60 -0
- package/dist/credentials/store.js.map +1 -0
- package/dist/credentials/store.test.d.ts +1 -0
- package/dist/credentials/store.test.js +48 -0
- package/dist/credentials/store.test.js.map +1 -0
- package/dist/detection/from-filesystem.d.ts +2 -0
- package/dist/detection/from-filesystem.js +26 -0
- package/dist/detection/from-filesystem.js.map +1 -0
- package/dist/detection/from-git.d.ts +2 -0
- package/dist/detection/from-git.js +53 -0
- package/dist/detection/from-git.js.map +1 -0
- package/dist/detection/from-package-json.d.ts +2 -0
- package/dist/detection/from-package-json.js +194 -0
- package/dist/detection/from-package-json.js.map +1 -0
- package/dist/detection/pre-flight.d.ts +5 -0
- package/dist/detection/pre-flight.js +47 -0
- package/dist/detection/pre-flight.js.map +1 -0
- package/dist/detection/types.d.ts +27 -0
- package/dist/detection/types.js +2 -0
- package/dist/detection/types.js.map +1 -0
- package/dist/entitlement/check.d.ts +7 -0
- package/dist/entitlement/check.js +37 -0
- package/dist/entitlement/check.js.map +1 -0
- package/dist/entitlement/index.d.ts +1 -0
- package/dist/entitlement/index.js +2 -0
- package/dist/entitlement/index.js.map +1 -0
- package/dist/entitlement/keys.d.ts +10 -0
- package/dist/entitlement/keys.js +14 -0
- package/dist/entitlement/keys.js.map +1 -0
- package/dist/history/ndjson-store.d.ts +70 -0
- package/dist/history/ndjson-store.js +102 -0
- package/dist/history/ndjson-store.js.map +1 -0
- package/dist/identity/index.d.ts +1 -0
- package/dist/identity/index.js +2 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/repo-bucket.d.ts +22 -0
- package/dist/identity/repo-bucket.js +78 -0
- package/dist/identity/repo-bucket.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/layer4-stage.d.ts +18 -0
- package/dist/llm/layer4-stage.js +12 -0
- package/dist/llm/layer4-stage.js.map +1 -0
- package/dist/loaders/components.d.ts +26 -0
- package/dist/loaders/components.js +285 -0
- package/dist/loaders/components.js.map +1 -0
- package/dist/loaders/stories.d.ts +2 -0
- package/dist/loaders/stories.js +231 -0
- package/dist/loaders/stories.js.map +1 -0
- package/dist/loaders/token-graph.d.ts +39 -0
- package/dist/loaders/token-graph.js +146 -0
- package/dist/loaders/token-graph.js.map +1 -0
- package/dist/loaders/tokens.d.ts +2 -0
- package/dist/loaders/tokens.js +521 -0
- package/dist/loaders/tokens.js.map +1 -0
- package/dist/mcp/_find-root.d.ts +12 -0
- package/dist/mcp/_find-root.js +28 -0
- package/dist/mcp/_find-root.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +42 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/audit-file.d.ts +25 -0
- package/dist/mcp/tools/audit-file.js +147 -0
- package/dist/mcp/tools/audit-file.js.map +1 -0
- package/dist/mcp/tools/suggest-fix.d.ts +13 -0
- package/dist/mcp/tools/suggest-fix.js +100 -0
- package/dist/mcp/tools/suggest-fix.js.map +1 -0
- package/dist/menu/action-menu.d.ts +6 -0
- package/dist/menu/action-menu.js +15 -0
- package/dist/menu/action-menu.js.map +1 -0
- package/dist/menu/prompts.d.ts +7 -0
- package/dist/menu/prompts.js +30 -0
- package/dist/menu/prompts.js.map +1 -0
- package/dist/menu/repl.d.ts +17 -0
- package/dist/menu/repl.js +77 -0
- package/dist/menu/repl.js.map +1 -0
- package/dist/parsers/css-in-js.d.ts +2 -0
- package/dist/parsers/css-in-js.js +69 -0
- package/dist/parsers/css-in-js.js.map +1 -0
- package/dist/parsers/css.d.ts +2 -0
- package/dist/parsers/css.js +32 -0
- package/dist/parsers/css.js.map +1 -0
- package/dist/parsers/scss-transform.d.ts +25 -0
- package/dist/parsers/scss-transform.js +55 -0
- package/dist/parsers/scss-transform.js.map +1 -0
- package/dist/parsers/tailwind-v4.d.ts +8 -0
- package/dist/parsers/tailwind-v4.js +90 -0
- package/dist/parsers/tailwind-v4.js.map +1 -0
- package/dist/parsers/ts-morph-project.d.ts +16 -0
- package/dist/parsers/ts-morph-project.js +77 -0
- package/dist/parsers/ts-morph-project.js.map +1 -0
- package/dist/parsers/ts.d.ts +2 -0
- package/dist/parsers/ts.js +61 -0
- package/dist/parsers/ts.js.map +1 -0
- package/dist/reliability/__tests__/types.test.d.ts +1 -0
- package/dist/reliability/__tests__/types.test.js +14 -0
- package/dist/reliability/__tests__/types.test.js.map +1 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.d.ts +1 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.js +23 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.js.map +1 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.d.ts +1 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js +27 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js.map +1 -0
- package/dist/reliability/catalogue/promotion.d.ts +8 -0
- package/dist/reliability/catalogue/promotion.js +25 -0
- package/dist/reliability/catalogue/promotion.js.map +1 -0
- package/dist/reliability/catalogue/sub-axes.d.ts +3 -0
- package/dist/reliability/catalogue/sub-axes.js +18 -0
- package/dist/reliability/catalogue/sub-axes.js.map +1 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.d.ts +1 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.js +103 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.js.map +1 -0
- package/dist/reliability/confidence/bundled-manifest.d.ts +2 -0
- package/dist/reliability/confidence/bundled-manifest.js +8 -0
- package/dist/reliability/confidence/bundled-manifest.js.map +1 -0
- package/dist/reliability/confidence/index.d.ts +3 -0
- package/dist/reliability/confidence/index.js +3 -0
- package/dist/reliability/confidence/index.js.map +1 -0
- package/dist/reliability/confidence/manifest-loader.d.ts +8 -0
- package/dist/reliability/confidence/manifest-loader.js +53 -0
- package/dist/reliability/confidence/manifest-loader.js.map +1 -0
- package/dist/reliability/feedback/__tests__/interactive.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/interactive.test.js +85 -0
- package/dist/reliability/feedback/__tests__/interactive.test.js.map +1 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.js +18 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.js.map +1 -0
- package/dist/reliability/feedback/__tests__/sender.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/sender.test.js +101 -0
- package/dist/reliability/feedback/__tests__/sender.test.js.map +1 -0
- package/dist/reliability/feedback/interactive.d.ts +20 -0
- package/dist/reliability/feedback/interactive.js +150 -0
- package/dist/reliability/feedback/interactive.js.map +1 -0
- package/dist/reliability/feedback/repo-bucket.d.ts +2 -0
- package/dist/reliability/feedback/repo-bucket.js +9 -0
- package/dist/reliability/feedback/repo-bucket.js.map +1 -0
- package/dist/reliability/feedback/sender.d.ts +16 -0
- package/dist/reliability/feedback/sender.js +28 -0
- package/dist/reliability/feedback/sender.js.map +1 -0
- package/dist/reliability/index.d.ts +1 -0
- package/dist/reliability/index.js +2 -0
- package/dist/reliability/index.js.map +1 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.d.ts +1 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.js +39 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.js.map +1 -0
- package/dist/reliability/llm-eval/budget.d.ts +14 -0
- package/dist/reliability/llm-eval/budget.js +43 -0
- package/dist/reliability/llm-eval/budget.js.map +1 -0
- package/dist/reliability/score/__tests__/formula-v1.test.d.ts +1 -0
- package/dist/reliability/score/__tests__/formula-v1.test.js +29 -0
- package/dist/reliability/score/__tests__/formula-v1.test.js.map +1 -0
- package/dist/reliability/score/formula-v1.d.ts +13 -0
- package/dist/reliability/score/formula-v1.js +19 -0
- package/dist/reliability/score/formula-v1.js.map +1 -0
- package/dist/reliability/score/version-pin.d.ts +1 -0
- package/dist/reliability/score/version-pin.js +2 -0
- package/dist/reliability/score/version-pin.js.map +1 -0
- package/dist/reliability/score/weight.d.ts +1 -0
- package/dist/reliability/score/weight.js +5 -0
- package/dist/reliability/score/weight.js.map +1 -0
- package/dist/reliability/types.d.ts +39 -0
- package/dist/reliability/types.js +2 -0
- package/dist/reliability/types.js.map +1 -0
- package/dist/reporters/coverage-footer.d.ts +2 -0
- package/dist/reporters/coverage-footer.js +7 -0
- package/dist/reporters/coverage-footer.js.map +1 -0
- package/dist/reporters/json.d.ts +5 -0
- package/dist/reporters/json.js +51 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/reporters/markdown.d.ts +7 -0
- package/dist/reporters/markdown.js +35 -0
- package/dist/reporters/markdown.js.map +1 -0
- package/dist/reporters/sarif.d.ts +5 -0
- package/dist/reporters/sarif.js +109 -0
- package/dist/reporters/sarif.js.map +1 -0
- package/dist/reporters/terminal-format.d.ts +34 -0
- package/dist/reporters/terminal-format.js +97 -0
- package/dist/reporters/terminal-format.js.map +1 -0
- package/dist/reporters/terminal.d.ts +4 -0
- package/dist/reporters/terminal.js +201 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/rule-runner.d.ts +8 -0
- package/dist/rule-runner.js +22 -0
- package/dist/rule-runner.js.map +1 -0
- package/dist/rules/_codemod-adapter.d.ts +16 -0
- package/dist/rules/_codemod-adapter.js +49 -0
- package/dist/rules/_codemod-adapter.js.map +1 -0
- package/dist/rules/_exclude.d.ts +11 -0
- package/dist/rules/_exclude.js +17 -0
- package/dist/rules/_exclude.js.map +1 -0
- package/dist/rules/_function-body-analysis.d.ts +82 -0
- package/dist/rules/_function-body-analysis.js +379 -0
- package/dist/rules/_function-body-analysis.js.map +1 -0
- package/dist/rules/_rule-module.d.ts +31 -0
- package/dist/rules/_rule-module.js +32 -0
- package/dist/rules/_rule-module.js.map +1 -0
- package/dist/rules/_skip-context.d.ts +36 -0
- package/dist/rules/_skip-context.js +128 -0
- package/dist/rules/_skip-context.js.map +1 -0
- package/dist/rules/a11y-essentials.d.ts +1 -0
- package/dist/rules/a11y-essentials.js +140 -0
- package/dist/rules/a11y-essentials.js.map +1 -0
- package/dist/rules/ai-surface-agents-md-quality.d.ts +22 -0
- package/dist/rules/ai-surface-agents-md-quality.js +233 -0
- package/dist/rules/ai-surface-agents-md-quality.js.map +1 -0
- package/dist/rules/ai-surface-component-manifest-json.d.ts +19 -0
- package/dist/rules/ai-surface-component-manifest-json.js +232 -0
- package/dist/rules/ai-surface-component-manifest-json.js.map +1 -0
- package/dist/rules/ai-surface-ds-index-exported.d.ts +19 -0
- package/dist/rules/ai-surface-ds-index-exported.js +239 -0
- package/dist/rules/ai-surface-ds-index-exported.js.map +1 -0
- package/dist/rules/components-shadow-native.d.ts +2 -0
- package/dist/rules/components-shadow-native.js +118 -0
- package/dist/rules/components-shadow-native.js.map +1 -0
- package/dist/rules/manifest.d.ts +5 -0
- package/dist/rules/manifest.js +20 -0
- package/dist/rules/manifest.js.map +1 -0
- package/dist/rules/naming-component-pascalcase.d.ts +7 -0
- package/dist/rules/naming-component-pascalcase.js +197 -0
- package/dist/rules/naming-component-pascalcase.js.map +1 -0
- package/dist/rules/naming-hook-prefix.d.ts +6 -0
- package/dist/rules/naming-hook-prefix.js +185 -0
- package/dist/rules/naming-hook-prefix.js.map +1 -0
- package/dist/rules/pack-loader.d.ts +30 -0
- package/dist/rules/pack-loader.js +60 -0
- package/dist/rules/pack-loader.js.map +1 -0
- package/dist/rules/pack-validator.d.ts +8 -0
- package/dist/rules/pack-validator.js +97 -0
- package/dist/rules/pack-validator.js.map +1 -0
- package/dist/rules/registry.d.ts +3 -0
- package/dist/rules/registry.js +28 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/rules/storybook-coverage.d.ts +1 -0
- package/dist/rules/storybook-coverage.js +49 -0
- package/dist/rules/storybook-coverage.js.map +1 -0
- package/dist/rules/templates/_regex-utils.d.ts +5 -0
- package/dist/rules/templates/_regex-utils.js +8 -0
- package/dist/rules/templates/_regex-utils.js.map +1 -0
- package/dist/rules/templates/a11y-jsx-template.d.ts +15 -0
- package/dist/rules/templates/a11y-jsx-template.js +69 -0
- package/dist/rules/templates/a11y-jsx-template.js.map +1 -0
- package/dist/rules/templates/css-property-token-compliance.d.ts +18 -0
- package/dist/rules/templates/css-property-token-compliance.js +56 -0
- package/dist/rules/templates/css-property-token-compliance.js.map +1 -0
- package/dist/rules/templates/import-source-restriction.d.ts +18 -0
- package/dist/rules/templates/import-source-restriction.js +60 -0
- package/dist/rules/templates/import-source-restriction.js.map +1 -0
- package/dist/rules/templates/js-call-token-compliance.d.ts +18 -0
- package/dist/rules/templates/js-call-token-compliance.js +61 -0
- package/dist/rules/templates/js-call-token-compliance.js.map +1 -0
- package/dist/rules/templates/js-prop-token-compliance.d.ts +21 -0
- package/dist/rules/templates/js-prop-token-compliance.js +56 -0
- package/dist/rules/templates/js-prop-token-compliance.js.map +1 -0
- package/dist/rules/templates/naming-convention.d.ts +18 -0
- package/dist/rules/templates/naming-convention.js +76 -0
- package/dist/rules/templates/naming-convention.js.map +1 -0
- package/dist/rules/templates/registry.d.ts +5 -0
- package/dist/rules/templates/registry.js +30 -0
- package/dist/rules/templates/registry.js.map +1 -0
- package/dist/rules/templates/storybook-coverage-template.d.ts +15 -0
- package/dist/rules/templates/storybook-coverage-template.js +58 -0
- package/dist/rules/templates/storybook-coverage-template.js.map +1 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.d.ts +15 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.js +70 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.js.map +1 -0
- package/dist/rules/templates/types.d.ts +16 -0
- package/dist/rules/templates/types.js +2 -0
- package/dist/rules/templates/types.js.map +1 -0
- package/dist/rules/tokens-description-coverage.d.ts +15 -0
- package/dist/rules/tokens-description-coverage.js +193 -0
- package/dist/rules/tokens-description-coverage.js.map +1 -0
- package/dist/rules/tokens-dtcg-conformance.d.ts +47 -0
- package/dist/rules/tokens-dtcg-conformance.js +363 -0
- package/dist/rules/tokens-dtcg-conformance.js.map +1 -0
- package/dist/rules/tokens-no-hardcoded-color.d.ts +18 -0
- package/dist/rules/tokens-no-hardcoded-color.js +436 -0
- package/dist/rules/tokens-no-hardcoded-color.js.map +1 -0
- package/dist/rules/tokens-no-hardcoded-spacing.d.ts +8 -0
- package/dist/rules/tokens-no-hardcoded-spacing.js +193 -0
- package/dist/rules/tokens-no-hardcoded-spacing.js.map +1 -0
- package/dist/scorer.d.ts +38 -0
- package/dist/scorer.js +126 -0
- package/dist/scorer.js.map +1 -0
- package/dist/share/clipboard.d.ts +26 -0
- package/dist/share/clipboard.js +76 -0
- package/dist/share/clipboard.js.map +1 -0
- package/dist/suppression/__tests__/inline.test.d.ts +1 -0
- package/dist/suppression/__tests__/inline.test.js +25 -0
- package/dist/suppression/__tests__/inline.test.js.map +1 -0
- package/dist/suppression/__tests__/lyseignore.test.d.ts +1 -0
- package/dist/suppression/__tests__/lyseignore.test.js +32 -0
- package/dist/suppression/__tests__/lyseignore.test.js.map +1 -0
- package/dist/suppression/defaults.d.ts +1 -0
- package/dist/suppression/defaults.js +14 -0
- package/dist/suppression/defaults.js.map +1 -0
- package/dist/suppression/inline.d.ts +7 -0
- package/dist/suppression/inline.js +32 -0
- package/dist/suppression/inline.js.map +1 -0
- package/dist/suppression/lyseignore.d.ts +2 -0
- package/dist/suppression/lyseignore.js +22 -0
- package/dist/suppression/lyseignore.js.map +1 -0
- package/dist/telemetry/consent.d.ts +48 -0
- package/dist/telemetry/consent.js +139 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/telemetry/index.js +3 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/local-log.d.ts +64 -0
- package/dist/telemetry/local-log.js +123 -0
- package/dist/telemetry/local-log.js.map +1 -0
- package/dist/tokens/dtcg-model.d.ts +53 -0
- package/dist/tokens/dtcg-model.js +18 -0
- package/dist/tokens/dtcg-model.js.map +1 -0
- package/dist/tokens/normalizer.d.ts +17 -0
- package/dist/tokens/normalizer.js +360 -0
- package/dist/tokens/normalizer.js.map +1 -0
- package/dist/types.d.ts +300 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/util/git.d.ts +6 -0
- package/dist/util/git.js +40 -0
- package/dist/util/git.js.map +1 -0
- package/dist/util/git.test.d.ts +5 -0
- package/dist/util/git.test.js +42 -0
- package/dist/util/git.test.js.map +1 -0
- package/dist/util/gitignore.d.ts +9 -0
- package/dist/util/gitignore.js +39 -0
- package/dist/util/gitignore.js.map +1 -0
- package/dist/util/hash-deps.d.ts +6 -0
- package/dist/util/hash-deps.js +24 -0
- package/dist/util/hash-deps.js.map +1 -0
- package/dist/util/spinner.d.ts +41 -0
- package/dist/util/spinner.js +126 -0
- package/dist/util/spinner.js.map +1 -0
- package/dist/util/with-spinner.d.ts +11 -0
- package/dist/util/with-spinner.js +19 -0
- package/dist/util/with-spinner.js.map +1 -0
- package/dist/walker.d.ts +14 -0
- package/dist/walker.js +91 -0
- package/dist/walker.js.map +1 -0
- package/package.json +83 -0
- package/rules-manifest.json +289 -0
- package/schemas/v1/lyse-config.json +82 -0
- package/schemas/v1/lyse-event.json +68 -0
- package/schemas/v1/lyse-license.json +19 -0
- package/schemas/v1/lyse-llm-payload.json +53 -0
- package/schemas/v1/lyse-llm-response.json +45 -0
- package/schemas/v1/lyse-result.json +98 -0
- package/schemas/v1/lyse-rules.json +42 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { isPathExcluded } from "./_exclude.js";
|
|
2
|
+
import { fixNamingComponentPascalCase } from "../codemods/naming-component-pascalcase.js";
|
|
3
|
+
import { adaptOldCodemodResult } from "./_codemod-adapter.js";
|
|
4
|
+
import { createLyseRule } from "./_rule-module.js";
|
|
5
|
+
import { arrowImplicitReturnsJsx, bodyReturnsJsx, extractFunctionBody, } from "./_function-body-analysis.js";
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// PascalCase check
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const PASCAL_CASE_RE = /^[A-Z][a-zA-Z0-9]*$/;
|
|
10
|
+
function isPascalCase(name) {
|
|
11
|
+
return PASCAL_CASE_RE.test(name);
|
|
12
|
+
}
|
|
13
|
+
// Known HOC prefixes to skip
|
|
14
|
+
const HOC_NAME_RE = /^with[A-Z]/;
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Compliance counter
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Counts PascalCase exported components (correct pattern)
|
|
19
|
+
const EXPORTED_PASCAL_COMPONENT_RE = /\bexport\s+(?:default\s+)?(?:function|const|class)\s+([A-Z][a-zA-Z0-9]*)\b/g;
|
|
20
|
+
/**
|
|
21
|
+
* Counts how many exported PascalCase component names exist in the source.
|
|
22
|
+
* These are compliant usages (denominator for scoring).
|
|
23
|
+
*/
|
|
24
|
+
export function countCompliantComponents(source) {
|
|
25
|
+
EXPORTED_PASCAL_COMPONENT_RE.lastIndex = 0;
|
|
26
|
+
let count = 0;
|
|
27
|
+
let m;
|
|
28
|
+
while ((m = EXPORTED_PASCAL_COMPONENT_RE.exec(source)) !== null) {
|
|
29
|
+
if (m[1] && isPascalCase(m[1]))
|
|
30
|
+
count++;
|
|
31
|
+
}
|
|
32
|
+
return count;
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Exported name extraction — finds exported function/const names that look
|
|
36
|
+
// like React components (return JSX or have displayName)
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Matches: export function myName(...), export const myName = ..., export default function myName(...)
|
|
39
|
+
const EXPORT_FUNC_RE = /\bexport\s+(?:default\s+)?(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\()/g;
|
|
40
|
+
function locationFromIndex(source, index) {
|
|
41
|
+
let line = 1;
|
|
42
|
+
let column = 1;
|
|
43
|
+
for (let i = 0; i < index && i < source.length; i++) {
|
|
44
|
+
if (source.charCodeAt(i) === 10) {
|
|
45
|
+
line++;
|
|
46
|
+
column = 1;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
column++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { line, column };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract candidate component names from a source file that are exported
|
|
56
|
+
* but NOT PascalCase.
|
|
57
|
+
*
|
|
58
|
+
* Detection heuristics:
|
|
59
|
+
* 1. Find exported named functions or arrow function consts
|
|
60
|
+
* 2. Check if the body contains JSX return (return <...) as component signal
|
|
61
|
+
* 3. Skip HOC patterns (withXxx)
|
|
62
|
+
* 4. Skip hook patterns (useXxx) — handled by naming/hook-prefix rule
|
|
63
|
+
* 5. Skip test utilities
|
|
64
|
+
*/
|
|
65
|
+
function detectNonPascalComponents(source, path) {
|
|
66
|
+
const results = [];
|
|
67
|
+
// Skip test files
|
|
68
|
+
if (/\.(test|spec)\.(tsx?|jsx?)$/.test(path))
|
|
69
|
+
return results;
|
|
70
|
+
EXPORT_FUNC_RE.lastIndex = 0;
|
|
71
|
+
let m;
|
|
72
|
+
while ((m = EXPORT_FUNC_RE.exec(source)) !== null) {
|
|
73
|
+
const name = m[1] ?? m[2];
|
|
74
|
+
if (!name)
|
|
75
|
+
continue;
|
|
76
|
+
// Skip already-PascalCase (correct)
|
|
77
|
+
if (isPascalCase(name))
|
|
78
|
+
continue;
|
|
79
|
+
// Skip HOCs
|
|
80
|
+
if (HOC_NAME_RE.test(name))
|
|
81
|
+
continue;
|
|
82
|
+
// Skip hooks (handled by hook-prefix rule)
|
|
83
|
+
if (/^use[A-Z]/.test(name))
|
|
84
|
+
continue;
|
|
85
|
+
const isConstArrow = m[2] !== undefined;
|
|
86
|
+
const bodySlice = extractFunctionBody(source, m.index);
|
|
87
|
+
const hasJsxReturn = bodyReturnsJsx(bodySlice) ||
|
|
88
|
+
(isConstArrow && arrowImplicitReturnsJsx(source, m.index));
|
|
89
|
+
const hasDisplayName = new RegExp(`${name}\\.displayName\\s*=`).test(source);
|
|
90
|
+
if (!hasJsxReturn && !hasDisplayName)
|
|
91
|
+
continue;
|
|
92
|
+
results.push({ name, index: m.index });
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Compliance counter for evaluate
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
function toPascalCase(name) {
|
|
100
|
+
// Simple converter: split on _, - or camelCase boundaries
|
|
101
|
+
// For camelCase: myComponent → MyComponent
|
|
102
|
+
// For snake_case: my_component → MyComponent
|
|
103
|
+
// For kebab-case: my-component → MyComponent
|
|
104
|
+
const parts = name
|
|
105
|
+
.replace(/[-_]/g, " ")
|
|
106
|
+
// Insert space before uppercase letters in camelCase
|
|
107
|
+
.replace(/([A-Z])/g, " $1")
|
|
108
|
+
.trim()
|
|
109
|
+
.split(/\s+/);
|
|
110
|
+
return parts
|
|
111
|
+
.map((p) => (p.length > 0 ? p[0].toUpperCase() + p.slice(1) : ""))
|
|
112
|
+
.join("");
|
|
113
|
+
}
|
|
114
|
+
const evaluate = async (ctx, files) => {
|
|
115
|
+
const findings = [];
|
|
116
|
+
let opportunities = 0;
|
|
117
|
+
for (const f of files.ts) {
|
|
118
|
+
if (isPathExcluded(f.path, ctx.excludePaths))
|
|
119
|
+
continue;
|
|
120
|
+
// Only scan JSX/TSX files (component files)
|
|
121
|
+
if (!/\.(tsx|jsx)$/.test(f.path))
|
|
122
|
+
continue;
|
|
123
|
+
// Skip test/spec files
|
|
124
|
+
if (/\.(test|spec)\.(tsx?|jsx?)$/.test(f.path))
|
|
125
|
+
continue;
|
|
126
|
+
opportunities += countCompliantComponents(f.source);
|
|
127
|
+
const hits = detectNonPascalComponents(f.source, f.path);
|
|
128
|
+
for (const h of hits) {
|
|
129
|
+
opportunities++;
|
|
130
|
+
const loc = locationFromIndex(f.source, h.index);
|
|
131
|
+
const suggested = toPascalCase(h.name);
|
|
132
|
+
findings.push({
|
|
133
|
+
ruleId: "naming/component-pascalcase",
|
|
134
|
+
axis: "components",
|
|
135
|
+
severity: "warning",
|
|
136
|
+
location: { file: f.path, line: loc.line, column: loc.column },
|
|
137
|
+
message: `Component '${h.name}' is not PascalCase`,
|
|
138
|
+
suggestion: `Rename to '${suggested}'`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { findings, opportunities };
|
|
143
|
+
};
|
|
144
|
+
const classifyConfidence = (finding, _ctx) => {
|
|
145
|
+
const nameMatch = finding.message.match(/Component '(\w+)'/);
|
|
146
|
+
const name = nameMatch?.[1] ?? "";
|
|
147
|
+
if (!name)
|
|
148
|
+
return "low";
|
|
149
|
+
// Simple renames (camelCase → PascalCase) are high confidence
|
|
150
|
+
// snake_case or kebab-case in name means more complex rename → medium
|
|
151
|
+
if (name.includes("_") || name.includes("-"))
|
|
152
|
+
return "medium";
|
|
153
|
+
// If it starts with a lowercase letter but is otherwise simple camelCase
|
|
154
|
+
return "high";
|
|
155
|
+
};
|
|
156
|
+
const applyCodemod = (finding, ctx) => {
|
|
157
|
+
const ruleCtx = {
|
|
158
|
+
repoRoot: "",
|
|
159
|
+
tokens: ctx.tokens,
|
|
160
|
+
componentsModule: ctx.config.designSystem?.componentsModule ?? null,
|
|
161
|
+
componentInventory: [],
|
|
162
|
+
storyIndex: null,
|
|
163
|
+
excludePaths: [],
|
|
164
|
+
};
|
|
165
|
+
const oldResult = fixNamingComponentPascalCase({
|
|
166
|
+
source: ctx.fileContent,
|
|
167
|
+
path: finding.location.file,
|
|
168
|
+
finding,
|
|
169
|
+
ctx: ruleCtx,
|
|
170
|
+
});
|
|
171
|
+
return adaptOldCodemodResult(oldResult);
|
|
172
|
+
};
|
|
173
|
+
export const rule = createLyseRule({
|
|
174
|
+
meta: {
|
|
175
|
+
axis: "components",
|
|
176
|
+
lyseRuleId: "naming/component-pascalcase",
|
|
177
|
+
defaultSeverity: "warning",
|
|
178
|
+
shortDescription: "Exported React/Vue/Solid components must be PascalCase",
|
|
179
|
+
fullDescription: "Exported component functions or const arrow-function components (those returning JSX) that are not named in PascalCase violate React/Vue/Solid component naming conventions. Non-PascalCase names are silently treated as plain elements in JSX, causing components to render as unknown DOM elements and breaking the React component model.",
|
|
180
|
+
helpUri: "https://github.com/lyse-labs/lyse/blob/main/docs/rules/naming-component-pascalcase.md",
|
|
181
|
+
rationale: `Why it matters
|
|
182
|
+
|
|
183
|
+
React, Vue, and Solid distinguish between HTML element types and component types by case: \`<myButton>\` creates an unknown HTML element whereas \`<MyButton>\` invokes the component. A component named \`myButton\` instead of \`MyButton\` is silently broken when used as JSX — it renders nothing useful.
|
|
184
|
+
|
|
185
|
+
Auto-fix renames the declaration and internal same-file references. Cross-file imports must be updated separately (the suggestion includes a warning when the name is exported).`,
|
|
186
|
+
examples: [
|
|
187
|
+
{ good: "export function MyButton() { return <button>Click</button>; }", bad: "export function myButton() { return <button>Click</button>; }" },
|
|
188
|
+
{ good: "export const MyCard = () => <div className=\"card\" />;", bad: "export const my_card = () => <div className=\"card\" />;" },
|
|
189
|
+
],
|
|
190
|
+
allowlist: ["HOC patterns (withRouter, withTheme — start with `with` lowercase)", "test utilities in .test.tsx / .spec.tsx files", "hooks starting with `use` (handled by naming/hook-prefix)"],
|
|
191
|
+
},
|
|
192
|
+
defaultOptions: [],
|
|
193
|
+
create: () => ({ evaluate }),
|
|
194
|
+
classifyConfidence,
|
|
195
|
+
applyCodemod,
|
|
196
|
+
});
|
|
197
|
+
//# sourceMappingURL=naming-component-pascalcase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming-component-pascalcase.js","sourceRoot":"","sources":["../../src/rules/naming-component-pascalcase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { isPathExcluded } from "./_exclude.js";
|
|
2
|
+
import { fixNamingHookPrefix } from "../codemods/naming-hook-prefix.js";
|
|
3
|
+
import { adaptOldCodemodResult } from "./_codemod-adapter.js";
|
|
4
|
+
import { createLyseRule } from "./_rule-module.js";
|
|
5
|
+
import { bodyCallsHook, extractFunctionBody, fileIsInHooksDir, filenameMatchesFunction, } from "./_function-body-analysis.js";
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Hook-prefix patterns
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// A valid custom hook name: starts with "use" + uppercase letter
|
|
10
|
+
const VALID_HOOK_NAME_RE = /^use[A-Z][a-zA-Z0-9]*$/;
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Compliance counter
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Already correctly named hooks (use + uppercase)
|
|
15
|
+
const VALID_HOOK_EXPORT_RE = /\bexport\s+(?:async\s+)?(?:function\s+use[A-Z]|(?:const|let|var)\s+use[A-Z])/g;
|
|
16
|
+
/**
|
|
17
|
+
* Counts exported functions that start with `use` + uppercase letter.
|
|
18
|
+
*/
|
|
19
|
+
export function countCompliantHooks(source) {
|
|
20
|
+
VALID_HOOK_EXPORT_RE.lastIndex = 0;
|
|
21
|
+
const m = source.match(VALID_HOOK_EXPORT_RE);
|
|
22
|
+
return m ? m.length : 0;
|
|
23
|
+
}
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Detection helpers
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Matches exported functions: export function name(...) / export const name = ...() / export async function name(...)
|
|
28
|
+
const EXPORTED_FUNC_RE = /\bexport\s+(?:default\s+)?(?:async\s+)?(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\()/g;
|
|
29
|
+
function locationFromIndex(source, index) {
|
|
30
|
+
let line = 1;
|
|
31
|
+
let column = 1;
|
|
32
|
+
for (let i = 0; i < index && i < source.length; i++) {
|
|
33
|
+
if (source.charCodeAt(i) === 10) {
|
|
34
|
+
line++;
|
|
35
|
+
column = 1;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
column++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { line, column };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Detect exported functions that look like hooks based on evidence and don't
|
|
45
|
+
* start with the `use` prefix followed by an uppercase letter.
|
|
46
|
+
*
|
|
47
|
+
* Evidence is provided by the shared `_function-body-analysis` helper:
|
|
48
|
+
* - body-call evidence: function body contains a top-level `use<Upper>(` call
|
|
49
|
+
* - path-evidence: file lives under `**\/hooks\/**` AND the function name
|
|
50
|
+
* matches the filename's advertised hook target (e.g. `toggle` in
|
|
51
|
+
* `use-toggle.ts`). Co-located helpers with unrelated names require
|
|
52
|
+
* body-call evidence — see issue #166.
|
|
53
|
+
*
|
|
54
|
+
* Without ANY evidence we do not flag — a pure utility named `flattenTree` in
|
|
55
|
+
* a `.tsx` file should remain a utility.
|
|
56
|
+
*/
|
|
57
|
+
function detectBadlyNamedHooks(source, path) {
|
|
58
|
+
const results = [];
|
|
59
|
+
// Skip test files — test utilities that call hooks internally aren't hooks
|
|
60
|
+
if (/\.(test|spec)\.(tsx?|jsx?)$/.test(path))
|
|
61
|
+
return results;
|
|
62
|
+
const hooksDir = fileIsInHooksDir(path);
|
|
63
|
+
EXPORTED_FUNC_RE.lastIndex = 0;
|
|
64
|
+
let m;
|
|
65
|
+
while ((m = EXPORTED_FUNC_RE.exec(source)) !== null) {
|
|
66
|
+
const name = m[1] ?? m[2];
|
|
67
|
+
if (!name)
|
|
68
|
+
continue;
|
|
69
|
+
// Already correctly named
|
|
70
|
+
if (VALID_HOOK_NAME_RE.test(name))
|
|
71
|
+
continue;
|
|
72
|
+
// Skip PascalCase — those are components, not hooks
|
|
73
|
+
if (/^[A-Z]/.test(name))
|
|
74
|
+
continue;
|
|
75
|
+
// Brace-matched body slice — bounded to the function under inspection,
|
|
76
|
+
// so sibling functions further down the file don't bleed in.
|
|
77
|
+
const bodySlice = extractFunctionBody(source, m.index);
|
|
78
|
+
const callEvidence = bodyCallsHook(bodySlice);
|
|
79
|
+
// Path-evidence (issue #166): a function in a `hooks/` directory is
|
|
80
|
+
// flagged via path alone ONLY when its name matches the filename's
|
|
81
|
+
// advertised target (e.g. `toggle` in `use-toggle.ts`). Unrelated
|
|
82
|
+
// co-located helpers (e.g. `composeRefs` in `use-combine-ref.ts`)
|
|
83
|
+
// require body-call evidence.
|
|
84
|
+
const filenameMatch = filenameMatchesFunction(path, name);
|
|
85
|
+
if (!callEvidence && !(hooksDir && filenameMatch))
|
|
86
|
+
continue;
|
|
87
|
+
results.push({ name, index: m.index });
|
|
88
|
+
}
|
|
89
|
+
return results;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Convert a function name to a valid hook name by prepending "use" + capitalize.
|
|
93
|
+
* Examples: getMyData → useMyData, fetchUser → useFetchUser
|
|
94
|
+
*/
|
|
95
|
+
function toHookName(name) {
|
|
96
|
+
// If it already starts with lowercase, just capitalize first letter and prepend "use"
|
|
97
|
+
const capitalized = name[0] ? name[0].toUpperCase() + name.slice(1) : name;
|
|
98
|
+
return `use${capitalized}`;
|
|
99
|
+
}
|
|
100
|
+
const evaluate = async (ctx, files) => {
|
|
101
|
+
const findings = [];
|
|
102
|
+
let opportunities = 0;
|
|
103
|
+
for (const f of files.ts) {
|
|
104
|
+
if (isPathExcluded(f.path, ctx.excludePaths))
|
|
105
|
+
continue;
|
|
106
|
+
// Only scan TS/TSX/JS/JSX files
|
|
107
|
+
if (!/\.(tsx?|jsx?)$/.test(f.path))
|
|
108
|
+
continue;
|
|
109
|
+
// Skip test/spec files
|
|
110
|
+
if (/\.(test|spec)\.(tsx?|jsx?)$/.test(f.path))
|
|
111
|
+
continue;
|
|
112
|
+
opportunities += countCompliantHooks(f.source);
|
|
113
|
+
const hits = detectBadlyNamedHooks(f.source, f.path);
|
|
114
|
+
for (const h of hits) {
|
|
115
|
+
opportunities++;
|
|
116
|
+
const loc = locationFromIndex(f.source, h.index);
|
|
117
|
+
const suggested = toHookName(h.name);
|
|
118
|
+
findings.push({
|
|
119
|
+
ruleId: "naming/hook-prefix",
|
|
120
|
+
axis: "components",
|
|
121
|
+
severity: "warning",
|
|
122
|
+
location: { file: f.path, line: loc.line, column: loc.column },
|
|
123
|
+
message: `Hook '${h.name}' does not start with 'use' + uppercase letter`,
|
|
124
|
+
suggestion: `Rename to '${suggested}' (custom hooks must start with \`use\` + capital letter)`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { findings, opportunities };
|
|
129
|
+
};
|
|
130
|
+
const classifyConfidence = (finding, _ctx) => {
|
|
131
|
+
const nameMatch = finding.message.match(/Hook '([\w-]+)'/);
|
|
132
|
+
const name = nameMatch?.[1] ?? "";
|
|
133
|
+
if (!name)
|
|
134
|
+
return "low";
|
|
135
|
+
// Simple rename (getXxx → useXxx) is high confidence
|
|
136
|
+
// Names with underscores or dashes are more complex → medium
|
|
137
|
+
if (name.includes("_") || name.includes("-"))
|
|
138
|
+
return "medium";
|
|
139
|
+
return "high";
|
|
140
|
+
};
|
|
141
|
+
const applyCodemod = (finding, ctx) => {
|
|
142
|
+
const ruleCtx = {
|
|
143
|
+
repoRoot: "",
|
|
144
|
+
tokens: ctx.tokens,
|
|
145
|
+
componentsModule: ctx.config.designSystem?.componentsModule ?? null,
|
|
146
|
+
componentInventory: [],
|
|
147
|
+
storyIndex: null,
|
|
148
|
+
excludePaths: [],
|
|
149
|
+
};
|
|
150
|
+
const oldResult = fixNamingHookPrefix({
|
|
151
|
+
source: ctx.fileContent,
|
|
152
|
+
path: finding.location.file,
|
|
153
|
+
finding,
|
|
154
|
+
ctx: ruleCtx,
|
|
155
|
+
});
|
|
156
|
+
return adaptOldCodemodResult(oldResult);
|
|
157
|
+
};
|
|
158
|
+
export const rule = createLyseRule({
|
|
159
|
+
meta: {
|
|
160
|
+
axis: "components",
|
|
161
|
+
lyseRuleId: "naming/hook-prefix",
|
|
162
|
+
defaultSeverity: "warning",
|
|
163
|
+
shortDescription: "Custom hooks must start with `use` + uppercase letter",
|
|
164
|
+
fullDescription: "Exported functions that call other React hooks internally (useState, useEffect, useMemo, useCallback, useRef, useContext, useReducer, useLayoutEffect, and custom use* hooks) are custom hooks by definition. React's rules-of-hooks linter and runtime depend on the `use` prefix to detect hooks — a function named `getMyData` that calls `useState` internally breaks lint, ESLint plugin react-hooks, and can cause subtle hook order violations.",
|
|
165
|
+
helpUri: "https://github.com/lyse-labs/lyse/blob/main/docs/rules/naming-hook-prefix.md",
|
|
166
|
+
rationale: `Why it matters
|
|
167
|
+
|
|
168
|
+
React's rules of hooks use the \`use\` prefix to determine if a function is a hook. A misnamed hook (\`getMyData\` calling \`useState\`) bypasses this detection, so:
|
|
169
|
+
1. \`eslint-plugin-react-hooks\` won't apply its rules (silently broken)
|
|
170
|
+
2. Calling the function conditionally becomes valid from ESLint's perspective — but will still crash at runtime
|
|
171
|
+
3. Other developers don't know the function has hook semantics and may call it in non-hook contexts
|
|
172
|
+
|
|
173
|
+
Auto-fix renames the declaration to \`use<CapitalizedName>\`. Cross-file callers must be updated separately.`,
|
|
174
|
+
examples: [
|
|
175
|
+
{ good: "export function useMyData() { const [d, setD] = useState(null); return d; }", bad: "export function getMyData() { const [d, setD] = useState(null); return d; }" },
|
|
176
|
+
{ good: "export const useAuth = () => { const ctx = useContext(AuthCtx); return ctx; };", bad: "export const fetchAuth = () => { const ctx = useContext(AuthCtx); return ctx; };" },
|
|
177
|
+
],
|
|
178
|
+
allowlist: ["PascalCase components that happen to call hooks (those are components, not hooks)", "test utilities in .test.ts / .spec.ts files", "non-exported functions (internal helpers)"],
|
|
179
|
+
},
|
|
180
|
+
defaultOptions: [],
|
|
181
|
+
create: () => ({ evaluate }),
|
|
182
|
+
classifyConfidence,
|
|
183
|
+
applyCodemod,
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=naming-hook-prefix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming-hook-prefix.js","sourceRoot":"","sources":["../../src/rules/naming-hook-prefix.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Rule } from '../types.js';
|
|
2
|
+
export interface RulePack {
|
|
3
|
+
version: 1;
|
|
4
|
+
generated_at: string;
|
|
5
|
+
generated_by: string;
|
|
6
|
+
generated_from: {
|
|
7
|
+
lyse_version: string;
|
|
8
|
+
template_catalog_version: number;
|
|
9
|
+
deps_hash: string;
|
|
10
|
+
files_hash: string;
|
|
11
|
+
};
|
|
12
|
+
rules: Array<{
|
|
13
|
+
id: string;
|
|
14
|
+
template: string;
|
|
15
|
+
axis: 'tokens' | 'a11y' | 'components' | 'stories';
|
|
16
|
+
severity: 'error' | 'warning' | 'info' | 'off';
|
|
17
|
+
config: Record<string, unknown>;
|
|
18
|
+
metadata?: {
|
|
19
|
+
description?: string;
|
|
20
|
+
auto_fixable?: boolean;
|
|
21
|
+
learn_url?: string | null;
|
|
22
|
+
};
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export interface LoadResult {
|
|
26
|
+
rules: Rule[];
|
|
27
|
+
warnings: string[];
|
|
28
|
+
pack?: RulePack;
|
|
29
|
+
}
|
|
30
|
+
export declare function loadGeneratedPack(repoRoot: string): LoadResult;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// packages/core/src/rules/pack-loader.ts
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { parse as parseYaml } from 'yaml';
|
|
5
|
+
import { getTemplate } from './templates/registry.js';
|
|
6
|
+
import { ruleMap } from './registry.js';
|
|
7
|
+
export function loadGeneratedPack(repoRoot) {
|
|
8
|
+
const packPath = join(repoRoot, '.lyse', 'generated-rules.yaml');
|
|
9
|
+
if (!existsSync(packPath)) {
|
|
10
|
+
return { rules: [], warnings: [] };
|
|
11
|
+
}
|
|
12
|
+
const raw = readFileSync(packPath, 'utf8');
|
|
13
|
+
let pack;
|
|
14
|
+
try {
|
|
15
|
+
pack = parseYaml(raw);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
return { rules: [], warnings: [`Failed to parse .lyse/generated-rules.yaml: ${err.message}`] };
|
|
19
|
+
}
|
|
20
|
+
if (pack?.version !== 1) {
|
|
21
|
+
return { rules: [], warnings: [`Unsupported pack version: ${pack?.version}`] };
|
|
22
|
+
}
|
|
23
|
+
const rules = [];
|
|
24
|
+
const warnings = [];
|
|
25
|
+
const seenIds = new Set();
|
|
26
|
+
for (const r of pack.rules ?? []) {
|
|
27
|
+
if (r.severity === 'off') {
|
|
28
|
+
// explicit off — skip rule entirely, no findings
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (ruleMap.has(r.id)) {
|
|
32
|
+
warnings.push(`Generated rule id "${r.id}" collides with a built-in rule — skipped (built-in wins)`);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (seenIds.has(r.id)) {
|
|
36
|
+
warnings.push(`Duplicate rule id "${r.id}" skipped`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
seenIds.add(r.id);
|
|
40
|
+
const template = getTemplate(r.template);
|
|
41
|
+
if (!template) {
|
|
42
|
+
warnings.push(`Unknown template "${r.template}" for rule "${r.id}" — skipped`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const rule = template.build({
|
|
47
|
+
ruleId: r.id,
|
|
48
|
+
axis: r.axis,
|
|
49
|
+
severity: r.severity,
|
|
50
|
+
config: r.config,
|
|
51
|
+
});
|
|
52
|
+
rules.push(rule);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
warnings.push(`Failed to build rule "${r.id}" from template "${r.template}": ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { rules, warnings, pack };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=pack-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-loader.js","sourceRoot":"","sources":["../../src/rules/pack-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RulePack } from './pack-loader.js';
|
|
2
|
+
export interface ValidationResult {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
errors: string[];
|
|
5
|
+
totalFindings: number;
|
|
6
|
+
durationMs: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function validatePack(pack: RulePack, fixtureRoot: string): Promise<ValidationResult>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// packages/core/src/rules/pack-validator.ts
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { walk } from '../walker.js';
|
|
4
|
+
import { parseTs } from '../parsers/ts.js';
|
|
5
|
+
import { parseCss } from '../parsers/css.js';
|
|
6
|
+
import { extractCssInJs } from '../parsers/css-in-js.js';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { relative } from 'node:path';
|
|
9
|
+
import { getTemplate } from './templates/registry.js';
|
|
10
|
+
const PackSchema = z.object({
|
|
11
|
+
version: z.literal(1),
|
|
12
|
+
generated_at: z.string(),
|
|
13
|
+
generated_by: z.string(),
|
|
14
|
+
generated_from: z.object({
|
|
15
|
+
lyse_version: z.string(),
|
|
16
|
+
template_catalog_version: z.number(),
|
|
17
|
+
deps_hash: z.string(),
|
|
18
|
+
files_hash: z.string(),
|
|
19
|
+
}),
|
|
20
|
+
rules: z.array(z.object({
|
|
21
|
+
id: z.string().min(1),
|
|
22
|
+
template: z.string().min(1),
|
|
23
|
+
axis: z.enum(['tokens', 'a11y', 'components', 'stories']),
|
|
24
|
+
severity: z.enum(['error', 'warning', 'info', 'off']),
|
|
25
|
+
config: z.record(z.string(), z.unknown()),
|
|
26
|
+
metadata: z.unknown().optional(),
|
|
27
|
+
})),
|
|
28
|
+
});
|
|
29
|
+
export async function validatePack(pack, fixtureRoot) {
|
|
30
|
+
const errors = [];
|
|
31
|
+
const t0 = Date.now();
|
|
32
|
+
// 1. Schema
|
|
33
|
+
const parsed = PackSchema.safeParse(pack);
|
|
34
|
+
if (!parsed.success) {
|
|
35
|
+
errors.push(`Schema invalid: ${parsed.error.errors.map((e) => `${e.path.join('.')} ${e.message}`).join('; ')}`);
|
|
36
|
+
return { ok: false, errors, totalFindings: 0, durationMs: Date.now() - t0 };
|
|
37
|
+
}
|
|
38
|
+
// 2. Unique IDs + known templates
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const r of parsed.data.rules) {
|
|
41
|
+
if (seen.has(r.id))
|
|
42
|
+
errors.push(`Duplicate rule id: ${r.id}`);
|
|
43
|
+
seen.add(r.id);
|
|
44
|
+
if (!getTemplate(r.template))
|
|
45
|
+
errors.push(`Unknown template: ${r.template} (rule ${r.id})`);
|
|
46
|
+
}
|
|
47
|
+
if (errors.length > 0) {
|
|
48
|
+
return { ok: false, errors, totalFindings: 0, durationMs: Date.now() - t0 };
|
|
49
|
+
}
|
|
50
|
+
// 3. Smoke test: build rules + run against fixture
|
|
51
|
+
const files = await walk(fixtureRoot);
|
|
52
|
+
const parsedFiles = { ts: [], css: [], cssInJs: [] };
|
|
53
|
+
for (const path of files) {
|
|
54
|
+
const source = readFileSync(path, 'utf8');
|
|
55
|
+
const rel = relative(fixtureRoot, path);
|
|
56
|
+
if (/\.(tsx?|jsx?)$/.test(path)) {
|
|
57
|
+
parsedFiles.ts.push(await parseTs(rel, source));
|
|
58
|
+
parsedFiles.cssInJs.push(...extractCssInJs(rel, source));
|
|
59
|
+
}
|
|
60
|
+
else if (/\.(s?css)$/.test(path)) {
|
|
61
|
+
parsedFiles.css.push(await parseCss(rel, source));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const ctx = {
|
|
65
|
+
repoRoot: fixtureRoot,
|
|
66
|
+
tokens: null,
|
|
67
|
+
componentsModule: null,
|
|
68
|
+
componentInventory: [],
|
|
69
|
+
storyIndex: null,
|
|
70
|
+
excludePaths: [],
|
|
71
|
+
};
|
|
72
|
+
let totalFindings = 0;
|
|
73
|
+
for (const r of parsed.data.rules) {
|
|
74
|
+
const template = getTemplate(r.template);
|
|
75
|
+
let rule;
|
|
76
|
+
try {
|
|
77
|
+
rule = template.build({ ruleId: r.id, axis: r.axis, severity: r.severity, config: r.config });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
errors.push(`Rule "${r.id}" failed to build: ${err.message}`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const result = await rule.evaluate(ctx, parsedFiles);
|
|
85
|
+
totalFindings += result.findings.length;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
errors.push(`Rule "${r.id}" crashed during smoke test: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (totalFindings === 0) {
|
|
92
|
+
errors.push(`Pack produced no findings on the validation fixture (likely too permissive or broken)`);
|
|
93
|
+
}
|
|
94
|
+
const ok = errors.length === 0;
|
|
95
|
+
return { ok, errors, totalFindings, durationMs: Date.now() - t0 };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=pack-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-validator.js","sourceRoot":"","sources":["../../src/rules/pack-validator.ts"],"names":[],"mappings":"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"}
|