@bluewombat/isolation-copy 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 +12 -0
- package/dist/copy-merge.d.ts +25 -0
- package/dist/copy-merge.d.ts.map +1 -0
- package/dist/copy-merge.js +156 -0
- package/dist/copy-merge.js.map +1 -0
- package/dist/copy-working-files.d.ts +14 -0
- package/dist/copy-working-files.d.ts.map +1 -0
- package/dist/copy-working-files.js +52 -0
- package/dist/copy-working-files.js.map +1 -0
- package/dist/fold.d.ts +6 -0
- package/dist/fold.d.ts.map +1 -0
- package/dist/fold.js +14 -0
- package/dist/fold.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/isolation.d.ts +6 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +21 -0
- package/dist/isolation.js.map +1 -0
- package/dist/strategy.d.ts +3 -0
- package/dist/strategy.d.ts.map +1 -0
- package/dist/strategy.js +7 -0
- package/dist/strategy.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Isolation: copy
|
|
2
|
+
|
|
3
|
+
Directory-copy attach and directory-merge fold. Host (or a Transformer CLI)
|
|
4
|
+
loads this package when `workLine.isolation` is `@bluewombat/isolation-copy`.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { strategy } from "@bluewombat/isolation-copy";
|
|
8
|
+
// strategy.isolation → Isolator
|
|
9
|
+
// strategy.fold → Integrator
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
No git bookkeeping. A Child is a plain directory snapshot of the Parent.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type FoldStop } from "@bluewombat/integrator";
|
|
2
|
+
export type PathKind = "file" | "directory" | "symlink" | "missing";
|
|
3
|
+
export type CopyMergeResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
stop: FoldStop;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
conflict: true;
|
|
11
|
+
report: string;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
detail: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Directory merge of Child working files into Parent. Never forced.
|
|
18
|
+
* Same-type bytes differences take the Child. Incompatible types are a conflict.
|
|
19
|
+
*/
|
|
20
|
+
export declare function copyMerge(input: {
|
|
21
|
+
parent: string;
|
|
22
|
+
child: string;
|
|
23
|
+
shouldStop: () => FoldStop | undefined;
|
|
24
|
+
}): Promise<CopyMergeResult>;
|
|
25
|
+
//# sourceMappingURL=copy-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-merge.d.ts","sourceRoot":"","sources":["../src/copy-merge.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,QAAQ,EAA2C,MAAM,wBAAwB,CAAC;AAEhG,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpE,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;GAGG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAC;CACxC,GAAG,OAAO,CAAC,eAAe,CAAC,CAyB3B"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { copyFile, lstat, mkdir, readdir, readFile, readlink, symlink, unlink, } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { IntegrationStoppedError, throwIfStopped } from "@bluewombat/integrator";
|
|
4
|
+
/**
|
|
5
|
+
* Directory merge of Child working files into Parent. Never forced.
|
|
6
|
+
* Same-type bytes differences take the Child. Incompatible types are a conflict.
|
|
7
|
+
*/
|
|
8
|
+
export async function copyMerge(input) {
|
|
9
|
+
try {
|
|
10
|
+
const conflictPath = await findTypeConflict(input.parent, input.child, true, "", input.shouldStop);
|
|
11
|
+
if (conflictPath !== undefined) {
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
conflict: true,
|
|
15
|
+
report: `Cannot fold without choosing a side: incompatible types at "${conflictPath}".`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
await applyCopyMerge(input.parent, input.child, true, input.shouldStop);
|
|
19
|
+
return { ok: true };
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof IntegrationStoppedError) {
|
|
23
|
+
return { ok: false, stop: error.stop };
|
|
24
|
+
}
|
|
25
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
26
|
+
return { ok: false, detail: `Integration could not complete: ${detail}` };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function direntKind(entry) {
|
|
30
|
+
if (entry.isSymbolicLink()) {
|
|
31
|
+
return "symlink";
|
|
32
|
+
}
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
return "directory";
|
|
35
|
+
}
|
|
36
|
+
if (entry.isFile()) {
|
|
37
|
+
return "file";
|
|
38
|
+
}
|
|
39
|
+
return "other";
|
|
40
|
+
}
|
|
41
|
+
async function pathKind(path) {
|
|
42
|
+
try {
|
|
43
|
+
const stats = await lstat(path);
|
|
44
|
+
if (stats.isSymbolicLink()) {
|
|
45
|
+
return "symlink";
|
|
46
|
+
}
|
|
47
|
+
if (stats.isDirectory()) {
|
|
48
|
+
return "directory";
|
|
49
|
+
}
|
|
50
|
+
if (stats.isFile()) {
|
|
51
|
+
return "file";
|
|
52
|
+
}
|
|
53
|
+
return "other";
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
57
|
+
return "missing";
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function findTypeConflict(parentDir, childDir, isRoot, relativePrefix, shouldStop) {
|
|
63
|
+
await throwIfStopped(shouldStop);
|
|
64
|
+
const entries = await readdir(childDir, { withFileTypes: true });
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
await throwIfStopped(shouldStop);
|
|
67
|
+
if (isRoot && entry.name === ".git") {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const relative = relativePrefix === "" ? entry.name : `${relativePrefix}/${entry.name}`;
|
|
71
|
+
const parentPath = join(parentDir, entry.name);
|
|
72
|
+
const childKind = direntKind(entry);
|
|
73
|
+
if (childKind === "other") {
|
|
74
|
+
throw new Error(`Cannot fold "${join(childDir, entry.name)}": unsupported file type.`);
|
|
75
|
+
}
|
|
76
|
+
const parentKind = await pathKind(parentPath);
|
|
77
|
+
if (parentKind === "other") {
|
|
78
|
+
throw new Error(`Cannot fold "${parentPath}": unsupported file type.`);
|
|
79
|
+
}
|
|
80
|
+
if (parentKind === "missing") {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (parentKind === "directory" && childKind === "directory") {
|
|
84
|
+
const nested = await findTypeConflict(parentPath, join(childDir, entry.name), false, relative, shouldStop);
|
|
85
|
+
if (nested !== undefined) {
|
|
86
|
+
return nested;
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (parentKind !== childKind) {
|
|
91
|
+
return relative;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
async function applyCopyMerge(parentDir, childDir, isRoot, shouldStop) {
|
|
97
|
+
await throwIfStopped(shouldStop);
|
|
98
|
+
const entries = await readdir(childDir, { withFileTypes: true });
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
await throwIfStopped(shouldStop);
|
|
101
|
+
if (isRoot && entry.name === ".git") {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const parentPath = join(parentDir, entry.name);
|
|
105
|
+
const childPath = join(childDir, entry.name);
|
|
106
|
+
const childKind = direntKind(entry);
|
|
107
|
+
if (childKind === "other") {
|
|
108
|
+
throw new Error(`Cannot fold "${childPath}": unsupported file type.`);
|
|
109
|
+
}
|
|
110
|
+
const parentKind = await pathKind(parentPath);
|
|
111
|
+
if (parentKind === "other") {
|
|
112
|
+
throw new Error(`Cannot fold "${parentPath}": unsupported file type.`);
|
|
113
|
+
}
|
|
114
|
+
if (parentKind === "missing") {
|
|
115
|
+
if (childKind !== "missing") {
|
|
116
|
+
await copyIncoming(childPath, parentPath, childKind, shouldStop);
|
|
117
|
+
}
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (parentKind === "directory" && childKind === "directory") {
|
|
121
|
+
await applyCopyMerge(parentPath, childPath, false, shouldStop);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (parentKind === "file" && childKind === "file") {
|
|
125
|
+
const parentBytes = await readFile(parentPath);
|
|
126
|
+
const childBytes = await readFile(childPath);
|
|
127
|
+
if (!parentBytes.equals(childBytes)) {
|
|
128
|
+
await copyFile(childPath, parentPath);
|
|
129
|
+
}
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (parentKind === "symlink" && childKind === "symlink") {
|
|
133
|
+
const parentTarget = await readlink(parentPath);
|
|
134
|
+
const childTarget = await readlink(childPath);
|
|
135
|
+
if (parentTarget !== childTarget) {
|
|
136
|
+
await unlink(parentPath);
|
|
137
|
+
await symlink(childTarget, parentPath);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function copyIncoming(childPath, parentPath, childKind, shouldStop) {
|
|
143
|
+
await throwIfStopped(shouldStop);
|
|
144
|
+
if (childKind === "directory") {
|
|
145
|
+
await mkdir(parentPath);
|
|
146
|
+
await applyCopyMerge(parentPath, childPath, false, shouldStop);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (childKind === "symlink") {
|
|
150
|
+
const target = await readlink(childPath);
|
|
151
|
+
await symlink(target, parentPath);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
await copyFile(childPath, parentPath);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=copy-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-merge.js","sourceRoot":"","sources":["../src/copy-merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type IsolationStop, IsolationStoppedError } from "@bluewombat/isolator";
|
|
2
|
+
/**
|
|
3
|
+
* Copy working files from `from` into an existing `to` directory.
|
|
4
|
+
* Skips `.git` only at the root of `from` when `skipGitAtRoot` is set.
|
|
5
|
+
*/
|
|
6
|
+
export declare function copyWorkingFiles(input: {
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
skipGitAtRoot: boolean;
|
|
10
|
+
shouldStop: () => IsolationStop | undefined;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function wipeWorkingFiles(directory: string, shouldStop: () => IsolationStop | undefined): Promise<void>;
|
|
13
|
+
export { IsolationStoppedError };
|
|
14
|
+
//# sourceMappingURL=copy-working-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-working-files.d.ts","sourceRoot":"","sources":["../src/copy-working-files.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,qBAAqB,EAAkB,MAAM,sBAAsB,CAAC;AAEjG;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,aAAa,GAAG,SAAS,CAAC;CAC7C,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhB;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,aAAa,GAAG,SAAS,GAC1C,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { copyFile, mkdir, readdir, readlink, rm, symlink } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { IsolationStoppedError, throwIfStopped } from "@bluewombat/isolator";
|
|
4
|
+
/**
|
|
5
|
+
* Copy working files from `from` into an existing `to` directory.
|
|
6
|
+
* Skips `.git` only at the root of `from` when `skipGitAtRoot` is set.
|
|
7
|
+
*/
|
|
8
|
+
export async function copyWorkingFiles(input) {
|
|
9
|
+
await copyDir(input.from, input.to, true, input.skipGitAtRoot, input.shouldStop);
|
|
10
|
+
}
|
|
11
|
+
export async function wipeWorkingFiles(directory, shouldStop) {
|
|
12
|
+
await throwIfStopped(shouldStop);
|
|
13
|
+
const entries = await readdir(directory);
|
|
14
|
+
for (const name of entries) {
|
|
15
|
+
await throwIfStopped(shouldStop);
|
|
16
|
+
if (name === ".git") {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
await rm(join(directory, name), { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export { IsolationStoppedError };
|
|
23
|
+
async function copyDir(from, to, isRoot, skipGitAtRoot, shouldStop) {
|
|
24
|
+
await throwIfStopped(shouldStop);
|
|
25
|
+
if (!isRoot) {
|
|
26
|
+
await mkdir(to);
|
|
27
|
+
}
|
|
28
|
+
const entries = await readdir(from, { withFileTypes: true });
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
await throwIfStopped(shouldStop);
|
|
31
|
+
if (isRoot && skipGitAtRoot && entry.name === ".git") {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const src = join(from, entry.name);
|
|
35
|
+
const dest = join(to, entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
await copyDir(src, dest, false, false, shouldStop);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (entry.isSymbolicLink()) {
|
|
41
|
+
const target = await readlink(src);
|
|
42
|
+
await symlink(target, dest);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (entry.isFile()) {
|
|
46
|
+
await copyFile(src, dest);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Cannot isolate "${src}": unsupported file type.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=copy-working-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-working-files.js","sourceRoot":"","sources":["../src/copy-working-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAsB,qBAAqB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjG;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAKtC;IACC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,UAA2C;IAE3C,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,SAAS;QACX,CAAC;QACD,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC;AAEjC,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,EAAU,EACV,MAAe,EACf,aAAsB,EACtB,UAA2C;IAE3C,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;QACjC,IAAI,MAAM,IAAI,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACrD,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,MAAM,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,2BAA2B,CAAC,CAAC;IACrE,CAAC;AACH,CAAC"}
|
package/dist/fold.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../src/fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,WAQtB,CAAC"}
|
package/dist/fold.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { copyMerge } from "./copy-merge.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fold by directory merge. Same-type bytes take the Child.
|
|
4
|
+
*/
|
|
5
|
+
export const copyFold = {
|
|
6
|
+
async fold(input) {
|
|
7
|
+
return await copyMerge({
|
|
8
|
+
parent: input.parent,
|
|
9
|
+
child: input.child,
|
|
10
|
+
shouldStop: input.shouldStop,
|
|
11
|
+
});
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=fold.js.map
|
package/dist/fold.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold.js","sourceRoot":"","sources":["../src/fold.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,KAAK,CAAC,IAAI,CAAC,KAAK;QACd,OAAO,MAAM,SAAS,CAAC;YACrB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolation.d.ts","sourceRoot":"","sources":["../src/isolation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,gBAc3B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { copyWorkingFiles } from "./copy-working-files.js";
|
|
3
|
+
/**
|
|
4
|
+
* Isolation by directory copy. No git bookkeeping.
|
|
5
|
+
*/
|
|
6
|
+
export const copyIsolation = {
|
|
7
|
+
async attach(input) {
|
|
8
|
+
await mkdir(input.child);
|
|
9
|
+
await copyWorkingFiles({
|
|
10
|
+
from: input.parent,
|
|
11
|
+
to: input.child,
|
|
12
|
+
skipGitAtRoot: false,
|
|
13
|
+
shouldStop: input.shouldStop,
|
|
14
|
+
});
|
|
15
|
+
return { ok: true };
|
|
16
|
+
},
|
|
17
|
+
async abort() {
|
|
18
|
+
// A copy leaves no bookkeeping on the Parent.
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=isolation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolation.js","sourceRoot":"","sources":["../src/isolation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAqB;IAC7C,KAAK,CAAC,MAAM,CAAC,KAAK;QAChB,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,MAAM,gBAAgB,CAAC;YACrB,IAAI,EAAE,KAAK,CAAC,MAAM;YAClB,EAAE,EAAE,KAAK,CAAC,KAAK;YACf,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,8CAA8C;IAChD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,QAAQ,EAAE,iBAGtB,CAAC"}
|
package/dist/strategy.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.js","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,SAAS,EAAE,aAAa;IACxB,IAAI,EAAE,QAAQ;CACf,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FoldBackend } from "@bluewombat/integrator";
|
|
2
|
+
import type { IsolationBackend } from "@bluewombat/isolator";
|
|
3
|
+
/** One Isolation method: how a Child is attached, and how it folds back. */
|
|
4
|
+
export type IsolationStrategy = {
|
|
5
|
+
isolation: IsolationBackend;
|
|
6
|
+
fold: FoldBackend;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bluewombat/isolation-copy",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Isolation strategy: directory copy attach, directory merge fold.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mason",
|
|
8
|
+
"bluewombat",
|
|
9
|
+
"isolation"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://github.com/tilap/bluewombat/tree/main/packages/plugins/isolation-copy#readme",
|
|
13
|
+
"bugs": "https://github.com/tilap/bluewombat/issues",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/tilap/bluewombat.git",
|
|
17
|
+
"directory": "packages/plugins/isolation-copy"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=24.20.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"lint": "biome check .",
|
|
38
|
+
"format": "biome check --write .",
|
|
39
|
+
"tsc": "tsc --noEmit",
|
|
40
|
+
"test": "tsx --test $(find src -name '*.test.ts')",
|
|
41
|
+
"build": "tsc -p tsconfig.build.json"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@bluewombat/integrator": "^0.1.0",
|
|
45
|
+
"@bluewombat/isolator": "^0.1.0"
|
|
46
|
+
}
|
|
47
|
+
}
|