@decohere/devkit 0.0.1-dev.119
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 +14 -0
- package/commonjs/src/cli/action.js +65 -0
- package/commonjs/src/cli/command.js +127 -0
- package/commonjs/src/cli/index.js +61 -0
- package/commonjs/src/cli/module.type.js +18 -0
- package/commonjs/src/cli/options.js +115 -0
- package/commonjs/src/diagnostics/index.js +22 -0
- package/commonjs/src/diagnostics/trace.js +79 -0
- package/commonjs/src/interop/docker/docker.js +54 -0
- package/commonjs/src/interop/errors/interop.error.js +12 -0
- package/commonjs/src/interop/git/git.js +134 -0
- package/commonjs/src/interop/git/git.types.js +4 -0
- package/commonjs/src/interop/index.js +97 -0
- package/commonjs/src/interop/node/index.js +18 -0
- package/commonjs/src/interop/node/node.js +45 -0
- package/commonjs/src/interop/npm/npm.js +231 -0
- package/commonjs/src/interop/npm/npm.types.js +16 -0
- package/commonjs/src/interop/pnpm/pnpm.js +34 -0
- package/commonjs/src/interop/pnpm/pnpm.types.js +4 -0
- package/commonjs/src/interop/shell/shell.argv.js +45 -0
- package/commonjs/src/interop/shell/shell.js +105 -0
- package/commonjs/src/interop/shell/shell.types.js +4 -0
- package/commonjs/src/interop/types/detect-package-manager.js +71 -0
- package/commonjs/src/interop/types/package-manager.js +4 -0
- package/commonjs/src/interop/yarn/yarn.js +34 -0
- package/commonjs/src/interop/yarn/yarn.types.js +4 -0
- package/commonjs/src/io/find-directories.js +21 -0
- package/commonjs/src/io/find-file.js +45 -0
- package/commonjs/src/io/index.js +20 -0
- package/commonjs/src/io/watch.js +261 -0
- package/es6/src/cli/action.js +47 -0
- package/es6/src/cli/command.js +106 -0
- package/es6/src/cli/index.js +4 -0
- package/es6/src/cli/module.type.js +11 -0
- package/es6/src/cli/options.js +76 -0
- package/es6/src/diagnostics/index.js +1 -0
- package/es6/src/diagnostics/trace.js +61 -0
- package/es6/src/interop/docker/docker.js +44 -0
- package/es6/src/interop/errors/interop.error.js +2 -0
- package/es6/src/interop/git/git.js +124 -0
- package/es6/src/interop/git/git.types.js +1 -0
- package/es6/src/interop/index.js +21 -0
- package/es6/src/interop/node/index.js +1 -0
- package/es6/src/interop/node/node.js +35 -0
- package/es6/src/interop/npm/npm.js +180 -0
- package/es6/src/interop/npm/npm.types.js +6 -0
- package/es6/src/interop/pnpm/pnpm.js +24 -0
- package/es6/src/interop/pnpm/pnpm.types.js +1 -0
- package/es6/src/interop/shell/shell.argv.js +35 -0
- package/es6/src/interop/shell/shell.js +95 -0
- package/es6/src/interop/shell/shell.types.js +1 -0
- package/es6/src/interop/types/detect-package-manager.js +50 -0
- package/es6/src/interop/types/package-manager.js +1 -0
- package/es6/src/interop/yarn/yarn.js +24 -0
- package/es6/src/interop/yarn/yarn.types.js +1 -0
- package/es6/src/io/find-directories.js +11 -0
- package/es6/src/io/find-file.js +27 -0
- package/es6/src/io/index.js +3 -0
- package/es6/src/io/watch.js +238 -0
- package/package.json +49 -0
- package/types/src/cli/action.d.ts +36 -0
- package/types/src/cli/command.d.ts +34 -0
- package/types/src/cli/index.d.ts +7 -0
- package/types/src/cli/module.type.d.ts +36 -0
- package/types/src/cli/options.d.ts +28 -0
- package/types/src/diagnostics/index.d.ts +1 -0
- package/types/src/diagnostics/trace.d.ts +10 -0
- package/types/src/interop/docker/docker.d.ts +19 -0
- package/types/src/interop/errors/interop.error.d.ts +2 -0
- package/types/src/interop/git/git.d.ts +16 -0
- package/types/src/interop/git/git.types.d.ts +14 -0
- package/types/src/interop/index.d.ts +14 -0
- package/types/src/interop/node/index.d.ts +1 -0
- package/types/src/interop/node/node.d.ts +5 -0
- package/types/src/interop/npm/npm.d.ts +29 -0
- package/types/src/interop/npm/npm.types.d.ts +24 -0
- package/types/src/interop/pnpm/pnpm.d.ts +9 -0
- package/types/src/interop/pnpm/pnpm.types.d.ts +3 -0
- package/types/src/interop/shell/shell.argv.d.ts +5 -0
- package/types/src/interop/shell/shell.d.ts +6 -0
- package/types/src/interop/shell/shell.types.d.ts +9 -0
- package/types/src/interop/types/detect-package-manager.d.ts +4 -0
- package/types/src/interop/types/package-manager.d.ts +10 -0
- package/types/src/interop/yarn/yarn.d.ts +9 -0
- package/types/src/interop/yarn/yarn.types.d.ts +3 -0
- package/types/src/io/find-directories.d.ts +2 -0
- package/types/src/io/find-file.d.ts +9 -0
- package/types/src/io/index.d.ts +3 -0
- package/types/src/io/watch.d.ts +16 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "Shell", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Shell;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _nodechild_process = require("node:child_process");
|
|
12
|
+
const _scribe = require("@decohere/scribe");
|
|
13
|
+
const _interoperror = require("../errors/interop.error.js");
|
|
14
|
+
const _shellargv = require("./shell.argv.js");
|
|
15
|
+
class Shell {
|
|
16
|
+
async run(options, ...args) {
|
|
17
|
+
const logger = _scribe.scribe.logger(Shell.name);
|
|
18
|
+
const argv = args ?? [];
|
|
19
|
+
const argvFields = _shellargv.shellArgv.fields(argv);
|
|
20
|
+
const positionals = Array.isArray(argvFields._) ? argvFields._ : [];
|
|
21
|
+
const commandName = [
|
|
22
|
+
this.program,
|
|
23
|
+
...positionals
|
|
24
|
+
].join(" ").trim();
|
|
25
|
+
logger.info("Running", {
|
|
26
|
+
program: this.program,
|
|
27
|
+
args: argvFields
|
|
28
|
+
});
|
|
29
|
+
return new Promise((resolve, reject)=>{
|
|
30
|
+
let settled = false;
|
|
31
|
+
const resolveOnce = (response)=>{
|
|
32
|
+
if (settled) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
settled = true;
|
|
36
|
+
resolve(response);
|
|
37
|
+
};
|
|
38
|
+
const rejectOnce = (error)=>{
|
|
39
|
+
if (settled) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
settled = true;
|
|
43
|
+
reject(error);
|
|
44
|
+
};
|
|
45
|
+
const { cwd, env } = options;
|
|
46
|
+
const spawnOpt = {
|
|
47
|
+
cwd: cwd ?? ".",
|
|
48
|
+
stdio: [
|
|
49
|
+
"inherit",
|
|
50
|
+
"pipe",
|
|
51
|
+
"pipe"
|
|
52
|
+
],
|
|
53
|
+
env: env ?? {
|
|
54
|
+
...process.env
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const proc = (0, _nodechild_process.spawn)(this.program, argv, spawnOpt);
|
|
58
|
+
const responseData = [];
|
|
59
|
+
const errorData = [];
|
|
60
|
+
proc.on("close", (code, signal)=>{
|
|
61
|
+
if (code === 0) {
|
|
62
|
+
resolveOnce({
|
|
63
|
+
message: `${commandName} completed`,
|
|
64
|
+
data: responseData
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const stderr = errorData.join("\n").trim();
|
|
69
|
+
const stdout = responseData.join("\n").trim();
|
|
70
|
+
const exitCodeText = code == null ? "unknown" : String(code);
|
|
71
|
+
const signalText = signal ? ` signal ${signal}` : "";
|
|
72
|
+
const base = `Running '${commandName}' failed with code ${exitCodeText}${signalText}`;
|
|
73
|
+
const details = [
|
|
74
|
+
stderr ? `stderr:\n${stderr}` : "",
|
|
75
|
+
!stderr && stdout ? `stdout:\n${stdout}` : ""
|
|
76
|
+
].filter(Boolean).join("\n");
|
|
77
|
+
rejectOnce(new _interoperror.InteropError(details ? `${base}\n${details}` : base));
|
|
78
|
+
});
|
|
79
|
+
proc.on("error", (err)=>{
|
|
80
|
+
rejectOnce(err);
|
|
81
|
+
});
|
|
82
|
+
proc.stdout.on("error", (err)=>{
|
|
83
|
+
rejectOnce(err);
|
|
84
|
+
});
|
|
85
|
+
proc.stdout.on("data", (data)=>{
|
|
86
|
+
const lines = this.parseStream(data);
|
|
87
|
+
console.log(data.toString());
|
|
88
|
+
responseData.push(...lines);
|
|
89
|
+
});
|
|
90
|
+
proc.stderr?.on("error", (err)=>{
|
|
91
|
+
rejectOnce(err);
|
|
92
|
+
});
|
|
93
|
+
proc.stderr?.on("data", (data)=>{
|
|
94
|
+
const lines = this.parseStream(data);
|
|
95
|
+
console.error(data.toString());
|
|
96
|
+
errorData.push(...lines);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
parseStream(data) {
|
|
101
|
+
const dataStr = data.toString();
|
|
102
|
+
const lines = dataStr.split("\n").filter((l)=>l !== "");
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get detectPackageManager () {
|
|
13
|
+
return detectPackageManager;
|
|
14
|
+
},
|
|
15
|
+
get packageManagerFromString () {
|
|
16
|
+
return packageManagerFromString;
|
|
17
|
+
},
|
|
18
|
+
get promptForPackageManager () {
|
|
19
|
+
return promptForPackageManager;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _nodefs = require("node:fs");
|
|
23
|
+
const _nodepath = require("node:path");
|
|
24
|
+
const _promises = require("node:readline/promises");
|
|
25
|
+
const _npm = require("../npm/npm.js");
|
|
26
|
+
const _pnpm = require("../pnpm/pnpm.js");
|
|
27
|
+
const _yarn = require("../yarn/yarn.js");
|
|
28
|
+
const LOCKFILES = [
|
|
29
|
+
[
|
|
30
|
+
"pnpm-lock.yaml",
|
|
31
|
+
()=>new _pnpm.Pnpm()
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
"yarn.lock",
|
|
35
|
+
()=>new _yarn.Yarn()
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
"package-lock.json",
|
|
39
|
+
()=>new _npm.Npm()
|
|
40
|
+
]
|
|
41
|
+
];
|
|
42
|
+
function fromLockfile(cwd) {
|
|
43
|
+
for (const [file, factory] of LOCKFILES){
|
|
44
|
+
if ((0, _nodefs.existsSync)((0, _nodepath.join)(cwd, file))) return factory();
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
function fromUserAgent() {
|
|
49
|
+
const agent = process.env.npm_config_user_agent ?? "";
|
|
50
|
+
if (agent.startsWith("pnpm")) return new _pnpm.Pnpm();
|
|
51
|
+
if (agent.startsWith("yarn")) return new _yarn.Yarn();
|
|
52
|
+
if (agent.startsWith("npm")) return new _npm.Npm();
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
function detectPackageManager(cwd) {
|
|
56
|
+
return fromLockfile(cwd) ?? fromUserAgent();
|
|
57
|
+
}
|
|
58
|
+
function packageManagerFromString(name) {
|
|
59
|
+
if (name === "yarn") return new _yarn.Yarn();
|
|
60
|
+
if (name === "npm") return new _npm.Npm();
|
|
61
|
+
return new _pnpm.Pnpm();
|
|
62
|
+
}
|
|
63
|
+
async function promptForPackageManager() {
|
|
64
|
+
const rl = (0, _promises.createInterface)({
|
|
65
|
+
input: process.stdin,
|
|
66
|
+
output: process.stdout
|
|
67
|
+
});
|
|
68
|
+
const answer = await rl.question("Package manager? [pnpm/yarn/npm] (default: pnpm): ");
|
|
69
|
+
rl.close();
|
|
70
|
+
return packageManagerFromString(answer.trim().toLowerCase());
|
|
71
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "Yarn", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Yarn;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _shell = require("../shell/shell.js");
|
|
12
|
+
const Commands = {
|
|
13
|
+
install: "install"
|
|
14
|
+
};
|
|
15
|
+
class Yarn extends _shell.Shell {
|
|
16
|
+
name = "yarn";
|
|
17
|
+
program = "yarn";
|
|
18
|
+
async install(options = {
|
|
19
|
+
cwd: "./"
|
|
20
|
+
}) {
|
|
21
|
+
const { cwd } = options;
|
|
22
|
+
return this.run({
|
|
23
|
+
cwd
|
|
24
|
+
}, Commands.install);
|
|
25
|
+
}
|
|
26
|
+
async syncLockFile(options = {
|
|
27
|
+
cwd: "./"
|
|
28
|
+
}) {
|
|
29
|
+
const { cwd } = options;
|
|
30
|
+
return this.run({
|
|
31
|
+
cwd
|
|
32
|
+
}, Commands.install, "--mode", "update-lockfile", "--ignore-scripts");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "findDirectories", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return findDirectories;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _glob = require("glob");
|
|
12
|
+
async function findDirectories(...pattern) {
|
|
13
|
+
const paths = await (0, _glob.glob)(pattern, {
|
|
14
|
+
withFileTypes: true
|
|
15
|
+
});
|
|
16
|
+
const dirs = paths.filter((p)=>p.isDirectory()).map((p)=>({
|
|
17
|
+
name: p.name,
|
|
18
|
+
parentPath: p.parentPath
|
|
19
|
+
}));
|
|
20
|
+
return dirs;
|
|
21
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get findFile () {
|
|
13
|
+
return findFile;
|
|
14
|
+
},
|
|
15
|
+
get findFiles () {
|
|
16
|
+
return findFiles;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _glob = require("glob");
|
|
20
|
+
const _io = require("@decohere/core/io");
|
|
21
|
+
async function findFile(pattern) {
|
|
22
|
+
const files = await (0, _glob.glob)(pattern, {
|
|
23
|
+
includeChildMatches: false
|
|
24
|
+
});
|
|
25
|
+
if (files.length === 0) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const file = {
|
|
29
|
+
relativePath: files.at(0)
|
|
30
|
+
};
|
|
31
|
+
return file;
|
|
32
|
+
}
|
|
33
|
+
async function findFiles(patterns, options) {
|
|
34
|
+
const paths = await (0, _glob.glob)(patterns, {
|
|
35
|
+
...options,
|
|
36
|
+
withFileTypes: true
|
|
37
|
+
});
|
|
38
|
+
const files = paths.filter((p)=>p.isFile()).map((p)=>{
|
|
39
|
+
return new _io.FileEx({
|
|
40
|
+
relativePath: p.relative(),
|
|
41
|
+
fullPath: p.fullpath()
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return files;
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./find-directories.js"), exports);
|
|
6
|
+
_export_star(require("./find-file.js"), exports);
|
|
7
|
+
_export_star(require("./watch.js"), exports);
|
|
8
|
+
function _export_star(from, to) {
|
|
9
|
+
Object.keys(from).forEach(function(k) {
|
|
10
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
11
|
+
Object.defineProperty(to, k, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function() {
|
|
14
|
+
return from[k];
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return from;
|
|
20
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get WatchEvents () {
|
|
13
|
+
return WatchEvents;
|
|
14
|
+
},
|
|
15
|
+
get watch () {
|
|
16
|
+
return watch;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _nodefs = require("node:fs");
|
|
20
|
+
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
21
|
+
const _picomatch = /*#__PURE__*/ _interop_require_default(require("picomatch"));
|
|
22
|
+
const _io = require("@decohere/core/io");
|
|
23
|
+
function _interop_require_default(obj) {
|
|
24
|
+
return obj && obj.__esModule ? obj : {
|
|
25
|
+
default: obj
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const WatchEvents = {
|
|
29
|
+
add: "add",
|
|
30
|
+
change: "change",
|
|
31
|
+
addDir: "addDir",
|
|
32
|
+
unlink: "unlink",
|
|
33
|
+
unlinkDir: "unlinkDir"
|
|
34
|
+
};
|
|
35
|
+
function watch(directory, options = {
|
|
36
|
+
cwd: "."
|
|
37
|
+
}) {
|
|
38
|
+
const { include, ignore, ignoreInitial = false } = options;
|
|
39
|
+
const changeCoalesceMs = 25;
|
|
40
|
+
const handlers = {
|
|
41
|
+
ready: new Set(),
|
|
42
|
+
add: new Set(),
|
|
43
|
+
change: new Set(),
|
|
44
|
+
addDir: new Set(),
|
|
45
|
+
unlink: new Set(),
|
|
46
|
+
unlinkDir: new Set()
|
|
47
|
+
};
|
|
48
|
+
let resolveReady;
|
|
49
|
+
const ready = new Promise((resolve)=>{
|
|
50
|
+
resolveReady = resolve;
|
|
51
|
+
});
|
|
52
|
+
const snapshot = buildSnapshot(directory);
|
|
53
|
+
const isFiltered = (relativePath)=>{
|
|
54
|
+
const posixRelativePath = toPosixPath(relativePath);
|
|
55
|
+
const posixFullPath = toPosixPath(_nodepath.default.resolve(directory, relativePath));
|
|
56
|
+
const matchesEitherPath = (patterns)=>_picomatch.default.isMatch(posixRelativePath, patterns) || _picomatch.default.isMatch(posixFullPath, patterns);
|
|
57
|
+
if (include && include.length > 0) {
|
|
58
|
+
return !matchesEitherPath(include);
|
|
59
|
+
}
|
|
60
|
+
if (ignore && ignore.length > 0) {
|
|
61
|
+
return matchesEitherPath(ignore);
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
};
|
|
65
|
+
const emit = (event, relativePath)=>{
|
|
66
|
+
if (isFiltered(relativePath)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const fullPath = _nodepath.default.resolve(directory, relativePath);
|
|
70
|
+
for (const handler of handlers[event]){
|
|
71
|
+
handler(new _io.FileEx({
|
|
72
|
+
fullPath,
|
|
73
|
+
relativePath
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const pendingChangeTimers = new Map();
|
|
78
|
+
const emitChange = (relativePath)=>{
|
|
79
|
+
const existing = pendingChangeTimers.get(relativePath);
|
|
80
|
+
if (existing != null) {
|
|
81
|
+
clearTimeout(existing);
|
|
82
|
+
}
|
|
83
|
+
const timer = setTimeout(()=>{
|
|
84
|
+
pendingChangeTimers.delete(relativePath);
|
|
85
|
+
emit("change", relativePath);
|
|
86
|
+
}, changeCoalesceMs);
|
|
87
|
+
pendingChangeTimers.set(relativePath, timer);
|
|
88
|
+
};
|
|
89
|
+
const emitReady = ()=>{
|
|
90
|
+
for (const handler of handlers.ready){
|
|
91
|
+
handler();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
queueMicrotask(()=>{
|
|
95
|
+
if (!ignoreInitial) {
|
|
96
|
+
for (const [relativePath, entry] of snapshot){
|
|
97
|
+
emit(entry.isDirectory ? "addDir" : "add", relativePath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
emitReady();
|
|
101
|
+
resolveReady?.();
|
|
102
|
+
resolveReady = undefined;
|
|
103
|
+
});
|
|
104
|
+
// One non-recursive watcher per directory. Node's recursive mode on Linux tracks files
|
|
105
|
+
// individually and goes silent for a file once an editor replaces it with an atomic save
|
|
106
|
+
// (write temp file, rename over the original); directory watchers keep seeing it (#505).
|
|
107
|
+
const directoryWatchers = new Map();
|
|
108
|
+
const watchDirectory = (relativeDir)=>{
|
|
109
|
+
if (directoryWatchers.has(relativeDir)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const watcher = (0, _nodefs.watch)(_nodepath.default.resolve(directory, relativeDir), (_eventType, fileName)=>{
|
|
114
|
+
if (fileName != null) {
|
|
115
|
+
onFsEvent(_nodepath.default.posix.join(relativeDir, toPosixPath(fileName.toString())));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
watcher.on("error", ()=>unwatchDirectory(relativeDir));
|
|
119
|
+
directoryWatchers.set(relativeDir, watcher);
|
|
120
|
+
} catch {
|
|
121
|
+
// The directory vanished before we could watch it; its unlink event covers it.
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const unwatchDirectory = (relativeDir)=>{
|
|
125
|
+
for (const [watchedDir, watcher] of directoryWatchers){
|
|
126
|
+
if (watchedDir === relativeDir || watchedDir.startsWith(`${relativeDir}/`)) {
|
|
127
|
+
watcher.close();
|
|
128
|
+
directoryWatchers.delete(watchedDir);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
/** A directory appeared: watch it, and report what was created in it before we were watching. */ const addDirectory = (relativeDir)=>{
|
|
133
|
+
watchDirectory(relativeDir);
|
|
134
|
+
const found = new Map();
|
|
135
|
+
try {
|
|
136
|
+
collectSnapshotEntries(directory, _nodepath.default.resolve(directory, relativeDir), found);
|
|
137
|
+
} catch {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
for (const [relativePath, entry] of found){
|
|
141
|
+
if (snapshot.has(relativePath)) continue;
|
|
142
|
+
snapshot.set(relativePath, entry);
|
|
143
|
+
if (entry.isDirectory) watchDirectory(relativePath);
|
|
144
|
+
emit(entry.isDirectory ? "addDir" : "add", relativePath);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
/** A directory went away: stop watching it and forget everything that was under it. */ const removeDirectoryContents = (relativeDir)=>{
|
|
148
|
+
unwatchDirectory(relativeDir);
|
|
149
|
+
// oxlint-disable-next-line unicorn/no-useless-spread -- iterate a copy: the loop deletes from the snapshot
|
|
150
|
+
for (const [relativePath, entry] of [
|
|
151
|
+
...snapshot
|
|
152
|
+
]){
|
|
153
|
+
if (relativePath.startsWith(`${relativeDir}/`)) {
|
|
154
|
+
snapshot.delete(relativePath);
|
|
155
|
+
emit(entry.isDirectory ? "unlinkDir" : "unlink", relativePath);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const onFsEvent = (eventPath)=>{
|
|
160
|
+
const relativePath = eventPath === "." ? "" : eventPath;
|
|
161
|
+
if (relativePath.length === 0) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const fullPath = _nodepath.default.resolve(directory, relativePath);
|
|
165
|
+
const previous = snapshot.get(relativePath);
|
|
166
|
+
try {
|
|
167
|
+
const stat = (0, _nodefs.statSync)(fullPath);
|
|
168
|
+
const current = toSnapshotEntry(stat);
|
|
169
|
+
snapshot.set(relativePath, current);
|
|
170
|
+
if (previous == null) {
|
|
171
|
+
emit(current.isDirectory ? "addDir" : "add", relativePath);
|
|
172
|
+
if (current.isDirectory) addDirectory(relativePath);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (previous.isDirectory !== current.isDirectory) {
|
|
176
|
+
if (previous.isDirectory) removeDirectoryContents(relativePath);
|
|
177
|
+
emit(previous.isDirectory ? "unlinkDir" : "unlink", relativePath);
|
|
178
|
+
emit(current.isDirectory ? "addDir" : "add", relativePath);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!current.isDirectory && previous.fingerprint !== current.fingerprint) {
|
|
182
|
+
emitChange(relativePath);
|
|
183
|
+
}
|
|
184
|
+
} catch {
|
|
185
|
+
if (previous == null) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
snapshot.delete(relativePath);
|
|
189
|
+
const pending = pendingChangeTimers.get(relativePath);
|
|
190
|
+
if (pending != null) {
|
|
191
|
+
clearTimeout(pending);
|
|
192
|
+
pendingChangeTimers.delete(relativePath);
|
|
193
|
+
}
|
|
194
|
+
emit(previous.isDirectory ? "unlinkDir" : "unlink", relativePath);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
watchDirectory("");
|
|
198
|
+
for (const [relativePath, entry] of snapshot){
|
|
199
|
+
if (entry.isDirectory) watchDirectory(relativePath);
|
|
200
|
+
}
|
|
201
|
+
const watchApi = {
|
|
202
|
+
ready,
|
|
203
|
+
on (event, handler) {
|
|
204
|
+
if (event === "ready") {
|
|
205
|
+
handlers.ready.add(handler);
|
|
206
|
+
return watchApi;
|
|
207
|
+
}
|
|
208
|
+
handlers[event].add(handler);
|
|
209
|
+
return watchApi;
|
|
210
|
+
},
|
|
211
|
+
close: ()=>{
|
|
212
|
+
for (const pending of pendingChangeTimers.values()){
|
|
213
|
+
clearTimeout(pending);
|
|
214
|
+
}
|
|
215
|
+
pendingChangeTimers.clear();
|
|
216
|
+
for (const watcher of directoryWatchers.values()){
|
|
217
|
+
watcher.close();
|
|
218
|
+
}
|
|
219
|
+
directoryWatchers.clear();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
return watchApi;
|
|
223
|
+
}
|
|
224
|
+
function buildSnapshot(directoryPath) {
|
|
225
|
+
const snapshot = new Map();
|
|
226
|
+
collectSnapshotEntries(directoryPath, directoryPath, snapshot);
|
|
227
|
+
return snapshot;
|
|
228
|
+
}
|
|
229
|
+
/** Never source, and huge: watching every folder inside them could exhaust OS watch limits. */ const UNWATCHED_DIRECTORIES = new Set([
|
|
230
|
+
"node_modules",
|
|
231
|
+
".git"
|
|
232
|
+
]);
|
|
233
|
+
function collectSnapshotEntries(rootDirectoryPath, currentDirectoryPath, snapshot) {
|
|
234
|
+
for (const entry of (0, _nodefs.readdirSync)(currentDirectoryPath, {
|
|
235
|
+
encoding: "utf8"
|
|
236
|
+
})){
|
|
237
|
+
const name = typeof entry === "string" ? entry : String(entry);
|
|
238
|
+
const fullPath = _nodepath.default.join(currentDirectoryPath, name);
|
|
239
|
+
if (UNWATCHED_DIRECTORIES.has(name)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const relativePath = toPosixPath(_nodepath.default.relative(rootDirectoryPath, fullPath));
|
|
243
|
+
const stat = (0, _nodefs.statSync)(fullPath);
|
|
244
|
+
const snapshotEntry = toSnapshotEntry(stat);
|
|
245
|
+
snapshot.set(relativePath, snapshotEntry);
|
|
246
|
+
if (!snapshotEntry.isDirectory) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
collectSnapshotEntries(rootDirectoryPath, fullPath, snapshot);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function toSnapshotEntry(stat) {
|
|
253
|
+
const isDirectory = stat.isDirectory();
|
|
254
|
+
return {
|
|
255
|
+
isDirectory,
|
|
256
|
+
fingerprint: isDirectory ? `dir:${stat.mtimeMs}` : `file:${stat.mtimeMs}:${stat.size}`
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function toPosixPath(filePath) {
|
|
260
|
+
return filePath.split(_nodepath.default.sep).join(_nodepath.default.posix.sep);
|
|
261
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const ActionMap = Symbol("ActionMap");
|
|
2
|
+
export class ActionResponse {
|
|
3
|
+
static Success(name, data) {
|
|
4
|
+
return new ActionResponse({
|
|
5
|
+
name,
|
|
6
|
+
data,
|
|
7
|
+
succeeded: true
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
static Skipped(name) {
|
|
11
|
+
return new ActionResponse({
|
|
12
|
+
name,
|
|
13
|
+
skipped: true
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
static Blocking(name) {
|
|
17
|
+
return new ActionResponse({
|
|
18
|
+
name,
|
|
19
|
+
succeeded: true,
|
|
20
|
+
blocking: true
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
static Error(name, messageOrData, data) {
|
|
24
|
+
if (Array.isArray(messageOrData)) {
|
|
25
|
+
const message = messageOrData.filter((r)=>!r.succeeded).map((r)=>r.error ?? "Unknown error").join("\n");
|
|
26
|
+
return new ActionResponse({
|
|
27
|
+
name,
|
|
28
|
+
message,
|
|
29
|
+
data: messageOrData
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return new ActionResponse({
|
|
33
|
+
name,
|
|
34
|
+
message: messageOrData,
|
|
35
|
+
data
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
constructor(data){
|
|
39
|
+
Object.assign(this, data);
|
|
40
|
+
}
|
|
41
|
+
name;
|
|
42
|
+
succeeded = false;
|
|
43
|
+
skipped = false;
|
|
44
|
+
blocking = false;
|
|
45
|
+
message;
|
|
46
|
+
data;
|
|
47
|
+
}
|