stdin-glob 1.3.0 → 1.4.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 CHANGED
@@ -31,6 +31,7 @@ This pipes all relevant TypeScript/TSX files directly into my clipboard, ready t
31
31
  - Support for absolute or relative paths
32
32
  - Option to show only file paths without content
33
33
  - **Intelligent handling of binary files** - shows metadata instead of attempting to display unreadable content
34
+ - **Automatic .gitignore filtering** - respects your project's ignore rules by default
34
35
  - Written in TypeScript
35
36
 
36
37
  ## Installation
@@ -47,15 +48,16 @@ stdin-glob [options] [patterns...]
47
48
 
48
49
  ### Options
49
50
 
50
- | Option | Description |
51
- | --------------------- | --------------------------------------------------------------------- |
52
- | `--no-content` | Do not show file contents, only list matching paths |
53
- | `--absolute` | Show absolute paths for entries |
54
- | `-c, --copy` | Copy the output to clipboard instead of printing to console |
55
- | `-m, --max-lines <n>` | Show only the first N lines of each file (shows full file if omitted) |
56
- | `-n, --line-numbers` | Display line numbers next to each line, like in IDE sidebars |
57
- | `-V, --version` | Output the version number |
58
- | `-h, --help` | Display help information |
51
+ | Option | Description |
52
+ | --------------------- | --------------------------------------------------------------------------- |
53
+ | `--no-content` | Do not show file contents, only list matching paths |
54
+ | `--absolute` | Show absolute paths for entries |
55
+ | `-c, --copy` | Copy the output to clipboard instead of printing to console |
56
+ | `-m, --max-lines <n>` | Show only the first N lines of each file (shows full file if omitted) |
57
+ | `-n, --line-numbers` | Display line numbers next to each line, like in IDE sidebars |
58
+ | `--no-gitignore` | Disable .gitignore filtering (include files that would normally be ignored) |
59
+ | `-V, --version` | Output the version number |
60
+ | `-h, --help` | Display help information |
59
61
 
60
62
  ### Arguments
61
63
 
@@ -251,3 +253,20 @@ stdin-glob "src/**/*.ts" --no-content | pbcopy
251
253
  stdin-glob "src/**/*.ts" --content
252
254
  stdin-glob "src/**/*.ts" --copy
253
255
  ```
256
+
257
+
258
+ ### .gitignore Support
259
+
260
+ By default, `stdin-glob` automatically respects your project's `.gitignore` rules. This means files and directories listed in `.gitignore` won't appear in the output. This is especially useful when you want to avoid including build artifacts, dependencies, or environment files in your context.
261
+
262
+ The gitignore pattern matching implementation is based on the official [gitignore pattern format documentation](https://git-scm.com/docs/gitignore#_pattern_format), ensuring compatibility with how git itself handles ignore rules.
263
+
264
+ #### Including ignored files
265
+
266
+ If you need to include files that would normally be ignored, use the `--no-gitignore` flag:
267
+
268
+ ```bash
269
+ stdin-glob "dist/**/*.js" --no-gitignore
270
+ ```
271
+
272
+ This disables all `.gitignore` filtering and includes every file matching your patterns.
package/dist/index.js CHANGED
@@ -9,8 +9,10 @@ const promises_1 = require("fs/promises");
9
9
  const fast_glob_1 = __importDefault(require("fast-glob"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const clipboardy_1 = __importDefault(require("clipboardy"));
12
+ const ignore_1 = __importDefault(require("ignore"));
12
13
  const binary_1 = require("./utils/binary");
13
14
  const pipes_1 = require("./utils/pipes");
15
+ const gitignore_1 = require("./utils/gitignore");
14
16
  const program = new commander_1.Command();
15
17
  program
16
18
  .name('stdin-glob')
@@ -25,25 +27,35 @@ program
25
27
  return parseInt(value);
26
28
  })
27
29
  .option('-n, --line-numbers', 'Show line numbers next to each line, like in IDE sidebars', false)
30
+ .option('--no-gitignore', 'Disable .gitignore filtering (include files that would normally be ignored)')
28
31
  .argument('[patterns...]', 'Glob patterns to match files')
29
32
  .action(async (patterns, options) => {
30
33
  if (patterns.length === 0) {
31
34
  console.error('Error: No patterns provided.');
32
35
  process.exit(1);
33
36
  }
34
- //expand glob
35
- const files = await (0, fast_glob_1.default)(patterns, {
37
+ // Expand glob
38
+ let files = await (0, fast_glob_1.default)(patterns, {
36
39
  onlyFiles: true,
37
- absolute: options.absolute ?? false,
40
+ dot: true,
41
+ absolute: false,
38
42
  });
39
43
  if (files.length === 0) {
40
44
  console.error('No files matched the given patterns.');
41
45
  process.exit(1);
42
46
  }
47
+ // Apply gitignore filtering if not disabled
48
+ if (options.gitignore) {
49
+ files = await filterByGitignore(files);
50
+ if (files.length === 0) {
51
+ console.error('No files remained after applying .gitignore rules.');
52
+ process.exit(1);
53
+ }
54
+ }
43
55
  let output = '';
44
56
  for (const file of files) {
45
57
  if (options.content) {
46
- const fileOutput = await getFileContent(file, options.maxLines ?? undefined, options.lineNumbers ?? false);
58
+ const fileOutput = await getFileContent(options.absolute ? path_1.default.join(process.cwd(), file) : file, options.maxLines ?? undefined, options.lineNumbers ?? false);
47
59
  output += fileOutput;
48
60
  }
49
61
  else {
@@ -65,6 +77,29 @@ program
65
77
  }
66
78
  });
67
79
  program.parse(process.argv);
80
+ /**
81
+ * Filter files by .gitignore rules recursively
82
+ */
83
+ const filterByGitignore = async (files) => {
84
+ try {
85
+ // Find all .gitignore files in the project
86
+ const gitignoreFiles = await (0, gitignore_1.findGitignoreFiles)();
87
+ if (gitignoreFiles.length === 0) {
88
+ return files;
89
+ }
90
+ // Create ignore instance with all rules
91
+ const ig = (0, ignore_1.default)().add(await (0, gitignore_1.loadGitignoreRules)(gitignoreFiles));
92
+ return files.filter((file) => {
93
+ // Get relative path from the root where gitignore rules apply
94
+ const relativePath = path_1.default.relative(process.cwd(), file);
95
+ return !ig.ignores(relativePath);
96
+ });
97
+ }
98
+ catch (error) {
99
+ console.warn('Warning: Error processing .gitignore files, proceeding without filtering:', error);
100
+ return files;
101
+ }
102
+ };
68
103
  /**
69
104
  * Find the maximum number of consecutive backticks in a string
70
105
  */
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Find all .gitignore files in the project
3
+ */
4
+ export declare const findGitignoreFiles: () => Promise<string[]>;
5
+ /**
6
+ * Load and combine rules from recursive/multiple .gitignore files
7
+ * @see https://git-scm.com/docs/gitignore#_pattern_format
8
+ */
9
+ export declare const loadGitignoreRules: (gitignoreFiles: string[]) => Promise<string[]>;
10
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadGitignoreRules = exports.findGitignoreFiles = void 0;
7
+ const promises_1 = require("fs/promises");
8
+ const fast_glob_1 = __importDefault(require("fast-glob"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * Find all .gitignore files in the project
12
+ */
13
+ const findGitignoreFiles = async () => {
14
+ try {
15
+ const files = await (0, fast_glob_1.default)('**/.gitignore', {
16
+ cwd: process.cwd(),
17
+ ignore: ['**/node_modules/**'],
18
+ });
19
+ return files;
20
+ }
21
+ catch (error) {
22
+ console.warn('Warning: Error finding .gitignore files:', error);
23
+ return [];
24
+ }
25
+ };
26
+ exports.findGitignoreFiles = findGitignoreFiles;
27
+ /**
28
+ * Parse a .gitignore file and return its rules
29
+ */
30
+ const parseGitignore = (content) => {
31
+ return content
32
+ .split('\n')
33
+ .map((line) => line.trim())
34
+ .filter((line) => line && // Not empty
35
+ !line.startsWith('#'));
36
+ };
37
+ /**
38
+ * Load and combine rules from recursive/multiple .gitignore files
39
+ * @see https://git-scm.com/docs/gitignore#_pattern_format
40
+ */
41
+ const loadGitignoreRules = async (gitignoreFiles) => {
42
+ const allRules = [];
43
+ for (const file of gitignoreFiles) {
44
+ try {
45
+ const content = await (0, promises_1.readFile)(file, 'utf-8');
46
+ const rules = parseGitignore(content);
47
+ // directory of this .gitignore
48
+ const gitignoreDir = path_1.default.dirname(file);
49
+ // to be relative to the gitignore location
50
+ const dirRelativeRules = rules.map((rule) => {
51
+ //handle negations
52
+ if (rule.startsWith('!')) {
53
+ return `!${path_1.default.join(gitignoreDir, rule.slice(1))}`;
54
+ }
55
+ return path_1.default.join(gitignoreDir, rule);
56
+ });
57
+ allRules.push(...dirRelativeRules);
58
+ }
59
+ catch (error) {
60
+ console.warn(`Warning: Error reading .gitignore file ${file}:`, error);
61
+ }
62
+ }
63
+ return allRules;
64
+ };
65
+ exports.loadGitignoreRules = loadGitignoreRules;
66
+ //# sourceMappingURL=gitignore.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stdin-glob",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Expand glob patterns and output file contents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -36,7 +36,8 @@
36
36
  "dependencies": {
37
37
  "clipboardy": "^5.3.1",
38
38
  "commander": "^11.1.0",
39
- "fast-glob": "^3.3.3"
39
+ "fast-glob": "^3.3.3",
40
+ "ignore": "^7.0.5"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/node": "^25.3.3",