sweepi 0.0.6 → 0.0.7

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 CHANGED
@@ -5,11 +5,19 @@ Run Sweepit lint rules against a project without changing that project's depende
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
- npx sweepi <project-dir>
8
+ npx sweepi [project-dir]
9
9
  ```
10
10
 
11
11
  If `~/.sweepi` has not been initialized yet, Sweepi will initialize it first.
12
12
 
13
+ By default, Sweepi lints changed files only (staged, unstaged, and untracked), limited to `.ts` and `.tsx`.
14
+
15
+ Use `--all` to lint all TypeScript files in the project:
16
+
17
+ ```bash
18
+ npx sweepi [project-dir] --all
19
+ ```
20
+
13
21
  ## Explicit initialization
14
22
 
15
23
  ```bash
@@ -26,7 +34,7 @@ This creates `~/.sweepi`, writes `~/.sweepi/eslint.config.mjs`, and installs:
26
34
  Sweepi executes ESLint from the private toolchain directory:
27
35
 
28
36
  ```bash
29
- ~/.sweepi/node_modules/.bin/eslint --config ~/.sweepi/eslint.config.mjs <project-dir>
37
+ ~/.sweepi/node_modules/.bin/eslint --config ~/.sweepi/eslint.config.mjs <changed-files>
30
38
  ```
31
39
 
32
40
  This keeps project dependencies and lockfiles untouched.
@@ -22,7 +22,10 @@ var TOOLCHAIN_PACKAGE_JSON_CONTENT = JSON.stringify(
22
22
  );
23
23
  var TOOLCHAIN_CONFIG_CONTENT = `import sweepitPlugin from 'eslint-plugin-sweepit';
24
24
 
25
+ const files = ['**/*.ts', '**/*.tsx'];
25
26
  const ignores = [
27
+ '**/*.test.*',
28
+ '**/*.spec.*',
26
29
  '**/node_modules/**',
27
30
  '**/.next/**',
28
31
  '**/dist/**',
@@ -32,7 +35,13 @@ const ignores = [
32
35
  '**/out/**',
33
36
  ];
34
37
 
35
- export default [{ ignores }, ...sweepitPlugin.configs.core, ...sweepitPlugin.configs.react];
38
+ const withFiles = (config) => ({ ...config, files });
39
+
40
+ export default [
41
+ { ignores },
42
+ ...sweepitPlugin.configs.core.map(withFiles),
43
+ ...sweepitPlugin.configs.react.map(withFiles),
44
+ ];
36
45
  `;
37
46
  async function initializeToolchain(options = {}) {
38
47
  assertSupportedNodeVersion();
@@ -101,7 +110,9 @@ async function runSweepi(projectDirectory, options = {}) {
101
110
  );
102
111
  const configPath = path.join(toolchainDirectory, TOOLCHAIN_CONFIG_NAME);
103
112
  const runLintCommand = options.runLintCommand ?? runLintCommandWithExecutable;
113
+ const listChangedFiles = options.listChangedFiles ?? listChangedFilesFromGit;
104
114
  const onStatus = options.onStatus;
115
+ const lintAllFiles = options.all === true;
105
116
  const eslintInstalled = await pathExists(eslintBinaryPath);
106
117
  const pluginInstalled = await pathExists(pluginPackagePath);
107
118
  const configInstalled = await pathExists(configPath);
@@ -111,12 +122,70 @@ async function runSweepi(projectDirectory, options = {}) {
111
122
  );
112
123
  }
113
124
  onStatus?.(`Using Sweepi toolchain in ${toolchainDirectory}`);
125
+ if (!lintAllFiles) {
126
+ const changedFiles = await listChangedFiles(resolvedProjectDirectory);
127
+ if (changedFiles.length === 0) {
128
+ onStatus?.("No changed files to lint.");
129
+ return 0;
130
+ }
131
+ return runLintCommand(
132
+ eslintBinaryPath,
133
+ [
134
+ "--config",
135
+ configPath,
136
+ "--no-error-on-unmatched-pattern",
137
+ ...changedFiles.map((filePath) => path.resolve(resolvedProjectDirectory, filePath))
138
+ ],
139
+ resolvedProjectDirectory
140
+ );
141
+ }
114
142
  return runLintCommand(
115
143
  eslintBinaryPath,
116
144
  ["--config", configPath, resolvedProjectDirectory],
117
145
  resolvedProjectDirectory
118
146
  );
119
147
  }
148
+ async function listChangedFilesFromGit(projectDirectory) {
149
+ const [unstagedFiles, stagedFiles, untrackedFiles] = await Promise.all([
150
+ runGitListCommand(projectDirectory, ["diff", "--name-only", "--diff-filter=ACMR"]),
151
+ runGitListCommand(projectDirectory, ["diff", "--cached", "--name-only", "--diff-filter=ACMR"]),
152
+ runGitListCommand(projectDirectory, ["ls-files", "--others", "--exclude-standard"])
153
+ ]);
154
+ return Array.from(/* @__PURE__ */ new Set([...unstagedFiles, ...stagedFiles, ...untrackedFiles]));
155
+ }
156
+ function runGitListCommand(projectDirectory, args) {
157
+ return new Promise((resolve2, reject) => {
158
+ const child = childProcess.spawn("git", args, {
159
+ cwd: projectDirectory,
160
+ stdio: ["ignore", "pipe", "pipe"],
161
+ env: process.env
162
+ });
163
+ let output = "";
164
+ let errorOutput = "";
165
+ child.stdout.on("data", (chunk) => {
166
+ output += chunk.toString();
167
+ });
168
+ child.stderr.on("data", (chunk) => {
169
+ errorOutput += chunk.toString();
170
+ });
171
+ child.on("error", (error) => {
172
+ reject(error);
173
+ });
174
+ child.on("exit", (code) => {
175
+ if (code !== 0) {
176
+ reject(
177
+ new Error(
178
+ `Failed to list changed files with "git ${args.join(" ")}" in ${projectDirectory}.
179
+ ${errorOutput.trim()}`
180
+ )
181
+ );
182
+ return;
183
+ }
184
+ const files = output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
185
+ resolve2(files);
186
+ });
187
+ });
188
+ }
120
189
  async function ensureFile(filePath, content) {
121
190
  const exists = await pathExists(filePath);
122
191
  if (!exists) {
package/dist/cli.js CHANGED
@@ -2,18 +2,17 @@
2
2
  import {
3
3
  initializeToolchain,
4
4
  runSweepi
5
- } from "./chunk-GTTA7GGB.js";
5
+ } from "./chunk-BWQN4NL3.js";
6
6
 
7
7
  // src/cli.ts
8
8
  async function run() {
9
- const command = process.argv[2];
10
- if (command === void 0 || command === "--help" || command === "-h") {
9
+ const [firstArgument, ...restArguments] = process.argv.slice(2);
10
+ if (firstArgument === void 0 || firstArgument === "--help" || firstArgument === "-h") {
11
11
  printHelp();
12
12
  return;
13
13
  }
14
- if (command === "init") {
15
- const initArguments = process.argv.slice(3);
16
- const forceReset = parseForceResetOption(initArguments);
14
+ if (firstArgument === "init") {
15
+ const forceReset = parseForceResetOption(restArguments);
17
16
  const initialization = await initializeToolchain({
18
17
  onStatus: logStatus,
19
18
  forceReset
@@ -31,21 +30,22 @@ async function run() {
31
30
  );
32
31
  return;
33
32
  }
34
- if (command.startsWith("-")) {
35
- throw new Error(`Unknown flag "${command}". Try "sweepi --help".`);
36
- }
37
- const lintExitCode = await runSweepi(command, {
38
- onStatus: logStatus
33
+ const runArguments = [firstArgument, ...restArguments];
34
+ const parsedRunOptions = parseRunOptions(runArguments);
35
+ const lintExitCode = await runSweepi(parsedRunOptions.projectDirectory, {
36
+ onStatus: logStatus,
37
+ all: parsedRunOptions.all
39
38
  });
40
39
  process.exitCode = lintExitCode;
41
40
  }
42
41
  function printHelp() {
43
42
  process.stdout.write(`Usage:
44
- sweepi <project-dir>
43
+ sweepi [project-dir] [--all]
45
44
  sweepi init
46
45
 
47
46
  Commands:
48
- <project-dir> Run eslint using ~/.sweepi (run "sweepi init" first)
47
+ [project-dir] Run eslint on changed ts/tsx files (default: current directory)
48
+ --all Run eslint on all ts/tsx files
49
49
  init [--force, -f] Create ~/.sweepi and install rules
50
50
 
51
51
  Tip:
@@ -67,6 +67,27 @@ function parseForceResetOption(argumentsList) {
67
67
  }
68
68
  return forceReset;
69
69
  }
70
+ function parseRunOptions(argumentsList) {
71
+ let projectDirectory = ".";
72
+ let all = false;
73
+ for (const argument of argumentsList) {
74
+ if (argument === "--all") {
75
+ all = true;
76
+ continue;
77
+ }
78
+ if (argument.startsWith("-")) {
79
+ throw new Error(`Unknown flag "${argument}". Try "sweepi --help".`);
80
+ }
81
+ if (projectDirectory !== ".") {
82
+ throw new Error(`Unexpected argument "${argument}". Try "sweepi --help".`);
83
+ }
84
+ projectDirectory = argument;
85
+ }
86
+ return {
87
+ projectDirectory,
88
+ all
89
+ };
90
+ }
70
91
  try {
71
92
  await run();
72
93
  } catch (error) {
package/dist/index.d.ts CHANGED
@@ -11,7 +11,9 @@ interface InitializeToolchainResult {
11
11
  interface RunSweepiOptions {
12
12
  homeDirectory?: string;
13
13
  runLintCommand?: (command: string, args: string[], cwd: string) => Promise<number>;
14
+ listChangedFiles?: (projectDirectory: string) => Promise<string[]>;
14
15
  onStatus?: (message: string) => void;
16
+ all?: boolean;
15
17
  }
16
18
  declare function initializeToolchain(options?: InitializeToolchainOptions): Promise<InitializeToolchainResult>;
17
19
  declare function runSweepi(projectDirectory: string, options?: RunSweepiOptions): Promise<number>;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  initializeToolchain,
3
3
  runSweepi
4
- } from "./chunk-GTTA7GGB.js";
4
+ } from "./chunk-BWQN4NL3.js";
5
5
  export {
6
6
  initializeToolchain,
7
7
  runSweepi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sweepi",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Run Sweepit lint rules without modifying project dependencies.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,5 +33,5 @@
33
33
  "typescript": "^5.9.2",
34
34
  "vitest": "^2.1.3"
35
35
  },
36
- "gitHead": "fe20d03de681ab0ca5c0e7c9b074d17fe8b53f5d"
36
+ "gitHead": "1d3f7a500a44c4caff15c44b5b0cd63df3e2f87a"
37
37
  }