barely-effect 0.1.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 +1 -0
- package/dist/ansi-colors/ansiColors.d.ts +11 -0
- package/dist/ansi-colors/ansiColors.d.ts.map +1 -0
- package/dist/ansi-colors/ansiColors.js +15 -0
- package/dist/ansi-colors/index.d.ts +2 -0
- package/dist/ansi-colors/index.d.ts.map +1 -0
- package/dist/ansi-colors/index.js +1 -0
- package/dist/assert.d.ts +10 -0
- package/dist/assert.d.ts.map +1 -0
- package/dist/assert.js +30 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/logger/LogFormatterJson.d.ts +5 -0
- package/dist/logger/LogFormatterJson.d.ts.map +1 -0
- package/dist/logger/LogFormatterJson.js +19 -0
- package/dist/logger/LogFormatterPretty.d.ts +17 -0
- package/dist/logger/LogFormatterPretty.d.ts.map +1 -0
- package/dist/logger/LogFormatterPretty.js +88 -0
- package/dist/logger/LogLevel.d.ts +4 -0
- package/dist/logger/LogLevel.d.ts.map +1 -0
- package/dist/logger/LogLevel.js +5 -0
- package/dist/logger/Logger.d.ts +36 -0
- package/dist/logger/Logger.d.ts.map +1 -0
- package/dist/logger/Logger.js +115 -0
- package/dist/logger/index.d.ts +7 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +5 -0
- package/dist/logger/parseLogArguments.d.ts +7 -0
- package/dist/logger/parseLogArguments.d.ts.map +1 -0
- package/dist/logger/parseLogArguments.js +51 -0
- package/dist/logger/resolveError.d.ts +7 -0
- package/dist/logger/resolveError.d.ts.map +1 -0
- package/dist/logger/resolveError.js +13 -0
- package/dist/logger/types.d.ts +38 -0
- package/dist/logger/types.d.ts.map +1 -0
- package/dist/logger/types.js +3 -0
- package/dist/networking/HttpClient.d.ts +78 -0
- package/dist/networking/HttpClient.d.ts.map +1 -0
- package/dist/networking/HttpClient.js +77 -0
- package/dist/networking/index.d.ts +2 -0
- package/dist/networking/index.d.ts.map +1 -0
- package/dist/networking/index.js +1 -0
- package/dist/platform/filesystem/AbsolutePath.d.ts +18 -0
- package/dist/platform/filesystem/AbsolutePath.d.ts.map +1 -0
- package/dist/platform/filesystem/AbsolutePath.js +41 -0
- package/dist/platform/filesystem/FileSystem.d.ts +30 -0
- package/dist/platform/filesystem/FileSystem.d.ts.map +1 -0
- package/dist/platform/filesystem/FileSystem.js +129 -0
- package/dist/platform/filesystem/IFileSystem.d.ts +98 -0
- package/dist/platform/filesystem/IFileSystem.d.ts.map +1 -0
- package/dist/platform/filesystem/IFileSystem.js +19 -0
- package/dist/platform/filesystem/KeyedMap.d.ts +23 -0
- package/dist/platform/filesystem/KeyedMap.d.ts.map +1 -0
- package/dist/platform/filesystem/KeyedMap.js +59 -0
- package/dist/platform/filesystem/MemoryFileSystem.d.ts +42 -0
- package/dist/platform/filesystem/MemoryFileSystem.d.ts.map +1 -0
- package/dist/platform/filesystem/MemoryFileSystem.js +200 -0
- package/dist/platform/filesystem/glob/cachedFs.d.ts +9 -0
- package/dist/platform/filesystem/glob/cachedFs.d.ts.map +1 -0
- package/dist/platform/filesystem/glob/cachedFs.js +25 -0
- package/dist/platform/filesystem/glob/glob.d.ts +15 -0
- package/dist/platform/filesystem/glob/glob.d.ts.map +1 -0
- package/dist/platform/filesystem/glob/glob.js +62 -0
- package/dist/platform/filesystem/glob/parseGlob.d.ts +11 -0
- package/dist/platform/filesystem/glob/parseGlob.d.ts.map +1 -0
- package/dist/platform/filesystem/glob/parseGlob.js +61 -0
- package/dist/platform/filesystem/index.d.ts +6 -0
- package/dist/platform/filesystem/index.d.ts.map +1 -0
- package/dist/platform/filesystem/index.js +5 -0
- package/dist/platform/process/EnvReader.d.ts +13 -0
- package/dist/platform/process/EnvReader.d.ts.map +1 -0
- package/dist/platform/process/EnvReader.js +92 -0
- package/dist/platform/process/ProcessContext.d.ts +34 -0
- package/dist/platform/process/ProcessContext.d.ts.map +1 -0
- package/dist/platform/process/ProcessContext.js +47 -0
- package/dist/time/Clock.d.ts +21 -0
- package/dist/time/Clock.d.ts.map +1 -0
- package/dist/time/Clock.js +27 -0
- package/dist/time/temporal.d.ts +5 -0
- package/dist/time/temporal.d.ts.map +1 -0
- package/dist/time/temporal.js +39 -0
- package/dist/utils/jsonStringify.d.ts +7 -0
- package/dist/utils/jsonStringify.d.ts.map +1 -0
- package/dist/utils/jsonStringify.js +23 -0
- package/dist/utils/runMain.d.ts +3 -0
- package/dist/utils/runMain.d.ts.map +1 -0
- package/dist/utils/runMain.js +75 -0
- package/package.json +71 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { AbsolutePath } from "./AbsolutePath";
|
|
3
|
+
import { FsDirNotEmptyError, FsNotADirError, type FsDirAccessError, type FsDirCreateError, type FsDirRemoveError, type FsFileAccessError, type FsFileWriteError, type FileSystemEntry, type IFileSystem } from "./IFileSystem";
|
|
4
|
+
export type MemoryFileSystemGenesisState = {
|
|
5
|
+
[path: string]: MemoryFileSystemGenesisState | string;
|
|
6
|
+
};
|
|
7
|
+
export declare class MemoryFileSystem implements IFileSystem {
|
|
8
|
+
private readonly entries;
|
|
9
|
+
private readonly root;
|
|
10
|
+
constructor(genesis?: MemoryFileSystemGenesisState);
|
|
11
|
+
readFile(path: AbsolutePath): Effect.Effect<string, FsFileAccessError>;
|
|
12
|
+
writeFile(path: AbsolutePath, contents: string): Effect.Effect<void, FsFileWriteError>;
|
|
13
|
+
exists(path: AbsolutePath): Effect.Effect<boolean>;
|
|
14
|
+
createDir(dirPath: AbsolutePath, options?: {
|
|
15
|
+
recursive: boolean;
|
|
16
|
+
}): Effect.Effect<void, FsDirCreateError>;
|
|
17
|
+
removeDir(dirPath: AbsolutePath, options: {
|
|
18
|
+
recursive: true;
|
|
19
|
+
force: true;
|
|
20
|
+
}): Effect.Effect<void, never>;
|
|
21
|
+
removeDir(dirPath: AbsolutePath, options: {
|
|
22
|
+
recursive: true;
|
|
23
|
+
force: false;
|
|
24
|
+
}): Effect.Effect<void, FsDirAccessError>;
|
|
25
|
+
removeDir(dirPath: AbsolutePath, options: {
|
|
26
|
+
recursive: false;
|
|
27
|
+
force: true;
|
|
28
|
+
}): Effect.Effect<void, FsDirNotEmptyError | FsNotADirError>;
|
|
29
|
+
removeDir(dirPath: AbsolutePath, options: {
|
|
30
|
+
recursive: false;
|
|
31
|
+
force: false;
|
|
32
|
+
}): Effect.Effect<void, FsDirRemoveError>;
|
|
33
|
+
listDir(path: AbsolutePath): Effect.Effect<FileSystemEntry[], FsDirAccessError>;
|
|
34
|
+
get(path: AbsolutePath): Effect.Effect<FileSystemEntry | undefined>;
|
|
35
|
+
private seedFromGenesis;
|
|
36
|
+
private writeFileSync;
|
|
37
|
+
private createDirectorySync;
|
|
38
|
+
private getDirectChildren;
|
|
39
|
+
private removeDirectoryRecursive;
|
|
40
|
+
private hasEntriesWithin;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=MemoryFileSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryFileSystem.d.ts","sourceRoot":"","sources":["../../../src/platform/filesystem/MemoryFileSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAEL,kBAAkB,EAIlB,cAAc,EAEd,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAA;AAGtB,MAAM,MAAM,4BAA4B,GAAG;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,4BAA4B,GAAG,MAAM,CAAA;CAAE,CAAA;AAIpG,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuD;IAC/E,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;gBAE7B,OAAO,GAAE,4BAAiC;IAKtD,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAetE,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAkBtF,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;IAMlD,SAAS,CACP,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAwB,GACpD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAiCxC,SAAS,CACP,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAE,GACxC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;IAC7B,SAAS,CACP,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,GACzC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC;IACxC,SAAS,CACP,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE;QAAE,SAAS,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,IAAI,CAAA;KAAE,GACzC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,CAAC;IAC3D,SAAS,CACP,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE;QAAE,SAAS,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,GAC1C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAuCxC,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,gBAAgB,CAAC;IAe/E,GAAG,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,GAAG,SAAS,CAAC;IAYnE,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,wBAAwB;IAUhC,OAAO,CAAC,gBAAgB;CASzB"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { AbsolutePath } from "./AbsolutePath.js";
|
|
3
|
+
import { FsAlreadyExistsError, FsDirNotEmptyError, FsDirNotFoundError, FsFileIsADirError, FsFileNotFoundError, FsNotADirError, FsParentNotFoundError, } from "./IFileSystem.js";
|
|
4
|
+
import { KeyedMap } from "./KeyedMap.js";
|
|
5
|
+
export class MemoryFileSystem {
|
|
6
|
+
entries = new KeyedMap((key) => key.path);
|
|
7
|
+
root = AbsolutePath("/");
|
|
8
|
+
constructor(genesis = {}) {
|
|
9
|
+
this.entries.set(this.root, { type: "dir" });
|
|
10
|
+
this.seedFromGenesis(AbsolutePath("/"), genesis);
|
|
11
|
+
}
|
|
12
|
+
readFile(path) {
|
|
13
|
+
return Effect.gen({ self: this }, function* () {
|
|
14
|
+
const entry = this.entries.get(path);
|
|
15
|
+
if (entry?.type === "dir") {
|
|
16
|
+
return yield* Effect.fail(new FsFileIsADirError({ path }));
|
|
17
|
+
}
|
|
18
|
+
if (!entry) {
|
|
19
|
+
return yield* Effect.fail(new FsFileNotFoundError({ path }));
|
|
20
|
+
}
|
|
21
|
+
return entry.content;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
writeFile(path, contents) {
|
|
25
|
+
return Effect.gen({ self: this }, function* () {
|
|
26
|
+
const parentPath = path.getDirPath();
|
|
27
|
+
const parentEntry = this.entries.get(parentPath);
|
|
28
|
+
if (!parentEntry) {
|
|
29
|
+
return yield* Effect.fail(new FsParentNotFoundError({ path }));
|
|
30
|
+
}
|
|
31
|
+
const entry = this.entries.get(path);
|
|
32
|
+
if (entry?.type === "dir") {
|
|
33
|
+
return yield* Effect.fail(new FsFileIsADirError({ path }));
|
|
34
|
+
}
|
|
35
|
+
this.entries.set(path, { type: "file", content: contents });
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
exists(path) {
|
|
39
|
+
return Effect.gen({ self: this }, function* () {
|
|
40
|
+
return (yield* this.get(path)) !== undefined;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
createDir(dirPath, options = { recursive: true }) {
|
|
44
|
+
return Effect.gen({ self: this }, function* () {
|
|
45
|
+
const entry = this.entries.get(dirPath);
|
|
46
|
+
if (entry?.type === "dir") {
|
|
47
|
+
if (!options.recursive) {
|
|
48
|
+
return yield* Effect.fail(new FsAlreadyExistsError({ path: dirPath }));
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const parentPath = dirPath.getDirPath();
|
|
53
|
+
if (!options.recursive && !this.entries.get(parentPath)) {
|
|
54
|
+
return yield* Effect.fail(new FsParentNotFoundError({ path: dirPath }));
|
|
55
|
+
}
|
|
56
|
+
if (options.recursive) {
|
|
57
|
+
let current = dirPath;
|
|
58
|
+
while (!this.entries.has(current)) {
|
|
59
|
+
this.entries.set(current, { type: "dir" });
|
|
60
|
+
const parent = current.getDirPath();
|
|
61
|
+
if (parent.eq(current)) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
current = parent;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this.entries.set(dirPath, { type: "dir" });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
removeDir(dirPath, options) {
|
|
73
|
+
return Effect.gen({ self: this }, function* () {
|
|
74
|
+
const entry = this.entries.get(dirPath);
|
|
75
|
+
if (entry?.type === "file") {
|
|
76
|
+
if (options.recursive && options.force) {
|
|
77
|
+
this.entries.delete(dirPath);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
return yield* Effect.fail(new FsNotADirError({ path: dirPath }));
|
|
81
|
+
}
|
|
82
|
+
if (!entry) {
|
|
83
|
+
if (options.force) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
return yield* Effect.fail(new FsDirNotFoundError({ path: dirPath }));
|
|
87
|
+
}
|
|
88
|
+
const hasChildren = this.hasEntriesWithin(dirPath);
|
|
89
|
+
if (hasChildren && !options.recursive) {
|
|
90
|
+
return yield* Effect.fail(new FsDirNotEmptyError({ path: dirPath }));
|
|
91
|
+
}
|
|
92
|
+
if (options.recursive) {
|
|
93
|
+
this.removeDirectoryRecursive(dirPath);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.entries.delete(dirPath);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
listDir(path) {
|
|
101
|
+
return Effect.gen({ self: this }, function* () {
|
|
102
|
+
const entry = this.entries.get(path);
|
|
103
|
+
if (entry?.type === "file") {
|
|
104
|
+
return yield* Effect.fail(new FsNotADirError({ path }));
|
|
105
|
+
}
|
|
106
|
+
if (!entry) {
|
|
107
|
+
return yield* Effect.fail(new FsDirNotFoundError({ path }));
|
|
108
|
+
}
|
|
109
|
+
return this.getDirectChildren(path);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
get(path) {
|
|
113
|
+
return Effect.sync(() => {
|
|
114
|
+
const entry = this.entries.get(path);
|
|
115
|
+
if (!entry) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
return { type: entry.type, path };
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
seedFromGenesis(cwd, genesis) {
|
|
122
|
+
for (const [key, value] of Object.entries(genesis)) {
|
|
123
|
+
const path = cwd.join(key);
|
|
124
|
+
if (typeof value === "string") {
|
|
125
|
+
this.createDirectorySync(path.getDirPath(), { recursive: true });
|
|
126
|
+
this.writeFileSync(path, value);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.createDirectorySync(path, { recursive: true });
|
|
130
|
+
this.seedFromGenesis(path, value);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
writeFileSync(path, contents) {
|
|
135
|
+
const parentPath = path.getDirPath();
|
|
136
|
+
const parentEntry = this.entries.get(parentPath);
|
|
137
|
+
if (!parentEntry) {
|
|
138
|
+
throw new Error(`Parent directory not found: ${parentPath.path}`);
|
|
139
|
+
}
|
|
140
|
+
const entry = this.entries.get(path);
|
|
141
|
+
if (entry?.type === "dir") {
|
|
142
|
+
throw new Error(`Path is a directory: ${path.path}`);
|
|
143
|
+
}
|
|
144
|
+
this.entries.set(path, { type: "file", content: contents });
|
|
145
|
+
}
|
|
146
|
+
createDirectorySync(dirPath, options) {
|
|
147
|
+
const entry = this.entries.get(dirPath);
|
|
148
|
+
if (entry?.type === "dir") {
|
|
149
|
+
if (!options.recursive) {
|
|
150
|
+
throw new Error(`Directory already exists: ${dirPath.path}`);
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (options.recursive) {
|
|
155
|
+
let current = dirPath;
|
|
156
|
+
while (!this.entries.has(current)) {
|
|
157
|
+
this.entries.set(current, { type: "dir" });
|
|
158
|
+
const parent = current.getDirPath();
|
|
159
|
+
if (parent.eq(current)) {
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
current = parent;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.entries.set(dirPath, { type: "dir" });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
getDirectChildren(dir) {
|
|
170
|
+
const files = [];
|
|
171
|
+
const dirs = [];
|
|
172
|
+
for (const [path, entry] of this.entries) {
|
|
173
|
+
if (path.getDirPath().eq(dir) && !path.eq(dir)) {
|
|
174
|
+
if (entry.type === "file") {
|
|
175
|
+
files.push({ type: "file", path });
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
dirs.push({ type: "dir", path });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return [...files, ...dirs];
|
|
183
|
+
}
|
|
184
|
+
removeDirectoryRecursive(dir) {
|
|
185
|
+
for (const [path] of this.entries) {
|
|
186
|
+
if (dir.contains(path)) {
|
|
187
|
+
this.entries.delete(path);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
this.entries.set(this.root, { type: "dir" });
|
|
191
|
+
}
|
|
192
|
+
hasEntriesWithin(dir) {
|
|
193
|
+
for (const [path] of this.entries) {
|
|
194
|
+
if (dir.contains(path) && !path.eq(dir)) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { AbsolutePath } from "../AbsolutePath";
|
|
3
|
+
import type { FsDirAccessError, FileSystemEntry, IFileSystem } from "../IFileSystem";
|
|
4
|
+
export interface GlobFs {
|
|
5
|
+
get(path: AbsolutePath): Effect.Effect<FileSystemEntry | undefined>;
|
|
6
|
+
listDir(path: AbsolutePath): Effect.Effect<FileSystemEntry[], FsDirAccessError>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createCachedFs(fs: IFileSystem): GlobFs;
|
|
9
|
+
//# sourceMappingURL=cachedFs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cachedFs.d.ts","sourceRoot":"","sources":["../../../../src/platform/filesystem/glob/cachedFs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEpF,MAAM,WAAW,MAAM;IACrB,GAAG,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,GAAG,SAAS,CAAC,CAAA;IACnE,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,gBAAgB,CAAC,CAAA;CAChF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAgCtD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
export function createCachedFs(fs) {
|
|
3
|
+
const getCache = new Map();
|
|
4
|
+
const listDirCache = new Map();
|
|
5
|
+
return {
|
|
6
|
+
get(path) {
|
|
7
|
+
const key = path.path;
|
|
8
|
+
if (getCache.has(key)) {
|
|
9
|
+
return Effect.succeed(getCache.get(key));
|
|
10
|
+
}
|
|
11
|
+
return fs.get(path).pipe(Effect.tap((result) => Effect.sync(() => {
|
|
12
|
+
getCache.set(key, result);
|
|
13
|
+
})));
|
|
14
|
+
},
|
|
15
|
+
listDir(path) {
|
|
16
|
+
const key = path.path;
|
|
17
|
+
if (listDirCache.has(key)) {
|
|
18
|
+
return Effect.succeed(listDirCache.get(key));
|
|
19
|
+
}
|
|
20
|
+
return fs.listDir(path).pipe(Effect.tap((result) => Effect.sync(() => {
|
|
21
|
+
listDirCache.set(key, result);
|
|
22
|
+
})));
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { FileSystemEntry, FsDirAccessError, IFileSystem } from "../IFileSystem";
|
|
3
|
+
import { AbsolutePath } from "../AbsolutePath";
|
|
4
|
+
export interface GlobOptions {
|
|
5
|
+
pattern: string;
|
|
6
|
+
onlyFiles?: boolean;
|
|
7
|
+
cwd: AbsolutePath;
|
|
8
|
+
}
|
|
9
|
+
export declare function glob(options: GlobOptions & {
|
|
10
|
+
onlyFiles: true;
|
|
11
|
+
}, fs: IFileSystem): Effect.Effect<AbsolutePath[], FsDirAccessError>;
|
|
12
|
+
export declare function glob(options: GlobOptions & {
|
|
13
|
+
onlyFiles?: false;
|
|
14
|
+
}, fs: IFileSystem): Effect.Effect<FileSystemEntry[], FsDirAccessError>;
|
|
15
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../../src/platform/filesystem/glob/glob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAGpF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAI9C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,GAAG,EAAE,YAAY,CAAA;CAClB;AAED,wBAAgB,IAAI,CAClB,OAAO,EAAE,WAAW,GAAG;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,EAC1C,EAAE,EAAE,WAAW,GACd,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,gBAAgB,CAAC,CAAA;AAClD,wBAAgB,IAAI,CAClB,OAAO,EAAE,WAAW,GAAG;IAAE,SAAS,CAAC,EAAE,KAAK,CAAA;CAAE,EAC5C,EAAE,EAAE,WAAW,GACd,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,gBAAgB,CAAC,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { assert } from "../../../assert.js";
|
|
3
|
+
import { AbsolutePath } from "../AbsolutePath.js";
|
|
4
|
+
import { createCachedFs } from "./cachedFs.js";
|
|
5
|
+
import { parseGlob } from "./parseGlob.js";
|
|
6
|
+
export function glob(options, fs) {
|
|
7
|
+
return Effect.gen(function* () {
|
|
8
|
+
const cwd = options.cwd;
|
|
9
|
+
const chunks = parseGlob(options.pattern);
|
|
10
|
+
const cachedFs = createCachedFs(fs);
|
|
11
|
+
const entries = yield* matchGlobWalker(chunks, cwd, cachedFs, new Set());
|
|
12
|
+
if (options.onlyFiles) {
|
|
13
|
+
return entries.filter((e) => e.type === "file").map((e) => e.path);
|
|
14
|
+
}
|
|
15
|
+
return entries;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function matchGlobWalker(chunks, cwd, fs, visited) {
|
|
19
|
+
return Effect.gen(function* () {
|
|
20
|
+
const cwdEntry = yield* fs.get(cwd);
|
|
21
|
+
assert(!!cwdEntry, `${cwd.path} does not exist`);
|
|
22
|
+
const [chunk, ...rest] = chunks;
|
|
23
|
+
if (!chunk) {
|
|
24
|
+
const alreadyVisited = visited.has(cwd.path);
|
|
25
|
+
if (alreadyVisited) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
visited.add(cwd.path);
|
|
29
|
+
return [cwdEntry];
|
|
30
|
+
}
|
|
31
|
+
if (cwdEntry.type === "file") {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
switch (chunk.type) {
|
|
35
|
+
case "literal": {
|
|
36
|
+
const newCwd = cwd.join(chunk.value);
|
|
37
|
+
if ((yield* fs.get(newCwd)) !== undefined) {
|
|
38
|
+
return yield* matchGlobWalker(rest, newCwd, fs, visited);
|
|
39
|
+
}
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
case "pattern": {
|
|
43
|
+
const entities = yield* fs.listDir(cwd);
|
|
44
|
+
const newCwds = entities
|
|
45
|
+
.filter((entity) => chunk.pattern.test(entity.path.getName()))
|
|
46
|
+
.map((m) => m.path);
|
|
47
|
+
const results = yield* Effect.all(newCwds.map((newCwd) => matchGlobWalker(rest, newCwd, fs, visited)), { concurrency: "unbounded" });
|
|
48
|
+
return results.flat();
|
|
49
|
+
}
|
|
50
|
+
case "globstar": {
|
|
51
|
+
const entities = yield* fs.listDir(cwd);
|
|
52
|
+
const newCwds = entities.map((m) => m.path);
|
|
53
|
+
const results = yield* Effect.all([
|
|
54
|
+
matchGlobWalker(rest, cwd, fs, visited),
|
|
55
|
+
...newCwds.map((newCwd) => matchGlobWalker(rest, newCwd, fs, visited)),
|
|
56
|
+
...newCwds.map((newCwd) => matchGlobWalker(chunks, newCwd, fs, visited)),
|
|
57
|
+
], { concurrency: "unbounded" });
|
|
58
|
+
return results.flat();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseGlob.d.ts","sourceRoot":"","sources":["../../../../src/platform/filesystem/glob/parseGlob.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAA;AAExB,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAItD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { assert } from "../../../assert.js";
|
|
2
|
+
export function parseGlob(pattern) {
|
|
3
|
+
const chunks = pattern.split("/").map(parseChunk);
|
|
4
|
+
return combineLiteralChunks(chunks);
|
|
5
|
+
}
|
|
6
|
+
function parseChunk(chunk) {
|
|
7
|
+
if (chunk === "**") {
|
|
8
|
+
return { type: "globstar" };
|
|
9
|
+
}
|
|
10
|
+
if (specialCharacters.some((c) => chunk.includes(c))) {
|
|
11
|
+
return { type: "pattern", pattern: globPatternToRegex(chunk) };
|
|
12
|
+
}
|
|
13
|
+
return { type: "literal", value: chunk };
|
|
14
|
+
}
|
|
15
|
+
const specialCharacters = ["*", "?", "{", "["];
|
|
16
|
+
function globPatternToRegex(globPattern) {
|
|
17
|
+
let regexString = "";
|
|
18
|
+
for (let i = 0; i < globPattern.length; i++) {
|
|
19
|
+
const c = globPattern[i];
|
|
20
|
+
if (c === "*") {
|
|
21
|
+
regexString += ".*";
|
|
22
|
+
}
|
|
23
|
+
else if (c === ".") {
|
|
24
|
+
regexString += "\\.";
|
|
25
|
+
}
|
|
26
|
+
else if (c === "?") {
|
|
27
|
+
regexString += ".";
|
|
28
|
+
}
|
|
29
|
+
else if (c === "{") {
|
|
30
|
+
const closingBracketIndex = globPattern.indexOf("}", i + 1);
|
|
31
|
+
assert(closingBracketIndex !== -1, `Glob pattern ${globPattern} incorrect: unbalanced {}`);
|
|
32
|
+
const optionsString = globPattern.slice(i + 1, closingBracketIndex);
|
|
33
|
+
const options = optionsString.split(",").map((s) => escapeRegex(s.trim()));
|
|
34
|
+
regexString += `(${options.join("|")})`;
|
|
35
|
+
i = closingBracketIndex;
|
|
36
|
+
}
|
|
37
|
+
else if (c === "[") {
|
|
38
|
+
assert(false, "[] not supported yet");
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
regexString += c;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return new RegExp(`^${regexString}$`);
|
|
45
|
+
}
|
|
46
|
+
function escapeRegex(str) {
|
|
47
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
48
|
+
}
|
|
49
|
+
function combineLiteralChunks(chunks) {
|
|
50
|
+
return chunks.reduce((acc, chunk) => {
|
|
51
|
+
if (chunk.type === "literal" && acc.length > 0) {
|
|
52
|
+
const lastChunk = acc[acc.length - 1];
|
|
53
|
+
if (lastChunk.type === "literal") {
|
|
54
|
+
lastChunk.value += "/" + chunk.value;
|
|
55
|
+
return acc;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
acc.push(chunk);
|
|
59
|
+
return acc;
|
|
60
|
+
}, []);
|
|
61
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from "./IFileSystem";
|
|
2
|
+
export { FileSystem } from "./FileSystem";
|
|
3
|
+
export { MemoryFileSystem, type MemoryFileSystemGenesisState } from "./MemoryFileSystem";
|
|
4
|
+
export { AbsolutePath } from "./AbsolutePath";
|
|
5
|
+
export { glob, type GlobOptions } from "./glob/glob";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/platform/filesystem/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,gBAAgB,EAAE,KAAK,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AACxF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
export declare class EnvReader {
|
|
3
|
+
private readonly env;
|
|
4
|
+
constructor(env: Record<string, string | undefined>);
|
|
5
|
+
optionalString(name: string): Effect.Effect<string | undefined>;
|
|
6
|
+
string(name: string, defaultValue?: string): Effect.Effect<string>;
|
|
7
|
+
stringOf<T extends string[]>(key: string, allowedValues: readonly [...T], fallback?: T[number]): Effect.Effect<T[number]>;
|
|
8
|
+
optionalNumber(name: string): Effect.Effect<number | undefined>;
|
|
9
|
+
number(name: string, defaultValue?: number): Effect.Effect<number>;
|
|
10
|
+
optionalBoolean(name: string): Effect.Effect<boolean | undefined>;
|
|
11
|
+
boolean(name: string, defaultValue?: boolean): Effect.Effect<boolean>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=EnvReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnvReader.d.ts","sourceRoot":"","sources":["../../../src/platform/process/EnvReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC;IAI/D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IAelE,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GACnB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IA0B3B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC;IAmB/D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IAelE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;IAoBjE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CActE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
export class EnvReader {
|
|
3
|
+
env;
|
|
4
|
+
constructor(env) {
|
|
5
|
+
this.env = env;
|
|
6
|
+
}
|
|
7
|
+
optionalString(name) {
|
|
8
|
+
return Effect.sync(() => this.env[name]);
|
|
9
|
+
}
|
|
10
|
+
string(name, defaultValue) {
|
|
11
|
+
return Effect.gen({ self: this }, function* () {
|
|
12
|
+
const value = yield* this.optionalString(name);
|
|
13
|
+
if (value !== undefined) {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
if (defaultValue !== undefined) {
|
|
17
|
+
return defaultValue;
|
|
18
|
+
}
|
|
19
|
+
return yield* Effect.die(new Error(`Environment variable ${name} not found`));
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
stringOf(key, allowedValues, fallback) {
|
|
23
|
+
return Effect.gen({ self: this }, function* () {
|
|
24
|
+
const value = yield* this.optionalString(key);
|
|
25
|
+
if (value === undefined) {
|
|
26
|
+
if (fallback !== undefined) {
|
|
27
|
+
return fallback;
|
|
28
|
+
}
|
|
29
|
+
return yield* Effect.die(new Error(`Environment variable ${key} not found`));
|
|
30
|
+
}
|
|
31
|
+
if (allowedValues.includes(value)) {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (fallback !== undefined) {
|
|
35
|
+
return fallback;
|
|
36
|
+
}
|
|
37
|
+
return yield* Effect.die(new Error(`Environment variable ${key} has invalid value "${value}". Allowed values: ${allowedValues.join(", ")}`));
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
optionalNumber(name) {
|
|
41
|
+
return Effect.gen({ self: this }, function* () {
|
|
42
|
+
const value = yield* this.optionalString(name);
|
|
43
|
+
if (value === undefined) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const parsed = Number(value);
|
|
47
|
+
if (Number.isNaN(parsed) || value.trim() === "") {
|
|
48
|
+
return yield* Effect.die(new Error(`Environment variable ${name} has invalid number value "${value}"`));
|
|
49
|
+
}
|
|
50
|
+
return parsed;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
number(name, defaultValue) {
|
|
54
|
+
return Effect.gen({ self: this }, function* () {
|
|
55
|
+
const value = yield* this.optionalNumber(name);
|
|
56
|
+
if (value !== undefined) {
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
if (defaultValue !== undefined) {
|
|
60
|
+
return defaultValue;
|
|
61
|
+
}
|
|
62
|
+
return yield* Effect.die(new Error(`Environment variable ${name} not found`));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
optionalBoolean(name) {
|
|
66
|
+
return Effect.gen({ self: this }, function* () {
|
|
67
|
+
const value = yield* this.optionalString(name);
|
|
68
|
+
if (value === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (value === "true" || value === "1" || value === "yes") {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
if (value === "false" || value === "0" || value === "no") {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return yield* Effect.die(new Error(`Environment variable ${name} has invalid boolean value "${value}"`));
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
boolean(name, defaultValue) {
|
|
81
|
+
return Effect.gen({ self: this }, function* () {
|
|
82
|
+
const value = yield* this.optionalBoolean(name);
|
|
83
|
+
if (value !== undefined) {
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
if (defaultValue !== undefined) {
|
|
87
|
+
return defaultValue;
|
|
88
|
+
}
|
|
89
|
+
return yield* Effect.die(new Error(`Environment variable ${name} not found`));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AbsolutePath } from "../filesystem/AbsolutePath";
|
|
2
|
+
import { EnvReader } from "./EnvReader";
|
|
3
|
+
export interface IProcessContext {
|
|
4
|
+
readonly cwd: AbsolutePath;
|
|
5
|
+
readonly env: EnvReader;
|
|
6
|
+
readonly home: AbsolutePath;
|
|
7
|
+
pathFromCwd(inputPath: string): AbsolutePath;
|
|
8
|
+
resolvePath(inputPath: string): AbsolutePath;
|
|
9
|
+
}
|
|
10
|
+
export declare abstract class AbstractProcessContext implements IProcessContext {
|
|
11
|
+
abstract readonly cwd: AbsolutePath;
|
|
12
|
+
abstract readonly env: EnvReader;
|
|
13
|
+
abstract readonly home: AbsolutePath;
|
|
14
|
+
pathFromCwd(inputPath: string): AbsolutePath;
|
|
15
|
+
resolvePath(inputPath: string): AbsolutePath;
|
|
16
|
+
}
|
|
17
|
+
export declare class ProcessContext extends AbstractProcessContext {
|
|
18
|
+
readonly home: AbsolutePath;
|
|
19
|
+
readonly cwd: AbsolutePath;
|
|
20
|
+
readonly env: EnvReader;
|
|
21
|
+
constructor();
|
|
22
|
+
}
|
|
23
|
+
export interface InMemoryProcessContextOptions {
|
|
24
|
+
cwd?: AbsolutePath;
|
|
25
|
+
home?: AbsolutePath;
|
|
26
|
+
env?: Record<string, string | undefined>;
|
|
27
|
+
}
|
|
28
|
+
export declare class InMemoryProcessContext extends AbstractProcessContext {
|
|
29
|
+
readonly home: AbsolutePath;
|
|
30
|
+
readonly cwd: AbsolutePath;
|
|
31
|
+
readonly env: EnvReader;
|
|
32
|
+
constructor(options?: InMemoryProcessContextOptions);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ProcessContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessContext.d.ts","sourceRoot":"","sources":["../../../src/platform/process/ProcessContext.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAA;IAC1B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAE3B,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAAA;IAC5C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAAA;CAC7C;AAED,8BAAsB,sBAAuB,YAAW,eAAe;IACrE,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;IAChC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAEpC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAI5C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;CAsB7C;AAED,qBAAa,cAAe,SAAQ,sBAAsB;IACxD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAiC;IAC5D,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAkC;IAC5D,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;;CAMxB;AAED,MAAM,WAAW,6BAA6B;IAC5C,GAAG,CAAC,EAAE,YAAY,CAAA;IAClB,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACzC;AAED,qBAAa,sBAAuB,SAAQ,sBAAsB;IAChE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAA;IAC1B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;gBAEX,OAAO,CAAC,EAAE,6BAA6B;CAMpD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { AbsolutePath } from "../filesystem/AbsolutePath.js";
|
|
4
|
+
import { EnvReader } from "./EnvReader.js";
|
|
5
|
+
export class AbstractProcessContext {
|
|
6
|
+
pathFromCwd(inputPath) {
|
|
7
|
+
return this.cwd.join(inputPath);
|
|
8
|
+
}
|
|
9
|
+
resolvePath(inputPath) {
|
|
10
|
+
if (inputPath === "") {
|
|
11
|
+
throw new Error("Path cannot be empty");
|
|
12
|
+
}
|
|
13
|
+
if (path.isAbsolute(inputPath)) {
|
|
14
|
+
return AbsolutePath(inputPath);
|
|
15
|
+
}
|
|
16
|
+
if (inputPath.startsWith("~")) {
|
|
17
|
+
const pathAfterTilde = inputPath.slice(1);
|
|
18
|
+
if (pathAfterTilde === "" || pathAfterTilde === "/") {
|
|
19
|
+
return this.home;
|
|
20
|
+
}
|
|
21
|
+
if (pathAfterTilde.startsWith("/")) {
|
|
22
|
+
return this.home.join(pathAfterTilde);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return this.cwd.join(inputPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class ProcessContext extends AbstractProcessContext {
|
|
29
|
+
home = new AbsolutePath(os.homedir());
|
|
30
|
+
cwd = new AbsolutePath(process.cwd());
|
|
31
|
+
env;
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
this.env = new EnvReader(process.env);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class InMemoryProcessContext extends AbstractProcessContext {
|
|
38
|
+
home;
|
|
39
|
+
cwd;
|
|
40
|
+
env;
|
|
41
|
+
constructor(options) {
|
|
42
|
+
super();
|
|
43
|
+
this.home = options?.home ?? AbsolutePath("/home");
|
|
44
|
+
this.cwd = options?.cwd ?? AbsolutePath("/home/workspace");
|
|
45
|
+
this.env = new EnvReader(options?.env ?? {});
|
|
46
|
+
}
|
|
47
|
+
}
|