@shivaedev/quality 0.23.0 → 0.25.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/CHANGELOG.md +18 -0
- package/README.md +6 -2
- package/dist/baseline/compare.d.ts +2 -2
- package/dist/baseline/compare.d.ts.map +1 -1
- package/dist/baseline/compare.js +6 -4
- package/dist/baseline/compare.js.map +1 -1
- package/dist/baseline/format.d.ts +5 -5
- package/dist/baseline/format.d.ts.map +1 -1
- package/dist/baseline/format.js +23 -13
- package/dist/baseline/format.js.map +1 -1
- package/dist/baseline/legacy.d.ts +2 -2
- package/dist/baseline/legacy.d.ts.map +1 -1
- package/dist/baseline/legacy.js +4 -4
- package/dist/baseline/legacy.js.map +1 -1
- package/dist/baseline/rewrite.d.ts +1 -1
- package/dist/baseline/rewrite.d.ts.map +1 -1
- package/dist/baseline/rewrite.js +2 -2
- package/dist/baseline/rewrite.js.map +1 -1
- package/dist/baseline/update.d.ts +2 -2
- package/dist/baseline/update.d.ts.map +1 -1
- package/dist/baseline/update.js +27 -21
- package/dist/baseline/update.js.map +1 -1
- package/dist/cli/args.d.ts +2 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +19 -18
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/baseline.d.ts +1 -1
- package/dist/cli/baseline.d.ts.map +1 -1
- package/dist/cli/baseline.js +10 -6
- package/dist/cli/baseline.js.map +1 -1
- package/dist/cli/fix.d.ts +2 -2
- package/dist/cli/fix.d.ts.map +1 -1
- package/dist/cli/fix.js +35 -41
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/lint.d.ts +1 -2
- package/dist/cli/lint.d.ts.map +1 -1
- package/dist/cli/lint.js +1 -2
- package/dist/cli/lint.js.map +1 -1
- package/dist/cli/messages.d.ts +1 -1
- package/dist/cli/messages.d.ts.map +1 -1
- package/dist/cli/messages.js +2 -2
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +2 -2
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/migrateExceptions.js +1 -1
- package/dist/cli/migrateExceptions.js.map +1 -1
- package/dist/cli/program.js +1 -1
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/{run-main.d.ts → runMain.d.ts} +1 -1
- package/dist/cli/runMain.d.ts.map +1 -0
- package/dist/cli/{run-main.js → runMain.js} +3 -3
- package/dist/cli/runMain.js.map +1 -0
- package/dist/cli/shrink.d.ts +2 -2
- package/dist/cli/shrink.d.ts.map +1 -1
- package/dist/cli/shrink.js +9 -3
- package/dist/cli/shrink.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/decode.d.ts +1 -1
- package/dist/config/decode.d.ts.map +1 -1
- package/dist/config/decode.js +13 -9
- package/dist/config/decode.js.map +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +26 -20
- package/dist/config/load.js.map +1 -1
- package/dist/config/resolve.d.ts +23 -3
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +19 -11
- package/dist/config/resolve.js.map +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/decoded.d.ts +3 -3
- package/dist/decoded.d.ts.map +1 -1
- package/dist/decoded.js +8 -6
- package/dist/decoded.js.map +1 -1
- package/dist/engine/{baseline-file.d.ts → baselineFile.d.ts} +2 -2
- package/dist/engine/baselineFile.d.ts.map +1 -0
- package/dist/engine/{baseline-file.js → baselineFile.js} +5 -3
- package/dist/engine/baselineFile.js.map +1 -0
- package/dist/engine/evaluate.d.ts +2 -3
- package/dist/engine/evaluate.d.ts.map +1 -1
- package/dist/engine/evaluate.js +6 -5
- package/dist/engine/evaluate.js.map +1 -1
- package/dist/engine/{run-rules.d.ts → runRules.d.ts} +2 -2
- package/dist/engine/runRules.d.ts.map +1 -0
- package/dist/engine/runRules.js +44 -0
- package/dist/engine/runRules.js.map +1 -0
- package/dist/engine/session.d.ts +1 -1
- package/dist/engine/session.d.ts.map +1 -1
- package/dist/engine/session.js +10 -6
- package/dist/engine/session.js.map +1 -1
- package/dist/engine/violation.d.ts +8 -8
- package/dist/engine/violation.d.ts.map +1 -1
- package/dist/engine/violation.js +23 -11
- package/dist/engine/violation.js.map +1 -1
- package/dist/exceptions/registry.d.ts +2 -2
- package/dist/exceptions/registry.d.ts.map +1 -1
- package/dist/exceptions/registry.js +10 -6
- package/dist/exceptions/registry.js.map +1 -1
- package/dist/git/base.d.ts +1 -2
- package/dist/git/base.d.ts.map +1 -1
- package/dist/git/base.js +22 -10
- package/dist/git/base.js.map +1 -1
- package/dist/git/command.d.ts +2 -2
- package/dist/git/command.d.ts.map +1 -1
- package/dist/git/command.js +13 -9
- package/dist/git/command.js.map +1 -1
- package/dist/git/history.d.ts +1 -1
- package/dist/git/history.d.ts.map +1 -1
- package/dist/git/history.js +5 -3
- package/dist/git/history.js.map +1 -1
- package/dist/hooks/preCommit.js +1 -1
- package/dist/hooks/preCommit.js.map +1 -1
- package/dist/imports/generated.js +1 -1
- package/dist/imports/generated.js.map +1 -1
- package/dist/imports/{pnpm-workspace.d.ts → pnpmWorkspacePatterns.d.ts} +1 -1
- package/dist/imports/pnpmWorkspacePatterns.d.ts.map +1 -0
- package/dist/imports/{pnpm-workspace.js → pnpmWorkspacePatterns.js} +1 -1
- package/dist/imports/pnpmWorkspacePatterns.js.map +1 -0
- package/dist/imports/resolve.js +1 -1
- package/dist/imports/resolve.js.map +1 -1
- package/dist/imports/workspace.js +1 -1
- package/dist/imports/workspace.js.map +1 -1
- package/dist/inventory/collect.d.ts +1 -1
- package/dist/inventory/collect.d.ts.map +1 -1
- package/dist/inventory/collect.js +8 -6
- package/dist/inventory/collect.js.map +1 -1
- package/dist/inventory/filesystem.d.ts +1 -1
- package/dist/inventory/filesystem.d.ts.map +1 -1
- package/dist/inventory/filesystem.js +11 -7
- package/dist/inventory/filesystem.js.map +1 -1
- package/dist/inventory/ignoreScope.d.ts +17 -0
- package/dist/inventory/ignoreScope.d.ts.map +1 -0
- package/dist/inventory/{ignore-scope.js → ignoreScope.js} +19 -10
- package/dist/inventory/ignoreScope.js.map +1 -0
- package/dist/inventory/walk.d.ts +1 -1
- package/dist/inventory/walk.d.ts.map +1 -1
- package/dist/inventory/walk.js +1 -1
- package/dist/inventory/walk.js.map +1 -1
- package/dist/manifests/sorted.d.ts +1 -1
- package/dist/manifests/sorted.d.ts.map +1 -1
- package/dist/manifests/sorted.js +15 -17
- package/dist/manifests/sorted.js.map +1 -1
- package/dist/report/plural.d.ts +1 -1
- package/dist/report/plural.d.ts.map +1 -1
- package/dist/report/plural.js +3 -1
- package/dist/report/plural.js.map +1 -1
- package/dist/report/render.d.ts +1 -3
- package/dist/report/render.d.ts.map +1 -1
- package/dist/report/render.js +30 -32
- package/dist/report/render.js.map +1 -1
- package/dist/report/stale.d.ts +1 -1
- package/dist/report/stale.d.ts.map +1 -1
- package/dist/report/stale.js +18 -8
- package/dist/report/stale.js.map +1 -1
- package/dist/rule.d.ts +14 -14
- package/dist/rule.d.ts.map +1 -1
- package/dist/rule.js +11 -9
- package/dist/rule.js.map +1 -1
- package/dist/rules/{built-in.d.ts → builtIn.d.ts} +3 -3
- package/dist/rules/builtIn.d.ts.map +1 -0
- package/dist/rules/{built-in.js → builtIn.js} +17 -13
- package/dist/rules/builtIn.js.map +1 -0
- package/dist/rules/comments/{pattern-rule.d.ts → definePattern.d.ts} +2 -2
- package/dist/rules/comments/definePattern.d.ts.map +1 -0
- package/dist/rules/comments/definePattern.js +18 -0
- package/dist/rules/comments/definePattern.js.map +1 -0
- package/dist/rules/comments/kinds.d.ts +4 -4
- package/dist/rules/comments/kinds.d.ts.map +1 -1
- package/dist/rules/comments/kinds.js +16 -8
- package/dist/rules/comments/kinds.js.map +1 -1
- package/dist/rules/comments/{max-per-file.d.ts → maxPerFile.d.ts} +1 -1
- package/dist/rules/comments/maxPerFile.d.ts.map +1 -0
- package/dist/rules/comments/{max-per-file.js → maxPerFile.js} +14 -10
- package/dist/rules/comments/maxPerFile.js.map +1 -0
- package/dist/rules/comments/{no-banner.d.ts → noBanner.d.ts} +1 -1
- package/dist/rules/comments/noBanner.d.ts.map +1 -0
- package/dist/rules/comments/{no-banner.js → noBanner.js} +2 -2
- package/dist/rules/comments/noBanner.js.map +1 -0
- package/dist/rules/comments/{no-environment-pragma.d.ts → noEnvironmentPragma.d.ts} +1 -1
- package/dist/rules/comments/noEnvironmentPragma.d.ts.map +1 -0
- package/dist/rules/comments/{no-environment-pragma.js → noEnvironmentPragma.js} +2 -2
- package/dist/rules/comments/noEnvironmentPragma.js.map +1 -0
- package/dist/rules/comments/{no-jsdoc.d.ts → noJsdoc.d.ts} +1 -1
- package/dist/rules/comments/noJsdoc.d.ts.map +1 -0
- package/dist/rules/comments/{no-jsdoc.js → noJsdoc.js} +1 -1
- package/dist/rules/comments/noJsdoc.js.map +1 -0
- package/dist/rules/comments/{no-line-reference.d.ts → noLineReference.d.ts} +1 -1
- package/dist/rules/comments/noLineReference.d.ts.map +1 -0
- package/dist/rules/comments/{no-line-reference.js → noLineReference.js} +2 -2
- package/dist/rules/comments/noLineReference.js.map +1 -0
- package/dist/rules/comments/{no-pr-reference.d.ts → noPrReference.d.ts} +1 -1
- package/dist/rules/comments/noPrReference.d.ts.map +1 -0
- package/dist/rules/comments/{no-pr-reference.js → noPrReference.js} +2 -2
- package/dist/rules/comments/noPrReference.js.map +1 -0
- package/dist/rules/comments/{no-todo.d.ts → noTodo.d.ts} +1 -1
- package/dist/rules/comments/noTodo.d.ts.map +1 -0
- package/dist/rules/comments/{no-todo.js → noTodo.js} +2 -2
- package/dist/rules/comments/noTodo.js.map +1 -0
- package/dist/rules/comments/scan.d.ts +3 -3
- package/dist/rules/comments/scan.d.ts.map +1 -1
- package/dist/rules/comments/scan.js +23 -19
- package/dist/rules/comments/scan.js.map +1 -1
- package/dist/rules/{manifests-sorted.d.ts → manifestsSorted.d.ts} +1 -1
- package/dist/rules/manifestsSorted.d.ts.map +1 -0
- package/dist/rules/{manifests-sorted.js → manifestsSorted.js} +1 -1
- package/dist/rules/manifestsSorted.js.map +1 -0
- package/dist/rules/manifestsSourceFirst.d.ts +2 -0
- package/dist/rules/manifestsSourceFirst.d.ts.map +1 -0
- package/dist/rules/manifestsSourceFirst.js +43 -0
- package/dist/rules/manifestsSourceFirst.js.map +1 -0
- package/dist/rules/{max-lines.d.ts → maxLines.d.ts} +1 -1
- package/dist/rules/maxLines.d.ts.map +1 -0
- package/dist/rules/{max-lines.js → maxLines.js} +13 -11
- package/dist/rules/maxLines.js.map +1 -0
- package/dist/rules/stories/origins.d.ts +10 -0
- package/dist/rules/stories/origins.d.ts.map +1 -0
- package/dist/rules/stories/origins.js +129 -0
- package/dist/rules/stories/origins.js.map +1 -0
- package/dist/rules/stories/prerequisites.d.ts +4 -0
- package/dist/rules/stories/prerequisites.d.ts.map +1 -0
- package/dist/rules/stories/prerequisites.js +32 -0
- package/dist/rules/stories/prerequisites.js.map +1 -0
- package/dist/rules/stories/program.d.ts +5 -0
- package/dist/rules/stories/program.d.ts.map +1 -0
- package/dist/rules/stories/program.js +22 -0
- package/dist/rules/stories/program.js.map +1 -0
- package/dist/rules/stories/specs.d.ts +2 -0
- package/dist/rules/stories/specs.d.ts.map +1 -0
- package/dist/rules/stories/specs.js +80 -0
- package/dist/rules/stories/specs.js.map +1 -0
- package/dist/rules/suppressions/biome/configs.d.ts +1 -1
- package/dist/rules/suppressions/biome/configs.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/configs.js +23 -17
- package/dist/rules/suppressions/biome/configs.js.map +1 -1
- package/dist/rules/suppressions/biome/declarations.d.ts +4 -4
- package/dist/rules/suppressions/biome/declarations.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/declarations.js +15 -7
- package/dist/rules/suppressions/biome/declarations.js.map +1 -1
- package/dist/rules/suppressions/biome/json.d.ts +6 -6
- package/dist/rules/suppressions/biome/json.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/json.js +27 -13
- package/dist/rules/suppressions/biome/json.js.map +1 -1
- package/dist/rules/suppressions/biome/resolve.d.ts +1 -1
- package/dist/rules/suppressions/biome/resolve.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/resolve.js +23 -17
- package/dist/rules/suppressions/biome/resolve.js.map +1 -1
- package/dist/rules/suppressions/biome/weakenings.d.ts +1 -1
- package/dist/rules/suppressions/biome/weakenings.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/weakenings.js +78 -52
- package/dist/rules/suppressions/biome/weakenings.js.map +1 -1
- package/dist/rules/suppressions/{biome-overrides.d.ts → biomeOverrides.d.ts} +1 -1
- package/dist/rules/suppressions/biomeOverrides.d.ts.map +1 -0
- package/dist/rules/suppressions/biomeOverrides.js +75 -0
- package/dist/rules/suppressions/biomeOverrides.js.map +1 -0
- package/dist/rules/suppressions/directives.d.ts +1 -1
- package/dist/rules/suppressions/directives.d.ts.map +1 -1
- package/dist/rules/suppressions/directives.js +5 -3
- package/dist/rules/suppressions/directives.js.map +1 -1
- package/dist/rules/suppressions/{no-double-cast.d.ts → noDoubleCast.d.ts} +1 -1
- package/dist/rules/suppressions/noDoubleCast.d.ts.map +1 -0
- package/dist/rules/suppressions/{no-double-cast.js → noDoubleCast.js} +15 -11
- package/dist/rules/suppressions/noDoubleCast.js.map +1 -0
- package/dist/rules/suppressions/noIgnoreDeprecations.js +1 -1
- package/dist/rules/suppressions/noIgnoreDeprecations.js.map +1 -1
- package/dist/rules/suppressions/{no-inline.d.ts → noInline.d.ts} +1 -1
- package/dist/rules/suppressions/noInline.d.ts.map +1 -0
- package/dist/rules/suppressions/{no-inline.js → noInline.js} +10 -8
- package/dist/rules/suppressions/noInline.js.map +1 -0
- package/dist/rules/suppressions/stylesheetComments.d.ts +4 -0
- package/dist/rules/suppressions/stylesheetComments.d.ts.map +1 -0
- package/dist/rules/suppressions/{stylesheet-comments.js → stylesheetComments.js} +12 -6
- package/dist/rules/suppressions/stylesheetComments.js.map +1 -0
- package/dist/rules/syntax.d.ts +1 -1
- package/dist/rules/syntax.d.ts.map +1 -1
- package/dist/rules/syntax.js +2 -2
- package/dist/rules/syntax.js.map +1 -1
- package/dist/{standard-schema.d.ts → standardSchema.d.ts} +7 -7
- package/dist/standardSchema.d.ts.map +1 -0
- package/dist/{standard-schema.js → standardSchema.js} +1 -1
- package/dist/standardSchema.js.map +1 -0
- package/docs/debt-and-hooks.md +2 -2
- package/docs/modules.md +27 -24
- package/docs/roadmap.md +1 -1
- package/docs/rules.md +2 -0
- package/package.json +2 -3
- package/src/baseline/compare.ts +6 -4
- package/src/baseline/format.ts +17 -10
- package/src/baseline/legacy.ts +4 -4
- package/src/baseline/rewrite.ts +2 -2
- package/src/baseline/update.ts +23 -19
- package/src/cli/args.ts +20 -21
- package/src/cli/baseline.ts +36 -35
- package/src/cli/fix.ts +40 -43
- package/src/cli/lint.ts +17 -21
- package/src/cli/messages.ts +2 -2
- package/src/cli/migrate.ts +21 -22
- package/src/cli/migrateExceptions.ts +1 -1
- package/src/cli/program.ts +1 -1
- package/src/cli/{run-main.ts → runMain.ts} +2 -2
- package/src/cli/shrink.ts +11 -8
- package/src/cli.ts +1 -1
- package/src/config/decode.ts +15 -10
- package/src/config/load.ts +44 -37
- package/src/config/resolve.ts +34 -29
- package/src/config.ts +5 -3
- package/src/decoded.ts +6 -5
- package/src/engine/baselineFile.ts +29 -0
- package/src/engine/evaluate.ts +7 -8
- package/src/engine/{run-rules.ts → runRules.ts} +22 -14
- package/src/engine/session.ts +34 -27
- package/src/engine/violation.ts +24 -13
- package/src/exceptions/registry.ts +10 -8
- package/src/git/base.ts +45 -37
- package/src/git/command.ts +6 -4
- package/src/git/history.ts +5 -4
- package/src/hooks/preCommit.ts +1 -1
- package/src/imports/generated.ts +1 -1
- package/src/imports/resolve.ts +1 -1
- package/src/imports/workspace.ts +1 -1
- package/src/inventory/collect.ts +40 -35
- package/src/inventory/filesystem.ts +38 -30
- package/src/inventory/{ignore-scope.ts → ignoreScope.ts} +20 -10
- package/src/inventory/walk.ts +1 -1
- package/src/manifests/sorted.ts +19 -19
- package/src/report/plural.ts +3 -1
- package/src/report/render.ts +24 -39
- package/src/report/stale.ts +33 -25
- package/src/rule.ts +26 -20
- package/src/rules/{built-in.ts → builtIn.ts} +16 -12
- package/src/rules/comments/{pattern-rule.ts → definePattern.ts} +5 -4
- package/src/rules/comments/kinds.ts +16 -9
- package/src/rules/comments/{max-per-file.ts → maxPerFile.ts} +15 -11
- package/src/rules/comments/{no-banner.ts → noBanner.ts} +1 -1
- package/src/rules/comments/{no-environment-pragma.ts → noEnvironmentPragma.ts} +1 -1
- package/src/rules/comments/{no-line-reference.ts → noLineReference.ts} +1 -1
- package/src/rules/comments/{no-pr-reference.ts → noPrReference.ts} +1 -1
- package/src/rules/comments/{no-todo.ts → noTodo.ts} +1 -1
- package/src/rules/comments/scan.ts +18 -15
- package/src/rules/manifestsSourceFirst.ts +48 -0
- package/src/rules/{max-lines.ts → maxLines.ts} +3 -2
- package/src/rules/stories/origins.ts +147 -0
- package/src/rules/stories/prerequisites.ts +37 -0
- package/src/rules/stories/program.ts +29 -0
- package/src/rules/stories/specs.ts +93 -0
- package/src/rules/suppressions/biome/configs.ts +23 -17
- package/src/rules/suppressions/biome/declarations.ts +15 -10
- package/src/rules/suppressions/biome/json.ts +25 -13
- package/src/rules/suppressions/biome/resolve.ts +23 -18
- package/src/rules/suppressions/biome/weakenings.ts +60 -41
- package/src/rules/suppressions/{biome-overrides.ts → biomeOverrides.ts} +32 -22
- package/src/rules/suppressions/directives.ts +5 -4
- package/src/rules/suppressions/{no-double-cast.ts → noDoubleCast.ts} +14 -10
- package/src/rules/suppressions/noIgnoreDeprecations.ts +1 -1
- package/src/rules/suppressions/{no-inline.ts → noInline.ts} +6 -5
- package/src/rules/suppressions/{stylesheet-comments.ts → stylesheetComments.ts} +11 -6
- package/src/rules/syntax.ts +2 -2
- package/src/{standard-schema.ts → standardSchema.ts} +4 -4
- package/dist/cli/run-main.d.ts.map +0 -1
- package/dist/cli/run-main.js.map +0 -1
- package/dist/engine/baseline-file.d.ts.map +0 -1
- package/dist/engine/baseline-file.js.map +0 -1
- package/dist/engine/run-rules.d.ts.map +0 -1
- package/dist/engine/run-rules.js +0 -34
- package/dist/engine/run-rules.js.map +0 -1
- package/dist/imports/pnpm-workspace.d.ts.map +0 -1
- package/dist/imports/pnpm-workspace.js.map +0 -1
- package/dist/inventory/ignore-scope.d.ts +0 -17
- package/dist/inventory/ignore-scope.d.ts.map +0 -1
- package/dist/inventory/ignore-scope.js.map +0 -1
- package/dist/rules/built-in.d.ts.map +0 -1
- package/dist/rules/built-in.js.map +0 -1
- package/dist/rules/comments/max-per-file.d.ts.map +0 -1
- package/dist/rules/comments/max-per-file.js.map +0 -1
- package/dist/rules/comments/no-banner.d.ts.map +0 -1
- package/dist/rules/comments/no-banner.js.map +0 -1
- package/dist/rules/comments/no-environment-pragma.d.ts.map +0 -1
- package/dist/rules/comments/no-environment-pragma.js.map +0 -1
- package/dist/rules/comments/no-jsdoc.d.ts.map +0 -1
- package/dist/rules/comments/no-jsdoc.js.map +0 -1
- package/dist/rules/comments/no-line-reference.d.ts.map +0 -1
- package/dist/rules/comments/no-line-reference.js.map +0 -1
- package/dist/rules/comments/no-pr-reference.d.ts.map +0 -1
- package/dist/rules/comments/no-pr-reference.js.map +0 -1
- package/dist/rules/comments/no-todo.d.ts.map +0 -1
- package/dist/rules/comments/no-todo.js.map +0 -1
- package/dist/rules/comments/pattern-rule.d.ts.map +0 -1
- package/dist/rules/comments/pattern-rule.js +0 -16
- package/dist/rules/comments/pattern-rule.js.map +0 -1
- package/dist/rules/manifests-sorted.d.ts.map +0 -1
- package/dist/rules/manifests-sorted.js.map +0 -1
- package/dist/rules/max-lines.d.ts.map +0 -1
- package/dist/rules/max-lines.js.map +0 -1
- package/dist/rules/suppressions/biome-overrides.d.ts.map +0 -1
- package/dist/rules/suppressions/biome-overrides.js +0 -63
- package/dist/rules/suppressions/biome-overrides.js.map +0 -1
- package/dist/rules/suppressions/no-double-cast.d.ts.map +0 -1
- package/dist/rules/suppressions/no-double-cast.js.map +0 -1
- package/dist/rules/suppressions/no-inline.d.ts.map +0 -1
- package/dist/rules/suppressions/no-inline.js.map +0 -1
- package/dist/rules/suppressions/stylesheet-comments.d.ts +0 -4
- package/dist/rules/suppressions/stylesheet-comments.d.ts.map +0 -1
- package/dist/rules/suppressions/stylesheet-comments.js.map +0 -1
- package/dist/standard-schema.d.ts.map +0 -1
- package/dist/standard-schema.js.map +0 -1
- package/src/engine/baseline-file.ts +0 -27
- /package/src/imports/{pnpm-workspace.ts → pnpmWorkspacePatterns.ts} +0 -0
- /package/src/rules/comments/{no-jsdoc.ts → noJsdoc.ts} +0 -0
- /package/src/rules/{manifests-sorted.ts → manifestsSorted.ts} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import type { WorkspacePackage } from "#imports/workspace.ts";
|
|
3
|
+
import type { RuleInputs } from "#rule.ts";
|
|
4
|
+
|
|
5
|
+
const DEPENDENCIES = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
6
|
+
|
|
7
|
+
function object(value: unknown): value is Record<string, unknown> {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function manifest(text: string | undefined): Record<string, unknown> {
|
|
12
|
+
const value: unknown = JSON.parse(text ?? "{}");
|
|
13
|
+
return object(value) ? value : {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function storyPrerequisites(inputs: RuleInputs, packages: readonly WorkspacePackage[]): Promise<ReadonlySet<string>> {
|
|
17
|
+
const root = manifest(await inputs.readText("package.json"));
|
|
18
|
+
const members = typeof root.name === "string" ? [...packages, { directory: "", name: root.name }] : packages;
|
|
19
|
+
const byName = new Map(members.map((member) => [member.name, member]));
|
|
20
|
+
const pending = ["@shivaedev/test-story"];
|
|
21
|
+
const directories = new Set<string>();
|
|
22
|
+
while (pending.length > 0) {
|
|
23
|
+
const current = byName.get(pending.pop() ?? "");
|
|
24
|
+
if (current === undefined || directories.has(current.directory)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
directories.add(current.directory);
|
|
28
|
+
const value = manifest(await inputs.readText(posix.join(current.directory, "package.json")));
|
|
29
|
+
for (const key of DEPENDENCIES) {
|
|
30
|
+
const dependencies = value[key];
|
|
31
|
+
if (object(dependencies)) {
|
|
32
|
+
pending.push(...Object.keys(dependencies).filter((name) => byName.has(name)));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return directories;
|
|
37
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import type { ImportGraph } from "#imports/graph.ts";
|
|
4
|
+
import type { RuleInputs } from "#rule.ts";
|
|
5
|
+
|
|
6
|
+
export function storyProgram(inputs: RuleInputs, graph: ImportGraph): ts.Program {
|
|
7
|
+
const sources = new Map(inputs.sources.map((file) => [join(inputs.root, file.path), file.text]));
|
|
8
|
+
const targets = new Map(
|
|
9
|
+
graph.edges.flatMap((edge) =>
|
|
10
|
+
edge.to.kind === "file" ? [[`${join(inputs.root, edge.from)}:${edge.specifier}`, join(inputs.root, edge.to.path)] as const] : [],
|
|
11
|
+
),
|
|
12
|
+
);
|
|
13
|
+
const options: ts.CompilerOptions = { allowJs: true, noLib: true, types: [] };
|
|
14
|
+
const host: ts.CompilerHost = {
|
|
15
|
+
...ts.createCompilerHost(options),
|
|
16
|
+
fileExists: (path) => sources.has(path),
|
|
17
|
+
getSourceFile: (path) => {
|
|
18
|
+
const text = sources.get(path);
|
|
19
|
+
return text === undefined ? undefined : ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true);
|
|
20
|
+
},
|
|
21
|
+
readFile: (path) => sources.get(path),
|
|
22
|
+
resolveModuleNames: (names, from) =>
|
|
23
|
+
names.map((name) => {
|
|
24
|
+
const path = targets.get(`${from}:${name}`);
|
|
25
|
+
return path === undefined ? undefined : { extension: ts.Extension.Ts, resolvedFileName: path };
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
return ts.createProgram([...sources.keys()], options, host);
|
|
29
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { importGraph } from "#imports/graph.ts";
|
|
3
|
+
import { packageOf } from "#imports/workspace.ts";
|
|
4
|
+
import { testName } from "#naming/testName.ts";
|
|
5
|
+
import { defineRule } from "#rule.ts";
|
|
6
|
+
import { storyOrigins } from "./origins.ts";
|
|
7
|
+
import { storyPrerequisites } from "./prerequisites.ts";
|
|
8
|
+
|
|
9
|
+
function namesTest(node: ts.Expression): boolean {
|
|
10
|
+
if (ts.isIdentifier(node)) {
|
|
11
|
+
return node.text === "it" || node.text === "test";
|
|
12
|
+
}
|
|
13
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
14
|
+
return node.name.text === "it" || namesTest(node.expression);
|
|
15
|
+
}
|
|
16
|
+
return ts.isCallExpression(node) && namesTest(node.expression);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type OriginOf = ReturnType<typeof storyOrigins>["origin"];
|
|
20
|
+
|
|
21
|
+
function callback(node: ts.Node, origin: OriginOf): boolean {
|
|
22
|
+
return (
|
|
23
|
+
ts.isArrowFunction(node)
|
|
24
|
+
|| ts.isFunctionExpression(node)
|
|
25
|
+
|| ((ts.isIdentifier(node) || ts.isPropertyAccessExpression(node)) && origin(node) === "function")
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function testShaped(call: ts.CallExpression, origin: OriginOf): boolean {
|
|
30
|
+
const title = call.arguments[0];
|
|
31
|
+
return (
|
|
32
|
+
title !== undefined
|
|
33
|
+
&& (ts.isStringLiteralLike(title) || ts.isTemplateExpression(title))
|
|
34
|
+
&& call.arguments.slice(1).some((argument) => callback(argument, origin))
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function declarationScope(node: ts.Node, origin: OriginOf): boolean {
|
|
39
|
+
for (let current = node.parent; current !== undefined; current = current.parent) {
|
|
40
|
+
if (ts.isFunctionLike(current) && (!ts.isCallExpression(current.parent) || origin(current.parent.expression) !== "suite")) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function uncoveredRegistration(call: ts.CallExpression, originOf: OriginOf): boolean {
|
|
48
|
+
const origin = originOf(call.expression);
|
|
49
|
+
if (origin === "story" || origin === "suite") {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return origin === "plain" || ((namesTest(call.expression) || testShaped(call, originOf)) && declarationScope(call, originOf));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const storySpecs = defineRule({
|
|
56
|
+
check: async (inputs) => {
|
|
57
|
+
const graph = await importGraph(inputs);
|
|
58
|
+
const exempt = await storyPrerequisites(inputs, graph.packages);
|
|
59
|
+
const origins = storyOrigins(inputs, graph);
|
|
60
|
+
return inputs.sources.flatMap((file) => {
|
|
61
|
+
const name = testName(file.path);
|
|
62
|
+
const owner = packageOf(graph.packages, file.path);
|
|
63
|
+
if (name === undefined || name.modifiers.includes("typecheck") || exempt.has(owner?.directory ?? "")) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const source = origins.source(file.path);
|
|
67
|
+
let plain: ts.CallExpression | undefined;
|
|
68
|
+
function visit(node: ts.Node): void {
|
|
69
|
+
if (ts.isCallExpression(node) && uncoveredRegistration(node, origins.origin)) {
|
|
70
|
+
plain ??= node;
|
|
71
|
+
}
|
|
72
|
+
ts.forEachChild(node, visit);
|
|
73
|
+
}
|
|
74
|
+
if (source !== undefined) {
|
|
75
|
+
visit(source);
|
|
76
|
+
}
|
|
77
|
+
if (source === undefined || plain === undefined) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
file: file.path,
|
|
83
|
+
line: source.getLineAndCharacterOfPosition(plain.getStart(source)).line + 1,
|
|
84
|
+
message:
|
|
85
|
+
"Declares tests without a test-story story kit. Build the package's kit with storyKit from @shivaedev/test-story/storyKit.ts in src/test-support, and declare every test through the kit's it. See https://github.com/ShivaeDev/platform/tree/main/packages/quality#story-tests.",
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
description:
|
|
91
|
+
"Every package tests its real engine through its own test-story kit. Typecheck tests and test-story's workspace prerequisites are exempt.",
|
|
92
|
+
id: "tests/story-specs",
|
|
93
|
+
});
|
|
@@ -35,23 +35,27 @@ const NESTED = /(?:^|\/)biome\.jsonc?$/u;
|
|
|
35
35
|
|
|
36
36
|
const RELATIVE = /^\.\.?(?:\/|$)/u;
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function directoryOf(path: string): string {
|
|
39
|
+
return posix.dirname(path) === "." ? "" : posix.dirname(path);
|
|
40
|
+
}
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
async function read(readText: ReadText, path: string): Promise<Parsed> {
|
|
41
43
|
const text = await readText(path);
|
|
42
44
|
return text === undefined ? { _tag: "Unreadable", reason: "the file does not exist" } : parseJsonc(path, text);
|
|
43
|
-
}
|
|
45
|
+
}
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
function problem(file: string, message: string, line?: number): Loaded {
|
|
48
|
+
return { layers: [], problems: [{ file, line, message }] };
|
|
49
|
+
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
async function local(readText: ReadText, path: string): Promise<Loaded> {
|
|
48
52
|
const parsed = await read(readText, path);
|
|
49
53
|
return parsed._tag === "Parsed"
|
|
50
54
|
? { layers: [{ json: parsed.json, path, preset: undefined }], problems: [] }
|
|
51
55
|
: problem(path, `Cannot read this Biome config: ${parsed.reason}.`);
|
|
52
|
-
}
|
|
56
|
+
}
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
async function fromPackage(readText: ReadText, from: string, entry: Json, specifier: string): Promise<Loaded> {
|
|
55
59
|
const target = await resolvePackage(readText, specifier);
|
|
56
60
|
if (target === undefined) {
|
|
57
61
|
return problem(from, `Cannot resolve the Biome config "${specifier}" from node_modules.`, entry.line);
|
|
@@ -67,9 +71,9 @@ const fromPackage = async (readText: ReadText, from: string, entry: Json, specif
|
|
|
67
71
|
}
|
|
68
72
|
const preset = { declared: declared.value, file: from, line: entry.line, specifier };
|
|
69
73
|
return { layers: [{ json: parsed.json, path: target, preset }], problems: [] };
|
|
70
|
-
}
|
|
74
|
+
}
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
async function extended(readText: ReadText, from: string, entry: Json): Promise<Loaded> {
|
|
73
77
|
const specifier = textOf(entry);
|
|
74
78
|
if (specifier === undefined || specifier === "//") {
|
|
75
79
|
return { layers: [], problems: [] };
|
|
@@ -79,11 +83,13 @@ const extended = async (readText: ReadText, from: string, entry: Json): Promise<
|
|
|
79
83
|
}
|
|
80
84
|
const relative = posix.normalize(specifier);
|
|
81
85
|
return (await readText(relative)) === undefined ? fromPackage(readText, from, entry, specifier) : local(readText, relative);
|
|
82
|
-
}
|
|
86
|
+
}
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
function extendsOf(json: Json): readonly Json[] {
|
|
89
|
+
return itemsOf(member(json, "extends"));
|
|
90
|
+
}
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
async function chainOf(readText: ReadText, path: string): Promise<Loaded> {
|
|
87
93
|
const own = await local(readText, path);
|
|
88
94
|
const [layer] = own.layers;
|
|
89
95
|
if (layer === undefined) {
|
|
@@ -91,12 +97,12 @@ const chainOf = async (readText: ReadText, path: string): Promise<Loaded> => {
|
|
|
91
97
|
}
|
|
92
98
|
const parents = await Promise.all(extendsOf(layer.json).map((entry) => extended(readText, path, entry)));
|
|
93
99
|
return { layers: [...parents.flatMap((parent) => parent.layers), layer], problems: parents.flatMap((parent) => parent.problems) };
|
|
94
|
-
}
|
|
100
|
+
}
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
async function rootConfig(readText: ReadText): Promise<string | undefined> {
|
|
97
103
|
const present = await Promise.all(ROOT_CONFIGS.map(async (path) => ((await readText(path)) === undefined ? [] : [path])));
|
|
98
104
|
return present.flat()[0];
|
|
99
|
-
}
|
|
105
|
+
}
|
|
100
106
|
|
|
101
107
|
export interface BiomeConfigs {
|
|
102
108
|
readonly chains: readonly Chain[];
|
|
@@ -104,7 +110,7 @@ export interface BiomeConfigs {
|
|
|
104
110
|
readonly root: string;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
export
|
|
113
|
+
export async function biomeConfigs({ files, readText }: RuleInputs): Promise<BiomeConfigs> {
|
|
108
114
|
const root = await rootConfig(readText);
|
|
109
115
|
const rootChain = root === undefined ? { layers: [], problems: [] } : await chainOf(readText, root);
|
|
110
116
|
const loaded = new Set(rootChain.layers.map((layer) => layer.path));
|
|
@@ -116,4 +122,4 @@ export const biomeConfigs = async ({ files, readText }: RuleInputs): Promise<Bio
|
|
|
116
122
|
problems: all.flatMap((chain) => chain.problems),
|
|
117
123
|
root: root ?? "biome.json",
|
|
118
124
|
};
|
|
119
|
-
}
|
|
125
|
+
}
|
|
@@ -15,23 +15,28 @@ const shipped = Schema.toStandardSchemaV1(Schema.fromJsonString(Schema.Array(Dec
|
|
|
15
15
|
parseOptions: { errors: "all", onExcessProperty: "error" },
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
export
|
|
19
|
-
text === undefined ? Promise.resolve({ _tag: "Valid", value: [] }) : decodeWith(shipped, text);
|
|
18
|
+
export function decodeShipped(text: string | undefined): Promise<Decoded<readonly Declaration[]>> {
|
|
19
|
+
return text === undefined ? Promise.resolve({ _tag: "Valid", value: [] }) : decodeWith(shipped, text);
|
|
20
|
+
}
|
|
20
21
|
|
|
21
22
|
export interface Scoped {
|
|
22
23
|
readonly includes: readonly string[];
|
|
23
24
|
readonly rule: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
new Set(left).size === new Set(right).size && left.every((glob) => right.includes(glob));
|
|
27
|
+
function sameScope(left: readonly string[], right: readonly string[]): boolean {
|
|
28
|
+
return new Set(left).size === new Set(right).size && left.every((glob) => right.includes(glob));
|
|
29
|
+
}
|
|
28
30
|
|
|
29
|
-
export
|
|
30
|
-
declaration.rule === weakening.rule && sameScope(declaration.includes, weakening.includes);
|
|
31
|
+
export function matches(declaration: Scoped, weakening: Scoped): boolean {
|
|
32
|
+
return declaration.rule === weakening.rule && sameScope(declaration.includes, weakening.includes);
|
|
33
|
+
}
|
|
31
34
|
|
|
32
|
-
export
|
|
33
|
-
const
|
|
35
|
+
export function scoped(base: string, glob: string): string {
|
|
36
|
+
const { negation = "", path = glob } = /^(?<negation>!*)(?<path>.*)$/u.exec(glob)?.groups ?? {};
|
|
34
37
|
return base === "" ? glob : `${negation}${base}/${path}`;
|
|
35
|
-
}
|
|
38
|
+
}
|
|
36
39
|
|
|
37
|
-
export
|
|
40
|
+
export function scopeText(includes: readonly string[]): string {
|
|
41
|
+
return includes.map((glob) => `"${glob}"`).join(", ");
|
|
42
|
+
}
|
|
@@ -12,14 +12,17 @@ const LITERALS: ReadonlyMap<ts.SyntaxKind, boolean> = new Map([
|
|
|
12
12
|
[ts.SyntaxKind.FalseKeyword, false],
|
|
13
13
|
]);
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
function scalarOf(node: ts.Expression): string | boolean | undefined {
|
|
16
|
+
return ts.isStringLiteral(node) ? node.text : LITERALS.get(node.kind);
|
|
17
|
+
}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
ts.isPropertyAssignment(property) && (ts.isStringLiteral(property.name) || ts.isIdentifier(property.name))
|
|
19
|
+
function entryOf(source: ts.JsonSourceFile, property: ts.ObjectLiteralElementLike): ReadonlyArray<readonly [string, Json]> {
|
|
20
|
+
return ts.isPropertyAssignment(property) && (ts.isStringLiteral(property.name) || ts.isIdentifier(property.name))
|
|
19
21
|
? [[property.name.text, toJson(source, property.initializer)]]
|
|
20
22
|
: [];
|
|
23
|
+
}
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
function toJson(source: ts.JsonSourceFile, node: ts.Expression): Json {
|
|
23
26
|
const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
24
27
|
if (ts.isObjectLiteralExpression(node)) {
|
|
25
28
|
return { _tag: "Object", entries: new Map(node.properties.flatMap((property) => entryOf(source, property))), line };
|
|
@@ -28,9 +31,9 @@ const toJson = (source: ts.JsonSourceFile, node: ts.Expression): Json => {
|
|
|
28
31
|
return { _tag: "Array", items: node.elements.map((element) => toJson(source, element)), line };
|
|
29
32
|
}
|
|
30
33
|
return { _tag: "Value", line, value: scalarOf(node) };
|
|
31
|
-
}
|
|
34
|
+
}
|
|
32
35
|
|
|
33
|
-
export
|
|
36
|
+
export function parseJsonc(path: string, text: string): Parsed {
|
|
34
37
|
const error = ts.parseConfigFileTextToJson(path, text).error;
|
|
35
38
|
const source = ts.parseJsonText(path, text);
|
|
36
39
|
const root = source.statements[0]?.expression;
|
|
@@ -41,15 +44,24 @@ export const parseJsonc = (path: string, text: string): Parsed => {
|
|
|
41
44
|
};
|
|
42
45
|
}
|
|
43
46
|
return { _tag: "Parsed", json: toJson(source, root) };
|
|
44
|
-
}
|
|
47
|
+
}
|
|
45
48
|
|
|
46
|
-
export
|
|
49
|
+
export function member(node: Json | undefined, key: string): Json | undefined {
|
|
50
|
+
return node?._tag === "Object" ? node.entries.get(key) : undefined;
|
|
51
|
+
}
|
|
47
52
|
|
|
48
|
-
export
|
|
53
|
+
export function entriesOf(node: Json | undefined): ReadonlyArray<readonly [string, Json]> {
|
|
54
|
+
return node?._tag === "Object" ? [...node.entries] : [];
|
|
55
|
+
}
|
|
49
56
|
|
|
50
|
-
export
|
|
57
|
+
export function itemsOf(node: Json | undefined): readonly Json[] {
|
|
58
|
+
return node?._tag === "Array" ? node.items : [];
|
|
59
|
+
}
|
|
51
60
|
|
|
52
|
-
export
|
|
53
|
-
node?._tag === "Value" && typeof node.value === "string" ? node.value : undefined;
|
|
61
|
+
export function textOf(node: Json | undefined): string | undefined {
|
|
62
|
+
return node?._tag === "Value" && typeof node.value === "string" ? node.value : undefined;
|
|
63
|
+
}
|
|
54
64
|
|
|
55
|
-
export
|
|
65
|
+
export function isFalse(node: Json | undefined): boolean {
|
|
66
|
+
return node?._tag === "Value" && node.value === false;
|
|
67
|
+
}
|
|
@@ -15,11 +15,13 @@ const manifestSchema = Schema.toStandardSchemaV1(Schema.fromJsonString(Manifest)
|
|
|
15
15
|
|
|
16
16
|
const CONDITIONS: ReadonlySet<string> = new Set(["biome", "default"]);
|
|
17
17
|
|
|
18
|
-
const SPECIFIER = /^((?:@[^/]+\/)?[^/]+)(?:\/(
|
|
18
|
+
const SPECIFIER = /^(?<name>(?:@[^/]+\/)?[^/]+)(?:\/(?<subpath>.+))?$/u;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
|
|
21
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
}
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
function targetOf(value: unknown, star: string | undefined): string | undefined {
|
|
23
25
|
if (typeof value === "string") {
|
|
24
26
|
return star === undefined ? value : value.replaceAll("*", star);
|
|
25
27
|
}
|
|
@@ -28,11 +30,13 @@ const targetOf = (value: unknown, star: string | undefined): string | undefined
|
|
|
28
30
|
}
|
|
29
31
|
const condition = isRecord(value) ? Object.keys(value).find((key) => CONDITIONS.has(key)) : undefined;
|
|
30
32
|
return isRecord(value) && condition !== undefined ? targetOf(value[condition], star) : undefined;
|
|
31
|
-
}
|
|
33
|
+
}
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
function bySpecificity(left: string, right: string): number {
|
|
36
|
+
return right.indexOf("*") - left.indexOf("*") || right.length - left.length;
|
|
37
|
+
}
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
function patternTarget(exports: Readonly<Record<string, unknown>>, key: string): string | undefined {
|
|
36
40
|
const pattern = Object.keys(exports)
|
|
37
41
|
.filter((candidate) => candidate.split("*").length === 2)
|
|
38
42
|
.sort(bySpecificity)
|
|
@@ -42,26 +46,27 @@ const patternTarget = (exports: Readonly<Record<string, unknown>>, key: string):
|
|
|
42
46
|
});
|
|
43
47
|
const [prefix = "", suffix = ""] = pattern?.split("*") ?? [];
|
|
44
48
|
return pattern === undefined ? undefined : targetOf(exports[pattern], key.slice(prefix.length, key.length - suffix.length));
|
|
45
|
-
}
|
|
49
|
+
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
function exported(exports: unknown, subpath: string): string | undefined {
|
|
48
52
|
const key = subpath === "" ? "." : `./${subpath}`;
|
|
49
53
|
if (!isRecord(exports)) {
|
|
50
54
|
return targetOf(exports, undefined);
|
|
51
55
|
}
|
|
52
56
|
return Object.hasOwn(exports, key) ? targetOf(exports[key], undefined) : (patternTarget(exports, key) ?? targetOf(exports, undefined));
|
|
53
|
-
}
|
|
57
|
+
}
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
target?.startsWith("./") === true ? posix.join(directory, target) : undefined;
|
|
59
|
+
function inPackage(directory: string, target: string | undefined): string | undefined {
|
|
60
|
+
return target?.startsWith("./") === true ? posix.join(directory, target) : undefined;
|
|
61
|
+
}
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
async function manifestAt(readText: RuleInputs["readText"], path: string): Promise<Manifest | undefined> {
|
|
59
64
|
const text = await readText(path);
|
|
60
65
|
const decoded = text === undefined ? undefined : await decodeWith(manifestSchema, text);
|
|
61
66
|
return decoded?._tag === "Valid" ? decoded.value : undefined;
|
|
62
|
-
}
|
|
67
|
+
}
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
function fromDependency(directory: string, manifest: Manifest, subpath: string): string | undefined {
|
|
65
70
|
if (manifest.exports !== undefined) {
|
|
66
71
|
return inPackage(directory, exported(manifest.exports, subpath));
|
|
67
72
|
}
|
|
@@ -69,10 +74,10 @@ const fromDependency = (directory: string, manifest: Manifest, subpath: string):
|
|
|
69
74
|
return posix.join(directory, manifest.main);
|
|
70
75
|
}
|
|
71
76
|
return subpath === "" ? undefined : posix.join(directory, subpath);
|
|
72
|
-
}
|
|
77
|
+
}
|
|
73
78
|
|
|
74
|
-
export
|
|
75
|
-
const
|
|
79
|
+
export async function resolvePackage(readText: RuleInputs["readText"], specifier: string): Promise<string | undefined> {
|
|
80
|
+
const { name, subpath = "" } = SPECIFIER.exec(specifier)?.groups ?? {};
|
|
76
81
|
if (name === undefined) {
|
|
77
82
|
return undefined;
|
|
78
83
|
}
|
|
@@ -83,4 +88,4 @@ export const resolvePackage = async (readText: RuleInputs["readText"], specifier
|
|
|
83
88
|
const directory = posix.join("node_modules", name);
|
|
84
89
|
const manifest = await manifestAt(readText, posix.join(directory, "package.json"));
|
|
85
90
|
return manifest === undefined ? undefined : fromDependency(directory, manifest, subpath);
|
|
86
|
-
}
|
|
91
|
+
}
|
|
@@ -20,29 +20,36 @@ const LINT_WEAK = new Set(["off", "warn", "info"]);
|
|
|
20
20
|
const ASSIST_WEAK = new Set(["off"]);
|
|
21
21
|
const PRESETS = new Set(["recommended", "preset"]);
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
function levelOf(node: Json): string | undefined {
|
|
24
|
+
return textOf(node) ?? textOf(member(node, "level"));
|
|
25
|
+
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
node === undefined ? [] : [{ line: node.line, rule, weak, wholeGroup }];
|
|
27
|
+
function at(rule: string, node: Json | undefined, weak: boolean, wholeGroup = false): readonly Setting[] {
|
|
28
|
+
return node === undefined ? [] : [{ line: node.line, rule, weak, wholeGroup }];
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
at(rule, member(section, "enabled"), isFalse(member(section, "enabled")));
|
|
31
|
+
function enabled(rule: string, section: Json | undefined): readonly Setting[] {
|
|
32
|
+
return at(rule, member(section, "enabled"), isFalse(member(section, "enabled")));
|
|
33
|
+
}
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
function defaults(rule: string, set: Json | undefined): readonly Setting[] {
|
|
36
|
+
return [
|
|
37
|
+
...at(rule, member(set, "recommended"), isFalse(member(set, "recommended"))),
|
|
38
|
+
...at(rule, member(set, "preset"), textOf(member(set, "preset")) === "none"),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
entriesOf(rules)
|
|
42
|
+
function ruleSettings(group: string, weak: ReadonlySet<string>, rules: Json): readonly Setting[] {
|
|
43
|
+
return entriesOf(rules)
|
|
38
44
|
.filter(([rule]) => !PRESETS.has(rule))
|
|
39
45
|
.flatMap(([rule, setting]) => {
|
|
40
46
|
const level = levelOf(setting);
|
|
41
47
|
return level === undefined ? [] : at(`${group}/${rule}`, setting, weak.has(level));
|
|
42
48
|
});
|
|
49
|
+
}
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
entriesOf(groups)
|
|
51
|
+
function groupSettings(prefix: string, weak: ReadonlySet<string>, groups: Json | undefined): readonly Setting[] {
|
|
52
|
+
return entriesOf(groups)
|
|
46
53
|
.filter(([group]) => !PRESETS.has(group))
|
|
47
54
|
.flatMap(([group, rules]) => {
|
|
48
55
|
const severity = textOf(rules);
|
|
@@ -50,19 +57,24 @@ const groupSettings = (prefix: string, weak: ReadonlySet<string>, groups: Json |
|
|
|
50
57
|
? [...defaults(`${prefix}/${group}`, rules), ...ruleSettings(`${prefix}/${group}`, weak, rules)]
|
|
51
58
|
: at(`${prefix}/${group}`, rules, weak.has(severity), true);
|
|
52
59
|
});
|
|
60
|
+
}
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
]
|
|
62
|
+
function linter(section: Json | undefined): readonly Setting[] {
|
|
63
|
+
return [
|
|
64
|
+
...enabled("lint", section),
|
|
65
|
+
...defaults("lint/recommended", member(section, "rules")),
|
|
66
|
+
...groupSettings("lint", LINT_WEAK, member(section, "rules")),
|
|
67
|
+
...entriesOf(member(section, "domains")).flatMap(([domain, value]) => at(`lint/domains/${domain}`, value, textOf(value) === "none")),
|
|
68
|
+
];
|
|
69
|
+
}
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
function assist(section: Json | undefined): readonly Setting[] {
|
|
72
|
+
return [
|
|
73
|
+
...enabled("assist", section),
|
|
74
|
+
...defaults("assist/recommended", member(section, "actions")),
|
|
75
|
+
...groupSettings("assist", ASSIST_WEAK, member(section, "actions")),
|
|
76
|
+
];
|
|
77
|
+
}
|
|
66
78
|
|
|
67
79
|
const LANGUAGES: readonly string[] = ["javascript", "json", "css", "graphql", "grit", "html"];
|
|
68
80
|
|
|
@@ -74,33 +86,39 @@ const TOOLS: ReadonlyArray<readonly [string, string]> = [
|
|
|
74
86
|
|
|
75
87
|
const SCOPED_SECTIONS: ReadonlyArray<readonly [string, string]> = [["files", "files"], ...TOOLS];
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
]
|
|
89
|
+
function settingsOf(scope: Json): readonly Setting[] {
|
|
90
|
+
return [
|
|
91
|
+
...linter(member(scope, "linter")),
|
|
92
|
+
...assist(member(scope, "assist")),
|
|
93
|
+
...enabled("format", member(scope, "formatter")),
|
|
94
|
+
...LANGUAGES.flatMap((language) => TOOLS.flatMap(([key, name]) => enabled(`${language}/${name}`, member(member(scope, language), key)))),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
83
97
|
|
|
84
|
-
|
|
85
|
-
later.rule === earlier.rule || (later.wholeGroup && earlier.rule.startsWith(`${later.rule}/`));
|
|
98
|
+
function replaces(later: Setting, earlier: Setting): boolean {
|
|
99
|
+
return later.rule === earlier.rule || (later.wholeGroup && earlier.rule.startsWith(`${later.rule}/`));
|
|
100
|
+
}
|
|
86
101
|
|
|
87
|
-
|
|
102
|
+
function includesOf(override: Json): readonly string[] {
|
|
88
103
|
const includes = itemsOf(member(override, "includes")).flatMap((item) => textOf(item) ?? []);
|
|
89
104
|
return includes.length === 0 ? ["**"] : includes;
|
|
90
|
-
}
|
|
105
|
+
}
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
function narrowsScope(globs: readonly string[]): boolean {
|
|
108
|
+
return globs.length > 0 && (globs.some((glob) => glob.startsWith("!")) || !globs.includes("**"));
|
|
109
|
+
}
|
|
93
110
|
|
|
94
|
-
|
|
95
|
-
SCOPED_SECTIONS.flatMap(([key, name]) => {
|
|
111
|
+
function narrowings(config: Json, base: string): readonly Omit<Weakening, "layer">[] {
|
|
112
|
+
return SCOPED_SECTIONS.flatMap(([key, name]) => {
|
|
96
113
|
const list = member(member(config, key), "includes");
|
|
97
114
|
const globs = itemsOf(list).flatMap((item) => textOf(item) ?? []);
|
|
98
115
|
return list === undefined || !narrowsScope(globs)
|
|
99
116
|
? []
|
|
100
117
|
: [{ includes: globs.map((glob) => scoped(base, glob)), line: list.line, rule: `${name}/includes` }];
|
|
101
118
|
});
|
|
119
|
+
}
|
|
102
120
|
|
|
103
|
-
|
|
121
|
+
function layerWeakenings(layer: Layer, later: readonly Layer[], base: string): readonly Weakening[] {
|
|
104
122
|
const overriding = later.flatMap((next) => settingsOf(next.json));
|
|
105
123
|
const top = settingsOf(layer.json).filter((setting) => setting.weak && !overriding.some((next) => replaces(next, setting)));
|
|
106
124
|
return [
|
|
@@ -112,7 +130,8 @@ const layerWeakenings = (layer: Layer, later: readonly Layer[], base: string): r
|
|
|
112
130
|
.map(({ line, rule }) => ({ includes: includesOf(override).map((glob) => scoped(base, glob)), line, rule })),
|
|
113
131
|
),
|
|
114
132
|
].map((weakening) => ({ ...weakening, layer }));
|
|
115
|
-
}
|
|
133
|
+
}
|
|
116
134
|
|
|
117
|
-
export
|
|
118
|
-
layers.flatMap((layer, index) => layerWeakenings(layer, layers.slice(index + 1), base));
|
|
135
|
+
export function weakeningsOf({ base, layers }: Chain): readonly Weakening[] {
|
|
136
|
+
return layers.flatMap((layer, index) => layerWeakenings(layer, layers.slice(index + 1), base));
|
|
137
|
+
}
|