llmview 0.1.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 +54 -32
- package/dist/cli.js +24 -93
- package/package.json +27 -22
- package/dist/build.js +0 -120
- package/dist/constants.js +0 -8
- package/dist/git.js +0 -74
- package/dist/render.js +0 -62
- package/dist/renderers.js +0 -131
- 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:
|
|
@@ -20,9 +22,9 @@ Create any number of view files in your project. These can be saved anywhere. Fo
|
|
|
20
22
|
new_feature.llmview
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
And use
|
|
25
|
+
And use one:
|
|
24
26
|
|
|
25
|
-
```
|
|
27
|
+
```bash
|
|
26
28
|
llmview .views/backend.llmview
|
|
27
29
|
```
|
|
28
30
|
|
|
@@ -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
|
-
|
|
46
|
+
After selecting, it outputs the contents of each file into a LLM-friendly format and prints to stdout.
|
|
45
47
|
|
|
46
|
-
|
|
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,39 +79,67 @@ my_project/
|
|
|
85
79
|
docs/
|
|
86
80
|
style_guide.md
|
|
87
81
|
</directory>
|
|
82
|
+
<file path="backend/main.py">
|
|
83
|
+
...
|
|
84
|
+
```
|
|
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'
|
|
88
96
|
```
|
|
89
97
|
|
|
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
|
+
}
|
|
90
111
|
```
|
|
91
|
-
<file path="my_project/backend/main.py">
|
|
92
|
-
...
|
|
93
|
-
````
|
|
94
112
|
|
|
95
|
-
|
|
113
|
+
The `directory` field is populated when using `-t`.
|
|
96
114
|
|
|
97
|
-
|
|
115
|
+
### Only list selected files
|
|
98
116
|
|
|
99
|
-
|
|
117
|
+
The `-l` argument lets you use selected files for something else besides rendering the context to stdout. For example, to create a zip of selected files.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
llmview .views/backend.llmview -l | zip context.zip -@
|
|
121
|
+
```
|
|
100
122
|
|
|
101
|
-
|
|
123
|
+
### Using as a filter
|
|
102
124
|
|
|
103
|
-
|
|
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:
|
|
104
126
|
|
|
105
127
|
```bash
|
|
106
|
-
|
|
128
|
+
git diff --name-only | llmview -
|
|
107
129
|
```
|
|
108
130
|
|
|
109
131
|
## Renderers
|
|
110
132
|
|
|
111
|
-
This tool comes with a set of opinionated file renderers
|
|
133
|
+
This tool comes with a set of opinionated file renderers based on the file extension. Currently they are:
|
|
112
134
|
|
|
113
135
|
- CSV (truncated by default, preserving the header and the first 10 lines)
|
|
114
136
|
- Excel, media files, and other non-text formats (omitted)
|
|
115
137
|
|
|
116
|
-
There is also a max size of 250KB per file. If a file is larger than that, it is not rendered.
|
|
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.)
|
|
117
139
|
|
|
118
|
-
##
|
|
140
|
+
## Verbose mode
|
|
119
141
|
|
|
120
|
-
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:
|
|
121
143
|
|
|
122
144
|
```bash
|
|
123
145
|
llmview -v .views/backend.llmview > /dev/null
|
package/dist/cli.js
CHANGED
|
@@ -1,104 +1,35 @@
|
|
|
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"));
|
|
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 parseLlmviewFile = (filePath) => {
|
|
43
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
44
|
-
return content
|
|
45
|
-
.split('\n')
|
|
46
|
-
.map((line) => line.trim())
|
|
47
|
-
.filter((line) => line !== '' && !line.startsWith('#'));
|
|
48
|
-
};
|
|
49
|
-
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
|
|
50
13
|
|
|
51
14
|
Usage: llmview [options] <view-file>
|
|
52
15
|
|
|
53
16
|
Arguments:
|
|
54
|
-
<view-file> Path to a .llmview file
|
|
17
|
+
<view-file> Path to a .llmview file, or - to read patterns from stdin
|
|
55
18
|
|
|
56
19
|
Options:
|
|
20
|
+
-j, --json Output as JSON instead of XML tags
|
|
21
|
+
-l, --list List selected files only (no content)
|
|
57
22
|
-n, --number Include line numbers in output
|
|
58
23
|
-t, --tree Include directory tree of selected files
|
|
59
24
|
-v, --verbose Print file statistics to stderr
|
|
60
25
|
-h, --help Show this help message
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const llmviewPath = args.find((arg) => !arg.startsWith('-'));
|
|
72
|
-
if (!llmviewPath) {
|
|
73
|
-
console.log(HELP_TEXT);
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
const resolvedPath = path.resolve(llmviewPath);
|
|
77
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
78
|
-
console.error(`File not found: ${resolvedPath}`);
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
const patterns = parseLlmviewFile(resolvedPath);
|
|
82
|
-
if (patterns.length === 0) {
|
|
83
|
-
console.error('No patterns found in llmview file');
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
const rootNode = (0, build_1.buildDirectory)(process.cwd());
|
|
87
|
-
const { selectedFiles, visiblePaths } = (0, select_1.selectFiles)(rootNode, patterns, {
|
|
88
|
-
verbose,
|
|
89
|
-
});
|
|
90
|
-
let output = '';
|
|
91
|
-
if (includeTree) {
|
|
92
|
-
output += (0, render_1.renderHierarchy)(rootNode, { verbose }, visiblePaths);
|
|
93
|
-
}
|
|
94
|
-
output += (0, render_1.renderFiles)(rootNode.rootPath, selectedFiles, {
|
|
95
|
-
verbose,
|
|
96
|
-
lineNumbers,
|
|
97
|
-
});
|
|
98
|
-
const estimatedTokens = Math.ceil(output.length / 4);
|
|
99
|
-
if (verbose) {
|
|
100
|
-
console.warn(`Estimated tokens: ${estimatedTokens}`);
|
|
101
|
-
}
|
|
102
|
-
console.log(output);
|
|
103
|
-
};
|
|
104
|
-
main();
|
|
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,36 +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": [
|
|
26
|
-
"dist",
|
|
27
|
-
"README.md"
|
|
28
|
-
],
|
|
29
|
-
"repository": {
|
|
30
|
-
"type": "git",
|
|
31
|
-
"url": "git+https://github.com/noahtren/llmview.git"
|
|
32
|
-
},
|
|
33
|
-
"bugs": {
|
|
34
|
-
"url": "https://github.com/noahtren/llmview/issues"
|
|
38
|
+
"typescript": "^5.8.2",
|
|
39
|
+
"vitest": "^4.0.18"
|
|
35
40
|
}
|
|
36
41
|
}
|
package/dist/build.js
DELETED
|
@@ -1,120 +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 os = __importStar(require("os"));
|
|
38
|
-
const fs = __importStar(require("fs"));
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
|
-
const git_1 = require("./git");
|
|
41
|
-
const constants_1 = require("./constants");
|
|
42
|
-
const expandUser = (inputPath) => {
|
|
43
|
-
return inputPath.replace(/^~/, os.homedir());
|
|
44
|
-
};
|
|
45
|
-
const buildDirectory = (projectPath) => {
|
|
46
|
-
projectPath = expandUser(projectPath);
|
|
47
|
-
const ignores = [
|
|
48
|
-
{ ig: (0, git_1.createIgnore)(constants_1.BASE_IGNORE_CONTENT), scope: '' },
|
|
49
|
-
];
|
|
50
|
-
const rootGitignore = (0, git_1.createIgnoreFromFile)(path.join(projectPath, '.gitignore'));
|
|
51
|
-
if (rootGitignore) {
|
|
52
|
-
ignores.push({ ig: rootGitignore, scope: '' });
|
|
53
|
-
}
|
|
54
|
-
const stat = fs.statSync(projectPath);
|
|
55
|
-
const rootNode = {
|
|
56
|
-
ino: stat.ino,
|
|
57
|
-
name: path.basename(projectPath),
|
|
58
|
-
relativePath: '',
|
|
59
|
-
createdAt: stat.birthtime,
|
|
60
|
-
updatedAt: stat.mtime,
|
|
61
|
-
type: 'directory',
|
|
62
|
-
rootPath: projectPath,
|
|
63
|
-
children: [],
|
|
64
|
-
};
|
|
65
|
-
rootNode.children = buildChildrenNodes(projectPath, rootNode, ignores);
|
|
66
|
-
return rootNode;
|
|
67
|
-
};
|
|
68
|
-
exports.buildDirectory = buildDirectory;
|
|
69
|
-
const buildChildrenNodes = (rootPath, parentNode, ignores) => {
|
|
70
|
-
const currentPath = path.join(rootPath, parentNode.relativePath);
|
|
71
|
-
const entries = fs.readdirSync(currentPath);
|
|
72
|
-
const nodes = [];
|
|
73
|
-
for (const entry of entries) {
|
|
74
|
-
const entryFullPath = path.join(currentPath, entry);
|
|
75
|
-
const lstat = fs.lstatSync(entryFullPath);
|
|
76
|
-
if (lstat.isSymbolicLink()) {
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
const isDirectory = lstat.isDirectory();
|
|
80
|
-
const nodeRelativePath = parentNode.relativePath
|
|
81
|
-
? `${parentNode.relativePath}/${entry}`
|
|
82
|
-
: entry;
|
|
83
|
-
if ((0, git_1.isPathIgnored)(nodeRelativePath, isDirectory, ignores)) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
const nodeBase = {
|
|
87
|
-
ino: lstat.ino,
|
|
88
|
-
name: entry,
|
|
89
|
-
relativePath: nodeRelativePath,
|
|
90
|
-
createdAt: lstat.birthtime,
|
|
91
|
-
updatedAt: lstat.mtime,
|
|
92
|
-
};
|
|
93
|
-
if (isDirectory) {
|
|
94
|
-
const dirNode = {
|
|
95
|
-
...nodeBase,
|
|
96
|
-
type: 'directory',
|
|
97
|
-
children: [],
|
|
98
|
-
};
|
|
99
|
-
const nestedIg = (0, git_1.createIgnoreFromFile)(path.join(entryFullPath, '.gitignore'));
|
|
100
|
-
const childIgnores = nestedIg
|
|
101
|
-
? [...ignores, { ig: nestedIg, scope: nodeRelativePath }]
|
|
102
|
-
: ignores;
|
|
103
|
-
dirNode.children = buildChildrenNodes(rootPath, dirNode, childIgnores);
|
|
104
|
-
nodes.push(dirNode);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
const fileNode = {
|
|
108
|
-
...nodeBase,
|
|
109
|
-
type: 'file',
|
|
110
|
-
};
|
|
111
|
-
nodes.push(fileNode);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return nodes.sort((a, b) => {
|
|
115
|
-
if (a.type !== b.type) {
|
|
116
|
-
return a.type === 'directory' ? -1 : 1;
|
|
117
|
-
}
|
|
118
|
-
return a.name.localeCompare(b.name);
|
|
119
|
-
});
|
|
120
|
-
};
|
package/dist/constants.js
DELETED
package/dist/git.js
DELETED
|
@@ -1,74 +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"));
|
|
41
|
-
const ignore_1 = __importDefault(require("ignore"));
|
|
42
|
-
const createIgnoreFromFile = (gitignorePath) => {
|
|
43
|
-
if (!fs.existsSync(gitignorePath)) {
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
return (0, ignore_1.default)().add(fs.readFileSync(gitignorePath, 'utf8'));
|
|
47
|
-
};
|
|
48
|
-
exports.createIgnoreFromFile = createIgnoreFromFile;
|
|
49
|
-
const createIgnore = (content) => {
|
|
50
|
-
return (0, ignore_1.default)().add(content);
|
|
51
|
-
};
|
|
52
|
-
exports.createIgnore = createIgnore;
|
|
53
|
-
const isPathIgnored = (relativePath, isDirectory, ignores) => {
|
|
54
|
-
const pathToCheck = isDirectory ? `${relativePath}/` : relativePath;
|
|
55
|
-
let ignored = false;
|
|
56
|
-
for (const { ig, scope } of ignores) {
|
|
57
|
-
const localPath = scope === ''
|
|
58
|
-
? pathToCheck
|
|
59
|
-
: pathToCheck.startsWith(scope + '/')
|
|
60
|
-
? pathToCheck.slice(scope.length + 1)
|
|
61
|
-
: null;
|
|
62
|
-
if (localPath === null)
|
|
63
|
-
continue;
|
|
64
|
-
const result = ig.test(localPath);
|
|
65
|
-
if (result.ignored) {
|
|
66
|
-
ignored = true;
|
|
67
|
-
}
|
|
68
|
-
else if (result.unignored) {
|
|
69
|
-
ignored = false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return ignored;
|
|
73
|
-
};
|
|
74
|
-
exports.isPathIgnored = isPathIgnored;
|
package/dist/render.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.renderFiles = exports.renderHierarchy = void 0;
|
|
4
|
-
const renderers_1 = require("./renderers");
|
|
5
|
-
const renderHierarchy = (node, options, visiblePaths, currentDepth = 0) => {
|
|
6
|
-
if (visiblePaths &&
|
|
7
|
-
node.relativePath &&
|
|
8
|
-
!visiblePaths.has(node.relativePath)) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const { indentChar = ' ' } = options;
|
|
12
|
-
const indent = indentChar.repeat(currentDepth);
|
|
13
|
-
if (node.type === 'file') {
|
|
14
|
-
return `${indent}${node.name}`;
|
|
15
|
-
}
|
|
16
|
-
let result = `${indent}${node.name}/`;
|
|
17
|
-
if (node.children.length === 0) {
|
|
18
|
-
return result;
|
|
19
|
-
}
|
|
20
|
-
const childrenOutput = node.children
|
|
21
|
-
.map((child) => (0, exports.renderHierarchy)(child, options, visiblePaths, currentDepth + 1))
|
|
22
|
-
.filter((output) => output !== null)
|
|
23
|
-
.join('\n');
|
|
24
|
-
if (currentDepth === 0) {
|
|
25
|
-
return `\`\`\`
|
|
26
|
-
<directory>
|
|
27
|
-
${result}
|
|
28
|
-
${childrenOutput}
|
|
29
|
-
</directory>
|
|
30
|
-
\`\`\`\n\n`;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
return `${result}\n${childrenOutput}`;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
exports.renderHierarchy = renderHierarchy;
|
|
37
|
-
const renderFiles = (rootPath, files, options) => {
|
|
38
|
-
return files
|
|
39
|
-
.map((file) => renderFileBlock(rootPath, file, options))
|
|
40
|
-
.join('\n\n');
|
|
41
|
-
};
|
|
42
|
-
exports.renderFiles = renderFiles;
|
|
43
|
-
const renderFileBlock = (rootPath, file, options) => {
|
|
44
|
-
const renderer = getRenderer(file);
|
|
45
|
-
const rendered = renderer(rootPath, file, options);
|
|
46
|
-
if (options.verbose) {
|
|
47
|
-
console.warn({ path: file.relativePath, length: rendered.length });
|
|
48
|
-
}
|
|
49
|
-
return `\`\`\`
|
|
50
|
-
<file path="${file.relativePath}">
|
|
51
|
-
${rendered}
|
|
52
|
-
</file>
|
|
53
|
-
\`\`\``;
|
|
54
|
-
};
|
|
55
|
-
const getRenderer = (file) => {
|
|
56
|
-
for (const { matcher, renderer } of renderers_1.RENDER_RULES) {
|
|
57
|
-
if (matcher(file.name)) {
|
|
58
|
-
return renderer;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return renderers_1.defaultRenderer;
|
|
62
|
-
};
|
package/dist/renderers.js
DELETED
|
@@ -1,131 +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 path = __importStar(require("path"));
|
|
39
|
-
const constants_1 = require("./constants");
|
|
40
|
-
const readFirstNLines = (filePath, n) => {
|
|
41
|
-
const fd = fs.openSync(filePath, 'r');
|
|
42
|
-
const bufferSize = 64 * 1024;
|
|
43
|
-
const buffer = Buffer.alloc(bufferSize);
|
|
44
|
-
const lines = [];
|
|
45
|
-
let leftover = '';
|
|
46
|
-
let hasMore = false;
|
|
47
|
-
try {
|
|
48
|
-
while (lines.length < n) {
|
|
49
|
-
const bytesRead = fs.readSync(fd, buffer, 0, bufferSize, null);
|
|
50
|
-
if (bytesRead === 0)
|
|
51
|
-
break; // EOF
|
|
52
|
-
const chunk = leftover + buffer.toString('utf-8', 0, bytesRead);
|
|
53
|
-
const chunkLines = chunk.split('\n');
|
|
54
|
-
leftover = chunkLines.pop() || '';
|
|
55
|
-
for (const line of chunkLines) {
|
|
56
|
-
if (lines.length < n) {
|
|
57
|
-
lines.push(line);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
hasMore = true;
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (hasMore)
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
if (!hasMore && lines.length >= n) {
|
|
68
|
-
if (leftover !== '') {
|
|
69
|
-
hasMore = true;
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
hasMore = fs.readSync(fd, buffer, 0, 1, null) > 0;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return { lines, hasMore };
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
fs.closeSync(fd);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
const numberLines = (lines) => {
|
|
82
|
-
return lines
|
|
83
|
-
.map((line, index) => {
|
|
84
|
-
const lineNumber = (index + 1).toString().padStart(6, ' ');
|
|
85
|
-
return `${lineNumber}\t${line}`;
|
|
86
|
-
})
|
|
87
|
-
.join('\n');
|
|
88
|
-
};
|
|
89
|
-
const defaultRenderer = (rootPath, file, options) => {
|
|
90
|
-
const fullPath = path.join(rootPath, file.relativePath);
|
|
91
|
-
const stats = fs.statSync(fullPath);
|
|
92
|
-
if (stats.size > constants_1.MAX_FILE_SIZE_KB * 1024) {
|
|
93
|
-
return `(File contents excluded: size ${(stats.size / 1024).toFixed(2)}KB exceeds ${constants_1.MAX_FILE_SIZE_KB}KB limit)`;
|
|
94
|
-
}
|
|
95
|
-
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
96
|
-
if (options.lineNumbers) {
|
|
97
|
-
const lines = content.split('\n');
|
|
98
|
-
return numberLines(lines);
|
|
99
|
-
}
|
|
100
|
-
return content;
|
|
101
|
-
};
|
|
102
|
-
exports.defaultRenderer = defaultRenderer;
|
|
103
|
-
exports.RENDER_RULES = [
|
|
104
|
-
// csv
|
|
105
|
-
{
|
|
106
|
-
matcher: (name) => ['.csv'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
107
|
-
renderer: (rootPath, file, options) => {
|
|
108
|
-
const fullPath = path.join(rootPath, file.relativePath);
|
|
109
|
-
const { lines, hasMore } = readFirstNLines(fullPath, 10);
|
|
110
|
-
const preview = options.lineNumbers
|
|
111
|
-
? numberLines(lines)
|
|
112
|
-
: lines.join('\n');
|
|
113
|
-
return hasMore ? `${preview}\n... (more rows)` : preview;
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
// excel
|
|
117
|
-
{
|
|
118
|
-
matcher: (name) => ['.xls', '.xlsx'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
119
|
-
renderer: (rootPath, file, options) => '(Contents excluded)',
|
|
120
|
-
},
|
|
121
|
-
// media
|
|
122
|
-
{
|
|
123
|
-
matcher: (name) => ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.webp', '.mp4'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
124
|
-
renderer: (rootPath, file, options) => '(Contents excluded)',
|
|
125
|
-
},
|
|
126
|
-
// misc
|
|
127
|
-
{
|
|
128
|
-
matcher: (name) => ['.pdf', '.zip'].some((ext) => name.toLowerCase().endsWith(ext)),
|
|
129
|
-
renderer: (rootPath, file, options) => '(Contents excluded)',
|
|
130
|
-
},
|
|
131
|
-
];
|
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