stdin-glob 1.0.0 → 1.0.5
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/.github/workflows/npm-publish.yml +10 -6
- package/README.md +137 -1
- package/dist/index.js +34 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +39 -10
|
@@ -6,18 +6,22 @@ name: NPM Package
|
|
|
6
6
|
on:
|
|
7
7
|
push:
|
|
8
8
|
branches: [main]
|
|
9
|
+
tags:
|
|
10
|
+
- 'v*'
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write # Required for OIDC
|
|
14
|
+
contents: read
|
|
9
15
|
|
|
10
16
|
jobs:
|
|
11
17
|
publish:
|
|
12
18
|
runs-on: ubuntu-latest
|
|
13
19
|
steps:
|
|
14
20
|
- uses: actions/checkout@v4
|
|
15
|
-
- uses: actions/setup-node@
|
|
21
|
+
- uses: actions/setup-node@v4
|
|
16
22
|
with:
|
|
17
|
-
node-version: '
|
|
23
|
+
node-version: '24'
|
|
24
|
+
registry-url: 'https://registry.npmjs.org'
|
|
18
25
|
|
|
19
26
|
- run: npm install
|
|
20
|
-
|
|
21
|
-
- uses: JS-DevTools/npm-publish@v3
|
|
22
|
-
with:
|
|
23
|
-
token: ${{ secrets.NPM_TOKEN }}
|
|
27
|
+
- run: npm publish
|
package/README.md
CHANGED
|
@@ -1,3 +1,139 @@
|
|
|
1
1
|
# stdin-glob
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/stdin-glob)
|
|
4
|
+
[](https://www.npmjs.com/package/stdin-glob)
|
|
5
|
+
[](https://www.typescriptlang.org)
|
|
6
|
+
[](https://github.com/rodnye/stdin-glob)
|
|
7
|
+
|
|
8
|
+
A simple CLI tool that expands glob patterns and outputs file contents or paths. Perfect for quickly previewing multiple files matching a pattern.
|
|
9
|
+
|
|
10
|
+
## Why?
|
|
11
|
+
|
|
12
|
+
This tool solves a common pain point: **aggregating file contents into a single, coherent output**. Whether you're doing code reviews, documentation, or working with LLMs, having to manually copy-paste multiple files is tedious and error-prone.
|
|
13
|
+
|
|
14
|
+
I created this for my personal workflow when working with Large Language Models (LLMs). Combined with clipboard tools, it lets me instantly gather specific project context:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
stdin-glob "src/**/*.ts" "src/**/*.tsx" | pbcopy # On macOS
|
|
18
|
+
# or
|
|
19
|
+
stdin-glob "src/**/*.js" | xclip -selection clipboard # On Linux
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This pipes all relevant TypeScript/TSX files directly into my clipboard, ready to paste into ChatGPT, Claude, or any other LLM. Perfect for getting targeted, comprehensive context without the friction of opening and copying files one by one.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- Expand glob patterns to find matching files
|
|
27
|
+
- Output file contents with syntax highlighting markers
|
|
28
|
+
- Support for absolute or relative paths
|
|
29
|
+
- Option to show only file paths without content
|
|
30
|
+
- Written in TypeScript
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install -g stdin-glob
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
stdin-glob [options] [patterns...]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Options
|
|
45
|
+
|
|
46
|
+
| Option | Description |
|
|
47
|
+
| --------------- | --------------------------------------------------- |
|
|
48
|
+
| `--no-content` | Do not show file contents, only list matching paths |
|
|
49
|
+
| `--absolute` | Show absolute paths for entries |
|
|
50
|
+
| `-V, --version` | Output the version number |
|
|
51
|
+
| `-h, --help` | Display help information |
|
|
52
|
+
|
|
53
|
+
### Arguments
|
|
54
|
+
|
|
55
|
+
| Argument | Description |
|
|
56
|
+
| ---------- | ------------------------------------------ |
|
|
57
|
+
| `patterns` | Glob patterns to match files (one or more) |
|
|
58
|
+
|
|
59
|
+
## Pattern Syntax
|
|
60
|
+
|
|
61
|
+
This tool uses [fast-glob](https://github.com/mrmlnc/fast-glob) for pattern matching, which supports the feature set of [picomatch](https://github.com/micromatch/picomatch). For detailed information about available globbing features and syntax options, refer to the [picomatch globbing features documentation](https://github.com/micromatch/picomatch?tab=readme-ov-file#globbing-features).
|
|
62
|
+
|
|
63
|
+
## Examples
|
|
64
|
+
|
|
65
|
+
### Basic usage
|
|
66
|
+
|
|
67
|
+
Display contents of all JavaScript files with syntax highlighting markers:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
stdin-glob "src/**/*.js" --content
|
|
71
|
+
# or
|
|
72
|
+
stdin-glob "src/**/*.js"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Output:
|
|
76
|
+
|
|
77
|
+
````
|
|
78
|
+
```js
|
|
79
|
+
// src/index.js
|
|
80
|
+
|
|
81
|
+
console.log('Hello, world!');
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// src/utils/helpers.js
|
|
86
|
+
|
|
87
|
+
function add(a, b) {
|
|
88
|
+
return a + b;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
````
|
|
92
|
+
|
|
93
|
+
### Only list files
|
|
94
|
+
|
|
95
|
+
List all TypeScript files in the src directory without content:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
stdin-glob "src/**/*.ts" --no-content
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Output:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
src/index.ts
|
|
105
|
+
src/utils/helpers.ts
|
|
106
|
+
src/types/index.ts
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Multiple patterns
|
|
110
|
+
|
|
111
|
+
Match files with different extensions:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
stdin-glob "src/**/*.ts" "src/**/*.js" --content
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Absolute paths
|
|
118
|
+
|
|
119
|
+
Show absolute paths instead of relative ones:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
stdin-glob "src/**/*.ts" --absolute --no-content
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Output:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
/home/pedrito/project/src/index.ts
|
|
129
|
+
/home/pedrito/project/src/utils/helpers.ts
|
|
130
|
+
/home/pedrito/project/src/types/index.ts
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Integration with other commands
|
|
134
|
+
|
|
135
|
+
Use with grep to search for specific content:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
stdin-glob "src/**/*.ts" | grep "function"
|
|
139
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const package_json_1 = require("../package.json");
|
|
|
8
8
|
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
|
+
const clipboardy_1 = __importDefault(require("clipboardy"));
|
|
11
12
|
const program = new commander_1.Command();
|
|
12
13
|
program
|
|
13
14
|
.name('stdin-glob')
|
|
@@ -15,6 +16,7 @@ program
|
|
|
15
16
|
.version(package_json_1.version)
|
|
16
17
|
.option('--no-content', 'Do not show file contents, only list matching paths')
|
|
17
18
|
.option('--absolute', 'Show the absolute path for entries')
|
|
19
|
+
.option('-c, --copy', 'Copy the output to clipboard instead of printing to console')
|
|
18
20
|
.argument('[patterns...]', 'Glob patterns to match files')
|
|
19
21
|
.action(async (patterns, options) => {
|
|
20
22
|
if (patterns.length === 0) {
|
|
@@ -30,29 +32,49 @@ program
|
|
|
30
32
|
console.error('No files matched the given patterns.');
|
|
31
33
|
process.exit(1);
|
|
32
34
|
}
|
|
35
|
+
let output = '';
|
|
33
36
|
for (const file of files) {
|
|
34
|
-
if (options.content)
|
|
35
|
-
await
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
if (options.content) {
|
|
38
|
+
const fileOutput = await getFileContent(file);
|
|
39
|
+
output += fileOutput;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
output += file + '\n';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (options.copy) {
|
|
46
|
+
try {
|
|
47
|
+
await clipboardy_1.default.write(output.trim());
|
|
48
|
+
console.log('-> Output copied to clipboard successfully!');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error('-X Error copying to clipboard:', error);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(output.trim());
|
|
38
57
|
}
|
|
39
58
|
});
|
|
40
59
|
program.parse(process.argv);
|
|
41
60
|
/**
|
|
42
|
-
*
|
|
61
|
+
* Get file content with markdown format
|
|
43
62
|
*/
|
|
44
|
-
const
|
|
63
|
+
const getFileContent = async (filePath) => {
|
|
45
64
|
try {
|
|
46
65
|
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
const extension = path_1.default.extname(filePath).replace('.', '');
|
|
67
|
+
return ('```' +
|
|
68
|
+
extension +
|
|
69
|
+
'\n' +
|
|
70
|
+
`// ${filePath}\n\n` +
|
|
71
|
+
content +
|
|
72
|
+
'\n' +
|
|
73
|
+
'```\n\n');
|
|
53
74
|
}
|
|
54
75
|
catch (e) {
|
|
55
76
|
console.error(`Error reading file ${filePath}:`, e);
|
|
77
|
+
return '';
|
|
56
78
|
}
|
|
57
79
|
};
|
|
58
80
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,yCAAoC;AACpC,kDAA0C;AAC1C,0CAAuC;AACvC,0DAA6B;AAC7B,gDAAwB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stdin-glob",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Expand glob patterns and output file contents
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Expand glob patterns and output file contents.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/rodnye/stdin-glob#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"clipboardy": "^5.3.1",
|
|
33
34
|
"commander": "^11.1.0",
|
|
34
35
|
"fast-glob": "^3.3.3"
|
|
35
36
|
},
|
package/src/index.ts
CHANGED
|
@@ -3,10 +3,12 @@ import { version } from '../package.json';
|
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
import glob from 'fast-glob';
|
|
5
5
|
import path from 'path';
|
|
6
|
+
import clipboard from 'clipboardy';
|
|
6
7
|
|
|
7
8
|
interface Options {
|
|
8
9
|
content?: boolean;
|
|
9
10
|
absolute?: boolean;
|
|
11
|
+
copy?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
const program = new Command();
|
|
@@ -17,6 +19,10 @@ program
|
|
|
17
19
|
.version(version)
|
|
18
20
|
.option('--no-content', 'Do not show file contents, only list matching paths')
|
|
19
21
|
.option('--absolute', 'Show the absolute path for entries')
|
|
22
|
+
.option(
|
|
23
|
+
'-c, --copy',
|
|
24
|
+
'Copy the output to clipboard instead of printing to console',
|
|
25
|
+
)
|
|
20
26
|
.argument('[patterns...]', 'Glob patterns to match files')
|
|
21
27
|
.action(async (patterns: string[], options: Options) => {
|
|
22
28
|
if (patterns.length === 0) {
|
|
@@ -35,27 +41,50 @@ program
|
|
|
35
41
|
process.exit(1);
|
|
36
42
|
}
|
|
37
43
|
|
|
44
|
+
let output = '';
|
|
45
|
+
|
|
38
46
|
for (const file of files) {
|
|
39
|
-
if (options.content)
|
|
40
|
-
|
|
47
|
+
if (options.content) {
|
|
48
|
+
const fileOutput = await getFileContent(file);
|
|
49
|
+
output += fileOutput;
|
|
50
|
+
} else {
|
|
51
|
+
output += file + '\n';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.copy) {
|
|
56
|
+
try {
|
|
57
|
+
await clipboard.write(output.trim());
|
|
58
|
+
console.log('-> Output copied to clipboard successfully!');
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('-X Error copying to clipboard:', error);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
console.log(output.trim());
|
|
41
65
|
}
|
|
42
66
|
});
|
|
43
67
|
|
|
44
68
|
program.parse(process.argv);
|
|
45
69
|
|
|
46
70
|
/**
|
|
47
|
-
*
|
|
71
|
+
* Get file content with markdown format
|
|
48
72
|
*/
|
|
49
|
-
const
|
|
73
|
+
const getFileContent = async (filePath: string): Promise<string> => {
|
|
50
74
|
try {
|
|
51
75
|
const content = await readFile(filePath, 'utf-8');
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
const extension = path.extname(filePath).replace('.', '');
|
|
77
|
+
return (
|
|
78
|
+
'```' +
|
|
79
|
+
extension +
|
|
80
|
+
'\n' +
|
|
81
|
+
`// ${filePath}\n\n` +
|
|
82
|
+
content +
|
|
83
|
+
'\n' +
|
|
84
|
+
'```\n\n'
|
|
85
|
+
);
|
|
58
86
|
} catch (e) {
|
|
59
87
|
console.error(`Error reading file ${filePath}:`, e);
|
|
88
|
+
return '';
|
|
60
89
|
}
|
|
61
90
|
};
|