llmview 0.2.0 → 0.3.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 +42 -26
- package/dist/cli.js +22 -121
- package/package.json +27 -19
- package/dist/build.js +0 -116
- package/dist/constants.js +0 -10
- package/dist/ignore.js +0 -77
- package/dist/render-rules.js +0 -111
- package/dist/render.js +0 -51
- package/dist/select.js +0 -52
- package/dist/types.js +0 -2
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# llmview
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generate LLM-friendly context from codebases using repeatable view files.
|
|
4
|
+
|
|
5
|
+
Designed for a middle ground in AI-assisted coding. Rather than copying files manually or relying on an LLM agent to search your codebase, define views once and reuse them as your code evolves. This can often "one-shot" problems by preparing the right context.
|
|
4
6
|
|
|
5
7
|
## Quick start
|
|
6
8
|
|
|
7
9
|
Install from npm
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
npm
|
|
12
|
+
npm i -g llmview
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
Create any number of view files in your project. These can be saved anywhere. For example, a full-stack monorepo:
|
|
@@ -30,23 +32,20 @@ Run `llmview --help` for all options.
|
|
|
30
32
|
|
|
31
33
|
## How it works
|
|
32
34
|
|
|
33
|
-
A view is a list of glob patterns to select.
|
|
35
|
+
A view is a list of glob patterns to select files. Use `**` for recursive matching.
|
|
34
36
|
|
|
35
37
|
```gitignore
|
|
36
38
|
# Code
|
|
37
|
-
backend
|
|
39
|
+
backend/**
|
|
38
40
|
!backend/migrations/**
|
|
39
41
|
|
|
40
42
|
# Docs
|
|
41
43
|
docs/style_guide.md
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
After selecting, it serializes the contents of each file into a LLM-friendly format and prints to stdout.
|
|
46
|
+
After selecting, it outputs the contents of each file into a LLM-friendly format and prints to stdout.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
```
|
|
48
|
+
```xml
|
|
50
49
|
<file path="backend/main.py">
|
|
51
50
|
from flask import Flask
|
|
52
51
|
|
|
@@ -60,9 +59,6 @@ if __name__ == "__main__":
|
|
|
60
59
|
app.run(debug=True)
|
|
61
60
|
|
|
62
61
|
</file>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
```
|
|
66
62
|
<file path="docs/style_guide.md">
|
|
67
63
|
# Style guide
|
|
68
64
|
|
|
@@ -70,14 +66,12 @@ Make no mistakes
|
|
|
70
66
|
|
|
71
67
|
</file>
|
|
72
68
|
```
|
|
73
|
-
````
|
|
74
69
|
|
|
75
|
-
###
|
|
70
|
+
### Include the project directory
|
|
76
71
|
|
|
77
|
-
The `-t` argument includes the file system
|
|
72
|
+
The `-t` argument includes the file system directory for all selected files at the beginning of the result.
|
|
78
73
|
|
|
79
|
-
|
|
80
|
-
```
|
|
74
|
+
```xml
|
|
81
75
|
<directory>
|
|
82
76
|
my_project/
|
|
83
77
|
backend/
|
|
@@ -85,16 +79,38 @@ my_project/
|
|
|
85
79
|
docs/
|
|
86
80
|
style_guide.md
|
|
87
81
|
</directory>
|
|
82
|
+
<file path="backend/main.py">
|
|
83
|
+
...
|
|
88
84
|
```
|
|
89
85
|
|
|
86
|
+
### Include line numbers
|
|
87
|
+
|
|
88
|
+
The `-n` argument includes line numbers in each file, similar to `cat -n`. This uses more tokens, but can also be useful context.
|
|
89
|
+
|
|
90
|
+
### JSON output
|
|
91
|
+
|
|
92
|
+
The `-j` argument outputs the result as JSON instead of XML tags. This can be useful for piping into other tools like `jq`.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
llmview -j .views/backend.llmview | jq '.files[].path'
|
|
90
96
|
```
|
|
91
|
-
<file path="my_project/backend/main.py">
|
|
92
|
-
...
|
|
93
|
-
````
|
|
94
97
|
|
|
95
|
-
|
|
98
|
+
The JSON structure:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"directory": null,
|
|
103
|
+
"files": [
|
|
104
|
+
{
|
|
105
|
+
"path": "backend/main.py",
|
|
106
|
+
"size": 245,
|
|
107
|
+
"content": "..."
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
96
112
|
|
|
97
|
-
The
|
|
113
|
+
The `directory` field is populated when using `-t`.
|
|
98
114
|
|
|
99
115
|
### Only list selected files
|
|
100
116
|
|
|
@@ -104,9 +120,9 @@ The `-l` argument lets you use selected files for something else besides renderi
|
|
|
104
120
|
llmview .views/backend.llmview -l | zip context.zip -@
|
|
105
121
|
```
|
|
106
122
|
|
|
107
|
-
### Using
|
|
123
|
+
### Using as a filter
|
|
108
124
|
|
|
109
|
-
Instead of reading from a view file, you can use it as a filter. For example, to render all the unstaged changes in your repo:
|
|
125
|
+
Instead of reading from a view file, you can use it as a filter by reading from stdin. For example, to render all the unstaged changes in your repo:
|
|
110
126
|
|
|
111
127
|
```bash
|
|
112
128
|
git diff --name-only | llmview -
|
|
@@ -121,9 +137,9 @@ This tool comes with a set of opinionated file renderers based on the file exten
|
|
|
121
137
|
|
|
122
138
|
There is also a max size of 250KB per file. If a code file is larger than that, it is not rendered. (If a CSV file is larger, it's still rendered and just truncated as usual.)
|
|
123
139
|
|
|
124
|
-
##
|
|
140
|
+
## Verbose mode
|
|
125
141
|
|
|
126
|
-
To see what files will be included and an estimate of tokens used,
|
|
142
|
+
To see what files will be included and an estimate of tokens used, use a verbose `-v` command like this:
|
|
127
143
|
|
|
128
144
|
```bash
|
|
129
145
|
llmview -v .views/backend.llmview > /dev/null
|
package/dist/cli.js
CHANGED
|
@@ -1,82 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
const fs = __importStar(require("fs/promises"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const build_1 = require("./build");
|
|
40
|
-
const render_1 = require("./render");
|
|
41
|
-
const select_1 = require("./select");
|
|
42
|
-
const constants_1 = require("./constants");
|
|
43
|
-
const readStdin = () => {
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
const chunks = [];
|
|
46
|
-
process.stdin.on('data', (chunk) => chunks.push(chunk));
|
|
47
|
-
process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
48
|
-
process.stdin.on('error', reject);
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
const readPatterns = async (pathArg) => {
|
|
52
|
-
let content;
|
|
53
|
-
if (!pathArg || pathArg === '-') {
|
|
54
|
-
if (process.stdin.isTTY) {
|
|
55
|
-
console.error('Error: No input file specified and stdin is a terminal');
|
|
56
|
-
console.error('Usage: llmview <view-file> or pipe patterns via stdin');
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
content = await readStdin();
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
const resolvedPath = path.resolve(pathArg);
|
|
63
|
-
try {
|
|
64
|
-
content = await fs.readFile(resolvedPath, 'utf-8');
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
if (err.code === 'ENOENT') {
|
|
68
|
-
console.error(`File not found: ${resolvedPath}`);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
throw err;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return content
|
|
75
|
-
.split('\n')
|
|
76
|
-
.map((line) => line.trim())
|
|
77
|
-
.filter((line) => line !== '' && !line.startsWith('#'));
|
|
78
|
-
};
|
|
79
|
-
const HELP_TEXT = `llmview - Generate LLM context from codebases using gitignore-style patterns
|
|
2
|
+
import*as V from"fs/promises";import*as H from"path";import{text as ne}from"node:stream/consumers";import*as N from"fs/promises";import*as h from"path";import*as E from"fs/promises";import I from"ignore";var w=async e=>{try{let t=await E.readFile(e,"utf8");return I().add(t)}catch{return}},v=e=>I().add(e),_=(e,t,r)=>{let n=t?`${e}/`:e,o=!1;for(let{ig:s,scope:i}of r){let l=i===""?n:n.startsWith(i+"/")?n.slice(i.length+1):null;if(l===null)continue;let d=s.test(l);d.ignored?o=!0:d.unignored&&(o=!1)}return o};var R=`.git
|
|
3
|
+
.DS_Store
|
|
4
|
+
__pycache__/
|
|
5
|
+
node_modules/`;var $=" ";var b=async e=>{let t=[{ig:v(R),scope:""}],r=await w(h.join(e,".gitignore"));r&&t.push({ig:r,scope:""});let n={name:h.basename(e),relativePath:"",type:"directory",children:[]};return n.children=await L(e,n,t),n},L=async(e,t,r)=>{let n=h.join(e,t.relativePath),o=await N.readdir(n),s=[];for(let i of o){let l=h.join(n,i),d=await N.lstat(l);if(d.isSymbolicLink())continue;let g=d.isDirectory(),m=t.relativePath?`${t.relativePath}/${i}`:i;if(_(m,g,r))continue;let f={name:i,relativePath:m};if(g){let p={...f,type:"directory",children:[]},a=await w(h.join(l,".gitignore")),c=a?[...r,{ig:a,scope:m}]:r;p.children=await L(e,p,c),s.push(p)}else{let p={...f,type:"file",size:d.size};s.push(p)}}return s.sort((i,l)=>i.type!==l.type?i.type==="directory"?-1:1:i.name.localeCompare(l.name))};import ee from"p-limit";import*as O from"fs";import*as j from"fs/promises";import*as x from"path";import*as T from"readline";var q=async(e,t)=>{let r=[],n=O.createReadStream(e,{encoding:"utf-8"}),o=T.createInterface({input:n,crlfDelay:1/0});try{for await(let s of o)if(r.length<t)r.push(s);else return{lines:r,hasMore:!0};return{lines:r,hasMore:!1}}finally{o.close(),n.destroy()}},C=e=>e.map((t,r)=>`${(r+1).toString().padStart(6," ")} ${t}`).join(`
|
|
6
|
+
`),M=async(e,t,r)=>{let n=x.join(e,t.relativePath);if(t.size>250*1024)return`(File contents excluded: size ${(t.size/1024).toFixed(2)}KB exceeds ${250}KB limit)`;let o=await j.readFile(n,"utf-8");if(r.lineNumbers){let s=o.split(`
|
|
7
|
+
`);return C(s)}return o},F=(...e)=>t=>e.some(r=>t.toLowerCase().endsWith(r)),A=[{matcher:F(".csv"),renderer:async(e,t,r)=>{let n=x.join(e,t.relativePath),{lines:o,hasMore:s}=await q(n,10),i=r.lineNumbers?C(o):o.join(`
|
|
8
|
+
`);return s?`${i}
|
|
9
|
+
... (more rows)`:i}},{matcher:F(".xls",".xlsx"),renderer:async()=>"(Contents excluded)"},{matcher:F(".ico",".png",".jpg",".jpeg",".gif",".webp",".mp4"),renderer:async()=>"(Contents excluded)"},{matcher:F(".pdf",".zip"),renderer:async()=>"(Contents excluded)"}];var z=(e,t)=>B(e,t,0),B=(e,t,r)=>{let n=$.repeat(r);if(e.type==="file")return`${n}${e.name}`;let o=e.children.filter(i=>i.relativePath===""||t.has(i.relativePath)).map(i=>B(i,t,r+1)).join(`
|
|
10
|
+
`),s=`${n}${e.name}/`;return o?`${s}
|
|
11
|
+
${o}`:s},W=async(e,t,r)=>{let n=ee(64);return await Promise.all(t.map(s=>n(async()=>{let i=await te(e,s,r);return{file:s,content:i}})))},te=async(e,t,r)=>await re(t)(e,t,r),re=e=>{for(let{matcher:t,renderer:r}of A)if(t(e.name))return r;return M};import{minimatch as X}from"minimatch";var G=(e,t)=>J(e).filter(o=>{let s=!1;for(let i of t)i.startsWith("!")?X(o.relativePath,i.slice(1),{dot:!0})&&(s=!1):X(o.relativePath,i,{dot:!0})&&(s=!0);return s}),J=e=>e.children.flatMap(t=>t.type==="file"?[t]:J(t)),K=e=>{let t=new Set;for(let r of e){t.add(r.relativePath);let n=r.relativePath.split("/"),o="";for(let s=0;s<n.length-1;s++)o=o?`${o}/${n[s]}`:n[s],t.add(o)}return t};var oe=()=>ne(process.stdin),se=async e=>{let t;if(!e||e==="-")process.stdin.isTTY&&(console.log(U),process.exit(1)),t=await oe();else{let r=H.resolve(e);try{t=await V.readFile(r,"utf-8")}catch(n){throw n.code==="ENOENT"&&(console.error(`File not found: ${r}`),process.exit(1)),n}}return t.split(`
|
|
12
|
+
`).map(r=>r.trim()).filter(r=>r!==""&&!r.startsWith("#"))},U=`llmview - Generate LLM context from codebases
|
|
80
13
|
|
|
81
14
|
Usage: llmview [options] <view-file>
|
|
82
15
|
|
|
@@ -84,51 +17,19 @@ Arguments:
|
|
|
84
17
|
<view-file> Path to a .llmview file, or - to read patterns from stdin
|
|
85
18
|
|
|
86
19
|
Options:
|
|
20
|
+
-j, --json Output as JSON instead of XML tags
|
|
87
21
|
-l, --list List selected files only (no content)
|
|
88
22
|
-n, --number Include line numbers in output
|
|
89
23
|
-t, --tree Include directory tree of selected files
|
|
90
24
|
-v, --verbose Print file statistics to stderr
|
|
91
25
|
-h, --help Show this help message
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const listOnly = args.includes('-l') || args.includes('--list');
|
|
103
|
-
const positionalArgs = args.filter((arg) => !arg.startsWith('-'));
|
|
104
|
-
const patterns = await readPatterns(positionalArgs[0]);
|
|
105
|
-
if (patterns.length === 0) {
|
|
106
|
-
console.error('No patterns found in input');
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
const rootNode = await (0, build_1.buildDirectory)(process.cwd());
|
|
110
|
-
const { selectedFiles, visiblePaths } = (0, select_1.selectFiles)(rootNode, patterns, {
|
|
111
|
-
verbose,
|
|
112
|
-
});
|
|
113
|
-
if (listOnly) {
|
|
114
|
-
selectedFiles.forEach((file) => console.log(file.relativePath));
|
|
115
|
-
process.exit(0);
|
|
116
|
-
}
|
|
117
|
-
let output = '';
|
|
118
|
-
if (includeTree) {
|
|
119
|
-
output += (0, render_1.renderDirectory)(rootNode, { verbose }, visiblePaths);
|
|
120
|
-
}
|
|
121
|
-
output += await (0, render_1.renderFiles)(rootNode.rootPath, selectedFiles, {
|
|
122
|
-
verbose,
|
|
123
|
-
lineNumbers,
|
|
124
|
-
});
|
|
125
|
-
const estimatedTokens = Math.ceil(output.length / constants_1.CHARS_PER_TOKEN_ESTIMATE);
|
|
126
|
-
if (verbose) {
|
|
127
|
-
console.warn(`Estimated tokens: ${estimatedTokens}`);
|
|
128
|
-
}
|
|
129
|
-
console.log(output);
|
|
130
|
-
};
|
|
131
|
-
main().catch((err) => {
|
|
132
|
-
console.error(err);
|
|
133
|
-
process.exit(1);
|
|
134
|
-
});
|
|
26
|
+
`,ie=async()=>{let e=process.argv.slice(2);(e.includes("-h")||e.includes("--help"))&&(console.log(U),process.exit(0));let t=e.includes("-v")||e.includes("--verbose"),r=e.includes("-t")||e.includes("--tree"),n=e.includes("-n")||e.includes("--number"),o=e.includes("-l")||e.includes("--list"),s=e.includes("-j")||e.includes("--json"),i=e.filter(c=>!c.startsWith("-")),l=await se(i[0]);l.length===0&&(console.error("No patterns found in input"),process.exit(1));let d=process.cwd(),g=await b(d),m=G(g,l);o&&(m.forEach(c=>console.log(c.relativePath)),process.exit(0));let f=null;if(r){let c=K(m);f=z(g,c)}let p=await W(d,m,{lineNumbers:n}),a="";if(s){let c={directory:f,files:p.map(({file:u,content:P})=>({path:u.relativePath,size:u.size,content:P}))};a=JSON.stringify(c,null,2)}else f&&(a+=`
|
|
27
|
+
<directory>
|
|
28
|
+
${f}
|
|
29
|
+
</directory>
|
|
30
|
+
`),a+=p.map(({file:c,content:u})=>`<file path="${c.relativePath}">
|
|
31
|
+
${u}
|
|
32
|
+
</file>`).join(`
|
|
33
|
+
`),a=`\`\`\`
|
|
34
|
+
${a}
|
|
35
|
+
\`\`\``;if(t){let c=l.join(", ");if(m.length===0)console.warn(`0 files matched (${c})`);else{console.warn(`${m.length} files matched (${c})`),console.warn(`Total characters: ${a.length}`),console.warn(""),console.warn("Files by size:");let u=[...p].sort((y,S)=>S.content.length-y.content.length),P=Math.max(...u.map(y=>y.file.relativePath.length));for(let{file:y,content:S}of u){let k=y.relativePath.padEnd(P),Z=S.length.toLocaleString().padStart(8);console.warn(` ${k} ${Z} chars`)}}}console.log(a)};ie().catch(e=>{console.error(e),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,33 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llmview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Generate LLM-friendly context from codebases using repeatable view files",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/noahtren/llmview.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/noahtren/llmview/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
4
16
|
"bin": {
|
|
5
17
|
"llmview": "dist/cli.js"
|
|
6
18
|
},
|
|
19
|
+
"files": ["dist", "README.md"],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
7
23
|
"scripts": {
|
|
8
|
-
"build": "
|
|
9
|
-
"
|
|
10
|
-
"test": "
|
|
24
|
+
"build": "esbuild src/cli.ts --bundle --platform=node --format=esm --minify --outfile=dist/cli.js --banner:js='#!/usr/bin/env node' --packages=external",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
11
28
|
},
|
|
12
|
-
"keywords": [],
|
|
13
|
-
"author": "",
|
|
14
|
-
"license": "ISC",
|
|
15
|
-
"description": "Generate LLM context from codebases using gitignore-style patterns",
|
|
16
29
|
"dependencies": {
|
|
17
30
|
"ignore": "^7.0.5",
|
|
18
|
-
"minimatch": "^10.0.1"
|
|
31
|
+
"minimatch": "^10.0.1",
|
|
32
|
+
"p-limit": "^7.2.0"
|
|
19
33
|
},
|
|
20
34
|
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.2.0",
|
|
36
|
+
"esbuild": "^0.27.2",
|
|
21
37
|
"prettier": "^3.8.1",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
},
|
|
25
|
-
"files": ["dist", "README.md"],
|
|
26
|
-
"repository": {
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/noahtren/llmview.git"
|
|
29
|
-
},
|
|
30
|
-
"bugs": {
|
|
31
|
-
"url": "https://github.com/noahtren/llmview/issues"
|
|
38
|
+
"typescript": "^5.8.2",
|
|
39
|
+
"vitest": "^4.0.18"
|
|
32
40
|
}
|
|
33
41
|
}
|
package/dist/build.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.buildDirectory = void 0;
|
|
37
|
-
const fs = __importStar(require("fs/promises"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const ignore_1 = require("./ignore");
|
|
40
|
-
const constants_1 = require("./constants");
|
|
41
|
-
const buildDirectory = async (projectPath) => {
|
|
42
|
-
const ignores = [
|
|
43
|
-
{ ig: (0, ignore_1.createIgnore)(constants_1.BASE_IGNORE_CONTENT), scope: '' },
|
|
44
|
-
];
|
|
45
|
-
const rootGitignore = await (0, ignore_1.createIgnoreFromFile)(path.join(projectPath, '.gitignore'));
|
|
46
|
-
if (rootGitignore) {
|
|
47
|
-
ignores.push({ ig: rootGitignore, scope: '' });
|
|
48
|
-
}
|
|
49
|
-
const stat = await fs.stat(projectPath);
|
|
50
|
-
const rootNode = {
|
|
51
|
-
ino: stat.ino,
|
|
52
|
-
name: path.basename(projectPath),
|
|
53
|
-
relativePath: '',
|
|
54
|
-
createdAt: stat.birthtime,
|
|
55
|
-
updatedAt: stat.mtime,
|
|
56
|
-
type: 'directory',
|
|
57
|
-
rootPath: projectPath,
|
|
58
|
-
children: [],
|
|
59
|
-
};
|
|
60
|
-
rootNode.children = await buildChildrenNodes(projectPath, rootNode, ignores);
|
|
61
|
-
return rootNode;
|
|
62
|
-
};
|
|
63
|
-
exports.buildDirectory = buildDirectory;
|
|
64
|
-
const buildChildrenNodes = async (rootPath, parentNode, ignores) => {
|
|
65
|
-
const currentPath = path.join(rootPath, parentNode.relativePath);
|
|
66
|
-
const entries = await fs.readdir(currentPath);
|
|
67
|
-
const nodes = [];
|
|
68
|
-
for (const entry of entries) {
|
|
69
|
-
const entryFullPath = path.join(currentPath, entry);
|
|
70
|
-
const lstat = await fs.lstat(entryFullPath);
|
|
71
|
-
if (lstat.isSymbolicLink()) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const isDirectory = lstat.isDirectory();
|
|
75
|
-
const nodeRelativePath = parentNode.relativePath
|
|
76
|
-
? `${parentNode.relativePath}/${entry}`
|
|
77
|
-
: entry;
|
|
78
|
-
if ((0, ignore_1.isPathIgnored)(nodeRelativePath, isDirectory, ignores)) {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const nodeBase = {
|
|
82
|
-
ino: lstat.ino,
|
|
83
|
-
name: entry,
|
|
84
|
-
relativePath: nodeRelativePath,
|
|
85
|
-
createdAt: lstat.birthtime,
|
|
86
|
-
updatedAt: lstat.mtime,
|
|
87
|
-
};
|
|
88
|
-
if (isDirectory) {
|
|
89
|
-
const dirNode = {
|
|
90
|
-
...nodeBase,
|
|
91
|
-
type: 'directory',
|
|
92
|
-
children: [],
|
|
93
|
-
};
|
|
94
|
-
const nestedIg = await (0, ignore_1.createIgnoreFromFile)(path.join(entryFullPath, '.gitignore'));
|
|
95
|
-
const childIgnores = nestedIg
|
|
96
|
-
? [...ignores, { ig: nestedIg, scope: nodeRelativePath }]
|
|
97
|
-
: ignores;
|
|
98
|
-
dirNode.children = await buildChildrenNodes(rootPath, dirNode, childIgnores);
|
|
99
|
-
nodes.push(dirNode);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
const fileNode = {
|
|
103
|
-
...nodeBase,
|
|
104
|
-
type: 'file',
|
|
105
|
-
size: lstat.size,
|
|
106
|
-
};
|
|
107
|
-
nodes.push(fileNode);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return nodes.sort((a, b) => {
|
|
111
|
-
if (a.type !== b.type) {
|
|
112
|
-
return a.type === 'directory' ? -1 : 1;
|
|
113
|
-
}
|
|
114
|
-
return a.name.localeCompare(b.name);
|
|
115
|
-
});
|
|
116
|
-
};
|
package/dist/constants.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CHARS_PER_TOKEN_ESTIMATE = exports.CSV_PREVIEW_LINES = exports.MAX_FILE_SIZE_KB = exports.BASE_IGNORE_CONTENT = void 0;
|
|
4
|
-
exports.BASE_IGNORE_CONTENT = `.git
|
|
5
|
-
.DS_Store
|
|
6
|
-
__pycache__/
|
|
7
|
-
node_modules/`;
|
|
8
|
-
exports.MAX_FILE_SIZE_KB = 250;
|
|
9
|
-
exports.CSV_PREVIEW_LINES = 10;
|
|
10
|
-
exports.CHARS_PER_TOKEN_ESTIMATE = 4;
|
package/dist/ignore.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.isPathIgnored = exports.createIgnore = exports.createIgnoreFromFile = void 0;
|
|
40
|
-
const fs = __importStar(require("fs/promises"));
|
|
41
|
-
const ignore_1 = __importDefault(require("ignore"));
|
|
42
|
-
const createIgnoreFromFile = async (gitignorePath) => {
|
|
43
|
-
try {
|
|
44
|
-
const content = await fs.readFile(gitignorePath, 'utf8');
|
|
45
|
-
return (0, ignore_1.default)().add(content);
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return undefined;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
exports.createIgnoreFromFile = createIgnoreFromFile;
|
|
52
|
-
const createIgnore = (content) => {
|
|
53
|
-
return (0, ignore_1.default)().add(content);
|
|
54
|
-
};
|
|
55
|
-
exports.createIgnore = createIgnore;
|
|
56
|
-
const isPathIgnored = (relativePath, isDirectory, ignores) => {
|
|
57
|
-
const pathToCheck = isDirectory ? `${relativePath}/` : relativePath;
|
|
58
|
-
let ignored = false;
|
|
59
|
-
for (const { ig, scope } of ignores) {
|
|
60
|
-
const localPath = scope === ''
|
|
61
|
-
? pathToCheck
|
|
62
|
-
: pathToCheck.startsWith(scope + '/')
|
|
63
|
-
? pathToCheck.slice(scope.length + 1)
|
|
64
|
-
: null;
|
|
65
|
-
if (localPath === null)
|
|
66
|
-
continue;
|
|
67
|
-
const result = ig.test(localPath);
|
|
68
|
-
if (result.ignored) {
|
|
69
|
-
ignored = true;
|
|
70
|
-
}
|
|
71
|
-
else if (result.unignored) {
|
|
72
|
-
ignored = false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return ignored;
|
|
76
|
-
};
|
|
77
|
-
exports.isPathIgnored = isPathIgnored;
|
package/dist/render-rules.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.RENDER_RULES = exports.defaultRenderer = void 0;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const fsPromises = __importStar(require("fs/promises"));
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
|
-
const readline = __importStar(require("readline"));
|
|
41
|
-
const constants_1 = require("./constants");
|
|
42
|
-
const readFirstNLines = async (filePath, n) => {
|
|
43
|
-
const lines = [];
|
|
44
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
45
|
-
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
46
|
-
try {
|
|
47
|
-
for await (const line of rl) {
|
|
48
|
-
if (lines.length < n) {
|
|
49
|
-
lines.push(line);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
return { lines, hasMore: true };
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return { lines, hasMore: false };
|
|
56
|
-
}
|
|
57
|
-
finally {
|
|
58
|
-
rl.close();
|
|
59
|
-
stream.destroy();
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
const numberLines = (lines) => {
|
|
63
|
-
return lines
|
|
64
|
-
.map((line, index) => {
|
|
65
|
-
const lineNumber = (index + 1).toString().padStart(6, ' ');
|
|
66
|
-
return `${lineNumber}\t${line}`;
|
|
67
|
-
})
|
|
68
|
-
.join('\n');
|
|
69
|
-
};
|
|
70
|
-
const defaultRenderer = async (rootPath, file, options) => {
|
|
71
|
-
const fullPath = path.join(rootPath, file.relativePath);
|
|
72
|
-
if (file.size > constants_1.MAX_FILE_SIZE_KB * 1024) {
|
|
73
|
-
return `(File contents excluded: size ${(file.size / 1024).toFixed(2)}KB exceeds ${constants_1.MAX_FILE_SIZE_KB}KB limit)`;
|
|
74
|
-
}
|
|
75
|
-
const content = await fsPromises.readFile(fullPath, 'utf-8');
|
|
76
|
-
if (options.lineNumbers) {
|
|
77
|
-
const lines = content.split('\n');
|
|
78
|
-
return numberLines(lines);
|
|
79
|
-
}
|
|
80
|
-
return content;
|
|
81
|
-
};
|
|
82
|
-
exports.defaultRenderer = defaultRenderer;
|
|
83
|
-
exports.RENDER_RULES = [
|
|
84
|
-
// csv
|
|
85
|
-
{
|
|
86
|
-
matcher: (name) => ['.csv'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
87
|
-
renderer: async (rootPath, file, options) => {
|
|
88
|
-
const fullPath = path.join(rootPath, file.relativePath);
|
|
89
|
-
const { lines, hasMore } = await readFirstNLines(fullPath, constants_1.CSV_PREVIEW_LINES);
|
|
90
|
-
const preview = options.lineNumbers
|
|
91
|
-
? numberLines(lines)
|
|
92
|
-
: lines.join('\n');
|
|
93
|
-
return hasMore ? `${preview}\n... (more rows)` : preview;
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
// excel
|
|
97
|
-
{
|
|
98
|
-
matcher: (name) => ['.xls', '.xlsx'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
99
|
-
renderer: async () => '(Contents excluded)',
|
|
100
|
-
},
|
|
101
|
-
// media
|
|
102
|
-
{
|
|
103
|
-
matcher: (name) => ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.webp', '.mp4'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
104
|
-
renderer: async () => '(Contents excluded)',
|
|
105
|
-
},
|
|
106
|
-
// misc
|
|
107
|
-
{
|
|
108
|
-
matcher: (name) => ['.pdf', '.zip'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
109
|
-
renderer: async () => '(Contents excluded)',
|
|
110
|
-
},
|
|
111
|
-
];
|
package/dist/render.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.renderFiles = exports.renderDirectory = void 0;
|
|
4
|
-
const render_rules_1 = require("./render-rules");
|
|
5
|
-
const renderDirectory = (rootNode, options, visiblePaths) => {
|
|
6
|
-
return renderDirectoryNode(rootNode, options, visiblePaths, 0);
|
|
7
|
-
};
|
|
8
|
-
exports.renderDirectory = renderDirectory;
|
|
9
|
-
const renderDirectoryNode = (node, options, visiblePaths, currentDepth) => {
|
|
10
|
-
const { indentChar = ' ' } = options;
|
|
11
|
-
const indent = indentChar.repeat(currentDepth);
|
|
12
|
-
if (node.type === 'file') {
|
|
13
|
-
return `${indent}${node.name}`;
|
|
14
|
-
}
|
|
15
|
-
const childrenOutput = node.children
|
|
16
|
-
.filter((child) => !visiblePaths ||
|
|
17
|
-
!child.relativePath ||
|
|
18
|
-
visiblePaths.has(child.relativePath))
|
|
19
|
-
.map((child) => renderDirectoryNode(child, options, visiblePaths, currentDepth + 1))
|
|
20
|
-
.join('\n');
|
|
21
|
-
const result = `${indent}${node.name}/`;
|
|
22
|
-
if (currentDepth === 0) {
|
|
23
|
-
return `\`\`\`\n<directory>\n${result}\n${childrenOutput}\n</directory>\n\`\`\`\n\n`;
|
|
24
|
-
}
|
|
25
|
-
return childrenOutput ? `${result}\n${childrenOutput}` : result;
|
|
26
|
-
};
|
|
27
|
-
const renderFiles = async (rootPath, files, options) => {
|
|
28
|
-
const renderedBlocks = await Promise.all(files.map((file) => renderFile(rootPath, file, options)));
|
|
29
|
-
return renderedBlocks.join('\n\n');
|
|
30
|
-
};
|
|
31
|
-
exports.renderFiles = renderFiles;
|
|
32
|
-
const renderFile = async (rootPath, file, options) => {
|
|
33
|
-
const renderer = getRenderer(file);
|
|
34
|
-
const rendered = await renderer(rootPath, file, options);
|
|
35
|
-
if (options.verbose) {
|
|
36
|
-
console.warn({ path: file.relativePath, length: rendered.length });
|
|
37
|
-
}
|
|
38
|
-
return `\`\`\`
|
|
39
|
-
<file path="${file.relativePath}">
|
|
40
|
-
${rendered}
|
|
41
|
-
</file>
|
|
42
|
-
\`\`\``;
|
|
43
|
-
};
|
|
44
|
-
const getRenderer = (file) => {
|
|
45
|
-
for (const { matcher, renderer } of render_rules_1.RENDER_RULES) {
|
|
46
|
-
if (matcher(file.name)) {
|
|
47
|
-
return renderer;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return render_rules_1.defaultRenderer;
|
|
51
|
-
};
|
package/dist/select.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getVisiblePaths = exports.selectFiles = void 0;
|
|
4
|
-
const minimatch_1 = require("minimatch");
|
|
5
|
-
const selectFiles = (node, globPatterns, options) => {
|
|
6
|
-
const allFiles = listAllFiles(node);
|
|
7
|
-
const selectedFiles = allFiles.filter((file) => {
|
|
8
|
-
let included = false;
|
|
9
|
-
for (const pattern of globPatterns) {
|
|
10
|
-
if (pattern.startsWith('!')) {
|
|
11
|
-
if ((0, minimatch_1.minimatch)(file.relativePath, pattern.slice(1), { dot: true })) {
|
|
12
|
-
included = false;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
if ((0, minimatch_1.minimatch)(file.relativePath, pattern, { dot: true })) {
|
|
17
|
-
included = true;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return included;
|
|
22
|
-
});
|
|
23
|
-
const visiblePaths = (0, exports.getVisiblePaths)(selectedFiles);
|
|
24
|
-
if (options.verbose) {
|
|
25
|
-
if (selectedFiles.length === 0) {
|
|
26
|
-
console.warn(`No file(s) found that satisfy these patterns: ${globPatterns.join(', ')}`);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
console.warn(`${selectedFiles.length} file(s) found satisfying these patterns: ${globPatterns.join(', ')}`);
|
|
30
|
-
console.warn({ visiblePaths });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return { selectedFiles, visiblePaths };
|
|
34
|
-
};
|
|
35
|
-
exports.selectFiles = selectFiles;
|
|
36
|
-
const listAllFiles = (node) => {
|
|
37
|
-
return node.children.flatMap((child) => child.type === 'file' ? [child] : listAllFiles(child));
|
|
38
|
-
};
|
|
39
|
-
const getVisiblePaths = (selectedFiles) => {
|
|
40
|
-
const visible = new Set();
|
|
41
|
-
for (const file of selectedFiles) {
|
|
42
|
-
visible.add(file.relativePath);
|
|
43
|
-
const parts = file.relativePath.split('/');
|
|
44
|
-
let current = '';
|
|
45
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
46
|
-
current = current ? `${current}/${parts[i]}` : parts[i];
|
|
47
|
-
visible.add(current);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return visible;
|
|
51
|
-
};
|
|
52
|
-
exports.getVisiblePaths = getVisiblePaths;
|
package/dist/types.js
DELETED