@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.
Files changed (89) hide show
  1. package/README.md +14 -0
  2. package/commonjs/src/cli/action.js +65 -0
  3. package/commonjs/src/cli/command.js +127 -0
  4. package/commonjs/src/cli/index.js +61 -0
  5. package/commonjs/src/cli/module.type.js +18 -0
  6. package/commonjs/src/cli/options.js +115 -0
  7. package/commonjs/src/diagnostics/index.js +22 -0
  8. package/commonjs/src/diagnostics/trace.js +79 -0
  9. package/commonjs/src/interop/docker/docker.js +54 -0
  10. package/commonjs/src/interop/errors/interop.error.js +12 -0
  11. package/commonjs/src/interop/git/git.js +134 -0
  12. package/commonjs/src/interop/git/git.types.js +4 -0
  13. package/commonjs/src/interop/index.js +97 -0
  14. package/commonjs/src/interop/node/index.js +18 -0
  15. package/commonjs/src/interop/node/node.js +45 -0
  16. package/commonjs/src/interop/npm/npm.js +231 -0
  17. package/commonjs/src/interop/npm/npm.types.js +16 -0
  18. package/commonjs/src/interop/pnpm/pnpm.js +34 -0
  19. package/commonjs/src/interop/pnpm/pnpm.types.js +4 -0
  20. package/commonjs/src/interop/shell/shell.argv.js +45 -0
  21. package/commonjs/src/interop/shell/shell.js +105 -0
  22. package/commonjs/src/interop/shell/shell.types.js +4 -0
  23. package/commonjs/src/interop/types/detect-package-manager.js +71 -0
  24. package/commonjs/src/interop/types/package-manager.js +4 -0
  25. package/commonjs/src/interop/yarn/yarn.js +34 -0
  26. package/commonjs/src/interop/yarn/yarn.types.js +4 -0
  27. package/commonjs/src/io/find-directories.js +21 -0
  28. package/commonjs/src/io/find-file.js +45 -0
  29. package/commonjs/src/io/index.js +20 -0
  30. package/commonjs/src/io/watch.js +261 -0
  31. package/es6/src/cli/action.js +47 -0
  32. package/es6/src/cli/command.js +106 -0
  33. package/es6/src/cli/index.js +4 -0
  34. package/es6/src/cli/module.type.js +11 -0
  35. package/es6/src/cli/options.js +76 -0
  36. package/es6/src/diagnostics/index.js +1 -0
  37. package/es6/src/diagnostics/trace.js +61 -0
  38. package/es6/src/interop/docker/docker.js +44 -0
  39. package/es6/src/interop/errors/interop.error.js +2 -0
  40. package/es6/src/interop/git/git.js +124 -0
  41. package/es6/src/interop/git/git.types.js +1 -0
  42. package/es6/src/interop/index.js +21 -0
  43. package/es6/src/interop/node/index.js +1 -0
  44. package/es6/src/interop/node/node.js +35 -0
  45. package/es6/src/interop/npm/npm.js +180 -0
  46. package/es6/src/interop/npm/npm.types.js +6 -0
  47. package/es6/src/interop/pnpm/pnpm.js +24 -0
  48. package/es6/src/interop/pnpm/pnpm.types.js +1 -0
  49. package/es6/src/interop/shell/shell.argv.js +35 -0
  50. package/es6/src/interop/shell/shell.js +95 -0
  51. package/es6/src/interop/shell/shell.types.js +1 -0
  52. package/es6/src/interop/types/detect-package-manager.js +50 -0
  53. package/es6/src/interop/types/package-manager.js +1 -0
  54. package/es6/src/interop/yarn/yarn.js +24 -0
  55. package/es6/src/interop/yarn/yarn.types.js +1 -0
  56. package/es6/src/io/find-directories.js +11 -0
  57. package/es6/src/io/find-file.js +27 -0
  58. package/es6/src/io/index.js +3 -0
  59. package/es6/src/io/watch.js +238 -0
  60. package/package.json +49 -0
  61. package/types/src/cli/action.d.ts +36 -0
  62. package/types/src/cli/command.d.ts +34 -0
  63. package/types/src/cli/index.d.ts +7 -0
  64. package/types/src/cli/module.type.d.ts +36 -0
  65. package/types/src/cli/options.d.ts +28 -0
  66. package/types/src/diagnostics/index.d.ts +1 -0
  67. package/types/src/diagnostics/trace.d.ts +10 -0
  68. package/types/src/interop/docker/docker.d.ts +19 -0
  69. package/types/src/interop/errors/interop.error.d.ts +2 -0
  70. package/types/src/interop/git/git.d.ts +16 -0
  71. package/types/src/interop/git/git.types.d.ts +14 -0
  72. package/types/src/interop/index.d.ts +14 -0
  73. package/types/src/interop/node/index.d.ts +1 -0
  74. package/types/src/interop/node/node.d.ts +5 -0
  75. package/types/src/interop/npm/npm.d.ts +29 -0
  76. package/types/src/interop/npm/npm.types.d.ts +24 -0
  77. package/types/src/interop/pnpm/pnpm.d.ts +9 -0
  78. package/types/src/interop/pnpm/pnpm.types.d.ts +3 -0
  79. package/types/src/interop/shell/shell.argv.d.ts +5 -0
  80. package/types/src/interop/shell/shell.d.ts +6 -0
  81. package/types/src/interop/shell/shell.types.d.ts +9 -0
  82. package/types/src/interop/types/detect-package-manager.d.ts +4 -0
  83. package/types/src/interop/types/package-manager.d.ts +10 -0
  84. package/types/src/interop/yarn/yarn.d.ts +9 -0
  85. package/types/src/interop/yarn/yarn.types.d.ts +3 -0
  86. package/types/src/io/find-directories.d.ts +2 -0
  87. package/types/src/io/find-file.d.ts +9 -0
  88. package/types/src/io/index.d.ts +3 -0
  89. 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,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -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,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -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,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -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
+ }