stdin-glob 1.2.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
@@ -30,6 +30,8 @@ This pipes all relevant TypeScript/TSX files directly into my clipboard, ready t
30
30
  - **Auto-copy output** directly to clipboard with `--copy` flag
31
31
  - Support for absolute or relative paths
32
32
  - Option to show only file paths without content
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
33
35
  - Written in TypeScript
34
36
 
35
37
  ## Installation
@@ -46,15 +48,16 @@ stdin-glob [options] [patterns...]
46
48
 
47
49
  ### Options
48
50
 
49
- | Option | Description |
50
- | --------------------- | --------------------------------------------------------------------- |
51
- | `--no-content` | Do not show file contents, only list matching paths |
52
- | `--absolute` | Show absolute paths for entries |
53
- | `-c, --copy` | Copy the output to clipboard instead of printing to console |
54
- | `-m, --max-lines <n>` | Show only the first N lines of each file (shows full file if omitted) |
55
- | `-n, --line-numbers` | Display line numbers next to each line, like in IDE sidebars |
56
- | `-V, --version` | Output the version number |
57
- | `-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 |
58
61
 
59
62
  ### Arguments
60
63
 
@@ -221,6 +224,17 @@ Output:
221
224
  /home/pedrito/project/src/types/index.ts
222
225
  ```
223
226
 
227
+ ### Binary file handling
228
+
229
+ When encountering binary files (like images, compiled binaries, etc.), the tool safely displays metadata instead of attempting to show unreadable content:
230
+
231
+ ````
232
+ ```png
233
+ // assets/logo.png
234
+ // [BINARY FILE] - Size: 0.024 MB
235
+ ```
236
+ ````
237
+
224
238
  ### Integration with other commands
225
239
 
226
240
  Use with grep to search for specific content:
@@ -239,3 +253,20 @@ stdin-glob "src/**/*.ts" --no-content | pbcopy
239
253
  stdin-glob "src/**/*.ts" --content
240
254
  stdin-glob "src/**/*.ts" --copy
241
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,6 +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"));
13
+ const binary_1 = require("./utils/binary");
14
+ const pipes_1 = require("./utils/pipes");
15
+ const gitignore_1 = require("./utils/gitignore");
12
16
  const program = new commander_1.Command();
13
17
  program
14
18
  .name('stdin-glob')
@@ -23,25 +27,35 @@ program
23
27
  return parseInt(value);
24
28
  })
25
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)')
26
31
  .argument('[patterns...]', 'Glob patterns to match files')
27
32
  .action(async (patterns, options) => {
28
33
  if (patterns.length === 0) {
29
34
  console.error('Error: No patterns provided.');
30
35
  process.exit(1);
31
36
  }
32
- //expand glob
33
- const files = await (0, fast_glob_1.default)(patterns, {
37
+ // Expand glob
38
+ let files = await (0, fast_glob_1.default)(patterns, {
34
39
  onlyFiles: true,
35
- absolute: options.absolute ?? false,
40
+ dot: true,
41
+ absolute: false,
36
42
  });
37
43
  if (files.length === 0) {
38
44
  console.error('No files matched the given patterns.');
39
45
  process.exit(1);
40
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
+ }
41
55
  let output = '';
42
56
  for (const file of files) {
43
57
  if (options.content) {
44
- 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);
45
59
  output += fileOutput;
46
60
  }
47
61
  else {
@@ -63,6 +77,29 @@ program
63
77
  }
64
78
  });
65
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
+ };
66
103
  /**
67
104
  * Find the maximum number of consecutive backticks in a string
68
105
  */
@@ -72,21 +109,6 @@ const findMaxConsecutiveBackticks = (str) => {
72
109
  return 0;
73
110
  return Math.max(...matches.map((m) => m.length));
74
111
  };
75
- /**
76
- * Add line numbers to content
77
- */
78
- const addLineNumbers = (content, startLine = 1) => {
79
- const lines = content.split('\n');
80
- // calculate width of bar
81
- const paddingWidth = (startLine + lines.length - 1).toString().length;
82
- return lines
83
- .map((line, index) => {
84
- const lineNumber = startLine + index;
85
- const paddedNumber = lineNumber.toString().padStart(paddingWidth, ' ');
86
- return `${paddedNumber} | ${line}`;
87
- })
88
- .join('\n');
89
- };
90
112
  /**
91
113
  * Get file content with markdown format
92
114
  * @param filePath - The path to the file
@@ -96,13 +118,28 @@ const addLineNumbers = (content, startLine = 1) => {
96
118
  */
97
119
  const getFileContent = async (filePath, maxLines, showLineNumbers) => {
98
120
  try {
99
- const content = await (0, promises_1.readFile)(filePath, 'utf-8');
121
+ const fileBuffer = await (0, promises_1.readFile)(filePath);
122
+ if ((0, binary_1.isBinaryFile)(fileBuffer)) {
123
+ // is binary!! not show content
124
+ const stats = await (0, promises_1.stat)(filePath);
125
+ const fileSize = stats.size;
126
+ const extension = path_1.default.extname(filePath).replace('.', '');
127
+ const sizeFormatted = (0, pipes_1.formatSizeInMB)(fileSize);
128
+ return ('```' +
129
+ extension +
130
+ '\n' +
131
+ `// ${filePath}\n` +
132
+ `// [BINARY FILE] - Size: ${sizeFormatted}\n` +
133
+ '```\n\n');
134
+ }
135
+ // is text file!! proceed with normal processing
136
+ const content = fileBuffer.toString('utf-8');
100
137
  const lines = content.split('\n');
101
138
  // maxLines if exists
102
139
  const linesToShow = maxLines ? lines.slice(0, maxLines) : lines;
103
140
  let contentToShow = linesToShow.join('\n');
104
141
  if (showLineNumbers)
105
- contentToShow = addLineNumbers(linesToShow.join('\n'), 1);
142
+ contentToShow = (0, pipes_1.addLineNumbers)(linesToShow.join('\n'), 1);
106
143
  const extension = path_1.default.extname(filePath).replace('.', '');
107
144
  const maxBackticks = findMaxConsecutiveBackticks(content);
108
145
  const wrapper = '`'.repeat(Math.max(3, maxBackticks + 1));
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Check if a file is binary
3
+ * @see https://gist.github.com/magnetikonline/7a21ec5f5bcdbf7adb92f9d617e6198f
4
+ */
5
+ export declare const isBinaryFile: (buffer: Buffer) => boolean;
6
+ //# sourceMappingURL=binary.d.ts.map
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isBinaryFile = void 0;
4
+ /**
5
+ * Check if a file is binary
6
+ * @see https://gist.github.com/magnetikonline/7a21ec5f5bcdbf7adb92f9d617e6198f
7
+ */
8
+ const isBinaryFile = (buffer) => {
9
+ // check for null bytes or control characters that indicate binary
10
+ for (let i = 0; i < Math.min(buffer.length, 512); i++) {
11
+ const byte = buffer[i];
12
+ // Null byte or control character
13
+ if (byte === 0 || (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13)) {
14
+ return true;
15
+ }
16
+ }
17
+ return false;
18
+ };
19
+ exports.isBinaryFile = isBinaryFile;
20
+ //# sourceMappingURL=binary.js.map
@@ -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
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Add line numbers to content
3
+ */
4
+ export declare const addLineNumbers: (content: string, startLine?: number) => string;
5
+ /**
6
+ * Format file size in MB with 3 decimal places
7
+ */
8
+ export declare const formatSizeInMB: (bytes: number) => string;
9
+ //# sourceMappingURL=pipes.d.ts.map
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSizeInMB = exports.addLineNumbers = void 0;
4
+ /**
5
+ * Add line numbers to content
6
+ */
7
+ const addLineNumbers = (content, startLine = 1) => {
8
+ const lines = content.split('\n');
9
+ // calculate width of bar
10
+ const paddingWidth = (startLine + lines.length - 1).toString().length;
11
+ return lines
12
+ .map((line, index) => {
13
+ const lineNumber = startLine + index;
14
+ const paddedNumber = lineNumber.toString().padStart(paddingWidth, ' ');
15
+ return `${paddedNumber} | ${line}`;
16
+ })
17
+ .join('\n');
18
+ };
19
+ exports.addLineNumbers = addLineNumbers;
20
+ /**
21
+ * Format file size in MB with 3 decimal places
22
+ */
23
+ const formatSizeInMB = (bytes) => {
24
+ const mb = bytes / (1024 * 1024);
25
+ return mb.toFixed(3) + ' MB';
26
+ };
27
+ exports.formatSizeInMB = formatSizeInMB;
28
+ //# sourceMappingURL=pipes.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stdin-glob",
3
- "version": "1.2.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",
@@ -12,6 +12,10 @@
12
12
  "prepare": "npm run build",
13
13
  "prepublishOnly": "npm run build"
14
14
  },
15
+ "files": [
16
+ "dist/**/*.js",
17
+ "dist/**/*.d.ts"
18
+ ],
15
19
  "keywords": [
16
20
  "glob",
17
21
  "stdin",
@@ -32,7 +36,8 @@
32
36
  "dependencies": {
33
37
  "clipboardy": "^5.3.1",
34
38
  "commander": "^11.1.0",
35
- "fast-glob": "^3.3.3"
39
+ "fast-glob": "^3.3.3",
40
+ "ignore": "^7.0.5"
36
41
  },
37
42
  "devDependencies": {
38
43
  "@types/node": "^25.3.3",
@@ -1,26 +0,0 @@
1
- # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
- # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
-
4
- name: NPM Package
5
-
6
- on:
7
- push:
8
- tags:
9
- - 'v*'
10
-
11
- permissions:
12
- id-token: write # Required for OIDC
13
- contents: read
14
-
15
- jobs:
16
- publish:
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@v4
20
- - uses: actions/setup-node@v4
21
- with:
22
- node-version: '24'
23
- registry-url: 'https://registry.npmjs.org'
24
-
25
- - run: npm install
26
- - run: npm publish
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/src/index.ts DELETED
@@ -1,164 +0,0 @@
1
- import { Command } from 'commander';
2
- import { version } from '../package.json';
3
- import { readFile } from 'fs/promises';
4
- import glob from 'fast-glob';
5
- import path from 'path';
6
- import clipboard from 'clipboardy';
7
-
8
- interface Options {
9
- content?: boolean;
10
- absolute?: boolean;
11
- copy?: boolean;
12
- maxLines?: number;
13
- lineNumbers?: boolean; // Nueva opción
14
- }
15
-
16
- const program = new Command();
17
-
18
- program
19
- .name('stdin-glob')
20
- .description('Expand glob patterns and output file contents and paths')
21
- .version(version)
22
- .option('--no-content', 'Do not show file contents, only list matching paths')
23
- .option('--absolute', 'Show the absolute path for entries', false)
24
- .option(
25
- '-c, --copy',
26
- 'Copy the output to clipboard instead of printing to console',
27
- false,
28
- )
29
- .option(
30
- '-m, --max-lines <int>',
31
- 'Show a limited number of lines in the file. If you not provide a number of lines it will show the full file content.',
32
- (value) => {
33
- if (isNaN(parseInt(value))) throw new Error('Lines must be a number');
34
- return parseInt(value);
35
- },
36
- )
37
- .option(
38
- '-n, --line-numbers',
39
- 'Show line numbers next to each line, like in IDE sidebars',
40
- false,
41
- )
42
- .argument('[patterns...]', 'Glob patterns to match files')
43
- .action(async (patterns: string[], options: Options) => {
44
- if (patterns.length === 0) {
45
- console.error('Error: No patterns provided.');
46
- process.exit(1);
47
- }
48
-
49
- //expand glob
50
- const files = await glob(patterns, {
51
- onlyFiles: true,
52
- absolute: options.absolute ?? false,
53
- });
54
-
55
- if (files.length === 0) {
56
- console.error('No files matched the given patterns.');
57
- process.exit(1);
58
- }
59
-
60
- let output = '';
61
-
62
- for (const file of files) {
63
- if (options.content) {
64
- const fileOutput = await getFileContent(
65
- file,
66
- options.maxLines ?? undefined,
67
- options.lineNumbers ?? false,
68
- );
69
- output += fileOutput;
70
- } else {
71
- output += file + '\n';
72
- }
73
- }
74
-
75
- if (options.copy) {
76
- try {
77
- await clipboard.write(output.trim());
78
- console.log('-> Output copied to clipboard successfully!');
79
- } catch (error) {
80
- console.error('-X Error copying to clipboard:', error);
81
- process.exit(1);
82
- }
83
- } else {
84
- console.log(output.trim());
85
- }
86
- });
87
-
88
- program.parse(process.argv);
89
-
90
- /**
91
- * Find the maximum number of consecutive backticks in a string
92
- */
93
- const findMaxConsecutiveBackticks = (str: string): number => {
94
- const matches = str.match(/`+/g);
95
- if (!matches) return 0;
96
- return Math.max(...matches.map((m) => m.length));
97
- };
98
-
99
- /**
100
- * Add line numbers to content
101
- */
102
- const addLineNumbers = (content: string, startLine: number = 1): string => {
103
- const lines = content.split('\n');
104
-
105
- // calculate width of bar
106
- const paddingWidth = (startLine + lines.length - 1).toString().length;
107
-
108
- return lines
109
- .map((line, index) => {
110
- const lineNumber = startLine + index;
111
- const paddedNumber = lineNumber.toString().padStart(paddingWidth, ' ');
112
- return `${paddedNumber} | ${line}`;
113
- })
114
- .join('\n');
115
- };
116
-
117
- /**
118
- * Get file content with markdown format
119
- * @param filePath - The path to the file
120
- * @param maxLines - The number of lines to show. If you not provide a number of lines it will show the full file content.
121
- * @param showLineNumbers - Whether to show line numbers
122
- * @returns The file content with markdown format
123
- */
124
- const getFileContent = async (
125
- filePath: string,
126
- maxLines?: number,
127
- showLineNumbers?: boolean,
128
- ): Promise<string> => {
129
- try {
130
- const content = await readFile(filePath, 'utf-8');
131
- const lines = content.split('\n');
132
-
133
- // maxLines if exists
134
- const linesToShow = maxLines ? lines.slice(0, maxLines) : lines;
135
- let contentToShow = linesToShow.join('\n');
136
-
137
- if (showLineNumbers)
138
- contentToShow = addLineNumbers(linesToShow.join('\n'), 1);
139
-
140
- const extension = path.extname(filePath).replace('.', '');
141
- const maxBackticks = findMaxConsecutiveBackticks(content);
142
- const wrapper = '`'.repeat(Math.max(3, maxBackticks + 1));
143
-
144
- const truncation =
145
- maxLines && lines.length > maxLines
146
- ? `\n// ... (${lines.length - maxLines} more lines truncated)`
147
- : '';
148
-
149
- return (
150
- wrapper +
151
- extension +
152
- '\n' +
153
- `// ${filePath}\n\n` +
154
- contentToShow +
155
- truncation +
156
- '\n' +
157
- wrapper +
158
- '\n\n'
159
- );
160
- } catch (e) {
161
- console.error(`Error reading file ${filePath}:`, e);
162
- return '';
163
- }
164
- };
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "lib": ["ES2020"],
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "declaration": true,
13
- "declarationMap": true,
14
- "sourceMap": true,
15
- "resolveJsonModule": true
16
- },
17
- "include": ["src/**/*"],
18
- "exclude": ["node_modules", "dist"]
19
- }