@package-pal/core 0.0.1
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/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1431 -0
- package/dist/index.js.map +50 -0
- package/dist/lib/api.d.ts +45 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/configuration/functions/check-bun.d.ts +2 -0
- package/dist/lib/configuration/functions/check-bun.d.ts.map +1 -0
- package/dist/lib/configuration/functions/get-default-logger.d.ts +4 -0
- package/dist/lib/configuration/functions/get-default-logger.d.ts.map +1 -0
- package/dist/lib/configuration/functions/is-root-dir.d.ts +2 -0
- package/dist/lib/configuration/functions/is-root-dir.d.ts.map +1 -0
- package/dist/lib/configuration/functions/load-config.d.ts +3 -0
- package/dist/lib/configuration/functions/load-config.d.ts.map +1 -0
- package/dist/lib/configuration/functions/parse-config.d.ts +27 -0
- package/dist/lib/configuration/functions/parse-config.d.ts.map +1 -0
- package/dist/lib/configuration/functions/search-config-path.d.ts +2 -0
- package/dist/lib/configuration/functions/search-config-path.d.ts.map +1 -0
- package/dist/lib/configuration/functions/validate-config-path.d.ts +6 -0
- package/dist/lib/configuration/functions/validate-config-path.d.ts.map +1 -0
- package/dist/lib/configuration/functions/z-loose-function.d.ts +3 -0
- package/dist/lib/configuration/functions/z-loose-function.d.ts.map +1 -0
- package/dist/lib/configuration/functions/z-loose-object-without-index-signature.d.ts +4 -0
- package/dist/lib/configuration/functions/z-loose-object-without-index-signature.d.ts.map +1 -0
- package/dist/lib/configuration/schemas/config.d.ts +121 -0
- package/dist/lib/configuration/schemas/config.d.ts.map +1 -0
- package/dist/lib/configuration/types/activated-config.d.ts +5 -0
- package/dist/lib/configuration/types/activated-config.d.ts.map +1 -0
- package/dist/lib/configuration/types/config-validation-result.d.ts +10 -0
- package/dist/lib/configuration/types/config-validation-result.d.ts.map +1 -0
- package/dist/lib/configuration/types/config.d.ts +25 -0
- package/dist/lib/configuration/types/config.d.ts.map +1 -0
- package/dist/lib/configuration/types/logger.d.ts +7 -0
- package/dist/lib/configuration/types/logger.d.ts.map +1 -0
- package/dist/lib/configuration/types/packages-ready-callback-props.d.ts +7 -0
- package/dist/lib/configuration/types/packages-ready-callback-props.d.ts.map +1 -0
- package/dist/lib/configuration/types/process-package-callback-props.d.ts +10 -0
- package/dist/lib/configuration/types/process-package-callback-props.d.ts.map +1 -0
- package/dist/lib/configuration/types/subprocess-callback.d.ts +2 -0
- package/dist/lib/configuration/types/subprocess-callback.d.ts.map +1 -0
- package/dist/lib/configuration/types/supported-config-type.d.ts +11 -0
- package/dist/lib/configuration/types/supported-config-type.d.ts.map +1 -0
- package/dist/lib/graph/functions/dfs-traverse-graph-paths.d.ts +3 -0
- package/dist/lib/graph/functions/dfs-traverse-graph-paths.d.ts.map +1 -0
- package/dist/lib/graph/functions/dfs-traverse-graph.d.ts +4 -0
- package/dist/lib/graph/functions/dfs-traverse-graph.d.ts.map +1 -0
- package/dist/lib/graph/functions/extract-subgraph.d.ts +3 -0
- package/dist/lib/graph/functions/extract-subgraph.d.ts.map +1 -0
- package/dist/lib/graph/functions/generate-graphs.d.ts +8 -0
- package/dist/lib/graph/functions/generate-graphs.d.ts.map +1 -0
- package/dist/lib/graph/functions/generate-package-circular-dependency-paths.d.ts +5 -0
- package/dist/lib/graph/functions/generate-package-circular-dependency-paths.d.ts.map +1 -0
- package/dist/lib/graph/functions/generate-topological-ranking-range.d.ts +3 -0
- package/dist/lib/graph/functions/generate-topological-ranking-range.d.ts.map +1 -0
- package/dist/lib/graph/functions/generate-topological-ranking.d.ts +2 -0
- package/dist/lib/graph/functions/generate-topological-ranking.d.ts.map +1 -0
- package/dist/lib/graph/functions/generate-topological-sorted-groups.d.ts +5 -0
- package/dist/lib/graph/functions/generate-topological-sorted-groups.d.ts.map +1 -0
- package/dist/lib/graph/functions/is-disjoint.d.ts +3 -0
- package/dist/lib/graph/functions/is-disjoint.d.ts.map +1 -0
- package/dist/lib/graph/functions/is-ranked-greater-than-or-equal.d.ts +3 -0
- package/dist/lib/graph/functions/is-ranked-greater-than-or-equal.d.ts.map +1 -0
- package/dist/lib/graph/functions/is-subgraph.d.ts +3 -0
- package/dist/lib/graph/functions/is-subgraph.d.ts.map +1 -0
- package/dist/lib/graph/types/package-graph.d.ts +3 -0
- package/dist/lib/graph/types/package-graph.d.ts.map +1 -0
- package/dist/lib/graph/types/package-graphs.d.ts +6 -0
- package/dist/lib/graph/types/package-graphs.d.ts.map +1 -0
- package/dist/lib/graph/types/package-node.d.ts +6 -0
- package/dist/lib/graph/types/package-node.d.ts.map +1 -0
- package/dist/lib/graph/types/package-order.d.ts +14 -0
- package/dist/lib/graph/types/package-order.d.ts.map +1 -0
- package/dist/lib/package/functions/load-packages.d.ts +4 -0
- package/dist/lib/package/functions/load-packages.d.ts.map +1 -0
- package/dist/lib/package/functions/parse-package.d.ts +3 -0
- package/dist/lib/package/functions/parse-package.d.ts.map +1 -0
- package/dist/lib/package/functions/scan-package-paths.d.ts +2 -0
- package/dist/lib/package/functions/scan-package-paths.d.ts.map +1 -0
- package/dist/lib/package/functions/scan-packages.d.ts +4 -0
- package/dist/lib/package/functions/scan-packages.d.ts.map +1 -0
- package/dist/lib/package/functions/update-package-version.d.ts +5 -0
- package/dist/lib/package/functions/update-package-version.d.ts.map +1 -0
- package/dist/lib/package/types/package-data.d.ts +11 -0
- package/dist/lib/package/types/package-data.d.ts.map +1 -0
- package/dist/lib/types/bump-package-version-options.d.ts +11 -0
- package/dist/lib/types/bump-package-version-options.d.ts.map +1 -0
- package/dist/lib/types/bump-version-type.d.ts +12 -0
- package/dist/lib/types/bump-version-type.d.ts.map +1 -0
- package/dist/lib/types/config-options.d.ts +5 -0
- package/dist/lib/types/config-options.d.ts.map +1 -0
- package/dist/lib/types/get-config-options.d.ts +5 -0
- package/dist/lib/types/get-config-options.d.ts.map +1 -0
- package/dist/lib/types/get-package-circular-dependency-paths-options.d.ts +6 -0
- package/dist/lib/types/get-package-circular-dependency-paths-options.d.ts.map +1 -0
- package/dist/lib/types/get-package-data-options.d.ts +4 -0
- package/dist/lib/types/get-package-data-options.d.ts.map +1 -0
- package/dist/lib/types/get-package-graph-options.d.ts +5 -0
- package/dist/lib/types/get-package-graph-options.d.ts.map +1 -0
- package/dist/lib/types/get-package-order-options.d.ts +5 -0
- package/dist/lib/types/get-package-order-options.d.ts.map +1 -0
- package/dist/lib/types/package-data-options.d.ts +5 -0
- package/dist/lib/types/package-data-options.d.ts.map +1 -0
- package/dist/lib/types/package-graphs-options.d.ts +5 -0
- package/dist/lib/types/package-graphs-options.d.ts.map +1 -0
- package/dist/lib/types/package-name-options.d.ts +4 -0
- package/dist/lib/types/package-name-options.d.ts.map +1 -0
- package/dist/lib/types/package-order-options.d.ts +5 -0
- package/dist/lib/types/package-order-options.d.ts.map +1 -0
- package/dist/lib/types/watch-packages-options.d.ts +6 -0
- package/dist/lib/types/watch-packages-options.d.ts.map +1 -0
- package/dist/lib/watch/functions/filter-files-modified-since.d.ts +2 -0
- package/dist/lib/watch/functions/filter-files-modified-since.d.ts.map +1 -0
- package/dist/lib/watch/functions/get-commands-for-shell.d.ts +2 -0
- package/dist/lib/watch/functions/get-commands-for-shell.d.ts.map +1 -0
- package/dist/lib/watch/functions/get-line-buffered-writer.d.ts +2 -0
- package/dist/lib/watch/functions/get-line-buffered-writer.d.ts.map +1 -0
- package/dist/lib/watch/functions/normalise-watched-file-path.d.ts +2 -0
- package/dist/lib/watch/functions/normalise-watched-file-path.d.ts.map +1 -0
- package/dist/lib/watch/functions/read-stream.d.ts +2 -0
- package/dist/lib/watch/functions/read-stream.d.ts.map +1 -0
- package/dist/lib/watch/functions/run-async.d.ts +3 -0
- package/dist/lib/watch/functions/run-async.d.ts.map +1 -0
- package/dist/lib/watch/functions/run-subprocess.d.ts +11 -0
- package/dist/lib/watch/functions/run-subprocess.d.ts.map +1 -0
- package/dist/lib/watch/functions/watch-package-changes.d.ts +8 -0
- package/dist/lib/watch/functions/watch-package-changes.d.ts.map +1 -0
- package/dist/lib/watch/types/change-action.d.ts +8 -0
- package/dist/lib/watch/types/change-action.d.ts.map +1 -0
- package/dist/lib/watch/types/exit-state.d.ts +8 -0
- package/dist/lib/watch/types/exit-state.d.ts.map +1 -0
- package/dist/lib/watch/types/package-changes.d.ts +2 -0
- package/dist/lib/watch/types/package-changes.d.ts.map +1 -0
- package/dist/lib/watch/types/run-async-type.d.ts +7 -0
- package/dist/lib/watch/types/run-async-type.d.ts.map +1 -0
- package/dist/lib/watch/types/spawn-options.d.ts +4 -0
- package/dist/lib/watch/types/spawn-options.d.ts.map +1 -0
- package/dist/lib/watch/types/std-type.d.ts +7 -0
- package/dist/lib/watch/types/std-type.d.ts.map +1 -0
- package/package.json +44 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1431 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/lib/types/bump-version-type.ts
|
|
3
|
+
var BumpVersionType = {
|
|
4
|
+
Major: "major",
|
|
5
|
+
Minor: "minor",
|
|
6
|
+
Patch: "patch",
|
|
7
|
+
Premajor: "premajor",
|
|
8
|
+
Preminor: "preminor",
|
|
9
|
+
Prepatch: "prepatch",
|
|
10
|
+
Prerelease: "prerelease"
|
|
11
|
+
};
|
|
12
|
+
// src/lib/api.ts
|
|
13
|
+
import { isDefined as isDefined5 } from "@package-pal/util";
|
|
14
|
+
|
|
15
|
+
// src/lib/configuration/functions/check-bun.ts
|
|
16
|
+
var checkBun = () => {
|
|
17
|
+
if (!Bun) {
|
|
18
|
+
throw new Error("This package must be run with the Bun runtime.");
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/lib/configuration/functions/load-config.ts
|
|
23
|
+
import {
|
|
24
|
+
deepMergeDefined,
|
|
25
|
+
formatSimpleLogObject,
|
|
26
|
+
noOp as noOp2
|
|
27
|
+
} from "@package-pal/util";
|
|
28
|
+
import {
|
|
29
|
+
bgGray,
|
|
30
|
+
dim
|
|
31
|
+
} from "yoctocolors";
|
|
32
|
+
|
|
33
|
+
// src/lib/configuration/functions/get-default-logger.ts
|
|
34
|
+
import {
|
|
35
|
+
assertDefined,
|
|
36
|
+
noOp
|
|
37
|
+
} from "@package-pal/util";
|
|
38
|
+
var levelOrder = {
|
|
39
|
+
debug: 0,
|
|
40
|
+
info: 1,
|
|
41
|
+
warn: 2,
|
|
42
|
+
error: 3,
|
|
43
|
+
silent: Infinity
|
|
44
|
+
};
|
|
45
|
+
var getDefaultLogger = (logLevel) => {
|
|
46
|
+
const level = assertDefined(levelOrder[logLevel]);
|
|
47
|
+
return {
|
|
48
|
+
debug: level <= levelOrder.debug ? console.debug : noOp,
|
|
49
|
+
info: level <= levelOrder.info ? console.info : noOp,
|
|
50
|
+
warn: level <= levelOrder.warn ? console.warn : noOp,
|
|
51
|
+
error: level <= levelOrder.error ? console.error : noOp
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/lib/configuration/schemas/config.ts
|
|
56
|
+
import * as z3 from "zod/mini";
|
|
57
|
+
|
|
58
|
+
// src/lib/configuration/functions/z-loose-function.ts
|
|
59
|
+
import { z } from "zod/mini";
|
|
60
|
+
var zLooseFunction = () => {
|
|
61
|
+
return z.transform((arg, ctx) => {
|
|
62
|
+
if (typeof arg !== "function") {
|
|
63
|
+
ctx.issues.push({
|
|
64
|
+
message: "Expected a function",
|
|
65
|
+
code: "custom",
|
|
66
|
+
input: arg
|
|
67
|
+
});
|
|
68
|
+
return z.NEVER;
|
|
69
|
+
}
|
|
70
|
+
return arg;
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/lib/configuration/functions/z-loose-object-without-index-signature.ts
|
|
75
|
+
import * as z2 from "zod/mini";
|
|
76
|
+
var zLooseObjectWithoutIndexSignature = (shape, params) => {
|
|
77
|
+
return z2.looseObject(shape, params);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/lib/configuration/schemas/config.ts
|
|
81
|
+
var LogLevel = z3.enum([
|
|
82
|
+
"debug",
|
|
83
|
+
"info",
|
|
84
|
+
"warn",
|
|
85
|
+
"error",
|
|
86
|
+
"silent"
|
|
87
|
+
]);
|
|
88
|
+
var Config = z3.object({
|
|
89
|
+
packages: z3.optional(z3.union([z3.string(), z3.array(z3.string())])),
|
|
90
|
+
version: z3.optional(z3.object({
|
|
91
|
+
preId: z3.optional(z3.string()),
|
|
92
|
+
exact: z3.optional(z3.boolean())
|
|
93
|
+
})),
|
|
94
|
+
watch: z3.optional(zLooseObjectWithoutIndexSignature({
|
|
95
|
+
debounceMs: z3.optional(z3.number()),
|
|
96
|
+
hooks: z3.optional(z3.object({
|
|
97
|
+
onBeforeProcessPackage: z3.optional(zLooseFunction()),
|
|
98
|
+
onProcessPackage: z3.optional(zLooseFunction()),
|
|
99
|
+
onProcessPackageError: z3.optional(zLooseFunction()),
|
|
100
|
+
onAfterProcessPackage: z3.optional(zLooseFunction()),
|
|
101
|
+
onBeforePackagesReady: z3.optional(zLooseFunction()),
|
|
102
|
+
onPackagesReady: z3.optional(zLooseFunction()),
|
|
103
|
+
onAfterPackagesReady: z3.optional(zLooseFunction())
|
|
104
|
+
})),
|
|
105
|
+
subprocess: z3.optional(z3.object({
|
|
106
|
+
partialProcessing: z3.optional(z3.boolean()),
|
|
107
|
+
parallelProcessing: z3.optional(z3.boolean()),
|
|
108
|
+
matchLongRunningOutputAsReady: z3.nullish(z3.string()),
|
|
109
|
+
matchLongRunningOutputAsErrored: z3.nullish(z3.string())
|
|
110
|
+
}))
|
|
111
|
+
})),
|
|
112
|
+
logLevel: z3.optional(LogLevel)
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// src/lib/configuration/functions/validate-config-path.ts
|
|
116
|
+
import {
|
|
117
|
+
basename,
|
|
118
|
+
extname
|
|
119
|
+
} from "path";
|
|
120
|
+
|
|
121
|
+
// src/lib/configuration/types/supported-config-type.ts
|
|
122
|
+
var SupportedConfigType = {
|
|
123
|
+
TS: "ts",
|
|
124
|
+
CTS: "cts",
|
|
125
|
+
MTS: "mts",
|
|
126
|
+
JS: "js",
|
|
127
|
+
CJS: "cjs",
|
|
128
|
+
MJS: "mjs"
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// src/lib/configuration/functions/validate-config-path.ts
|
|
132
|
+
var CONFIG_SUPPORTED_BASE_NAME = "ppal.config";
|
|
133
|
+
var CONFIG_SUPPORTED_TYPES = Object.values(SupportedConfigType);
|
|
134
|
+
var CONFIG_SUPPORTED_NAMES = CONFIG_SUPPORTED_TYPES.map((type) => `${CONFIG_SUPPORTED_BASE_NAME}.${type}`);
|
|
135
|
+
var validateConfigPath = (path) => {
|
|
136
|
+
const name = basename(path);
|
|
137
|
+
const extension = extname(path);
|
|
138
|
+
const type = CONFIG_SUPPORTED_TYPES.find((option) => `.${option}` === extension);
|
|
139
|
+
if (!name.startsWith(CONFIG_SUPPORTED_BASE_NAME) || !type) {
|
|
140
|
+
return {
|
|
141
|
+
valid: false,
|
|
142
|
+
errorMessage: `'${name}' is not a valid config file. Only '${CONFIG_SUPPORTED_NAMES.join(", ")}' are supported.`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
valid: true,
|
|
147
|
+
name,
|
|
148
|
+
type
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// src/lib/configuration/functions/parse-config.ts
|
|
153
|
+
var parseConfig = async (path) => {
|
|
154
|
+
const result = validateConfigPath(path);
|
|
155
|
+
if (!result.valid) {
|
|
156
|
+
throw new Error(result.errorMessage);
|
|
157
|
+
}
|
|
158
|
+
const module = await import(path);
|
|
159
|
+
const base = module.default ?? module;
|
|
160
|
+
return Config.parse(base);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/lib/configuration/functions/search-config-path.ts
|
|
164
|
+
import {
|
|
165
|
+
isAbsolute,
|
|
166
|
+
join,
|
|
167
|
+
dirname as dirname2
|
|
168
|
+
} from "path";
|
|
169
|
+
import { isDefined } from "@package-pal/util";
|
|
170
|
+
|
|
171
|
+
// src/lib/configuration/functions/is-root-dir.ts
|
|
172
|
+
import { dirname } from "path";
|
|
173
|
+
var isRootDir = (path) => {
|
|
174
|
+
return dirname(path) === path;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// src/lib/configuration/functions/search-config-path.ts
|
|
178
|
+
var dirDistLimit = 25;
|
|
179
|
+
var checkForConfigInDir = async (dir) => {
|
|
180
|
+
return new Promise((resolve) => {
|
|
181
|
+
let pending = CONFIG_SUPPORTED_NAMES.length;
|
|
182
|
+
for (const name of CONFIG_SUPPORTED_NAMES) {
|
|
183
|
+
const pathToCheck = join(dir, name);
|
|
184
|
+
Bun.file(pathToCheck).exists().then((exists) => {
|
|
185
|
+
pending--;
|
|
186
|
+
if (exists) {
|
|
187
|
+
resolve(pathToCheck);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!pending) {
|
|
191
|
+
resolve(undefined);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
var searchConfigPath = async (pathOverride) => {
|
|
198
|
+
let activeDir = process.cwd();
|
|
199
|
+
if (isDefined(pathOverride)) {
|
|
200
|
+
if (isAbsolute(pathOverride)) {
|
|
201
|
+
return pathOverride;
|
|
202
|
+
}
|
|
203
|
+
return join(activeDir, pathOverride);
|
|
204
|
+
}
|
|
205
|
+
let trackDist = 0;
|
|
206
|
+
while (!isRootDir(activeDir)) {
|
|
207
|
+
if (trackDist > dirDistLimit) {
|
|
208
|
+
throw new Error(`Maximum config search directory distance reached (${dirDistLimit.toString()}).`);
|
|
209
|
+
}
|
|
210
|
+
const configPath = await checkForConfigInDir(activeDir);
|
|
211
|
+
if (configPath) {
|
|
212
|
+
return configPath;
|
|
213
|
+
}
|
|
214
|
+
trackDist++;
|
|
215
|
+
activeDir = dirname2(activeDir);
|
|
216
|
+
}
|
|
217
|
+
return checkForConfigInDir(activeDir);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/lib/configuration/functions/load-config.ts
|
|
221
|
+
var defaultConfig = {
|
|
222
|
+
packages: "packages/*",
|
|
223
|
+
version: {
|
|
224
|
+
preId: "",
|
|
225
|
+
exact: false
|
|
226
|
+
},
|
|
227
|
+
watch: {
|
|
228
|
+
debounceMs: 500,
|
|
229
|
+
hooks: {
|
|
230
|
+
onBeforeProcessPackage: noOp2,
|
|
231
|
+
onProcessPackage: noOp2,
|
|
232
|
+
onProcessPackageError: noOp2,
|
|
233
|
+
onAfterProcessPackage: noOp2,
|
|
234
|
+
onBeforePackagesReady: noOp2,
|
|
235
|
+
onPackagesReady: noOp2,
|
|
236
|
+
onAfterPackagesReady: noOp2
|
|
237
|
+
},
|
|
238
|
+
subprocess: {
|
|
239
|
+
partialProcessing: false,
|
|
240
|
+
parallelProcessing: true,
|
|
241
|
+
matchLongRunningOutputAsReady: null,
|
|
242
|
+
matchLongRunningOutputAsErrored: null
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
logger: getDefaultLogger("info"),
|
|
246
|
+
logLevel: "info"
|
|
247
|
+
};
|
|
248
|
+
var loadConfig = async (overrideConfigPath) => {
|
|
249
|
+
const path = await searchConfigPath(overrideConfigPath);
|
|
250
|
+
if (!path) {
|
|
251
|
+
defaultConfig.logger.info("No config file found. Defaults will be applied.");
|
|
252
|
+
return defaultConfig;
|
|
253
|
+
}
|
|
254
|
+
const parsedConfig = await parseConfig(path);
|
|
255
|
+
const parsedLogger = parsedConfig["logger"];
|
|
256
|
+
const logger = parsedLogger ?? (!parsedConfig.logLevel || parsedConfig.logLevel === defaultConfig.logLevel ? defaultConfig.logger : getDefaultLogger(parsedConfig.logLevel));
|
|
257
|
+
logger.info(`Successfully loaded config file '${path}'.`);
|
|
258
|
+
logger.debug(dim(bgGray("User config:")), `
|
|
259
|
+
${dim(formatSimpleLogObject(parsedConfig))}`);
|
|
260
|
+
logger.debug(dim(bgGray("Default config:")), `
|
|
261
|
+
${dim(formatSimpleLogObject(defaultConfig))}`);
|
|
262
|
+
const activatedConfig = deepMergeDefined(defaultConfig, parsedConfig);
|
|
263
|
+
activatedConfig.logger = logger;
|
|
264
|
+
logger.debug(dim(bgGray("Activated config:")), `
|
|
265
|
+
${dim(formatSimpleLogObject(activatedConfig))}`);
|
|
266
|
+
return activatedConfig;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// src/lib/graph/functions/generate-graphs.ts
|
|
270
|
+
import { assertDefined as assertDefined2 } from "@package-pal/util";
|
|
271
|
+
import { dim as dim2 } from "yoctocolors";
|
|
272
|
+
var trackPackageEntryDependencies = ({
|
|
273
|
+
trackedDependencies,
|
|
274
|
+
packageNames,
|
|
275
|
+
packageData
|
|
276
|
+
}) => {
|
|
277
|
+
const iterateEntries = [packageData.dependencies, packageData.peerDependencies];
|
|
278
|
+
for (const packageEntries of iterateEntries) {
|
|
279
|
+
if (!packageEntries) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
for (const trackPackageName of Object.keys(packageEntries)) {
|
|
283
|
+
if (!packageNames.has(trackPackageName)) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
trackedDependencies.add(trackPackageName);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
var generateReverseGraph = (packages, packageGraph) => {
|
|
291
|
+
const reversePackageGraph = new Map(packages.map((packageData) => [packageData.name, {
|
|
292
|
+
packageData,
|
|
293
|
+
pointsToPackages: new Set
|
|
294
|
+
}]));
|
|
295
|
+
for (const packageData of packages) {
|
|
296
|
+
const packageNode = assertDefined2(packageGraph.get(packageData.name));
|
|
297
|
+
for (const dependency of packageNode.pointsToPackages) {
|
|
298
|
+
const reverseNode = assertDefined2(reversePackageGraph.get(dependency));
|
|
299
|
+
reverseNode.pointsToPackages.add(packageData.name);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return reversePackageGraph;
|
|
303
|
+
};
|
|
304
|
+
var generateGraphs = (packages, logger) => {
|
|
305
|
+
logger.debug(dim2(`Generating package graphs for ${packages.length.toString()} packages...`));
|
|
306
|
+
const packageNames = new Set(packages.map((packageData) => packageData.name));
|
|
307
|
+
const packageGraph = new Map;
|
|
308
|
+
for (const packageData of packages) {
|
|
309
|
+
const trackedDependencies = new Set;
|
|
310
|
+
trackPackageEntryDependencies({
|
|
311
|
+
trackedDependencies,
|
|
312
|
+
packageNames,
|
|
313
|
+
packageData
|
|
314
|
+
});
|
|
315
|
+
packageGraph.set(packageData.name, {
|
|
316
|
+
packageData,
|
|
317
|
+
pointsToPackages: trackedDependencies
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const reversePackageGraph = generateReverseGraph(packages, packageGraph);
|
|
321
|
+
return {
|
|
322
|
+
dependencies: packageGraph,
|
|
323
|
+
dependents: reversePackageGraph
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// src/lib/graph/functions/generate-package-circular-dependency-paths.ts
|
|
328
|
+
import { assertDefined as assertDefined6 } from "@package-pal/util";
|
|
329
|
+
import {
|
|
330
|
+
dim as dim3,
|
|
331
|
+
yellow
|
|
332
|
+
} from "yoctocolors";
|
|
333
|
+
|
|
334
|
+
// src/lib/graph/functions/dfs-traverse-graph-paths.ts
|
|
335
|
+
import { assertDefined as assertDefined3 } from "@package-pal/util";
|
|
336
|
+
var dfsTraverseGraphPaths = function* (graph, traverseFromPackages) {
|
|
337
|
+
const globalVisited = new Set;
|
|
338
|
+
const startPackages = Array.isArray(traverseFromPackages) ? traverseFromPackages : [traverseFromPackages];
|
|
339
|
+
for (const start of startPackages) {
|
|
340
|
+
const stack = [{
|
|
341
|
+
node: start,
|
|
342
|
+
path: [],
|
|
343
|
+
localVisited: new Set
|
|
344
|
+
}];
|
|
345
|
+
while (stack.length) {
|
|
346
|
+
const {
|
|
347
|
+
node,
|
|
348
|
+
path,
|
|
349
|
+
localVisited
|
|
350
|
+
} = assertDefined3(stack.pop());
|
|
351
|
+
if (localVisited.has(node)) {
|
|
352
|
+
const idx = path.indexOf(node);
|
|
353
|
+
if (idx !== -1) {
|
|
354
|
+
yield [...path.slice(idx), node];
|
|
355
|
+
}
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (globalVisited.has(node)) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const newPath = [...path, node];
|
|
362
|
+
const newLocalVisited = new Set(localVisited);
|
|
363
|
+
newLocalVisited.add(node);
|
|
364
|
+
const neighbours = graph.get(node)?.pointsToPackages;
|
|
365
|
+
let pushed = false;
|
|
366
|
+
if (neighbours) {
|
|
367
|
+
for (const neighbour of neighbours) {
|
|
368
|
+
stack.push({
|
|
369
|
+
node: neighbour,
|
|
370
|
+
path: newPath,
|
|
371
|
+
localVisited: newLocalVisited
|
|
372
|
+
});
|
|
373
|
+
pushed = true;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (!pushed) {
|
|
377
|
+
yield newPath;
|
|
378
|
+
}
|
|
379
|
+
globalVisited.add(node);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// src/lib/graph/functions/extract-subgraph.ts
|
|
385
|
+
import { assertDefined as assertDefined5 } from "@package-pal/util";
|
|
386
|
+
|
|
387
|
+
// src/lib/graph/functions/dfs-traverse-graph.ts
|
|
388
|
+
import { assertDefined as assertDefined4 } from "@package-pal/util";
|
|
389
|
+
var dfsTraverseGraph = function* (graph, traverseFromPackages) {
|
|
390
|
+
const visited = new Set;
|
|
391
|
+
const stack = Array.isArray(traverseFromPackages) ? [...traverseFromPackages] : [traverseFromPackages];
|
|
392
|
+
while (stack.length) {
|
|
393
|
+
const activePackage = assertDefined4(stack.pop());
|
|
394
|
+
if (visited.has(activePackage)) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
visited.add(activePackage);
|
|
398
|
+
const node = graph.get(activePackage);
|
|
399
|
+
if (!node) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
yield node.packageData;
|
|
403
|
+
for (const dep of node.pointsToPackages) {
|
|
404
|
+
if (!visited.has(dep)) {
|
|
405
|
+
stack.push(dep);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/lib/graph/functions/extract-subgraph.ts
|
|
412
|
+
var extractSubgraph = (graph, fromPackages) => {
|
|
413
|
+
const reachablePackages = new Set(dfsTraverseGraph(graph, fromPackages).map((packageData) => packageData.name));
|
|
414
|
+
const subgraph = new Map;
|
|
415
|
+
for (const packageName of reachablePackages) {
|
|
416
|
+
const node = assertDefined5(graph.get(packageName));
|
|
417
|
+
const filteredNeighbours = new Set([...node.pointsToPackages].filter((dep) => reachablePackages.has(dep)));
|
|
418
|
+
subgraph.set(packageName, {
|
|
419
|
+
packageData: node.packageData,
|
|
420
|
+
pointsToPackages: filteredNeighbours
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return subgraph;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// src/lib/graph/functions/generate-package-circular-dependency-paths.ts
|
|
427
|
+
var findStronglyConnectedComponents = (graph) => {
|
|
428
|
+
let index = 0;
|
|
429
|
+
const indices = new Map;
|
|
430
|
+
const lowlinks = new Map;
|
|
431
|
+
const stack = [];
|
|
432
|
+
const onStack = new Set;
|
|
433
|
+
const sccs = [];
|
|
434
|
+
const strongConnect = (node) => {
|
|
435
|
+
indices.set(node, index);
|
|
436
|
+
lowlinks.set(node, index);
|
|
437
|
+
index++;
|
|
438
|
+
stack.push(node);
|
|
439
|
+
onStack.add(node);
|
|
440
|
+
const neighbors = graph.get(node)?.pointsToPackages ?? new Set;
|
|
441
|
+
for (const neighbor of neighbors) {
|
|
442
|
+
if (!indices.has(neighbor)) {
|
|
443
|
+
strongConnect(neighbor);
|
|
444
|
+
lowlinks.set(node, Math.min(assertDefined6(lowlinks.get(node)), assertDefined6(lowlinks.get(neighbor))));
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (onStack.has(neighbor)) {
|
|
448
|
+
lowlinks.set(node, Math.min(assertDefined6(lowlinks.get(node)), assertDefined6(indices.get(neighbor))));
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (lowlinks.get(node) === indices.get(node)) {
|
|
452
|
+
const scc = [];
|
|
453
|
+
let stackNode = assertDefined6(stack.pop());
|
|
454
|
+
onStack.delete(stackNode);
|
|
455
|
+
scc.push(stackNode);
|
|
456
|
+
while (stackNode !== node) {
|
|
457
|
+
stackNode = assertDefined6(stack.pop());
|
|
458
|
+
onStack.delete(stackNode);
|
|
459
|
+
scc.push(stackNode);
|
|
460
|
+
}
|
|
461
|
+
const firstNode = scc[0];
|
|
462
|
+
const isSelfCycle = !!firstNode && (graph.get(firstNode)?.pointsToPackages.has(firstNode) ?? false);
|
|
463
|
+
if (scc.length > 1 || isSelfCycle) {
|
|
464
|
+
sccs.push(scc);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
for (const node of graph.keys()) {
|
|
469
|
+
if (!indices.has(node)) {
|
|
470
|
+
strongConnect(node);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return sccs;
|
|
474
|
+
};
|
|
475
|
+
var findSampleCyclePath = (scc, graph) => {
|
|
476
|
+
const sccSet = new Set(scc);
|
|
477
|
+
return assertDefined6(dfsTraverseGraphPaths(graph, scc).find((path) => {
|
|
478
|
+
const lastPackage = path[path.length - 1];
|
|
479
|
+
return path.length >= 2 && lastPackage && sccSet.has(lastPackage);
|
|
480
|
+
}));
|
|
481
|
+
};
|
|
482
|
+
var generatePackageCircularDependencyPaths = ({ dependents }, packageSorted, logger) => {
|
|
483
|
+
logger.debug(dim3("Generating circular dependency paths..."));
|
|
484
|
+
const subgraph = extractSubgraph(dependents, packageSorted.circular);
|
|
485
|
+
const scss = findStronglyConnectedComponents(subgraph);
|
|
486
|
+
const sampleCycles = scss.map((scc) => findSampleCyclePath(scc, subgraph).reverse());
|
|
487
|
+
if (sampleCycles.length) {
|
|
488
|
+
const sampleCycleContents = sampleCycles.map((cycle, index) => {
|
|
489
|
+
return ` ${(index + 1).toString()}. ` + cycle.map((name) => `'${name}'`).join(" \u2192 ");
|
|
490
|
+
}).join(`
|
|
491
|
+
`);
|
|
492
|
+
logger.warn(yellow(`${sampleCycles.length.toString()} cyclic paths found:
|
|
493
|
+
${sampleCycleContents}`));
|
|
494
|
+
} else {
|
|
495
|
+
logger.debug(dim3(`No cyclic paths found.`));
|
|
496
|
+
}
|
|
497
|
+
return sampleCycles;
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/lib/graph/functions/generate-topological-sorted-groups.ts
|
|
501
|
+
import { assertDefined as assertDefined7 } from "@package-pal/util";
|
|
502
|
+
import {
|
|
503
|
+
dim as dim4,
|
|
504
|
+
yellow as yellow2
|
|
505
|
+
} from "yoctocolors";
|
|
506
|
+
var getCircularDependencies = (inDegree) => {
|
|
507
|
+
return Array.from(inDegree.keys()).sort((a, b) => {
|
|
508
|
+
const degA = assertDefined7(inDegree.get(a));
|
|
509
|
+
const degB = assertDefined7(inDegree.get(b));
|
|
510
|
+
return degB - degA;
|
|
511
|
+
}).sort();
|
|
512
|
+
};
|
|
513
|
+
var generateTopologicalSortedGroups = (packageGraph, logger) => {
|
|
514
|
+
logger.debug(dim4("Generating topological sorted groups..."));
|
|
515
|
+
const graphEntries = Array.from(packageGraph.entries());
|
|
516
|
+
const inDegree = new Map(graphEntries.map(([packageName]) => [packageName, 0]));
|
|
517
|
+
const graph = new Map(graphEntries.map(([packageName]) => [packageName, new Set]));
|
|
518
|
+
for (const [packageName, node] of graphEntries) {
|
|
519
|
+
for (const dependencyName of node.pointsToPackages) {
|
|
520
|
+
assertDefined7(graph.get(dependencyName)).add(packageName);
|
|
521
|
+
inDegree.set(packageName, assertDefined7(inDegree.get(packageName)) + 1);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const result = [];
|
|
525
|
+
let ready = [];
|
|
526
|
+
for (const [packageName, deg] of inDegree) {
|
|
527
|
+
if (deg === 0) {
|
|
528
|
+
ready.push(packageName);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
while (ready.length > 0) {
|
|
532
|
+
result.push(ready);
|
|
533
|
+
const nextReady = [];
|
|
534
|
+
for (const packageName of ready) {
|
|
535
|
+
inDegree.delete(packageName);
|
|
536
|
+
const dependentPackages = graph.get(packageName);
|
|
537
|
+
if (!dependentPackages) {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
for (const dependentPackage of dependentPackages) {
|
|
541
|
+
inDegree.set(dependentPackage, assertDefined7(inDegree.get(dependentPackage)) - 1);
|
|
542
|
+
if (inDegree.get(dependentPackage) === 0) {
|
|
543
|
+
nextReady.push(dependentPackage);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
ready = nextReady;
|
|
548
|
+
}
|
|
549
|
+
logger.debug(dim4(`Sorted packages into ${result.length.toString()} sequential groups of parallelizable dependencies.`));
|
|
550
|
+
const circular = getCircularDependencies(inDegree);
|
|
551
|
+
if (circular.length) {
|
|
552
|
+
logger.warn(yellow2(`${circular.length.toString()} packages could not be sorted due to circular dependencies. Correct ordering cannot be guaranteed.`));
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
groups: result.map((group) => group.sort()),
|
|
556
|
+
circular
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// src/lib/package/functions/load-packages.ts
|
|
561
|
+
import { dim as dim6 } from "yoctocolors";
|
|
562
|
+
|
|
563
|
+
// src/lib/package/functions/scan-packages.ts
|
|
564
|
+
import {
|
|
565
|
+
dirname as dirname4,
|
|
566
|
+
join as join2
|
|
567
|
+
} from "path";
|
|
568
|
+
import { formatUnknownError } from "@package-pal/util";
|
|
569
|
+
import {
|
|
570
|
+
dim as dim5,
|
|
571
|
+
red
|
|
572
|
+
} from "yoctocolors";
|
|
573
|
+
|
|
574
|
+
// src/lib/package/functions/parse-package.ts
|
|
575
|
+
import {
|
|
576
|
+
dirname as dirname3,
|
|
577
|
+
basename as basename2
|
|
578
|
+
} from "path";
|
|
579
|
+
import { isDefined as isDefined2 } from "@package-pal/util";
|
|
580
|
+
var parsePackage = (path, text) => {
|
|
581
|
+
const base = JSON.parse(text);
|
|
582
|
+
if (!isDefined2(base) || typeof base !== "object") {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
const props = base;
|
|
586
|
+
const {
|
|
587
|
+
dependencies,
|
|
588
|
+
peerDependencies,
|
|
589
|
+
devDependencies
|
|
590
|
+
} = props;
|
|
591
|
+
if (isDefined2(dependencies) && !(typeof dependencies === "object") || isDefined2(peerDependencies) && !(typeof peerDependencies === "object") || isDefined2(devDependencies) && !(typeof devDependencies === "object")) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
rawContent: text,
|
|
596
|
+
path,
|
|
597
|
+
name: props.name ?? path,
|
|
598
|
+
dir: basename2(dirname3(path)),
|
|
599
|
+
version: props.version ?? undefined,
|
|
600
|
+
dependencies: dependencies ?? undefined,
|
|
601
|
+
peerDependencies: peerDependencies ?? undefined,
|
|
602
|
+
devDependencies: devDependencies ?? undefined
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
// src/lib/package/functions/scan-package-paths.ts
|
|
607
|
+
import { scanGlobPatternPaths } from "@package-pal/util";
|
|
608
|
+
var scanPackagePaths = (packages) => {
|
|
609
|
+
return scanGlobPatternPaths(packages, {
|
|
610
|
+
absolute: true,
|
|
611
|
+
onlyFiles: false
|
|
612
|
+
});
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
// src/lib/package/functions/scan-packages.ts
|
|
616
|
+
var scanPackages = async function* (patterns, logger) {
|
|
617
|
+
for await (const path of scanPackagePaths(patterns)) {
|
|
618
|
+
const packagePath = join2(path, "package.json");
|
|
619
|
+
const dir = dirname4(packagePath);
|
|
620
|
+
try {
|
|
621
|
+
const file = Bun.file(packagePath);
|
|
622
|
+
const text = await file.text();
|
|
623
|
+
const packageData = parsePackage(packagePath, text);
|
|
624
|
+
if (!packageData) {
|
|
625
|
+
logger.debug(dim5(`Invalid package.json found in '${dir}'.`));
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
logger.debug(dim5(`Successfully read package.json in '${dir}'.`));
|
|
629
|
+
yield packageData;
|
|
630
|
+
} catch (e) {
|
|
631
|
+
logger.debug(dim5(`Failed to read package.json in '${dir}' - ${red(formatUnknownError(e))}.`));
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
// src/lib/package/functions/load-packages.ts
|
|
637
|
+
var loadPackages = async (packagePatterns, logger) => {
|
|
638
|
+
const patternContent = packagePatterns.map((pattern) => `'${pattern}'`).join(", ");
|
|
639
|
+
logger.debug(dim6(`Loading packages matching pattern/s ${patternContent}...`));
|
|
640
|
+
const packages = [];
|
|
641
|
+
const seen = new Set;
|
|
642
|
+
for await (const packageData of scanPackages(Array.from(new Set(packagePatterns)), logger)) {
|
|
643
|
+
if (seen.has(packageData.name)) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
seen.add(packageData.name);
|
|
647
|
+
packages.push(packageData);
|
|
648
|
+
}
|
|
649
|
+
if (!packages.length) {
|
|
650
|
+
throw new Error(`No packages found for pattern/s ${patternContent}.`);
|
|
651
|
+
}
|
|
652
|
+
return packages;
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// src/lib/package/functions/update-package-version.ts
|
|
656
|
+
var {semver } = globalThis.Bun;
|
|
657
|
+
import { inc } from "semver";
|
|
658
|
+
import { dim as dim7 } from "yoctocolors";
|
|
659
|
+
var findAndReplaceVersion = ({
|
|
660
|
+
raw,
|
|
661
|
+
field,
|
|
662
|
+
packageName,
|
|
663
|
+
updatePackageName,
|
|
664
|
+
newVersion,
|
|
665
|
+
exact,
|
|
666
|
+
logger
|
|
667
|
+
}) => {
|
|
668
|
+
if (field === "version" && packageName === updatePackageName) {
|
|
669
|
+
const versionKey = `"version"`;
|
|
670
|
+
const keyIndex = raw.indexOf(versionKey);
|
|
671
|
+
if (keyIndex === -1) {
|
|
672
|
+
return raw;
|
|
673
|
+
}
|
|
674
|
+
const versionStart2 = raw.indexOf('"', keyIndex + versionKey.length);
|
|
675
|
+
const versionEnd2 = raw.indexOf('"', versionStart2 + 1);
|
|
676
|
+
if (versionStart2 === -1 || versionEnd2 === -1) {
|
|
677
|
+
return raw;
|
|
678
|
+
}
|
|
679
|
+
const currentVersionString2 = raw.slice(versionStart2 + 1, versionEnd2);
|
|
680
|
+
const updatedVersion2 = newVersion;
|
|
681
|
+
logger.info(`Updating '${updatePackageName}' version: ${currentVersionString2} \u2192 ${updatedVersion2}.`);
|
|
682
|
+
const before2 = raw.slice(0, versionStart2 + 1);
|
|
683
|
+
const after2 = raw.slice(versionEnd2);
|
|
684
|
+
return `${before2}${updatedVersion2}${after2}`;
|
|
685
|
+
}
|
|
686
|
+
const fieldIndex = raw.indexOf(`"${field}"`);
|
|
687
|
+
if (fieldIndex === -1) {
|
|
688
|
+
return raw;
|
|
689
|
+
}
|
|
690
|
+
const fieldStart = raw.indexOf("{", fieldIndex);
|
|
691
|
+
if (fieldStart === -1) {
|
|
692
|
+
return raw;
|
|
693
|
+
}
|
|
694
|
+
const fieldEnd = raw.indexOf("}", fieldStart);
|
|
695
|
+
if (fieldEnd === -1) {
|
|
696
|
+
return raw;
|
|
697
|
+
}
|
|
698
|
+
const fieldBlock = raw.slice(fieldStart, fieldEnd);
|
|
699
|
+
const depKey = `"${packageName}"`;
|
|
700
|
+
const depIndex = fieldBlock.indexOf(depKey);
|
|
701
|
+
if (depIndex === -1) {
|
|
702
|
+
return raw;
|
|
703
|
+
}
|
|
704
|
+
const versionStart = fieldBlock.indexOf('"', depIndex + depKey.length);
|
|
705
|
+
const versionEnd = fieldBlock.indexOf('"', versionStart + 1);
|
|
706
|
+
if (versionStart === -1 || versionEnd === -1) {
|
|
707
|
+
return raw;
|
|
708
|
+
}
|
|
709
|
+
const currentVersionString = fieldBlock.slice(versionStart + 1, versionEnd);
|
|
710
|
+
const preservedPrefix = exact ? "" : /^([~^><=]*)/.exec(currentVersionString)?.[1] ?? "";
|
|
711
|
+
const updatedVersion = `${preservedPrefix}${newVersion}`;
|
|
712
|
+
logger.info(`Updating '${updatePackageName}' ${field} '${packageName}': ${currentVersionString} \u2192 ${updatedVersion}.`);
|
|
713
|
+
const before = raw.slice(0, fieldStart + versionStart + 1);
|
|
714
|
+
const after = raw.slice(fieldStart + versionEnd);
|
|
715
|
+
return `${before}${updatedVersion}${after}`;
|
|
716
|
+
};
|
|
717
|
+
var updatePackageVersion = async (packageName, type, packageGraphs, preId, exact, logger) => {
|
|
718
|
+
logger.debug(dim7(`Bumping package '${packageName}'...`));
|
|
719
|
+
const packageNode = packageGraphs.dependencies.get(packageName);
|
|
720
|
+
if (!packageNode) {
|
|
721
|
+
throw new Error(`Package '${packageName}' not found.`);
|
|
722
|
+
}
|
|
723
|
+
const currentVersion = packageNode.packageData.version;
|
|
724
|
+
if (!currentVersion) {
|
|
725
|
+
throw new Error(`Package '${packageName}' has no version.`);
|
|
726
|
+
}
|
|
727
|
+
const bumpedVersion = inc(currentVersion, type, undefined, preId);
|
|
728
|
+
if (!bumpedVersion) {
|
|
729
|
+
throw new Error(`Package '${packageName}' version '${currentVersion}' is invalid.`);
|
|
730
|
+
}
|
|
731
|
+
const updatedContent = findAndReplaceVersion({
|
|
732
|
+
raw: packageNode.packageData.rawContent,
|
|
733
|
+
field: "version",
|
|
734
|
+
packageName,
|
|
735
|
+
updatePackageName: packageName,
|
|
736
|
+
newVersion: bumpedVersion,
|
|
737
|
+
exact,
|
|
738
|
+
logger
|
|
739
|
+
});
|
|
740
|
+
const baseWrite = Bun.write(packageNode.packageData.path, updatedContent);
|
|
741
|
+
const dependentWrites = Array.from(dfsTraverseGraph(packageGraphs.dependents, packageName).flatMap((dependent) => {
|
|
742
|
+
const fields = ["dependencies", "peerDependencies"];
|
|
743
|
+
return fields.flatMap((field) => {
|
|
744
|
+
const entry = dependent[field];
|
|
745
|
+
const depVersion = entry?.[packageName];
|
|
746
|
+
if (!depVersion) {
|
|
747
|
+
return [];
|
|
748
|
+
}
|
|
749
|
+
if (exact ? depVersion === bumpedVersion : semver.satisfies(bumpedVersion, depVersion)) {
|
|
750
|
+
logger.debug(dim7(`Skipping '${dependent.name}': ${field} version '${depVersion}' already satisfies '${bumpedVersion}'.`));
|
|
751
|
+
return [];
|
|
752
|
+
}
|
|
753
|
+
const updatedContent2 = findAndReplaceVersion({
|
|
754
|
+
raw: dependent.rawContent,
|
|
755
|
+
field,
|
|
756
|
+
packageName,
|
|
757
|
+
updatePackageName: dependent.name,
|
|
758
|
+
newVersion: bumpedVersion,
|
|
759
|
+
exact,
|
|
760
|
+
logger
|
|
761
|
+
});
|
|
762
|
+
return [Bun.write(dependent.path, updatedContent2)];
|
|
763
|
+
});
|
|
764
|
+
}));
|
|
765
|
+
return Promise.all([baseWrite, ...dependentWrites]).then(() => {
|
|
766
|
+
return;
|
|
767
|
+
});
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// src/lib/watch/functions/watch-package-changes.ts
|
|
771
|
+
import {
|
|
772
|
+
watch
|
|
773
|
+
} from "fs";
|
|
774
|
+
import {
|
|
775
|
+
dirname as dirname6,
|
|
776
|
+
join as join4
|
|
777
|
+
} from "path";
|
|
778
|
+
import {
|
|
779
|
+
assertDefined as assertDefined9,
|
|
780
|
+
DedupePathsBy,
|
|
781
|
+
dedupeSharedPaths,
|
|
782
|
+
getDeferredPromise,
|
|
783
|
+
getStringMatcher,
|
|
784
|
+
isDefined as isDefined4
|
|
785
|
+
} from "@package-pal/util";
|
|
786
|
+
import {
|
|
787
|
+
dim as dim9,
|
|
788
|
+
red as red3
|
|
789
|
+
} from "yoctocolors";
|
|
790
|
+
|
|
791
|
+
// src/lib/graph/functions/generate-topological-ranking-range.ts
|
|
792
|
+
import { isDefined as isDefined3 } from "@package-pal/util";
|
|
793
|
+
var generateTopologicalRankingRange = (graph, ranking) => {
|
|
794
|
+
let min = Infinity;
|
|
795
|
+
let max = -Infinity;
|
|
796
|
+
for (const key of graph.keys()) {
|
|
797
|
+
const rank = ranking.get(key);
|
|
798
|
+
if (!isDefined3(rank)) {
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (rank < min) {
|
|
802
|
+
min = rank;
|
|
803
|
+
}
|
|
804
|
+
if (rank > max) {
|
|
805
|
+
max = rank;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (min === Infinity) {
|
|
809
|
+
return [-1, -1];
|
|
810
|
+
}
|
|
811
|
+
return [min, max];
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
// src/lib/graph/functions/generate-topological-ranking.ts
|
|
815
|
+
import { assertDefined as assertDefined8 } from "@package-pal/util";
|
|
816
|
+
var generateTopologicalRanking = (packageProcessOrder) => {
|
|
817
|
+
const rankMap = new Map;
|
|
818
|
+
for (let i = 0;i < packageProcessOrder.length; i++) {
|
|
819
|
+
for (const packageName of assertDefined8(packageProcessOrder[i])) {
|
|
820
|
+
rankMap.set(packageName, i);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return rankMap;
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// src/lib/graph/functions/is-disjoint.ts
|
|
827
|
+
var isDisjoint = (a, b) => {
|
|
828
|
+
for (const key of a.keys()) {
|
|
829
|
+
if (b.has(key)) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
return true;
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// src/lib/graph/functions/is-ranked-greater-than-or-equal.ts
|
|
837
|
+
var isRankedGreaterThanOrEqual = (a, b, ranking) => {
|
|
838
|
+
const [prevMin] = generateTopologicalRankingRange(a, ranking);
|
|
839
|
+
for (const key of b.keys()) {
|
|
840
|
+
const rank = ranking.get(key);
|
|
841
|
+
if (rank !== undefined && rank < prevMin) {
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return true;
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// src/lib/graph/functions/is-subgraph.ts
|
|
849
|
+
var recordEqual = (a, b) => {
|
|
850
|
+
if (!a && !b) {
|
|
851
|
+
return true;
|
|
852
|
+
}
|
|
853
|
+
if (!a || !b) {
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
const aKeys = Object.keys(a);
|
|
857
|
+
const bKeys = Object.keys(b);
|
|
858
|
+
if (aKeys.length !== bKeys.length) {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
return aKeys.every((key) => b[key] === a[key]);
|
|
862
|
+
};
|
|
863
|
+
var isPackageDataLooseEqual = (a, b) => {
|
|
864
|
+
return a.name === b.name && recordEqual(a.dependencies, b.dependencies) && recordEqual(a.peerDependencies, b.peerDependencies) && recordEqual(a.devDependencies, b.devDependencies);
|
|
865
|
+
};
|
|
866
|
+
var isSubgraph = (a, b) => {
|
|
867
|
+
for (const [key, nodeB] of b) {
|
|
868
|
+
const nodeA = a.get(key);
|
|
869
|
+
if (!nodeA) {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
872
|
+
if (!isPackageDataLooseEqual(nodeA.packageData, nodeB.packageData)) {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
for (const dep of nodeB.pointsToPackages) {
|
|
876
|
+
if (!nodeA.pointsToPackages.has(dep)) {
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return true;
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/lib/watch/types/change-action.ts
|
|
885
|
+
var ChangeAction = {
|
|
886
|
+
Ignore: "Ignore",
|
|
887
|
+
Partial: "Partial",
|
|
888
|
+
Restart: "Restart"
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/lib/watch/types/exit-state.ts
|
|
892
|
+
var ExitState = {
|
|
893
|
+
Completed: "Completed",
|
|
894
|
+
Errored: "Errored",
|
|
895
|
+
Cancelled: "Cancelled"
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// src/lib/watch/types/run-async-type.ts
|
|
899
|
+
var RunAsyncType = {
|
|
900
|
+
Sequential: "Sequential",
|
|
901
|
+
Parallel: "Parallel"
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// src/lib/watch/functions/filter-files-modified-since.ts
|
|
905
|
+
var filterFilesModifiedSince = (paths, sinceMs) => {
|
|
906
|
+
return paths.filter((path) => {
|
|
907
|
+
const changedFile = Bun.file(path);
|
|
908
|
+
return changedFile.lastModified >= sinceMs;
|
|
909
|
+
});
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
// src/lib/watch/functions/normalise-watched-file-path.ts
|
|
913
|
+
import {
|
|
914
|
+
basename as basename3,
|
|
915
|
+
dirname as dirname5,
|
|
916
|
+
join as join3
|
|
917
|
+
} from "path";
|
|
918
|
+
var removeTrailing = [
|
|
919
|
+
"~",
|
|
920
|
+
".tmp",
|
|
921
|
+
".temp",
|
|
922
|
+
".bak",
|
|
923
|
+
".backup",
|
|
924
|
+
".swp",
|
|
925
|
+
".swo",
|
|
926
|
+
".swn"
|
|
927
|
+
];
|
|
928
|
+
var normaliseWatchedFilePath = (filePath) => {
|
|
929
|
+
const dir = dirname5(filePath);
|
|
930
|
+
let base = basename3(filePath);
|
|
931
|
+
for (const trailing of removeTrailing) {
|
|
932
|
+
if (base.toLowerCase().endsWith(trailing)) {
|
|
933
|
+
const sliceStart = base.startsWith(".") ? 1 : 0;
|
|
934
|
+
base = base.slice(sliceStart, -trailing.length);
|
|
935
|
+
break;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return join3(dir, base);
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
// src/lib/watch/functions/run-async.ts
|
|
942
|
+
var runAsync = async (type, tasks) => {
|
|
943
|
+
if (type === RunAsyncType.Parallel) {
|
|
944
|
+
return Promise.all(tasks.map((task) => task()));
|
|
945
|
+
}
|
|
946
|
+
const outputs = [];
|
|
947
|
+
for (const task of tasks) {
|
|
948
|
+
const result = await task();
|
|
949
|
+
outputs.push(result);
|
|
950
|
+
}
|
|
951
|
+
return outputs;
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
// src/lib/watch/functions/run-subprocess.ts
|
|
955
|
+
import {
|
|
956
|
+
dim as dim8,
|
|
957
|
+
red as red2
|
|
958
|
+
} from "yoctocolors";
|
|
959
|
+
|
|
960
|
+
// src/lib/watch/types/std-type.ts
|
|
961
|
+
var StdType = {
|
|
962
|
+
Out: "Out",
|
|
963
|
+
Err: "Err"
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
// src/lib/watch/functions/get-commands-for-shell.ts
|
|
967
|
+
var getCommandsForShell = (shellCommand) => {
|
|
968
|
+
const isWindows = process.platform === "win32";
|
|
969
|
+
if (!isWindows) {
|
|
970
|
+
return [
|
|
971
|
+
"sh",
|
|
972
|
+
"-c",
|
|
973
|
+
`"${shellCommand}"`
|
|
974
|
+
];
|
|
975
|
+
}
|
|
976
|
+
const shell = Bun.which("pwsh") ? "pwsh" : Bun.which("powershell") ? "powershell" : "cmd";
|
|
977
|
+
if (shell === "cmd") {
|
|
978
|
+
return [
|
|
979
|
+
shell,
|
|
980
|
+
"/c",
|
|
981
|
+
`"${shellCommand}"`
|
|
982
|
+
];
|
|
983
|
+
}
|
|
984
|
+
const encodedCommand = Buffer.from(shellCommand, "utf16le").toString("base64");
|
|
985
|
+
return [
|
|
986
|
+
shell,
|
|
987
|
+
"-EncodedCommand",
|
|
988
|
+
encodedCommand
|
|
989
|
+
];
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// src/lib/watch/functions/get-line-buffered-writer.ts
|
|
993
|
+
import { identity } from "@package-pal/util";
|
|
994
|
+
var getLineBufferedWriter = (prefix, style = identity, write = process.stdout.write.bind(process.stdout)) => {
|
|
995
|
+
let buffer = "";
|
|
996
|
+
return (chunk) => {
|
|
997
|
+
buffer += chunk;
|
|
998
|
+
const lines = buffer.split(`
|
|
999
|
+
`);
|
|
1000
|
+
buffer = lines.pop() ?? "";
|
|
1001
|
+
for (const line of lines) {
|
|
1002
|
+
write(`${prefix}${style(line)}
|
|
1003
|
+
`);
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
// src/lib/watch/functions/read-stream.ts
|
|
1009
|
+
var readStream = async (stream, use) => {
|
|
1010
|
+
if (!stream) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
const decoder = new TextDecoder;
|
|
1014
|
+
const reader = stream.getReader();
|
|
1015
|
+
let result = await reader.read();
|
|
1016
|
+
while (!result.done) {
|
|
1017
|
+
use(decoder.decode(result.value, { stream: true }));
|
|
1018
|
+
result = await reader.read();
|
|
1019
|
+
}
|
|
1020
|
+
const flush = decoder.decode();
|
|
1021
|
+
if (flush) {
|
|
1022
|
+
use(flush);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
|
|
1026
|
+
// src/lib/watch/functions/run-subprocess.ts
|
|
1027
|
+
var sigintCode = 130;
|
|
1028
|
+
var sigtermCode = 143;
|
|
1029
|
+
var sigkillCode = 137;
|
|
1030
|
+
var cancelCodes = new Set([
|
|
1031
|
+
sigintCode,
|
|
1032
|
+
sigtermCode,
|
|
1033
|
+
sigkillCode
|
|
1034
|
+
]);
|
|
1035
|
+
var runSubprocess = async (opts) => {
|
|
1036
|
+
if (opts.signal?.aborted) {
|
|
1037
|
+
opts.logger.debug(dim8(`Skipped '${opts.debugName}' subprocess command; signal already cancelled.`));
|
|
1038
|
+
return ExitState.Cancelled;
|
|
1039
|
+
}
|
|
1040
|
+
const commands = getCommandsForShell(opts.shellCommand);
|
|
1041
|
+
const subprocess = Bun.spawn(commands, {
|
|
1042
|
+
cwd: opts.cwd,
|
|
1043
|
+
stdout: "pipe",
|
|
1044
|
+
stderr: "pipe",
|
|
1045
|
+
stdin: "ignore",
|
|
1046
|
+
signal: opts.signal
|
|
1047
|
+
});
|
|
1048
|
+
const pid = subprocess.pid.toString();
|
|
1049
|
+
const [readStdout, readStderr] = [{
|
|
1050
|
+
source: subprocess.stdout,
|
|
1051
|
+
type: StdType.Out,
|
|
1052
|
+
write: getLineBufferedWriter(dim8(`[OUT-${pid}] `))
|
|
1053
|
+
}, {
|
|
1054
|
+
source: subprocess.stderr,
|
|
1055
|
+
type: StdType.Err,
|
|
1056
|
+
write: getLineBufferedWriter(red2(dim8(`[ERR-${pid}] `)))
|
|
1057
|
+
}].map(({
|
|
1058
|
+
source,
|
|
1059
|
+
type,
|
|
1060
|
+
write
|
|
1061
|
+
}) => {
|
|
1062
|
+
return readStream(source, (chunk) => {
|
|
1063
|
+
write(chunk);
|
|
1064
|
+
if (opts.onStdChunk) {
|
|
1065
|
+
opts.onStdChunk(chunk, type);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
const executedCommand = commands.join(" ");
|
|
1070
|
+
opts.logger.debug(dim8(`Started '${opts.debugName}' subprocess command '${opts.shellCommand}' (${executedCommand}) with PID ${pid}.`));
|
|
1071
|
+
const [
|
|
1072
|
+
,
|
|
1073
|
+
,
|
|
1074
|
+
exitState
|
|
1075
|
+
] = await Promise.all([
|
|
1076
|
+
readStdout,
|
|
1077
|
+
readStderr,
|
|
1078
|
+
subprocess.exited.then((exitCode) => {
|
|
1079
|
+
if (cancelCodes.has(exitCode)) {
|
|
1080
|
+
opts.logger.debug(dim8(`Cancelled '${opts.debugName}' subprocess command; PID ${pid} exited.`));
|
|
1081
|
+
return ExitState.Cancelled;
|
|
1082
|
+
}
|
|
1083
|
+
if (exitCode !== 0) {
|
|
1084
|
+
opts.logger.error(red2(`'${opts.debugName}' command '${opts.shellCommand}' (${executedCommand}) with PID ${pid} failed with exit code ${exitCode.toString()}.`));
|
|
1085
|
+
return ExitState.Errored;
|
|
1086
|
+
}
|
|
1087
|
+
opts.logger.debug(dim8(`Completed '${opts.debugName}' subprocess command; PID ${pid} exited.`));
|
|
1088
|
+
return ExitState.Completed;
|
|
1089
|
+
})
|
|
1090
|
+
]);
|
|
1091
|
+
return exitState;
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
// src/lib/watch/functions/watch-package-changes.ts
|
|
1095
|
+
var fileModifiedThresholdMs = 5000;
|
|
1096
|
+
var lastProcessedSubgraph;
|
|
1097
|
+
var getChangeLogic = (packageGraphs, packageChanges, config, logger) => {
|
|
1098
|
+
const changedPackages = Array.from(packageChanges.keys());
|
|
1099
|
+
const changedFilePaths = Array.from(packageChanges.values()).flat();
|
|
1100
|
+
if (packageChanges.size) {
|
|
1101
|
+
logger.debug(dim9(`Changes detected in ${changedPackages.map((packageName) => `'${packageName}'`).join(", ")}.`));
|
|
1102
|
+
logger.debug(dim9(`Changed file paths: ${changedFilePaths.map((filePath) => `'${filePath}'`).join(", ")}.`));
|
|
1103
|
+
}
|
|
1104
|
+
const packageOrder = generateTopologicalSortedGroups(packageGraphs.dependents, logger);
|
|
1105
|
+
const packageProcessOrder = packageOrder.groups.toReversed().concat(packageOrder.circular);
|
|
1106
|
+
const packageRankings = generateTopologicalRanking(packageProcessOrder);
|
|
1107
|
+
const changedPackageSubgraph = extractSubgraph(packageGraphs.dependents, changedPackages);
|
|
1108
|
+
const changedPackageOrder = generateTopologicalSortedGroups(changedPackageSubgraph, logger);
|
|
1109
|
+
const changedPackageProcessOrder = changedPackageOrder.groups.toReversed().concat(changedPackageOrder.circular);
|
|
1110
|
+
const isSubgraphOfPrevious = !!lastProcessedSubgraph && isSubgraph(lastProcessedSubgraph, changedPackageSubgraph);
|
|
1111
|
+
const isDisjointFromPrevious = !lastProcessedSubgraph || !isSubgraphOfPrevious && isDisjoint(lastProcessedSubgraph, changedPackageSubgraph);
|
|
1112
|
+
const isRankedGreaterThanOrEqualToPrevious = !!lastProcessedSubgraph && !isSubgraphOfPrevious && isRankedGreaterThanOrEqual(lastProcessedSubgraph, changedPackageSubgraph, packageRankings);
|
|
1113
|
+
logger.debug(dim9(`Changes are subgraph of previous: ${isSubgraphOfPrevious.toString()}.`));
|
|
1114
|
+
logger.debug(dim9(`Changes are disjoint from previous: ${isDisjointFromPrevious.toString()}.`));
|
|
1115
|
+
logger.debug(dim9(`Changes are ranked greater than or equal to previous: ${isRankedGreaterThanOrEqualToPrevious.toString()}.`));
|
|
1116
|
+
let action = ChangeAction.Restart;
|
|
1117
|
+
if (!packageChanges.size) {
|
|
1118
|
+
action = ChangeAction.Ignore;
|
|
1119
|
+
} else if (!config.subprocess.partialProcessing) {
|
|
1120
|
+
action = ChangeAction.Restart;
|
|
1121
|
+
} else if (isSubgraphOfPrevious) {
|
|
1122
|
+
action = ChangeAction.Ignore;
|
|
1123
|
+
} else if (isDisjointFromPrevious || isRankedGreaterThanOrEqualToPrevious) {
|
|
1124
|
+
action = ChangeAction.Partial;
|
|
1125
|
+
}
|
|
1126
|
+
if (action === ChangeAction.Partial && isRankedGreaterThanOrEqualToPrevious) {
|
|
1127
|
+
const [prevMinRank] = generateTopologicalRankingRange(assertDefined9(lastProcessedSubgraph), packageRankings);
|
|
1128
|
+
for (let i = 0;i < changedPackageProcessOrder.length; i++) {
|
|
1129
|
+
changedPackageProcessOrder[i] = assertDefined9(changedPackageProcessOrder[i]).filter((packageName) => {
|
|
1130
|
+
const rank = packageRankings.get(packageName);
|
|
1131
|
+
return rank !== undefined && rank >= prevMinRank;
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
logger.debug(dim9(`Determined change action: ${action}.`));
|
|
1136
|
+
return {
|
|
1137
|
+
changedPackageProcessOrder,
|
|
1138
|
+
changedPackageSubgraph,
|
|
1139
|
+
action
|
|
1140
|
+
};
|
|
1141
|
+
};
|
|
1142
|
+
var onProcessPackage = async (packageGraphs, packageChanges, watchConfig, determineAbortController, logger) => {
|
|
1143
|
+
const {
|
|
1144
|
+
action,
|
|
1145
|
+
changedPackageProcessOrder,
|
|
1146
|
+
changedPackageSubgraph
|
|
1147
|
+
} = getChangeLogic(packageGraphs, packageChanges, watchConfig, logger);
|
|
1148
|
+
const controller = determineAbortController(action === ChangeAction.Restart);
|
|
1149
|
+
const onProcessFailure = () => {
|
|
1150
|
+
logger.debug(dim9("Aborting controller: process failed."));
|
|
1151
|
+
controller.abort();
|
|
1152
|
+
lastProcessedSubgraph = undefined;
|
|
1153
|
+
};
|
|
1154
|
+
if (action === ChangeAction.Ignore && packageChanges.size) {
|
|
1155
|
+
logger.info(`Changes detected; but were ignored due to 'partialProcessing: true'. Waiting for changes..`);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
if (packageChanges.size) {
|
|
1159
|
+
logger.info(`Changes detected. ${action === ChangeAction.Restart ? "Restarting processing" : "Initiating partial processing"} ${watchConfig.subprocess.parallelProcessing ? "in parallel" : "sequentially"}.`);
|
|
1160
|
+
lastProcessedSubgraph = changedPackageSubgraph;
|
|
1161
|
+
}
|
|
1162
|
+
for (const group of changedPackageProcessOrder) {
|
|
1163
|
+
const {
|
|
1164
|
+
promise: longRunningParallelProcessReady,
|
|
1165
|
+
resolve: matchedParallelLongReadyRunningOutput
|
|
1166
|
+
} = getDeferredPromise();
|
|
1167
|
+
let matchedLongRunningOutputCount = 0;
|
|
1168
|
+
await runAsync(watchConfig.subprocess.parallelProcessing ? RunAsyncType.Parallel : RunAsyncType.Sequential, group.map((packageName) => async () => {
|
|
1169
|
+
const {
|
|
1170
|
+
promise: longRunningSequentialProcessReady,
|
|
1171
|
+
resolve: matchedSequentialLongRunningReadyOutput
|
|
1172
|
+
} = getDeferredPromise();
|
|
1173
|
+
const packageNode = assertDefined9(packageGraphs.dependencies.get(packageName));
|
|
1174
|
+
const changedPaths = packageChanges.get(packageName) ?? [];
|
|
1175
|
+
const processPackageProps = {
|
|
1176
|
+
name: packageName,
|
|
1177
|
+
dir: packageNode.packageData.dir,
|
|
1178
|
+
filePaths: changedPaths,
|
|
1179
|
+
totalChanges: packageChanges,
|
|
1180
|
+
totalProcessOrder: changedPackageProcessOrder,
|
|
1181
|
+
signal: controller.signal
|
|
1182
|
+
};
|
|
1183
|
+
const processPackageCwd = dirname6(packageNode.packageData.path);
|
|
1184
|
+
const beforeProcessPackageShellCommand = await watchConfig.hooks.onBeforeProcessPackage(processPackageProps);
|
|
1185
|
+
if (beforeProcessPackageShellCommand) {
|
|
1186
|
+
await runSubprocess({
|
|
1187
|
+
debugName: `before process ${packageName}`,
|
|
1188
|
+
shellCommand: beforeProcessPackageShellCommand,
|
|
1189
|
+
cwd: processPackageCwd,
|
|
1190
|
+
signal: controller.signal,
|
|
1191
|
+
logger
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
const processPackageShellCommand = await watchConfig.hooks.onProcessPackage(processPackageProps);
|
|
1195
|
+
if (processPackageShellCommand) {
|
|
1196
|
+
const longRunningOutputReadyText = watchConfig.subprocess.matchLongRunningOutputAsReady;
|
|
1197
|
+
const longRunningOutputErroredText = watchConfig.subprocess.matchLongRunningOutputAsErrored;
|
|
1198
|
+
const readyMatcher = longRunningOutputReadyText ? getStringMatcher(longRunningOutputReadyText) : undefined;
|
|
1199
|
+
const erroredMatcher = longRunningOutputErroredText ? getStringMatcher(longRunningOutputErroredText) : undefined;
|
|
1200
|
+
let ready = false;
|
|
1201
|
+
let errored = false;
|
|
1202
|
+
const exit = runSubprocess({
|
|
1203
|
+
debugName: `process ${packageName}`,
|
|
1204
|
+
shellCommand: processPackageShellCommand,
|
|
1205
|
+
cwd: processPackageCwd,
|
|
1206
|
+
signal: controller.signal,
|
|
1207
|
+
logger,
|
|
1208
|
+
onStdChunk: (chunk) => {
|
|
1209
|
+
if (!ready && readyMatcher?.push(chunk).matched()) {
|
|
1210
|
+
ready = true;
|
|
1211
|
+
matchedLongRunningOutputCount++;
|
|
1212
|
+
logger.debug(`'${packageName}' (${matchedLongRunningOutputCount.toString()}/${group.length.toString()}) subprocess matched ready text '${assertDefined9(longRunningOutputReadyText)}'.`);
|
|
1213
|
+
if (!watchConfig.subprocess.parallelProcessing && matchedLongRunningOutputCount) {
|
|
1214
|
+
matchedSequentialLongRunningReadyOutput();
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
if (!errored && erroredMatcher?.push(chunk).matched()) {
|
|
1218
|
+
logger.error(red3(`'${packageName}' subprocess matched error text '${assertDefined9(longRunningOutputErroredText)}'.`));
|
|
1219
|
+
errored = true;
|
|
1220
|
+
Promise.resolve(watchConfig.hooks.onProcessPackageError(processPackageProps)).then((processPackageErrorCommand) => {
|
|
1221
|
+
if (!processPackageErrorCommand) {
|
|
1222
|
+
onProcessFailure();
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
return runSubprocess({
|
|
1226
|
+
debugName: `after process ${packageName}`,
|
|
1227
|
+
shellCommand: processPackageErrorCommand,
|
|
1228
|
+
cwd: processPackageCwd,
|
|
1229
|
+
signal: controller.signal,
|
|
1230
|
+
logger
|
|
1231
|
+
});
|
|
1232
|
+
}).then((exitState) => {
|
|
1233
|
+
if (exitState === ExitState.Errored) {
|
|
1234
|
+
onProcessFailure();
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
if (watchConfig.subprocess.parallelProcessing && matchedLongRunningOutputCount === group.length) {
|
|
1239
|
+
matchedParallelLongReadyRunningOutput();
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}).then((exitState) => {
|
|
1243
|
+
if (exitState === ExitState.Errored) {
|
|
1244
|
+
onProcessFailure();
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
await Promise.race([
|
|
1248
|
+
longRunningParallelProcessReady,
|
|
1249
|
+
longRunningSequentialProcessReady,
|
|
1250
|
+
exit
|
|
1251
|
+
]);
|
|
1252
|
+
}
|
|
1253
|
+
const afterProcessPackageShellCommand = await watchConfig.hooks.onAfterProcessPackage(processPackageProps);
|
|
1254
|
+
if (afterProcessPackageShellCommand) {
|
|
1255
|
+
await runSubprocess({
|
|
1256
|
+
debugName: `after process ${packageName}`,
|
|
1257
|
+
shellCommand: afterProcessPackageShellCommand,
|
|
1258
|
+
cwd: processPackageCwd,
|
|
1259
|
+
signal: controller.signal,
|
|
1260
|
+
logger
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
}));
|
|
1264
|
+
}
|
|
1265
|
+
if (packageChanges.size) {
|
|
1266
|
+
logger.info(`Processing ${controller.signal.aborted ? "cancelled due to new changes" : "completed"}.`);
|
|
1267
|
+
}
|
|
1268
|
+
const packagesReadyProps = {
|
|
1269
|
+
totalChanges: packageChanges,
|
|
1270
|
+
totalProcessOrder: changedPackageProcessOrder,
|
|
1271
|
+
signal: controller.signal
|
|
1272
|
+
};
|
|
1273
|
+
const beforePackagesReadyShellCommand = await watchConfig.hooks.onBeforePackagesReady(packagesReadyProps);
|
|
1274
|
+
if (beforePackagesReadyShellCommand) {
|
|
1275
|
+
await runSubprocess({
|
|
1276
|
+
debugName: "before packages ready",
|
|
1277
|
+
shellCommand: beforePackagesReadyShellCommand,
|
|
1278
|
+
signal: controller.signal,
|
|
1279
|
+
logger
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
const packagesReadyShellCommand = await watchConfig.hooks.onPackagesReady(packagesReadyProps);
|
|
1283
|
+
if (packagesReadyShellCommand) {
|
|
1284
|
+
await runSubprocess({
|
|
1285
|
+
debugName: "packages ready",
|
|
1286
|
+
shellCommand: packagesReadyShellCommand,
|
|
1287
|
+
signal: controller.signal,
|
|
1288
|
+
logger
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
const afterPackagesReadyShellCommand = await watchConfig.hooks.onAfterPackagesReady(packagesReadyProps);
|
|
1292
|
+
if (afterPackagesReadyShellCommand) {
|
|
1293
|
+
await runSubprocess({
|
|
1294
|
+
debugName: "after packages ready",
|
|
1295
|
+
shellCommand: afterPackagesReadyShellCommand,
|
|
1296
|
+
logger
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
var watchPackageChanges = (packageData, packageGraphs, watchConfig, logger) => {
|
|
1301
|
+
const dedupedRootPackageData = dedupeSharedPaths(packageData.map((packageData2) => packageData2.path), DedupePathsBy.Parent).map((packagePath) => assertDefined9(packageData.find((data) => data.path === packagePath)));
|
|
1302
|
+
logger.debug(dim9(`Starting ${dedupedRootPackageData.length.toString()} watchers for ${packageData.length.toString()} packages.`));
|
|
1303
|
+
let closed = false;
|
|
1304
|
+
let debounceTimeout;
|
|
1305
|
+
let startedDebounceMs;
|
|
1306
|
+
let abortController;
|
|
1307
|
+
const changedPackagePaths = new Map;
|
|
1308
|
+
const useController = (reset) => {
|
|
1309
|
+
if (abortController && (reset || abortController.signal.aborted)) {
|
|
1310
|
+
if (reset) {
|
|
1311
|
+
logger.debug(dim9("Aborting controller: reset for new packages."));
|
|
1312
|
+
abortController.abort();
|
|
1313
|
+
}
|
|
1314
|
+
abortController = undefined;
|
|
1315
|
+
}
|
|
1316
|
+
abortController ??= new AbortController;
|
|
1317
|
+
return abortController;
|
|
1318
|
+
};
|
|
1319
|
+
const onWatchEvent = (watchPath, packageName, _event, filePath, forceEmpty = false) => {
|
|
1320
|
+
if (!isDefined4(startedDebounceMs)) {
|
|
1321
|
+
startedDebounceMs = Date.now();
|
|
1322
|
+
}
|
|
1323
|
+
if (debounceTimeout) {
|
|
1324
|
+
clearTimeout(debounceTimeout);
|
|
1325
|
+
}
|
|
1326
|
+
if (packageName && watchPath && filePath) {
|
|
1327
|
+
const changedPath = join4(watchPath, normaliseWatchedFilePath(filePath));
|
|
1328
|
+
const existingPaths = changedPackagePaths.get(packageName);
|
|
1329
|
+
if (existingPaths) {
|
|
1330
|
+
existingPaths.add(changedPath);
|
|
1331
|
+
} else {
|
|
1332
|
+
changedPackagePaths.set(packageName, new Set([changedPath]));
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
debounceTimeout = setTimeout(() => {
|
|
1336
|
+
if (closed) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
const packageChanges = new Map;
|
|
1340
|
+
for (const [packageName2, paths] of changedPackagePaths) {
|
|
1341
|
+
const processedPaths = filterFilesModifiedSince(dedupeSharedPaths(Array.from(paths), DedupePathsBy.Child).sort(), assertDefined9(startedDebounceMs) - fileModifiedThresholdMs);
|
|
1342
|
+
if (processedPaths.length) {
|
|
1343
|
+
packageChanges.set(packageName2, processedPaths);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
startedDebounceMs = undefined;
|
|
1347
|
+
changedPackagePaths.clear();
|
|
1348
|
+
if (!packageChanges.size && !forceEmpty) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
onProcessPackage(packageGraphs, packageChanges, watchConfig, (reset) => useController(reset), logger);
|
|
1352
|
+
}, watchConfig.debounceMs);
|
|
1353
|
+
};
|
|
1354
|
+
const watchers = dedupedRootPackageData.map(({
|
|
1355
|
+
name,
|
|
1356
|
+
path
|
|
1357
|
+
}) => {
|
|
1358
|
+
const watchPath = dirname6(path);
|
|
1359
|
+
return watch(watchPath, { recursive: true }, (event, filePath) => {
|
|
1360
|
+
onWatchEvent(watchPath, name, event, filePath);
|
|
1361
|
+
});
|
|
1362
|
+
});
|
|
1363
|
+
const closeWatchers = () => {
|
|
1364
|
+
watchers.forEach((watcher) => {
|
|
1365
|
+
watcher.close();
|
|
1366
|
+
});
|
|
1367
|
+
logger.debug(dim9("Aborting controller: closing watchers."));
|
|
1368
|
+
abortController?.abort();
|
|
1369
|
+
closed = true;
|
|
1370
|
+
};
|
|
1371
|
+
process.on("SIGINT", () => {
|
|
1372
|
+
logger.debug(dim9("Received SIGINT: closing watchers."));
|
|
1373
|
+
closeWatchers();
|
|
1374
|
+
process.exit(0);
|
|
1375
|
+
});
|
|
1376
|
+
onWatchEvent(undefined, undefined, undefined, null, true);
|
|
1377
|
+
return { close: () => {
|
|
1378
|
+
if (closed) {
|
|
1379
|
+
logger.debug(dim9("Watchers already closed."));
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
logger.debug(dim9("Closing watchers."));
|
|
1383
|
+
closeWatchers();
|
|
1384
|
+
} };
|
|
1385
|
+
};
|
|
1386
|
+
|
|
1387
|
+
// src/lib/api.ts
|
|
1388
|
+
var readPackagePalConfig = (options) => {
|
|
1389
|
+
checkBun();
|
|
1390
|
+
return loadConfig(options?.overrideConfigPath);
|
|
1391
|
+
};
|
|
1392
|
+
var readPackageData = async (options) => {
|
|
1393
|
+
checkBun();
|
|
1394
|
+
const packagePatterns = Array.isArray(options.config.packages) ? options.config.packages : [options.config.packages];
|
|
1395
|
+
return loadPackages(packagePatterns, options.config.logger);
|
|
1396
|
+
};
|
|
1397
|
+
var getPackageGraphs = (options) => {
|
|
1398
|
+
checkBun();
|
|
1399
|
+
return generateGraphs(options.packageData, options.config.logger);
|
|
1400
|
+
};
|
|
1401
|
+
var getPackageOrder = (options) => {
|
|
1402
|
+
checkBun();
|
|
1403
|
+
return generateTopologicalSortedGroups(options.packageGraphs.dependencies, options.config.logger);
|
|
1404
|
+
};
|
|
1405
|
+
var getPackageCircularDependencyPaths = (options) => {
|
|
1406
|
+
checkBun();
|
|
1407
|
+
return generatePackageCircularDependencyPaths(options.packageGraphs, options.packageOrder, options.config.logger);
|
|
1408
|
+
};
|
|
1409
|
+
var bumpPackageVersion = (options) => {
|
|
1410
|
+
checkBun();
|
|
1411
|
+
const exact = isDefined5(options.exact) ? options.exact : options.config.version.exact;
|
|
1412
|
+
const preId = isDefined5(options.preId) ? options.preId : options.config.version.preId;
|
|
1413
|
+
return updatePackageVersion(options.packageName, options.type, options.packageGraphs, preId, exact, options.config.logger);
|
|
1414
|
+
};
|
|
1415
|
+
var watchPackages = (options) => {
|
|
1416
|
+
checkBun();
|
|
1417
|
+
watchPackageChanges(options.packageData, options.packageGraphs, options.config.watch, options.config.logger);
|
|
1418
|
+
};
|
|
1419
|
+
export {
|
|
1420
|
+
watchPackages,
|
|
1421
|
+
readPackagePalConfig,
|
|
1422
|
+
readPackageData,
|
|
1423
|
+
getPackageOrder,
|
|
1424
|
+
getPackageGraphs,
|
|
1425
|
+
getPackageCircularDependencyPaths,
|
|
1426
|
+
bumpPackageVersion,
|
|
1427
|
+
BumpVersionType
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
//# debugId=E0ED0EB8F615FC9B64756E2164756E21
|
|
1431
|
+
//# sourceMappingURL=index.js.map
|