@savvy-web/silk-effects 0.6.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -17
- package/_virtual/_rolldown/runtime.js +18 -0
- package/changesets/api/categories.js +247 -0
- package/changesets/api/changelog.js +134 -0
- package/changesets/api/dependency-table.js +163 -0
- package/changesets/api/linter.js +168 -0
- package/changesets/api/transformer.js +140 -0
- package/changesets/categories/index.js +299 -0
- package/changesets/categories/types.js +66 -0
- package/changesets/changelog/formatting.js +119 -0
- package/changesets/changelog/getDependencyReleaseLine.js +114 -0
- package/changesets/changelog/getReleaseLine.js +122 -0
- package/changesets/changelog/index.js +99 -0
- package/changesets/constants.js +43 -0
- package/changesets/errors.js +305 -0
- package/changesets/index.js +146 -0
- package/changesets/markdownlint/index.js +29 -0
- package/changesets/markdownlint/rules/content-structure.js +98 -0
- package/changesets/markdownlint/rules/dependency-table-format.js +170 -0
- package/changesets/markdownlint/rules/heading-hierarchy.js +61 -0
- package/changesets/markdownlint/rules/required-sections.js +54 -0
- package/changesets/markdownlint/rules/uncategorized-content.js +54 -0
- package/changesets/markdownlint/rules/utils.js +30 -0
- package/changesets/remark/plugins/aggregate-dependency-tables.js +47 -0
- package/changesets/remark/plugins/contributor-footnotes.js +123 -0
- package/changesets/remark/plugins/deduplicate-items.js +30 -0
- package/changesets/remark/plugins/issue-link-refs.js +58 -0
- package/changesets/remark/plugins/merge-sections.js +43 -0
- package/changesets/remark/plugins/normalize-format.js +47 -0
- package/changesets/remark/plugins/reorder-sections.js +34 -0
- package/changesets/remark/presets.js +119 -0
- package/changesets/remark/rules/content-structure.js +22 -0
- package/changesets/remark/rules/dependency-table-format.js +40 -0
- package/changesets/remark/rules/heading-hierarchy.js +19 -0
- package/changesets/remark/rules/required-sections.js +17 -0
- package/changesets/remark/rules/uncategorized-content.js +31 -0
- package/changesets/schemas/changeset.js +146 -0
- package/changesets/schemas/dependency-table.js +189 -0
- package/changesets/schemas/git.js +69 -0
- package/changesets/schemas/github.js +175 -0
- package/changesets/schemas/options.js +182 -0
- package/changesets/schemas/package-scope.js +128 -0
- package/changesets/schemas/primitives.js +72 -0
- package/changesets/schemas/version-files.js +151 -0
- package/changesets/services/branch-analyzer.js +278 -0
- package/changesets/services/changelog.js +50 -0
- package/changesets/services/config-inspector.js +390 -0
- package/changesets/services/github.js +178 -0
- package/changesets/services/markdown.js +106 -0
- package/changesets/services/workspace-snapshot.js +182 -0
- package/changesets/utils/commit-parser.js +80 -0
- package/changesets/utils/dep-diff.js +77 -0
- package/changesets/utils/dependency-table.js +347 -0
- package/changesets/utils/issue-refs.js +101 -0
- package/changesets/utils/jsonpath.js +175 -0
- package/changesets/utils/logger.js +50 -0
- package/changesets/utils/markdown-link.js +57 -0
- package/changesets/utils/publishability.js +39 -0
- package/changesets/utils/remark-pipeline.js +79 -0
- package/changesets/utils/section-parser.js +94 -0
- package/changesets/utils/strip-frontmatter.js +46 -0
- package/changesets/utils/version-blocks.js +108 -0
- package/changesets/utils/version-files.js +336 -0
- package/changesets/utils/worktree-snapshot.js +142 -0
- package/changesets/vendor/github-info.js +55 -0
- package/commitlint/config/factory.js +69 -0
- package/commitlint/config/plugins.js +227 -0
- package/commitlint/config/rules.js +155 -0
- package/commitlint/config/schema.js +46 -0
- package/commitlint/detection/dco.js +53 -0
- package/commitlint/detection/scopes.js +45 -0
- package/commitlint/formatter/format.js +85 -0
- package/commitlint/formatter/messages.js +79 -0
- package/commitlint/hook/diagnostics/branch.js +36 -0
- package/commitlint/hook/diagnostics/cache.js +37 -0
- package/commitlint/hook/diagnostics/commitlint-config.js +36 -0
- package/commitlint/hook/diagnostics/open-issues.js +56 -0
- package/commitlint/hook/diagnostics/package-manager.js +51 -0
- package/commitlint/hook/diagnostics/signing.js +107 -0
- package/commitlint/hook/envelope.js +46 -0
- package/commitlint/hook/output.js +45 -0
- package/commitlint/hook/parse-bash-command.js +105 -0
- package/commitlint/hook/rules/closes-trailer.js +31 -0
- package/commitlint/hook/rules/forbidden-content.js +32 -0
- package/commitlint/hook/rules/plan-leakage.js +36 -0
- package/commitlint/hook/rules/signing-flag-conflict.js +25 -0
- package/commitlint/hook/rules/soft-wrap.js +37 -0
- package/commitlint/hook/rules/types.js +14 -0
- package/commitlint/hook/rules/verbosity.js +31 -0
- package/commitlint/hook/silence-logger.js +39 -0
- package/commitlint/index.js +146 -0
- package/commitlint/prompt/config.js +91 -0
- package/commitlint/prompt/emojis.js +74 -0
- package/commitlint/prompt/prompter.js +135 -0
- package/commitlint/static.js +73 -0
- package/errors/BiomeSyncError.js +21 -0
- package/errors/ChangesetConfigError.js +20 -0
- package/errors/ConfigNotFoundError.js +21 -0
- package/errors/SectionParseError.js +16 -0
- package/errors/SectionValidationError.js +16 -0
- package/errors/SectionWriteError.js +16 -0
- package/errors/TagFormatError.js +20 -0
- package/errors/ToolNotFoundError.js +11 -0
- package/errors/ToolResolutionError.js +11 -0
- package/errors/ToolVersionMismatchError.js +11 -0
- package/errors/VersioningDetectionError.js +20 -0
- package/errors/WorkspaceAnalysisError.js +21 -0
- package/index.d.ts +9743 -8380
- package/index.js +36 -6657
- package/lint/Handler.js +39 -0
- package/lint/cli/sections.js +65 -0
- package/lint/cli/templates/markdownlint.gen.js +183 -0
- package/lint/config/Preset.js +152 -0
- package/lint/config/createConfig.js +89 -0
- package/lint/handlers/Biome.js +179 -0
- package/lint/handlers/Markdown.js +139 -0
- package/lint/handlers/PackageJson.js +130 -0
- package/lint/handlers/PnpmWorkspace.js +141 -0
- package/lint/handlers/ShellScripts.js +58 -0
- package/lint/handlers/TypeScript.js +134 -0
- package/lint/handlers/Yaml.js +167 -0
- package/lint/index.js +52 -0
- package/lint/utils/Command.js +285 -0
- package/lint/utils/Filter.js +100 -0
- package/lint/utils/Workspace.js +86 -0
- package/package.json +52 -63
- package/schemas/CommentStyle.js +16 -0
- package/schemas/ResolvedTool.js +63 -0
- package/schemas/SavvySections.js +113 -0
- package/schemas/SectionBlock.js +70 -0
- package/schemas/SectionDefinition.js +121 -0
- package/schemas/SectionResults.js +12 -0
- package/schemas/TagStrategySchemas.js +18 -0
- package/schemas/ToolDefinition.js +39 -0
- package/schemas/ToolResults.js +14 -0
- package/schemas/VersioningSchemas.js +95 -0
- package/schemas/WorkspaceAnalysisSchemas.js +190 -0
- package/services/BiomeSchemaSync.js +133 -0
- package/services/ChangesetConfig.js +78 -0
- package/services/ChangesetConfigReader.js +106 -0
- package/services/ConfigDiscovery.js +71 -0
- package/services/ManagedSection.js +288 -0
- package/services/SilkPublishability.js +193 -0
- package/services/SilkWorkspaceAnalyzer.js +213 -0
- package/services/TagStrategy.js +54 -0
- package/services/ToolDiscovery.js +229 -0
- package/services/VersioningStrategy.js +67 -0
- package/tsdoc-metadata.json +11 -11
- package/turbo/digest.js +127 -0
- package/turbo/errors.js +48 -0
- package/turbo/index.js +32 -0
- package/turbo/schemas/DryRun.js +57 -0
- package/turbo/schemas/results.js +61 -0
- package/turbo/services/TurboInspector.js +100 -0
- package/utils/ToolCommand.js +40 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Command } from "../utils/Command.js";
|
|
2
|
+
import { Filter } from "../utils/Filter.js";
|
|
3
|
+
import { getWorkspaceRoot } from "../utils/Workspace.js";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
//#region src/lint/handlers/Markdown.ts
|
|
8
|
+
/**
|
|
9
|
+
* Handler for Markdown files.
|
|
10
|
+
*
|
|
11
|
+
* Lints and auto-fixes with markdownlint-cli2.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Handler for Markdown files.
|
|
15
|
+
*
|
|
16
|
+
* Lints and auto-fixes with markdownlint-cli2.
|
|
17
|
+
*
|
|
18
|
+
* Tool discovery order:
|
|
19
|
+
* 1. Global `markdownlint-cli2` command (preferred)
|
|
20
|
+
* 2. Local installation via `pnpm exec markdownlint-cli2`
|
|
21
|
+
* 3. Local installation via `npx markdownlint-cli2`
|
|
22
|
+
*
|
|
23
|
+
* Config file discovery order:
|
|
24
|
+
* 1. Explicit `config` option if provided
|
|
25
|
+
* 2. `lib/configs/.markdownlint-cli2.jsonc` (and variants)
|
|
26
|
+
* 3. Standard locations (`.markdownlint-cli2.jsonc` at repo root, etc.)
|
|
27
|
+
*
|
|
28
|
+
* @throws Error if markdownlint-cli2 is not available (globally or locally)
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { Markdown } from '@savvy-web/lint-staged';
|
|
33
|
+
*
|
|
34
|
+
* export default {
|
|
35
|
+
* // Auto-discovers command and config file
|
|
36
|
+
* [Markdown.glob]: Markdown.handler,
|
|
37
|
+
*
|
|
38
|
+
* // Or explicit config path
|
|
39
|
+
* [Markdown.glob]: Markdown.create({
|
|
40
|
+
* config: './config/.markdownlint.jsonc',
|
|
41
|
+
* }),
|
|
42
|
+
* };
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
var Markdown = class Markdown {
|
|
46
|
+
/**
|
|
47
|
+
* Glob pattern for matching Markdown files.
|
|
48
|
+
* @defaultValue `'**\/*.{md,mdx}'`
|
|
49
|
+
*/
|
|
50
|
+
static glob = "**/*.{md,mdx}";
|
|
51
|
+
/**
|
|
52
|
+
* Default patterns to exclude from processing.
|
|
53
|
+
* @defaultValue `[]`
|
|
54
|
+
*/
|
|
55
|
+
static defaultExcludes = [];
|
|
56
|
+
/**
|
|
57
|
+
* Pre-configured handler with default options.
|
|
58
|
+
* Auto-discovers command and config file location.
|
|
59
|
+
*/
|
|
60
|
+
static handler = Markdown.create();
|
|
61
|
+
/**
|
|
62
|
+
* Find the markdownlint-cli2 executable.
|
|
63
|
+
*
|
|
64
|
+
* Searches in order:
|
|
65
|
+
* 1. Global `markdownlint-cli2` command
|
|
66
|
+
* 2. `pnpm exec markdownlint-cli2`
|
|
67
|
+
* 3. `npx markdownlint-cli2`
|
|
68
|
+
*
|
|
69
|
+
* @returns The command to run markdownlint-cli2, or undefined if not found
|
|
70
|
+
*/
|
|
71
|
+
static findMarkdownlint() {
|
|
72
|
+
return Command.findTool("markdownlint-cli2").command;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if markdownlint-cli2 is available.
|
|
76
|
+
*
|
|
77
|
+
* @returns `true` if markdownlint-cli2 is available globally or locally
|
|
78
|
+
*/
|
|
79
|
+
static isAvailable() {
|
|
80
|
+
return Command.findTool("markdownlint-cli2").available;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Find the markdownlint config file.
|
|
84
|
+
*
|
|
85
|
+
* Paths are anchored to the workspace root (via {@link getWorkspaceRoot}),
|
|
86
|
+
* falling back to `process.cwd()` when not inside a workspace.
|
|
87
|
+
*
|
|
88
|
+
* Searches in order:
|
|
89
|
+
* 1. `{workspaceRoot}/lib/configs/` directory
|
|
90
|
+
* 2. `{workspaceRoot}/` (repo root)
|
|
91
|
+
*
|
|
92
|
+
* @returns The config file path, or undefined if not found
|
|
93
|
+
*/
|
|
94
|
+
static findConfig() {
|
|
95
|
+
const root = getWorkspaceRoot() ?? process.cwd();
|
|
96
|
+
for (const name of [
|
|
97
|
+
".markdownlint-cli2.jsonc",
|
|
98
|
+
".markdownlint-cli2.json",
|
|
99
|
+
".markdownlint-cli2.yaml",
|
|
100
|
+
".markdownlint-cli2.cjs",
|
|
101
|
+
".markdownlint.jsonc",
|
|
102
|
+
".markdownlint.json",
|
|
103
|
+
".markdownlint.yaml"
|
|
104
|
+
]) {
|
|
105
|
+
const libPath = join(root, "lib/configs", name);
|
|
106
|
+
if (existsSync(libPath)) return libPath;
|
|
107
|
+
const rootPath = join(root, name);
|
|
108
|
+
if (existsSync(rootPath)) return rootPath;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Create a handler with custom options.
|
|
113
|
+
*
|
|
114
|
+
* @param options - Configuration options
|
|
115
|
+
* @returns A lint-staged compatible handler function
|
|
116
|
+
* @throws Error if markdownlint-cli2 is not available when handler is invoked
|
|
117
|
+
*/
|
|
118
|
+
static create(options = {}) {
|
|
119
|
+
const excludes = options.exclude ?? [...Markdown.defaultExcludes];
|
|
120
|
+
const noFix = options.noFix ?? false;
|
|
121
|
+
const config = options.config ?? Markdown.findConfig();
|
|
122
|
+
return (filenames) => {
|
|
123
|
+
const filtered = Filter.exclude(filenames, excludes);
|
|
124
|
+
if (filtered.length === 0) return [];
|
|
125
|
+
const mdlintCmd = Command.requireTool("markdownlint-cli2", "markdownlint-cli2 is not available. Install it globally or add it as a dev dependency.");
|
|
126
|
+
const files = Filter.shellEscape(filtered);
|
|
127
|
+
const fixFlag = noFix ? "" : "--fix";
|
|
128
|
+
return [
|
|
129
|
+
mdlintCmd,
|
|
130
|
+
config ? `--config '${config}'` : "",
|
|
131
|
+
fixFlag,
|
|
132
|
+
files
|
|
133
|
+
].filter(Boolean).join(" ");
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
export { Markdown };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Command } from "../utils/Command.js";
|
|
2
|
+
import { Filter } from "../utils/Filter.js";
|
|
3
|
+
import { isWorkspacePackagePath } from "../utils/Workspace.js";
|
|
4
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import sortPackageJson from "sort-package-json";
|
|
6
|
+
|
|
7
|
+
//#region src/lint/handlers/PackageJson.ts
|
|
8
|
+
/**
|
|
9
|
+
* Handler for package.json files.
|
|
10
|
+
*
|
|
11
|
+
* Sorts fields with sort-package-json and formats with Biome.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Handler for package.json files.
|
|
15
|
+
*
|
|
16
|
+
* Sorts fields with sort-package-json and formats with Biome.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { PackageJson } from '@savvy-web/lint-staged';
|
|
21
|
+
*
|
|
22
|
+
* export default {
|
|
23
|
+
* // Use defaults
|
|
24
|
+
* [PackageJson.glob]: PackageJson.handler,
|
|
25
|
+
*
|
|
26
|
+
* // Or customize
|
|
27
|
+
* [PackageJson.glob]: PackageJson.create({
|
|
28
|
+
* exclude: ['packages/legacy/package.json'],
|
|
29
|
+
* skipSort: true,
|
|
30
|
+
* }),
|
|
31
|
+
* };
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
var PackageJson = class PackageJson {
|
|
35
|
+
/**
|
|
36
|
+
* Glob pattern for matching package.json files.
|
|
37
|
+
* @defaultValue `'**\/package.json'`
|
|
38
|
+
*/
|
|
39
|
+
static glob = "**/package.json";
|
|
40
|
+
/**
|
|
41
|
+
* Default patterns to exclude from processing.
|
|
42
|
+
* @defaultValue `['dist/package.json', '__fixtures__']`
|
|
43
|
+
*/
|
|
44
|
+
static defaultExcludes = ["dist/package.json", "__fixtures__"];
|
|
45
|
+
/**
|
|
46
|
+
* Pre-configured handler with default options.
|
|
47
|
+
*/
|
|
48
|
+
static handler = PackageJson.create();
|
|
49
|
+
/**
|
|
50
|
+
* Filter filenames to workspace roots only.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* Applies exclude patterns first (for backward compatibility with custom
|
|
54
|
+
* excludes), then filters to workspace root and leaf workspace roots only.
|
|
55
|
+
* Falls back permissively when not in a workspace.
|
|
56
|
+
*
|
|
57
|
+
* @param filenames - Incoming file list from lint-staged
|
|
58
|
+
* @param excludes - Patterns to exclude before workspace filtering
|
|
59
|
+
* @returns Filtered list of files at workspace roots
|
|
60
|
+
*/
|
|
61
|
+
static filterToWorkspaceRoots(filenames, excludes) {
|
|
62
|
+
return Filter.exclude(filenames, [...excludes]).filter((f) => isWorkspacePackagePath(f));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a handler with custom options.
|
|
66
|
+
*
|
|
67
|
+
* @param options - Configuration options
|
|
68
|
+
* @returns A lint-staged compatible handler function
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* Create a handler that returns a CLI command to sort package.json files.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* Unlike {@link create}, this does not modify files in the handler function
|
|
75
|
+
* body. Instead it returns a `savvy-lint fmt package-json` command so
|
|
76
|
+
* lint-staged can detect the modification and auto-stage it.
|
|
77
|
+
* Use this in lint-staged array syntax for sequential execution.
|
|
78
|
+
*
|
|
79
|
+
* @param options - Configuration options
|
|
80
|
+
* @returns A lint-staged compatible handler function
|
|
81
|
+
*/
|
|
82
|
+
static fmtCommand(options = {}) {
|
|
83
|
+
const excludes = options.exclude ?? [...PackageJson.defaultExcludes];
|
|
84
|
+
return (filenames) => {
|
|
85
|
+
const filtered = PackageJson.filterToWorkspaceRoots(filenames, excludes);
|
|
86
|
+
if (filtered.length === 0) return [];
|
|
87
|
+
return `${Command.findSavvyLint()} fmt package-json ${Filter.shellEscape(filtered)}`;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Sort the keys of a package.json document string.
|
|
92
|
+
*
|
|
93
|
+
* @remarks
|
|
94
|
+
* Pure transform over the file contents using `sort-package-json`. Used by
|
|
95
|
+
* the `savvy lint fmt package-json` subcommand so the CLI does not depend on
|
|
96
|
+
* `sort-package-json` directly.
|
|
97
|
+
*
|
|
98
|
+
* @param content - The raw package.json file contents
|
|
99
|
+
* @returns The sorted package.json file contents
|
|
100
|
+
*/
|
|
101
|
+
static sortContent(content) {
|
|
102
|
+
return sortPackageJson(content);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a handler with custom options.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Configuration options
|
|
108
|
+
* @returns A lint-staged compatible handler function
|
|
109
|
+
*/
|
|
110
|
+
static create(options = {}) {
|
|
111
|
+
const excludes = options.exclude ?? [...PackageJson.defaultExcludes];
|
|
112
|
+
const skipSort = options.skipSort ?? false;
|
|
113
|
+
const skipFormat = options.skipFormat ?? false;
|
|
114
|
+
return (filenames) => {
|
|
115
|
+
const filtered = PackageJson.filterToWorkspaceRoots(filenames, excludes);
|
|
116
|
+
if (filtered.length === 0) return [];
|
|
117
|
+
if (!skipSort) for (const filepath of filtered) {
|
|
118
|
+
const content = readFileSync(filepath, "utf-8");
|
|
119
|
+
const sorted = sortPackageJson(content);
|
|
120
|
+
if (sorted !== content) writeFileSync(filepath, sorted, "utf-8");
|
|
121
|
+
}
|
|
122
|
+
if (skipFormat) return [];
|
|
123
|
+
const files = Filter.shellEscape(filtered);
|
|
124
|
+
return options.biomeConfig ? `biome check --write --max-diagnostics=none --config-path=${options.biomeConfig} ${files}` : `biome check --write --max-diagnostics=none ${files}`;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
export { PackageJson };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Command } from "../utils/Command.js";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { parse, stringify } from "yaml";
|
|
4
|
+
|
|
5
|
+
//#region src/lint/handlers/PnpmWorkspace.ts
|
|
6
|
+
/**
|
|
7
|
+
* Handler for pnpm-workspace.yaml.
|
|
8
|
+
*
|
|
9
|
+
* Sorts, formats, and validates pnpm-workspace.yaml using bundled libraries.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Default YAML stringify options for consistent formatting.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_STRINGIFY_OPTIONS = {
|
|
15
|
+
indent: 2,
|
|
16
|
+
lineWidth: 0,
|
|
17
|
+
singleQuote: false
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Handler for pnpm-workspace.yaml.
|
|
21
|
+
*
|
|
22
|
+
* Sorts, formats, and validates pnpm-workspace.yaml using bundled libraries.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* This handler processes the workspace file entirely in JavaScript:
|
|
26
|
+
* - Sorts the `packages` array alphabetically (if present)
|
|
27
|
+
* - Sorts `onlyBuiltDependencies` and `publicHoistPattern` arrays (if present)
|
|
28
|
+
* - Sorts all top-level keys alphabetically, keeping `packages` first
|
|
29
|
+
* - Formats the output with consistent YAML styling
|
|
30
|
+
* - Validates the YAML structure
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* import { PnpmWorkspace } from '\@savvy-web/lint-staged';
|
|
35
|
+
*
|
|
36
|
+
* export default {
|
|
37
|
+
* [PnpmWorkspace.glob]: PnpmWorkspace.create({
|
|
38
|
+
* skipSort: true, // Skip sorting
|
|
39
|
+
* }),
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
var PnpmWorkspace = class PnpmWorkspace {
|
|
44
|
+
/**
|
|
45
|
+
* Glob pattern for matching pnpm-workspace.yaml.
|
|
46
|
+
* @defaultValue `'pnpm-workspace.yaml'`
|
|
47
|
+
*/
|
|
48
|
+
static glob = "pnpm-workspace.yaml";
|
|
49
|
+
/**
|
|
50
|
+
* Default patterns to exclude (none, since this is a single file).
|
|
51
|
+
* @defaultValue `[]`
|
|
52
|
+
*/
|
|
53
|
+
static defaultExcludes = [];
|
|
54
|
+
/**
|
|
55
|
+
* Pre-configured handler with default options.
|
|
56
|
+
*/
|
|
57
|
+
static handler = PnpmWorkspace.create();
|
|
58
|
+
/**
|
|
59
|
+
* Keys whose array values should be sorted alphabetically.
|
|
60
|
+
*/
|
|
61
|
+
static SORTABLE_ARRAY_KEYS = new Set([
|
|
62
|
+
"packages",
|
|
63
|
+
"onlyBuiltDependencies",
|
|
64
|
+
"publicHoistPattern"
|
|
65
|
+
]);
|
|
66
|
+
/**
|
|
67
|
+
* Sort the pnpm-workspace.yaml content.
|
|
68
|
+
*
|
|
69
|
+
* Sorts:
|
|
70
|
+
* - `packages` array alphabetically
|
|
71
|
+
* - `onlyBuiltDependencies` array (if present)
|
|
72
|
+
* - `publicHoistPattern` array (if present)
|
|
73
|
+
* - All keys alphabetically, keeping `packages` first
|
|
74
|
+
*
|
|
75
|
+
* @param content - Parsed pnpm-workspace.yaml content
|
|
76
|
+
* @returns Sorted content
|
|
77
|
+
*/
|
|
78
|
+
static sortContent(content) {
|
|
79
|
+
const result = {};
|
|
80
|
+
const keys = Object.keys(content).sort((a, b) => {
|
|
81
|
+
if (a === "packages") return -1;
|
|
82
|
+
if (b === "packages") return 1;
|
|
83
|
+
return a.localeCompare(b);
|
|
84
|
+
});
|
|
85
|
+
for (const key of keys) {
|
|
86
|
+
const value = content[key];
|
|
87
|
+
if (PnpmWorkspace.SORTABLE_ARRAY_KEYS.has(key) && Array.isArray(value)) result[key] = [...value].sort();
|
|
88
|
+
else result[key] = value;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a handler that returns a CLI command to sort/format pnpm-workspace.yaml.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* Unlike {@link create}, this does not modify files in the handler function
|
|
97
|
+
* body. Instead it returns a `savvy-lint fmt pnpm-workspace` command so
|
|
98
|
+
* lint-staged can detect the modification and auto-stage it.
|
|
99
|
+
* Use this in lint-staged array syntax for sequential execution.
|
|
100
|
+
*
|
|
101
|
+
* @returns A lint-staged compatible handler function
|
|
102
|
+
*/
|
|
103
|
+
static fmtCommand() {
|
|
104
|
+
return () => {
|
|
105
|
+
if (!existsSync("pnpm-workspace.yaml")) return [];
|
|
106
|
+
return `${Command.findSavvyLint()} fmt pnpm-workspace`;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a handler with custom options.
|
|
111
|
+
*
|
|
112
|
+
* @param options - Configuration options
|
|
113
|
+
* @returns A lint-staged compatible handler function
|
|
114
|
+
*/
|
|
115
|
+
static create(options = {}) {
|
|
116
|
+
const skipSort = options.skipSort ?? false;
|
|
117
|
+
const skipFormat = options.skipFormat ?? false;
|
|
118
|
+
const skipLint = options.skipLint ?? false;
|
|
119
|
+
return () => {
|
|
120
|
+
const filepath = "pnpm-workspace.yaml";
|
|
121
|
+
if (!existsSync(filepath)) return [];
|
|
122
|
+
const content = readFileSync(filepath, "utf-8");
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = parse(content);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (!skipLint) throw new Error(`Invalid YAML in ${filepath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
if (!skipSort) parsed = PnpmWorkspace.sortContent(parsed);
|
|
131
|
+
if (!skipSort || !skipFormat) {
|
|
132
|
+
writeFileSync(filepath, stringify(parsed, DEFAULT_STRINGIFY_OPTIONS), "utf-8");
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
return [];
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { PnpmWorkspace };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Filter } from "../utils/Filter.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lint/handlers/ShellScripts.ts
|
|
4
|
+
/**
|
|
5
|
+
* Handler for shell script files.
|
|
6
|
+
*
|
|
7
|
+
* Removes executable bit by default (security best practice).
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* By default, excludes `.claude/scripts/` which need to remain executable
|
|
11
|
+
* for lint-staged hooks to work.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { ShellScripts } from '@savvy-web/lint-staged';
|
|
16
|
+
*
|
|
17
|
+
* export default {
|
|
18
|
+
* [ShellScripts.glob]: ShellScripts.create({
|
|
19
|
+
* exclude: ['.claude/scripts/', 'bin/'],
|
|
20
|
+
* }),
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
var ShellScripts = class ShellScripts {
|
|
25
|
+
/**
|
|
26
|
+
* Glob pattern for matching shell script files.
|
|
27
|
+
* @defaultValue `'**\/*.sh'`
|
|
28
|
+
*/
|
|
29
|
+
static glob = "**/*.sh";
|
|
30
|
+
/**
|
|
31
|
+
* Default patterns to exclude from processing.
|
|
32
|
+
* @defaultValue `['.claude/scripts/']`
|
|
33
|
+
*/
|
|
34
|
+
static defaultExcludes = [".claude/scripts/"];
|
|
35
|
+
/**
|
|
36
|
+
* Pre-configured handler with default options.
|
|
37
|
+
*/
|
|
38
|
+
static handler = ShellScripts.create();
|
|
39
|
+
/**
|
|
40
|
+
* Create a handler with custom options.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Configuration options
|
|
43
|
+
* @returns A lint-staged compatible handler function
|
|
44
|
+
*/
|
|
45
|
+
static create(options = {}) {
|
|
46
|
+
const excludes = options.exclude ?? [...ShellScripts.defaultExcludes];
|
|
47
|
+
const makeExecutable = options.makeExecutable ?? false;
|
|
48
|
+
return (filenames) => {
|
|
49
|
+
const filtered = Filter.exclude(filenames, excludes);
|
|
50
|
+
if (filtered.length === 0) return [];
|
|
51
|
+
const chmodFlag = makeExecutable ? "+x" : "-x";
|
|
52
|
+
return filtered.map((file) => `chmod ${chmodFlag} ${file}`);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { ShellScripts };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Command } from "../utils/Command.js";
|
|
2
|
+
import { Filter } from "../utils/Filter.js";
|
|
3
|
+
|
|
4
|
+
//#region src/lint/handlers/TypeScript.ts
|
|
5
|
+
/**
|
|
6
|
+
* Handler for TypeScript files.
|
|
7
|
+
*
|
|
8
|
+
* Runs type checking with tsgo or tsc.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Type checking runs on all staged TypeScript files using the configured
|
|
12
|
+
* compiler (tsgo or tsc). The compiler is auto-detected at runtime using
|
|
13
|
+
* `Command.findTool()`, which correctly handles pnpm catalogs, peer
|
|
14
|
+
* dependencies, and hoisted/transitive deps.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { TypeScript } from '\@savvy-web/lint-staged';
|
|
19
|
+
*
|
|
20
|
+
* export default {
|
|
21
|
+
* // Auto-detects compiler and runs type checking
|
|
22
|
+
* [TypeScript.glob]: TypeScript.handler,
|
|
23
|
+
*
|
|
24
|
+
* // Or explicit config
|
|
25
|
+
* [TypeScript.glob]: TypeScript.create({
|
|
26
|
+
* skipTypecheck: true,
|
|
27
|
+
* }),
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
var TypeScript = class TypeScript {
|
|
32
|
+
/**
|
|
33
|
+
* Glob pattern for matching TypeScript files.
|
|
34
|
+
* @defaultValue `'*.{ts,cts,mts,tsx}'`
|
|
35
|
+
*/
|
|
36
|
+
static glob = "*.{ts,cts,mts,tsx}";
|
|
37
|
+
/**
|
|
38
|
+
* Default patterns to exclude from processing.
|
|
39
|
+
* @defaultValue `[]`
|
|
40
|
+
*/
|
|
41
|
+
static defaultExcludes = [];
|
|
42
|
+
/** Cached compiler detection result */
|
|
43
|
+
static cachedCompilerResult = null;
|
|
44
|
+
/**
|
|
45
|
+
* Detect which TypeScript compiler to use.
|
|
46
|
+
*
|
|
47
|
+
* Uses `Command.findTool()` to check for available compilers:
|
|
48
|
+
* 1. `tsgo` (native TypeScript) — checked first
|
|
49
|
+
* 2. `tsc` (standard TypeScript) — fallback
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Unlike the previous implementation that parsed `package.json` dependencies,
|
|
53
|
+
* this uses runtime tool detection which works correctly with pnpm catalogs,
|
|
54
|
+
* peer dependencies, and hoisted/transitive deps.
|
|
55
|
+
*
|
|
56
|
+
* @param _cwd - Ignored (kept for backward compatibility)
|
|
57
|
+
* @returns The compiler to use, or undefined if neither is available
|
|
58
|
+
*/
|
|
59
|
+
static detectCompiler(_cwd) {
|
|
60
|
+
if (TypeScript.cachedCompilerResult !== null) return TypeScript.cachedCompilerResult.compiler;
|
|
61
|
+
const tsgo = Command.findTool("tsgo");
|
|
62
|
+
if (tsgo.available) {
|
|
63
|
+
TypeScript.cachedCompilerResult = {
|
|
64
|
+
compiler: "tsgo",
|
|
65
|
+
tool: tsgo
|
|
66
|
+
};
|
|
67
|
+
return "tsgo";
|
|
68
|
+
}
|
|
69
|
+
const tsc = Command.findTool("tsc");
|
|
70
|
+
if (tsc.available) {
|
|
71
|
+
TypeScript.cachedCompilerResult = {
|
|
72
|
+
compiler: "tsc",
|
|
73
|
+
tool: tsc
|
|
74
|
+
};
|
|
75
|
+
return "tsc";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if a TypeScript compiler is available.
|
|
80
|
+
*
|
|
81
|
+
* @returns `true` if either tsgo or tsc is available
|
|
82
|
+
*/
|
|
83
|
+
static isAvailable() {
|
|
84
|
+
return TypeScript.detectCompiler() !== void 0;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get the default type checking command for the detected compiler.
|
|
88
|
+
*
|
|
89
|
+
* @remarks
|
|
90
|
+
* Uses the cached `ToolSearchResult` from `detectCompiler()` to build
|
|
91
|
+
* the command string, avoiding a separate package manager detection step.
|
|
92
|
+
*
|
|
93
|
+
* @returns Command string like `pnpm exec tsgo --noEmit` or `tsgo --noEmit`
|
|
94
|
+
* @throws Error if no TypeScript compiler is available
|
|
95
|
+
*/
|
|
96
|
+
static getDefaultTypecheckCommand() {
|
|
97
|
+
if (!TypeScript.detectCompiler() || !TypeScript.cachedCompilerResult) throw new Error("No TypeScript compiler found. Install 'typescript' or '@typescript/native-preview' as a dev dependency.");
|
|
98
|
+
return `${TypeScript.cachedCompilerResult.tool.command} --noEmit`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clear the cached compiler detection result.
|
|
102
|
+
* Useful for testing or when the environment changes.
|
|
103
|
+
*/
|
|
104
|
+
static clearCache() {
|
|
105
|
+
TypeScript.cachedCompilerResult = null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Pre-configured handler with default options.
|
|
109
|
+
*/
|
|
110
|
+
static handler = TypeScript.create();
|
|
111
|
+
/**
|
|
112
|
+
* Create a handler with custom options.
|
|
113
|
+
*
|
|
114
|
+
* @param options - Configuration options
|
|
115
|
+
* @returns A lint-staged compatible handler function
|
|
116
|
+
*/
|
|
117
|
+
static create(options = {}) {
|
|
118
|
+
const excludes = options.exclude ?? [...TypeScript.defaultExcludes];
|
|
119
|
+
const skipTypecheck = options.skipTypecheck ?? false;
|
|
120
|
+
let typecheckCommand;
|
|
121
|
+
const getTypecheckCommand = () => {
|
|
122
|
+
if (typecheckCommand === void 0) typecheckCommand = options.typecheckCommand ?? TypeScript.getDefaultTypecheckCommand();
|
|
123
|
+
return typecheckCommand;
|
|
124
|
+
};
|
|
125
|
+
return (filenames) => {
|
|
126
|
+
if (Filter.exclude(filenames, excludes).length === 0) return [];
|
|
127
|
+
if (!skipTypecheck) return [getTypecheckCommand()];
|
|
128
|
+
return [];
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { TypeScript };
|