@savvy-web/silk-effects 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +48 -17
  2. package/_virtual/_rolldown/runtime.js +18 -0
  3. package/changesets/api/categories.js +247 -0
  4. package/changesets/api/changelog.js +134 -0
  5. package/changesets/api/dependency-table.js +163 -0
  6. package/changesets/api/linter.js +168 -0
  7. package/changesets/api/transformer.js +140 -0
  8. package/changesets/categories/index.js +299 -0
  9. package/changesets/categories/types.js +66 -0
  10. package/changesets/changelog/formatting.js +119 -0
  11. package/changesets/changelog/getDependencyReleaseLine.js +114 -0
  12. package/changesets/changelog/getReleaseLine.js +122 -0
  13. package/changesets/changelog/index.js +99 -0
  14. package/changesets/constants.js +43 -0
  15. package/changesets/errors.js +305 -0
  16. package/changesets/index.js +146 -0
  17. package/changesets/markdownlint/index.js +29 -0
  18. package/changesets/markdownlint/rules/content-structure.js +98 -0
  19. package/changesets/markdownlint/rules/dependency-table-format.js +170 -0
  20. package/changesets/markdownlint/rules/heading-hierarchy.js +61 -0
  21. package/changesets/markdownlint/rules/required-sections.js +54 -0
  22. package/changesets/markdownlint/rules/uncategorized-content.js +54 -0
  23. package/changesets/markdownlint/rules/utils.js +30 -0
  24. package/changesets/remark/plugins/aggregate-dependency-tables.js +47 -0
  25. package/changesets/remark/plugins/contributor-footnotes.js +123 -0
  26. package/changesets/remark/plugins/deduplicate-items.js +30 -0
  27. package/changesets/remark/plugins/issue-link-refs.js +58 -0
  28. package/changesets/remark/plugins/merge-sections.js +43 -0
  29. package/changesets/remark/plugins/normalize-format.js +47 -0
  30. package/changesets/remark/plugins/reorder-sections.js +34 -0
  31. package/changesets/remark/presets.js +119 -0
  32. package/changesets/remark/rules/content-structure.js +22 -0
  33. package/changesets/remark/rules/dependency-table-format.js +40 -0
  34. package/changesets/remark/rules/heading-hierarchy.js +19 -0
  35. package/changesets/remark/rules/required-sections.js +17 -0
  36. package/changesets/remark/rules/uncategorized-content.js +31 -0
  37. package/changesets/schemas/changeset.js +146 -0
  38. package/changesets/schemas/dependency-table.js +189 -0
  39. package/changesets/schemas/git.js +69 -0
  40. package/changesets/schemas/github.js +175 -0
  41. package/changesets/schemas/options.js +182 -0
  42. package/changesets/schemas/package-scope.js +128 -0
  43. package/changesets/schemas/primitives.js +72 -0
  44. package/changesets/schemas/version-files.js +151 -0
  45. package/changesets/services/branch-analyzer.js +278 -0
  46. package/changesets/services/changelog.js +50 -0
  47. package/changesets/services/config-inspector.js +390 -0
  48. package/changesets/services/github.js +178 -0
  49. package/changesets/services/markdown.js +106 -0
  50. package/changesets/services/workspace-snapshot.js +182 -0
  51. package/changesets/utils/commit-parser.js +80 -0
  52. package/changesets/utils/dep-diff.js +77 -0
  53. package/changesets/utils/dependency-table.js +347 -0
  54. package/changesets/utils/issue-refs.js +101 -0
  55. package/changesets/utils/jsonpath.js +175 -0
  56. package/changesets/utils/logger.js +50 -0
  57. package/changesets/utils/markdown-link.js +57 -0
  58. package/changesets/utils/publishability.js +39 -0
  59. package/changesets/utils/remark-pipeline.js +79 -0
  60. package/changesets/utils/section-parser.js +94 -0
  61. package/changesets/utils/strip-frontmatter.js +46 -0
  62. package/changesets/utils/version-blocks.js +108 -0
  63. package/changesets/utils/version-files.js +336 -0
  64. package/changesets/utils/worktree-snapshot.js +142 -0
  65. package/changesets/vendor/github-info.js +55 -0
  66. package/commitlint/config/factory.js +69 -0
  67. package/commitlint/config/plugins.js +227 -0
  68. package/commitlint/config/rules.js +155 -0
  69. package/commitlint/config/schema.js +46 -0
  70. package/commitlint/detection/dco.js +53 -0
  71. package/commitlint/detection/scopes.js +45 -0
  72. package/commitlint/formatter/format.js +85 -0
  73. package/commitlint/formatter/messages.js +79 -0
  74. package/commitlint/hook/diagnostics/branch.js +36 -0
  75. package/commitlint/hook/diagnostics/cache.js +37 -0
  76. package/commitlint/hook/diagnostics/commitlint-config.js +36 -0
  77. package/commitlint/hook/diagnostics/open-issues.js +56 -0
  78. package/commitlint/hook/diagnostics/package-manager.js +51 -0
  79. package/commitlint/hook/diagnostics/signing.js +107 -0
  80. package/commitlint/hook/envelope.js +46 -0
  81. package/commitlint/hook/output.js +45 -0
  82. package/commitlint/hook/parse-bash-command.js +105 -0
  83. package/commitlint/hook/rules/closes-trailer.js +31 -0
  84. package/commitlint/hook/rules/forbidden-content.js +32 -0
  85. package/commitlint/hook/rules/plan-leakage.js +36 -0
  86. package/commitlint/hook/rules/signing-flag-conflict.js +25 -0
  87. package/commitlint/hook/rules/soft-wrap.js +37 -0
  88. package/commitlint/hook/rules/types.js +14 -0
  89. package/commitlint/hook/rules/verbosity.js +31 -0
  90. package/commitlint/hook/silence-logger.js +39 -0
  91. package/commitlint/index.js +146 -0
  92. package/commitlint/prompt/config.js +91 -0
  93. package/commitlint/prompt/emojis.js +74 -0
  94. package/commitlint/prompt/prompter.js +135 -0
  95. package/commitlint/static.js +73 -0
  96. package/errors/BiomeSyncError.js +21 -0
  97. package/errors/ChangesetConfigError.js +20 -0
  98. package/errors/ConfigNotFoundError.js +21 -0
  99. package/errors/SectionParseError.js +16 -0
  100. package/errors/SectionValidationError.js +16 -0
  101. package/errors/SectionWriteError.js +16 -0
  102. package/errors/TagFormatError.js +20 -0
  103. package/errors/ToolNotFoundError.js +11 -0
  104. package/errors/ToolResolutionError.js +11 -0
  105. package/errors/ToolVersionMismatchError.js +11 -0
  106. package/errors/VersioningDetectionError.js +20 -0
  107. package/errors/WorkspaceAnalysisError.js +21 -0
  108. package/index.d.ts +9743 -8380
  109. package/index.js +36 -6657
  110. package/lint/Handler.js +39 -0
  111. package/lint/cli/sections.js +65 -0
  112. package/lint/cli/templates/markdownlint.gen.js +183 -0
  113. package/lint/config/Preset.js +152 -0
  114. package/lint/config/createConfig.js +89 -0
  115. package/lint/handlers/Biome.js +179 -0
  116. package/lint/handlers/Markdown.js +139 -0
  117. package/lint/handlers/PackageJson.js +130 -0
  118. package/lint/handlers/PnpmWorkspace.js +141 -0
  119. package/lint/handlers/ShellScripts.js +58 -0
  120. package/lint/handlers/TypeScript.js +134 -0
  121. package/lint/handlers/Yaml.js +167 -0
  122. package/lint/index.js +52 -0
  123. package/lint/utils/Command.js +285 -0
  124. package/lint/utils/Filter.js +100 -0
  125. package/lint/utils/Workspace.js +86 -0
  126. package/package.json +52 -63
  127. package/schemas/CommentStyle.js +16 -0
  128. package/schemas/ResolvedTool.js +63 -0
  129. package/schemas/SavvySections.js +113 -0
  130. package/schemas/SectionBlock.js +70 -0
  131. package/schemas/SectionDefinition.js +121 -0
  132. package/schemas/SectionResults.js +12 -0
  133. package/schemas/TagStrategySchemas.js +18 -0
  134. package/schemas/ToolDefinition.js +39 -0
  135. package/schemas/ToolResults.js +14 -0
  136. package/schemas/VersioningSchemas.js +95 -0
  137. package/schemas/WorkspaceAnalysisSchemas.js +190 -0
  138. package/services/BiomeSchemaSync.js +133 -0
  139. package/services/ChangesetConfig.js +78 -0
  140. package/services/ChangesetConfigReader.js +106 -0
  141. package/services/ConfigDiscovery.js +71 -0
  142. package/services/ManagedSection.js +288 -0
  143. package/services/SilkPublishability.js +193 -0
  144. package/services/SilkWorkspaceAnalyzer.js +213 -0
  145. package/services/TagStrategy.js +54 -0
  146. package/services/ToolDiscovery.js +229 -0
  147. package/services/VersioningStrategy.js +67 -0
  148. package/tsdoc-metadata.json +11 -11
  149. package/turbo/digest.js +127 -0
  150. package/turbo/errors.js +48 -0
  151. package/turbo/index.js +32 -0
  152. package/turbo/schemas/DryRun.js +57 -0
  153. package/turbo/schemas/results.js +61 -0
  154. package/turbo/services/TurboInspector.js +100 -0
  155. package/utils/ToolCommand.js +40 -0
@@ -0,0 +1,39 @@
1
+ //#region src/lint/Handler.ts
2
+ /**
3
+ * Abstract base class for lint-staged handlers.
4
+ *
5
+ * All handler classes follow this pattern and implement:
6
+ * - `glob` - The recommended glob pattern for matching files
7
+ * - `defaultExcludes` - Default patterns to exclude
8
+ * - `handler` - Pre-configured handler with defaults
9
+ * - `create()` - Factory method for custom configuration
10
+ */
11
+ var Handler = class {
12
+ /**
13
+ * Default glob pattern for this handler.
14
+ * Use as the key in lint-staged config.
15
+ */
16
+ static glob;
17
+ /**
18
+ * Default exclude patterns applied when no options provided.
19
+ */
20
+ static defaultExcludes;
21
+ /**
22
+ * Pre-configured handler with default options.
23
+ * Ready to use directly in lint-staged config.
24
+ */
25
+ static handler;
26
+ /**
27
+ * Factory method to create a handler with custom options.
28
+ *
29
+ * @param _options - Configuration options for this handler
30
+ * @returns A lint-staged compatible handler function
31
+ */
32
+ static create(_options) {
33
+ /* v8 ignore next -- abstract factory; always overridden by concrete subclasses */
34
+ throw new Error("Handler.create() must be implemented by subclass");
35
+ }
36
+ };
37
+
38
+ //#endregion
39
+ export { Handler };
@@ -0,0 +1,65 @@
1
+ import { SectionDefinition } from "../../schemas/SectionDefinition.js";
2
+ import { savvyToolSection } from "../../schemas/SavvySections.js";
3
+
4
+ //#region src/lint/cli/sections.ts
5
+ /**
6
+ * Shared managed section definitions and constants for CLI commands.
7
+ *
8
+ * @internal
9
+ */
10
+ /** Path for the husky pre-commit hook. */
11
+ const HUSKY_HOOK_PATH = ".husky/pre-commit";
12
+ /** Path for the husky post-checkout hook. */
13
+ const POST_CHECKOUT_HOOK_PATH = ".husky/post-checkout";
14
+ /** Path for the husky post-merge hook. */
15
+ const POST_MERGE_HOOK_PATH = ".husky/post-merge";
16
+ /** Default path for the lint-staged config file. */
17
+ const DEFAULT_CONFIG_PATH = "lib/configs/lint-staged.config.ts";
18
+ /** Path for the markdownlint-cli2 config file. */
19
+ const MARKDOWNLINT_CONFIG_PATH = "lib/configs/.markdownlint-cli2.jsonc";
20
+ /** Identity definition for the savvy-lint tool section (read / check / remove). */
21
+ const SavvyLintSectionDef = SectionDefinition.make({ toolName: "savvy-lint" });
22
+ /**
23
+ * Identity definition for the legacy `SAVVY-LINT` hygiene section that previously
24
+ * lived in `.husky/post-checkout` and `.husky/post-merge`.
25
+ *
26
+ * @remarks
27
+ * The hygiene block has been replaced by a co-owned `savvy-hooks` section emitted from
28
+ * silk-effects. Use this definition with `ManagedSection.remove` during migration to
29
+ * delete the leftover block from those hooks. The marker matched is identical to
30
+ * `SavvyLintSectionDef`'s; the two definitions are split only by intent (live tool
31
+ * section vs. legacy hygiene block that lives in a different hook).
32
+ */
33
+ const LegacySavvyLintHygieneDef = SectionDefinition.make({ toolName: "savvy-lint" });
34
+ /**
35
+ * Build the lint-staged command run inside the savvy-lint tool section.
36
+ *
37
+ * @param configPath - Path to the lint-staged config file (relative to repo root)
38
+ */
39
+ function lintStagedCommand(configPath) {
40
+ return `lint-staged --config "$ROOT/${configPath}"`;
41
+ }
42
+ /**
43
+ * Build the savvy-lint tool section block for the given config path.
44
+ *
45
+ * @remarks
46
+ * Depends on the savvy-base preamble (`in_ci`, `pm_exec`) preceding it in the hook.
47
+ */
48
+ function savvyLintBlock(configPath) {
49
+ return savvyToolSection("savvy-lint", lintStagedCommand(configPath));
50
+ }
51
+ /**
52
+ * Rendered content of the savvy-lint tool section.
53
+ *
54
+ * @remarks
55
+ * Equivalent to `savvyLintBlock(configPath).content`. Retained for the check command
56
+ * and tests.
57
+ *
58
+ * @param configPath - Path to the lint-staged config file
59
+ */
60
+ function generateManagedContent(configPath) {
61
+ return savvyLintBlock(configPath).content;
62
+ }
63
+
64
+ //#endregion
65
+ export { DEFAULT_CONFIG_PATH, HUSKY_HOOK_PATH, LegacySavvyLintHygieneDef, MARKDOWNLINT_CONFIG_PATH, POST_CHECKOUT_HOOK_PATH, POST_MERGE_HOOK_PATH, SavvyLintSectionDef, generateManagedContent, savvyLintBlock };
@@ -0,0 +1,183 @@
1
+ //#region src/lint/cli/templates/markdownlint.gen.ts
2
+ /**
3
+ * Auto-generated markdownlint template data.
4
+ *
5
+ * DO NOT EDIT — regenerate with: pnpm generate:templates
6
+ *
7
+ * @internal
8
+ */
9
+ /** Full markdownlint-cli2 config template. */
10
+ const MARKDOWNLINT_TEMPLATE = {
11
+ $schema: "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/v0.22.0/schema/markdownlint-cli2-config-schema.json",
12
+ globs: ["**/*.{md,mdx}"],
13
+ fix: true,
14
+ gitignore: true,
15
+ noBanner: true,
16
+ ignores: [
17
+ "**/node_modules",
18
+ "**/.cache",
19
+ "**/coverage",
20
+ "**/.coverage",
21
+ "**/dist",
22
+ "**/CHANGELOG.md",
23
+ "**/.claude/plans",
24
+ "**/docs/superpowers"
25
+ ],
26
+ customRules: ["@savvy-web/silk/changesets/markdownlint"],
27
+ config: {
28
+ default: true,
29
+ MD001: true,
30
+ MD002: true,
31
+ MD003: true,
32
+ MD004: true,
33
+ MD005: true,
34
+ MD006: true,
35
+ MD007: true,
36
+ MD008: true,
37
+ MD009: true,
38
+ MD010: true,
39
+ MD011: true,
40
+ MD012: true,
41
+ MD013: false,
42
+ MD014: true,
43
+ MD015: true,
44
+ MD016: true,
45
+ MD017: true,
46
+ MD018: true,
47
+ MD019: true,
48
+ MD020: true,
49
+ MD021: true,
50
+ MD022: true,
51
+ MD023: true,
52
+ MD024: { siblings_only: true },
53
+ MD025: true,
54
+ MD026: true,
55
+ MD027: true,
56
+ MD028: true,
57
+ MD029: true,
58
+ MD030: true,
59
+ MD031: true,
60
+ MD032: true,
61
+ MD033: { allowed_elements: [
62
+ "br",
63
+ "details",
64
+ "summary",
65
+ "img",
66
+ "sup",
67
+ "sub"
68
+ ] },
69
+ MD034: true,
70
+ MD035: true,
71
+ MD036: true,
72
+ MD037: true,
73
+ MD038: true,
74
+ MD039: true,
75
+ MD040: true,
76
+ MD041: true,
77
+ MD042: true,
78
+ MD043: false,
79
+ MD044: false,
80
+ MD045: true,
81
+ MD046: true,
82
+ MD047: true,
83
+ MD048: true,
84
+ MD049: true,
85
+ MD050: true,
86
+ MD051: true,
87
+ MD052: true,
88
+ MD053: true,
89
+ MD054: true,
90
+ MD055: true,
91
+ MD056: true,
92
+ MD057: true,
93
+ MD058: true,
94
+ MD059: true,
95
+ MD060: { style: "compact" },
96
+ "changeset-heading-hierarchy": false,
97
+ "changeset-required-sections": false,
98
+ "changeset-content-structure": false,
99
+ "changeset-uncategorized-content": false,
100
+ "changeset-dependency-table-format": false
101
+ }
102
+ };
103
+ /** The `$schema` URL from the template. */
104
+ const MARKDOWNLINT_SCHEMA = "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/v0.22.0/schema/markdownlint-cli2-config-schema.json";
105
+ /** The `config` rules object from the template. */
106
+ const MARKDOWNLINT_CONFIG = {
107
+ default: true,
108
+ MD001: true,
109
+ MD002: true,
110
+ MD003: true,
111
+ MD004: true,
112
+ MD005: true,
113
+ MD006: true,
114
+ MD007: true,
115
+ MD008: true,
116
+ MD009: true,
117
+ MD010: true,
118
+ MD011: true,
119
+ MD012: true,
120
+ MD013: false,
121
+ MD014: true,
122
+ MD015: true,
123
+ MD016: true,
124
+ MD017: true,
125
+ MD018: true,
126
+ MD019: true,
127
+ MD020: true,
128
+ MD021: true,
129
+ MD022: true,
130
+ MD023: true,
131
+ MD024: { siblings_only: true },
132
+ MD025: true,
133
+ MD026: true,
134
+ MD027: true,
135
+ MD028: true,
136
+ MD029: true,
137
+ MD030: true,
138
+ MD031: true,
139
+ MD032: true,
140
+ MD033: { allowed_elements: [
141
+ "br",
142
+ "details",
143
+ "summary",
144
+ "img",
145
+ "sup",
146
+ "sub"
147
+ ] },
148
+ MD034: true,
149
+ MD035: true,
150
+ MD036: true,
151
+ MD037: true,
152
+ MD038: true,
153
+ MD039: true,
154
+ MD040: true,
155
+ MD041: true,
156
+ MD042: true,
157
+ MD043: false,
158
+ MD044: false,
159
+ MD045: true,
160
+ MD046: true,
161
+ MD047: true,
162
+ MD048: true,
163
+ MD049: true,
164
+ MD050: true,
165
+ MD051: true,
166
+ MD052: true,
167
+ MD053: true,
168
+ MD054: true,
169
+ MD055: true,
170
+ MD056: true,
171
+ MD057: true,
172
+ MD058: true,
173
+ MD059: true,
174
+ MD060: { style: "compact" },
175
+ "changeset-heading-hierarchy": false,
176
+ "changeset-required-sections": false,
177
+ "changeset-content-structure": false,
178
+ "changeset-uncategorized-content": false,
179
+ "changeset-dependency-table-format": false
180
+ };
181
+
182
+ //#endregion
183
+ export { MARKDOWNLINT_CONFIG, MARKDOWNLINT_SCHEMA, MARKDOWNLINT_TEMPLATE };
@@ -0,0 +1,152 @@
1
+ import { createConfig } from "./createConfig.js";
2
+
3
+ //#region src/lint/config/Preset.ts
4
+ /**
5
+ * Preset configurations for common lint-staged setups.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { Preset } from '@savvy-web/lint-staged';
10
+ *
11
+ * // Use a preset directly
12
+ * export default Preset.standard();
13
+ *
14
+ * // Extend a preset with customizations
15
+ * export default Preset.standard({
16
+ * biome: { exclude: ['vendor/'] },
17
+ * custom: {
18
+ * '*.css': (files) => `stylelint ${files.join(' ')}`,
19
+ * },
20
+ * });
21
+ * ```
22
+ */
23
+ var Preset = class Preset {
24
+ /**
25
+ * Minimal preset: formatting only.
26
+ *
27
+ * Includes:
28
+ * - PackageJson (sort + format)
29
+ * - Biome (format JS/TS/JSON)
30
+ *
31
+ * @param extend - Options to customize or extend the preset
32
+ * @returns A lint-staged configuration object
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { Preset } from '@savvy-web/lint-staged';
37
+ *
38
+ * export default Preset.minimal();
39
+ * ```
40
+ */
41
+ static minimal(extend = {}) {
42
+ const options = {
43
+ packageJson: extend.packageJson ?? {},
44
+ biome: extend.biome ?? {},
45
+ markdown: extend.markdown ?? false,
46
+ yaml: extend.yaml ?? false,
47
+ pnpmWorkspace: extend.pnpmWorkspace ?? false,
48
+ shellScripts: extend.shellScripts ?? false,
49
+ typescript: extend.typescript ?? false
50
+ };
51
+ if (extend.custom !== void 0) options.custom = extend.custom;
52
+ return createConfig(options);
53
+ }
54
+ /**
55
+ * Standard preset: formatting + linting.
56
+ *
57
+ * Includes:
58
+ * - PackageJson (sort + format)
59
+ * - Biome (format JS/TS/JSON)
60
+ * - Markdown (lint + fix)
61
+ * - Yaml (format + lint)
62
+ * - PnpmWorkspace (sort + format)
63
+ * - ShellScripts (chmod management)
64
+ *
65
+ * @param extend - Options to customize or extend the preset
66
+ * @returns A lint-staged configuration object
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * import { Preset } from '@savvy-web/lint-staged';
71
+ *
72
+ * export default Preset.standard({
73
+ * biome: { exclude: ['legacy/'] },
74
+ * });
75
+ * ```
76
+ */
77
+ static standard(extend = {}) {
78
+ const options = {
79
+ packageJson: extend.packageJson ?? {},
80
+ biome: extend.biome ?? {},
81
+ markdown: extend.markdown ?? {},
82
+ yaml: extend.yaml ?? {},
83
+ pnpmWorkspace: extend.pnpmWorkspace ?? {},
84
+ shellScripts: extend.shellScripts ?? {},
85
+ typescript: extend.typescript ?? false
86
+ };
87
+ if (extend.custom !== void 0) options.custom = extend.custom;
88
+ return createConfig(options);
89
+ }
90
+ /**
91
+ * Silk preset: all handlers enabled.
92
+ *
93
+ * Includes:
94
+ * - PackageJson (sort + format)
95
+ * - Biome (format JS/TS/JSON)
96
+ * - Markdown (lint + fix)
97
+ * - Yaml (format + lint)
98
+ * - PnpmWorkspace (sort + format)
99
+ * - ShellScripts (chmod management)
100
+ * - TypeScript (TSDoc + typecheck)
101
+ *
102
+ * @param extend - Options to customize or extend the preset
103
+ * @returns A lint-staged configuration object
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * import { Preset } from '@savvy-web/lint-staged';
108
+ *
109
+ * export default Preset.silk({
110
+ * typescript: { skipTypecheck: true },
111
+ * });
112
+ * ```
113
+ */
114
+ static silk(extend = {}) {
115
+ const options = {
116
+ packageJson: extend.packageJson ?? {},
117
+ biome: extend.biome ?? {},
118
+ markdown: extend.markdown ?? {},
119
+ yaml: extend.yaml ?? {},
120
+ pnpmWorkspace: extend.pnpmWorkspace ?? {},
121
+ shellScripts: extend.shellScripts ?? {},
122
+ typescript: extend.typescript ?? {}
123
+ };
124
+ if (extend.custom !== void 0) options.custom = extend.custom;
125
+ return createConfig(options);
126
+ }
127
+ /**
128
+ * Get a preset by name.
129
+ *
130
+ * @param name - The preset name: 'minimal', 'standard', or 'silk'
131
+ * @param extend - Options to customize or extend the preset
132
+ * @returns A lint-staged configuration object
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * import { Preset } from '@savvy-web/lint-staged';
137
+ *
138
+ * const presetName = process.env.LINT_PRESET || 'standard';
139
+ * export default Preset.get(presetName);
140
+ * ```
141
+ */
142
+ static get(name, extend = {}) {
143
+ switch (name) {
144
+ case "minimal": return Preset.minimal(extend);
145
+ case "silk": return Preset.silk(extend);
146
+ default: return Preset.standard(extend);
147
+ }
148
+ }
149
+ };
150
+
151
+ //#endregion
152
+ export { Preset };
@@ -0,0 +1,89 @@
1
+ import { Biome } from "../handlers/Biome.js";
2
+ import { Markdown } from "../handlers/Markdown.js";
3
+ import { PackageJson } from "../handlers/PackageJson.js";
4
+ import { PnpmWorkspace } from "../handlers/PnpmWorkspace.js";
5
+ import { ShellScripts } from "../handlers/ShellScripts.js";
6
+ import { TypeScript } from "../handlers/TypeScript.js";
7
+ import { Yaml } from "../handlers/Yaml.js";
8
+
9
+ //#region src/lint/config/createConfig.ts
10
+ /**
11
+ * Configuration factory for generating complete lint-staged configurations.
12
+ */
13
+ /**
14
+ * Create a complete lint-staged configuration with all handlers.
15
+ *
16
+ * @param options - Configuration options for each handler
17
+ * @returns A lint-staged compatible configuration object
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { createConfig } from '@savvy-web/lint-staged';
22
+ *
23
+ * // Use all defaults
24
+ * export default createConfig();
25
+ *
26
+ * // Customize specific handlers
27
+ * export default createConfig({
28
+ * packageJson: { skipSort: true },
29
+ * biome: { exclude: ['vendor/'] },
30
+ * custom: {
31
+ * '*.css': (files) => `stylelint ${files.join(' ')}`,
32
+ * },
33
+ * });
34
+ * ```
35
+ */
36
+ function createConfig(options = {}) {
37
+ const config = {};
38
+ const pkgJsonEnabled = options.packageJson !== false;
39
+ const biomeEnabled = options.biome !== false;
40
+ if (pkgJsonEnabled && biomeEnabled) {
41
+ const pkgOpts = typeof options.packageJson === "object" ? options.packageJson : {};
42
+ const biomeOpts = typeof options.biome === "object" ? options.biome : {};
43
+ config[PackageJson.glob] = [PackageJson.fmtCommand(pkgOpts), Biome.create({
44
+ ...biomeOpts,
45
+ exclude: [...PackageJson.defaultExcludes]
46
+ })];
47
+ } else if (pkgJsonEnabled) {
48
+ const pkgOpts = typeof options.packageJson === "object" ? options.packageJson : {};
49
+ config[PackageJson.glob] = PackageJson.create(pkgOpts);
50
+ }
51
+ if (biomeEnabled) {
52
+ const handlerOptions = typeof options.biome === "object" ? options.biome : {};
53
+ config[Biome.glob] = Biome.create(handlerOptions);
54
+ }
55
+ if (options.markdown !== false) {
56
+ const handlerOptions = typeof options.markdown === "object" ? options.markdown : {};
57
+ config[Markdown.glob] = Markdown.create(handlerOptions);
58
+ }
59
+ const pnpmEnabled = options.pnpmWorkspace !== false;
60
+ const yamlEnabled = options.yaml !== false;
61
+ if (pnpmEnabled && yamlEnabled) config[PnpmWorkspace.glob] = [PnpmWorkspace.fmtCommand(), Yaml.create({
62
+ exclude: [],
63
+ skipFormat: true
64
+ })];
65
+ else if (pnpmEnabled) {
66
+ const pnpmOpts = typeof options.pnpmWorkspace === "object" ? options.pnpmWorkspace : {};
67
+ config[PnpmWorkspace.glob] = PnpmWorkspace.create(pnpmOpts);
68
+ }
69
+ if (yamlEnabled) {
70
+ const yamlOpts = typeof options.yaml === "object" ? options.yaml : {};
71
+ config[Yaml.glob] = [Yaml.fmtCommand(yamlOpts), Yaml.create({
72
+ ...yamlOpts,
73
+ skipFormat: true
74
+ })];
75
+ }
76
+ if (options.shellScripts !== false) {
77
+ const handlerOptions = typeof options.shellScripts === "object" ? options.shellScripts : {};
78
+ config[ShellScripts.glob] = ShellScripts.create(handlerOptions);
79
+ }
80
+ if (options.typescript !== false) {
81
+ const handlerOptions = typeof options.typescript === "object" ? options.typescript : {};
82
+ config[TypeScript.glob] = TypeScript.create(handlerOptions);
83
+ }
84
+ if (options.custom) for (const [glob, handler] of Object.entries(options.custom)) config[glob] = handler;
85
+ return config;
86
+ }
87
+
88
+ //#endregion
89
+ export { createConfig };
@@ -0,0 +1,179 @@
1
+ import { Command } from "../utils/Command.js";
2
+ import { Filter } from "../utils/Filter.js";
3
+ import { getWorkspacePackagePaths, getWorkspaceRoot } from "../utils/Workspace.js";
4
+ import { existsSync } from "node:fs";
5
+ import { join } from "node:path";
6
+
7
+ //#region src/lint/handlers/Biome.ts
8
+ /**
9
+ * Handler for JavaScript/TypeScript/JSON files.
10
+ *
11
+ * Formats and lints with Biome.
12
+ */
13
+ /**
14
+ * Handler for JavaScript, TypeScript, and JSON files.
15
+ *
16
+ * Formats and lints with Biome.
17
+ *
18
+ * Biome discovery order:
19
+ * 1. Global `biome` command (preferred)
20
+ * 2. Local installation via `pnpm exec biome`
21
+ * 3. Local installation via `npx biome`
22
+ *
23
+ * Config file discovery:
24
+ * - Searches the workspace root for `biome.jsonc` or `biome.json`.
25
+ * - Falls back to CWD when not in a workspace.
26
+ * - No `lib/configs/` convention — biome configs live at workspace roots only.
27
+ *
28
+ * @throws Error if Biome is not available (globally or locally)
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { Biome } from '@savvy-web/lint-staged';
33
+ *
34
+ * export default {
35
+ * // Auto-discovers biome command and config file
36
+ * [Biome.glob]: Biome.handler,
37
+ *
38
+ * // Or with custom excludes
39
+ * [Biome.glob]: Biome.create({
40
+ * exclude: ['vendor/', 'generated/'],
41
+ * }),
42
+ * };
43
+ * ```
44
+ */
45
+ var Biome = class Biome {
46
+ /**
47
+ * Glob pattern for matching JavaScript/TypeScript/JSON files.
48
+ * @defaultValue `'*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}'`
49
+ */
50
+ static glob = "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}";
51
+ /**
52
+ * Default patterns to exclude from processing.
53
+ * Excludes package.json since PackageJson handler processes those files.
54
+ * @defaultValue `['package.json', 'package-lock.json', '__fixtures__', '__test__/fixtures']`
55
+ */
56
+ static defaultExcludes = [
57
+ "package.json",
58
+ "package-lock.json",
59
+ "__fixtures__",
60
+ "__test__/fixtures"
61
+ ];
62
+ /** Candidate config file names in preference order. */
63
+ static CONFIG_NAMES = ["biome.jsonc", "biome.json"];
64
+ /**
65
+ * Pre-configured handler with default options.
66
+ * Auto-discovers biome command and config file location.
67
+ */
68
+ static handler = Biome.create();
69
+ /**
70
+ * Find the Biome executable.
71
+ *
72
+ * Searches in order:
73
+ * 1. Global `biome` command
74
+ * 2. `pnpm exec biome`
75
+ * 3. `npx biome`
76
+ *
77
+ * @returns The command to run biome, or undefined if not found
78
+ */
79
+ static findBiome() {
80
+ return Command.findTool("biome").command;
81
+ }
82
+ /**
83
+ * Check if Biome is available.
84
+ *
85
+ * @returns `true` if biome is available globally or locally
86
+ */
87
+ static isAvailable() {
88
+ return Command.findTool("biome").available;
89
+ }
90
+ /**
91
+ * Find the Biome config file at the workspace root.
92
+ *
93
+ * @remarks
94
+ * Searches the workspace root directory for `biome.jsonc` then `biome.json`.
95
+ * Falls back to CWD when not running inside a workspace. The `lib/configs/`
96
+ * convention is not used — biome configs are expected at workspace roots only.
97
+ *
98
+ * @returns Absolute path to the config file, or undefined if not found
99
+ */
100
+ static findConfig() {
101
+ const searchDir = getWorkspaceRoot() ?? process.cwd();
102
+ for (const name of Biome.CONFIG_NAMES) {
103
+ const fullPath = join(searchDir, name);
104
+ if (existsSync(fullPath)) return fullPath;
105
+ }
106
+ }
107
+ /**
108
+ * Find all Biome config files across workspace roots.
109
+ *
110
+ * @remarks
111
+ * Searches the workspace root and each leaf workspace root for a
112
+ * `biome.jsonc` or `biome.json` config file. At most one config is
113
+ * collected per directory (the first match in preference order).
114
+ * Falls back to CWD when not running inside a workspace.
115
+ *
116
+ * This method is intended for the CLI check command, which validates
117
+ * `$schema` URLs across all workspace biome configs.
118
+ *
119
+ * @returns Array of absolute config file paths (may be empty)
120
+ */
121
+ static findAllConfigs() {
122
+ const root = getWorkspaceRoot();
123
+ const configs = [];
124
+ if (root === null) {
125
+ const cwd = process.cwd();
126
+ for (const name of Biome.CONFIG_NAMES) {
127
+ const fullPath = join(cwd, name);
128
+ if (existsSync(fullPath)) {
129
+ configs.push(fullPath);
130
+ break;
131
+ }
132
+ }
133
+ return configs;
134
+ }
135
+ for (const name of Biome.CONFIG_NAMES) {
136
+ const fullPath = join(root, name);
137
+ if (existsSync(fullPath)) {
138
+ configs.push(fullPath);
139
+ break;
140
+ }
141
+ }
142
+ for (const pkgPath of getWorkspacePackagePaths()) for (const name of Biome.CONFIG_NAMES) {
143
+ const fullPath = join(pkgPath, name);
144
+ if (existsSync(fullPath)) {
145
+ configs.push(fullPath);
146
+ break;
147
+ }
148
+ }
149
+ return configs;
150
+ }
151
+ /**
152
+ * Create a handler with custom options.
153
+ *
154
+ * @param options - Configuration options
155
+ * @returns A lint-staged compatible handler function
156
+ * @throws Error if Biome is not available when handler is invoked
157
+ */
158
+ static create(options = {}) {
159
+ const excludes = options.exclude ?? [...Biome.defaultExcludes];
160
+ const config = options.config ?? Biome.findConfig();
161
+ return (filenames) => {
162
+ const filtered = Filter.exclude(filenames, excludes);
163
+ if (filtered.length === 0) return [];
164
+ const biomeCmd = Command.requireTool("biome", "Biome is not available. Install it globally (recommended) or add @biomejs/biome as a dev dependency.");
165
+ const files = Filter.shellEscape(filtered);
166
+ const flags = options.flags ?? [];
167
+ const configFlag = config ? `--config-path=${config}` : "";
168
+ return [
169
+ `${biomeCmd} check --write --no-errors-on-unmatched`,
170
+ configFlag,
171
+ ...flags,
172
+ files
173
+ ].filter(Boolean).join(" ");
174
+ };
175
+ }
176
+ };
177
+
178
+ //#endregion
179
+ export { Biome };