@vnejs/monorepo 0.0.5 → 0.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vnejs/monorepo",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Monorepo tooling for @vnejs",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -16,6 +16,8 @@
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
18
  "commander": "~15.0.0",
19
- "typescript": "6.0.3"
19
+ "happy-dom": "~20.0.0",
20
+ "typescript": "6.0.3",
21
+ "vitest": "~3.2.4"
20
22
  }
21
23
  }
package/src/bump/index.js CHANGED
@@ -3,6 +3,8 @@ const listWorkspacePackages = require("../workspace/list-packages");
3
3
  const syncDeps = require("../sync-deps");
4
4
  const runChanged = require("../run-changed");
5
5
  const { run } = require("../publish/utils");
6
+ const confirm = require("../utils/confirm");
7
+ const { formatPackageLine } = require("../utils/format-package");
6
8
 
7
9
  const PHASES = ["graph", "sync-all", "patch"];
8
10
 
@@ -27,9 +29,45 @@ const previousMinorLine = (version) => {
27
29
  process.exit(1);
28
30
  };
29
31
 
30
- module.exports = (version, options = {}) => {
32
+ const describeBumpPlan = (version, options, phases) => {
33
+ const expectVersion = options.expectVersion ?? version;
34
+ const onlyVersion = options.onlyVersion ?? previousMinorLine(version);
35
+ const lines = [`\nBump target: ${expectVersion}.x`];
36
+
37
+ if (phases.includes("graph")) {
38
+ const { order } = resolveGraph({
39
+ cwd: options.cwd,
40
+ onlyVersion,
41
+ script: "publish:minor",
42
+ });
43
+
44
+ if (!order.length) {
45
+ console.error("No packages matched graph filters for phase 1.");
46
+ process.exit(1);
47
+ }
48
+
49
+ lines.push(`Phase 1: sync-deps + publish:minor (${order.length} packages, filter ${onlyVersion}.x)`);
50
+ }
51
+
52
+ if (phases.includes("sync-all")) {
53
+ const { packages } = listWorkspacePackages({ cwd: options.cwd });
54
+ lines.push(`Phase 2: sync-deps --all (${packages.length} packages)`);
55
+ }
56
+
57
+ if (phases.includes("patch")) {
58
+ lines.push(`Phase 3: publish:patch changed packages (ref ${options.ref ?? "HEAD"})`);
59
+ }
60
+
61
+ if (options.dryRun) {
62
+ lines.push("\nMode: dry run");
63
+ }
64
+
65
+ return lines.join("\n");
66
+ };
67
+
68
+ module.exports = async (version, options = {}) => {
31
69
  const dryRun = Boolean(options.dryRun);
32
- const phases = options.phase ? [options.phase] : ["graph", "sync-all", "patch"];
70
+ const phases = options.phase ? [options.phase] : PHASES;
33
71
 
34
72
  if (options.phase && !PHASES.includes(options.phase)) {
35
73
  console.error(`phase must be one of: ${PHASES.join(", ")}`);
@@ -41,6 +79,17 @@ module.exports = (version, options = {}) => {
41
79
  const expectVersion = options.expectVersion ?? version;
42
80
  const onlyVersion = options.onlyVersion ?? previousMinorLine(version);
43
81
 
82
+ console.log(describeBumpPlan(version, { ...options, expectVersion, onlyVersion }, phases));
83
+
84
+ if (!dryRun) {
85
+ const confirmed = await confirm("Continue? [y/N] ");
86
+
87
+ if (!confirmed) {
88
+ console.log("Aborted.");
89
+ return;
90
+ }
91
+ }
92
+
44
93
  const graphOptions = {
45
94
  cwd: options.cwd,
46
95
  onlyVersion,
@@ -66,7 +115,7 @@ module.exports = (version, options = {}) => {
66
115
  }
67
116
 
68
117
  order.forEach((pkg, index) => {
69
- console.log(`\n==> [${index + 1}/${order.length}] ${pkg.name} (${pkg.dir})`);
118
+ console.log(formatPackageLine(pkg, { leadingNewline: true, tag: `[${index + 1}/${order.length}]` }));
70
119
 
71
120
  if (dryRun) {
72
121
  console.log(` sync-deps --expect-version ${syncOptions.expectVersion}`);
@@ -96,7 +145,8 @@ module.exports = (version, options = {}) => {
96
145
  if (phases.includes("patch")) {
97
146
  console.log(`\n=== Phase 3: publish:changed:patch ===`);
98
147
 
99
- runChanged("publish:patch", {
148
+ await runChanged({
149
+ script: "publish:patch",
100
150
  ref: options.ref ?? "HEAD",
101
151
  dryRun,
102
152
  });
@@ -3,6 +3,7 @@ const { existsSync } = require("fs");
3
3
  const path = require("path");
4
4
  const readPackageJson = require("./workspace/read-package-json");
5
5
  const findMonorepoRoot = require("./workspace/find-root");
6
+ const isStubTestScript = require("./workspace/is-stub-test-script");
6
7
 
7
8
  const getChangedFiles = (root, ref = "HEAD") => {
8
9
  const files = new Set();
@@ -30,7 +31,7 @@ const findPackageForFile = (root, filePath) => {
30
31
  const pkg = readPackageJson(dir);
31
32
  if (dir === root) return null;
32
33
 
33
- return { name: pkg.name, dir: path.relative(root, dir) || "." };
34
+ return { name: pkg.name, version: pkg.version ?? "0.0.0", dir: path.relative(root, dir) || "." };
34
35
  }
35
36
 
36
37
  if (dir === root) break;
@@ -54,7 +55,12 @@ const getChangedPackages = (options = {}) => {
54
55
  if (options.script) {
55
56
  result = result.filter((pkg) => {
56
57
  const pkgJson = readPackageJson(path.join(root, pkg.dir));
57
- return Boolean(pkgJson.scripts?.[options.script]);
58
+ const script = pkgJson.scripts?.[options.script];
59
+
60
+ if (!script) return false;
61
+ if (options.script === "test" && isStubTestScript(script)) return false;
62
+
63
+ return true;
58
64
  });
59
65
  }
60
66
 
package/src/cli.js CHANGED
@@ -4,12 +4,11 @@ const { Command } = require("commander");
4
4
 
5
5
  const packageJson = require("../package.json");
6
6
  const publishAction = require("./publish");
7
- const { getChangedPackages } = require("./changed-packages");
8
7
  const runChangedAction = require("./run-changed");
9
8
  const graphAction = require("./graph");
10
9
  const syncDepsAction = require("./sync-deps");
11
10
  const bumpAction = require("./bump");
12
- const buildAction = require("./build");
11
+ const runAction = require("./run");
13
12
  const clearAction = require("./clear");
14
13
 
15
14
  const program = new Command();
@@ -39,7 +38,7 @@ program
39
38
  .option("--only-version <pattern>", "filter by version prefix, e.g. 0.0.x")
40
39
  .option("--name <pattern>", "filter by package name substring")
41
40
  .option("--script <script>", "only packages that define this npm script")
42
- .option("--layers", "group packages into parallel publish layers", false)
41
+ .option("--flat", "show packages as a flat list with layer column", false)
43
42
  .option("--format <format>", "output format: text | json", "text")
44
43
  .action(graphAction);
45
44
 
@@ -67,7 +66,7 @@ program
67
66
  .option("--dry-run", "show planned steps without making changes", false)
68
67
  .option("--only-version <pattern>", "graph version filter for phase 1 (default: previous minor line)")
69
68
  .option("--phase <phase>", "run only one phase: graph | sync-all | patch")
70
- .option("--ref <ref>", "git ref for phase 3 changed-packages", "HEAD")
69
+ .option("--ref <ref>", "git ref for phase 3 run-changed", "HEAD")
71
70
  .option("--workspace", "use workspace versions in sync-deps (phase 2)", false)
72
71
  .option("--expect-version <version>", "wait until npm has this major.minor line (default: <version>)")
73
72
  .option("--expect-wait <ms>", "delay between npm retries", "10000")
@@ -81,37 +80,28 @@ program
81
80
  );
82
81
 
83
82
  program
84
- .command("build")
85
- .description("Build workspace packages in dependency order (turbo per layer)")
83
+ .command("test")
84
+ .description("run vitest in current directory")
85
+ .action((options) => require("./test")(options));
86
+
87
+ program
88
+ .command("run")
89
+ .description("Run an npm script in workspace packages in dependency order (turbo per layer)")
86
90
  .option("--script <script>", "npm script to run in each package", "build")
87
91
  .option("--only-version <pattern>", "filter by version prefix, e.g. 0.0.x")
88
92
  .option("--name <pattern>", "filter by package name substring (includes dependency closure)")
89
- .option("--sequential", "build one package at a time in flat graph order", false)
93
+ .option("-s, --sequential", "run one package at a time in flat graph order (stdio inherit, no turbo parallelism)", false)
90
94
  .option("--force", "pass --force to turbo (bypass cache)", false)
91
- .option("--dry-run", "show build plan without running", false)
92
- .action((options) => buildAction(options));
93
-
94
- program
95
- .command("changed-packages")
96
- .description("List workspace packages changed in git")
97
- .option("--ref <ref>", "git ref to compare against", "HEAD")
98
- .option("--script <script>", "only packages that define this npm script")
99
- .action((options) => {
100
- const { packages } = getChangedPackages({ ref: options.ref, script: options.script });
101
-
102
- packages.forEach((pkg, index) => {
103
- console.log(`==> [${index + 1}/${packages.length}] ${pkg.name} (${pkg.dir})`);
104
- });
105
- console.log("");
106
- console.log(`Total: ${packages.length}`);
107
- });
95
+ .option("--dry-run", "show run plan without executing", false)
96
+ .action((options) => runAction(options));
108
97
 
109
98
  program
110
99
  .command("run-changed")
111
100
  .description("Run npm script sequentially in git-changed workspace packages")
112
- .argument("<script>", "npm script name from package.json")
101
+ .option("--script <script>", "npm script name from package.json")
113
102
  .option("--ref <ref>", "git ref to compare against", "HEAD")
114
- .option("--dry-run", "list packages without running the script", false)
103
+ .option("--dry-run", "list changed packages without running the script", false)
104
+ .option("--confirm", "ask for confirmation before running the script", false)
115
105
  .action(runChangedAction);
116
106
 
117
107
  program
@@ -1,5 +1,30 @@
1
1
  const path = require("path");
2
2
  const resolveGraph = require("../workspace/resolve-graph");
3
+ const { formatPackageLine, formatPackageRef } = require("../utils/format-package");
4
+
5
+ const buildLayerMeta = (layers) => {
6
+ const byName = new Map();
7
+
8
+ layers.forEach((layer, layerIndex) => {
9
+ layer.forEach((pkg, packageIndex) => {
10
+ byName.set(pkg.name, {
11
+ layer: layerIndex + 1,
12
+ layerTotal: layers.length,
13
+ layerIndex: packageIndex + 1,
14
+ layerSize: layer.length,
15
+ });
16
+ });
17
+ });
18
+
19
+ return byName;
20
+ };
21
+
22
+ const toPackageEntry = (pkg, meta) => ({
23
+ name: pkg.name,
24
+ version: pkg.version,
25
+ dir: pkg.dir,
26
+ ...meta,
27
+ });
3
28
 
4
29
  module.exports = (options = {}) => {
5
30
  const { root, order, layers } = resolveGraph(options);
@@ -9,16 +34,26 @@ module.exports = (options = {}) => {
9
34
  return { root, packages: [], layers: [], order: [] };
10
35
  }
11
36
 
37
+ const layerMetaByName = buildLayerMeta(layers);
38
+
12
39
  if (options.format === "json") {
13
40
  console.log(
14
41
  JSON.stringify(
15
42
  {
16
43
  root,
17
44
  total: order.length,
18
- layers: layers.map((layer) =>
19
- layer.map((pkg) => ({ name: pkg.name, version: pkg.version, dir: pkg.dir })),
45
+ layerTotal: layers.length,
46
+ layers: layers.map((layer, layerIndex) =>
47
+ layer.map((pkg, packageIndex) =>
48
+ toPackageEntry(pkg, {
49
+ layer: layerIndex + 1,
50
+ layerTotal: layers.length,
51
+ layerIndex: packageIndex + 1,
52
+ layerSize: layer.length,
53
+ }),
54
+ ),
20
55
  ),
21
- order: order.map((pkg) => ({ name: pkg.name, version: pkg.version, dir: pkg.dir })),
56
+ order: order.map((pkg) => toPackageEntry(pkg, layerMetaByName.get(pkg.name))),
22
57
  },
23
58
  null,
24
59
  2,
@@ -28,26 +63,31 @@ module.exports = (options = {}) => {
28
63
  return { root, packages: order, layers, order: order.map((pkg) => pkg.name) };
29
64
  }
30
65
 
31
- if (options.layers) {
32
- layers.forEach((layer, index) => {
33
- console.log(`# layer ${index + 1} (${layer.length})`);
66
+ console.log(`\n=== Graph: ${order.length} packages, ${layers.length} layers ===`);
67
+ console.log(`Root: ${path.relative(process.cwd(), root) || "."}\n`);
34
68
 
35
- layer.forEach((pkg) => {
36
- console.log(`${pkg.name}\t${pkg.version}\t${pkg.dir}`);
37
- });
38
-
39
- if (index < layers.length - 1) console.log("");
40
- });
41
- } else {
69
+ if (options.flat) {
42
70
  order.forEach((pkg, index) => {
43
- console.log(`${index + 1}\t${pkg.name}\t${pkg.version}\t${pkg.dir}`);
71
+ const meta = layerMetaByName.get(pkg.name);
72
+ console.log(
73
+ `${index + 1}\t${meta.layer}/${meta.layerTotal}\t${formatPackageRef(pkg)}\t${pkg.dir}`,
74
+ );
44
75
  });
45
- }
76
+ } else {
77
+ for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
78
+ const layer = layers[layerIndex];
79
+ console.log(`\n=== Layer ${layerIndex + 1}/${layers.length} (${layer.length} packages) ===`);
46
80
 
47
- console.log("");
48
- console.log(`Root: ${path.relative(process.cwd(), root) || "."}`);
49
- console.log(`Packages: ${order.length}`);
50
- console.log(`Layers: ${layers.length}`);
81
+ layer.forEach((pkg, packageIndex) => {
82
+ console.log(
83
+ formatPackageLine(pkg, {
84
+ indent: " ",
85
+ tag: `[${layerIndex + 1}/${layers.length}:${packageIndex + 1}/${layer.length}]`,
86
+ }),
87
+ );
88
+ });
89
+ }
90
+ }
51
91
 
52
92
  return {
53
93
  root,
package/src/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  module.exports = {
2
2
  package: require("./package"),
3
+ test: require("./test"),
3
4
  publish: require("./publish"),
4
5
  getChangedPackages: require("./changed-packages").getChangedPackages,
5
6
  runChanged: require("./run-changed"),
6
7
  graph: require("./graph"),
7
8
  syncDeps: require("./sync-deps"),
8
9
  bump: require("./bump"),
9
- build: require("./build"),
10
+ run: require("./run"),
10
11
  clear: require("./clear"),
11
12
  resolveGraph: require("./workspace/resolve-graph"),
12
13
  listWorkspacePackages: require("./workspace/list-packages"),
@@ -1,6 +1,7 @@
1
1
  const resolveGraph = require("../workspace/resolve-graph");
2
2
  const findRoot = require("../workspace/find-root");
3
3
  const { run } = require("../publish/utils");
4
+ const { formatPackageLine } = require("../utils/format-package");
4
5
 
5
6
  const runLayerTurbo = (layer, root, { script, force }) => {
6
7
  const filters = layer.map((pkg) => `--filter=${pkg.name}`).join(" ");
@@ -28,13 +29,13 @@ module.exports = (options = {}) => {
28
29
  process.exit(1);
29
30
  }
30
31
 
31
- console.log(`\n=== Build: ${order.length} packages, ${layers.length} layers ===`);
32
+ console.log(`\n=== Run: ${order.length} packages, ${layers.length} layers ===`);
32
33
  console.log(`Script: ${script}`);
33
34
  console.log(`Root: ${root}`);
34
35
  console.log(`Mode: ${sequential ? "sequential" : "layers (turbo)"}\n`);
35
36
 
36
37
  const runPackage = (pkg, label) => {
37
- console.log(`\n==> ${label} ${pkg.name} (${pkg.dir})`);
38
+ console.log(formatPackageLine(pkg, { leadingNewline: true, tag: label }));
38
39
 
39
40
  if (dryRun) return;
40
41
 
@@ -51,7 +52,12 @@ module.exports = (options = {}) => {
51
52
  if (dryRun) {
52
53
  console.log(` turbo run ${script} ${layer.map((pkg) => `--filter=${pkg.name}`).join(" ")}`);
53
54
  layer.forEach((pkg, index) => {
54
- console.log(` ==> [${layerIndex + 1}/${layers.length}:${index + 1}/${layer.length}] ${pkg.name} (${pkg.dir})`);
55
+ console.log(
56
+ formatPackageLine(pkg, {
57
+ indent: " ",
58
+ tag: `[${layerIndex + 1}/${layers.length}:${index + 1}/${layer.length}]`,
59
+ }),
60
+ );
55
61
  });
56
62
  continue;
57
63
  }
@@ -1,24 +1,70 @@
1
1
  const path = require("path");
2
2
 
3
3
  const { getChangedPackages } = require("../changed-packages");
4
+ const resolveGraph = require("../workspace/resolve-graph");
4
5
  const { run } = require("../publish/utils");
6
+ const confirm = require("../utils/confirm");
7
+ const { formatPackageLine } = require("../utils/format-package");
5
8
 
6
- module.exports = (script, options = {}) => {
7
- const { root, packages } = getChangedPackages({ ref: options.ref, script });
9
+ const sortByGraphOrder = (root, changedPackages, script) => {
10
+ const changedNames = new Set(changedPackages.map((pkg) => pkg.name));
11
+ const { order } = resolveGraph({ cwd: root, script });
8
12
 
9
- if (!packages.length) {
10
- console.log(`No changed packages with script "${script}".`);
13
+ const sorted = order.filter((pkg) => changedNames.has(pkg.name));
14
+
15
+ const sortedNames = new Set(sorted.map((pkg) => pkg.name));
16
+ const rest = changedPackages.filter((pkg) => !sortedNames.has(pkg.name));
17
+
18
+ return [...sorted, ...rest];
19
+ };
20
+
21
+ const printPackages = (packages) => {
22
+ packages.forEach((pkg, index) => {
23
+ console.log(formatPackageLine(pkg, { tag: `[${index + 1}/${packages.length}]` }));
24
+ });
25
+ console.log("");
26
+ console.log(`Total: ${packages.length}`);
27
+ };
28
+
29
+ module.exports = async (options = {}) => {
30
+ const script = options.script;
31
+
32
+ if (!options.dryRun && !script) {
33
+ console.error('Missing required option "--script".');
34
+ process.exit(1);
35
+ }
36
+
37
+ const { root, packages: changedPackages } = getChangedPackages({ ref: options.ref, script });
38
+
39
+ if (!changedPackages.length) {
40
+ console.log(script ? `No changed packages with script "${script}".` : "No changed packages.");
11
41
  return;
12
42
  }
13
43
 
14
- for (const [index, pkg] of packages.entries()) {
15
- const pkgDir = path.join(root, pkg.dir);
16
- console.log(`\n==> [${index + 1}/${packages.length}] ${pkg.name} (${pkg.dir})`);
44
+ const packages = sortByGraphOrder(root, changedPackages, script);
45
+
46
+ if (options.dryRun) {
47
+ printPackages(packages);
48
+ return;
49
+ }
17
50
 
18
- if (options.dryRun) continue;
51
+ if (options.confirm) {
52
+ console.log(`\nThe following packages will run "${script}":\n`);
53
+ printPackages(packages);
19
54
 
20
- run(`npm run ${script}`, pkgDir);
55
+ const confirmed = await confirm(`Continue? [y/N] `);
56
+
57
+ if (!confirmed) {
58
+ console.log("Aborted.");
59
+ return;
60
+ }
61
+
62
+ console.log("");
21
63
  }
22
64
 
23
- if (options.dryRun) console.log(`\nTotal: ${packages.length}`);
65
+ for (const [index, pkg] of packages.entries()) {
66
+ const pkgDir = path.join(root, pkg.dir);
67
+ console.log(formatPackageLine(pkg, { leadingNewline: true, tag: `[${index + 1}/${packages.length}]` }));
68
+ run(`npm run ${script}`, pkgDir);
69
+ }
24
70
  };
@@ -5,6 +5,7 @@ const listWorkspacePackages = require("../workspace/list-packages");
5
5
  const fetchNpmVersion = require("../workspace/fetch-npm-version");
6
6
  const toTildeMinor = require("../workspace/to-tilde-minor");
7
7
  const { DEPENDENCY_FIELDS } = require("../workspace/build-graph");
8
+ const { formatPackageLine } = require("../utils/format-package");
8
9
 
9
10
  const resolveVersion = (name, options) => {
10
11
  if (options.workspace) {
@@ -102,7 +103,7 @@ module.exports = (options = {}) => {
102
103
  console.log(`Syncing dependencies in ${packages.length} workspace packages...`);
103
104
 
104
105
  for (const pkg of packages) {
105
- console.log(`\n==> ${pkg.name} (${pkg.dir})`);
106
+ console.log(formatPackageLine(pkg, { leadingNewline: true }));
106
107
 
107
108
  if (options.dryRun) {
108
109
  console.log(" sync-deps");
@@ -0,0 +1,16 @@
1
+ const { execSync } = require("child_process");
2
+ const { existsSync } = require("fs");
3
+ const path = require("path");
4
+
5
+ module.exports = (options = {}) => {
6
+ const pkgDir = options.cwd || process.cwd();
7
+ const configPath = path.join(pkgDir, "vitest.config.js");
8
+
9
+ if (!existsSync(configPath)) {
10
+ console.error(`vitest.config.js not found: ${configPath}`);
11
+ process.exit(1);
12
+ }
13
+
14
+ const vitest = require.resolve("vitest/vitest.mjs");
15
+ execSync(`node "${vitest}" run`, { cwd: pkgDir, stdio: "inherit" });
16
+ };
@@ -0,0 +1,14 @@
1
+ const readline = require("readline/promises");
2
+
3
+ const confirm = async (message) => {
4
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
5
+
6
+ try {
7
+ const answer = await rl.question(message);
8
+ return /^y(es)?$/i.test(answer.trim());
9
+ } finally {
10
+ rl.close();
11
+ }
12
+ };
13
+
14
+ module.exports = confirm;
@@ -0,0 +1,13 @@
1
+ const formatPackageRef = (pkg) => `${pkg.name}@${pkg.version ?? "0.0.0"}`;
2
+
3
+ const formatPackageLine = (pkg, options = {}) => {
4
+ const { prefix = "==>", tag, indent = "", leadingNewline = false } = options;
5
+ const tagPart = tag ? `${tag} ` : "";
6
+
7
+ return `${leadingNewline ? "\n" : ""}${indent}${prefix} ${tagPart}${formatPackageRef(pkg)} (${pkg.dir})`;
8
+ };
9
+
10
+ module.exports = {
11
+ formatPackageRef,
12
+ formatPackageLine,
13
+ };
@@ -1,5 +1,6 @@
1
1
  const readPackageJson = require("./read-package-json");
2
2
  const matchVersion = require("./match-version");
3
+ const isStubTestScript = require("./is-stub-test-script");
3
4
 
4
5
  const DEFAULT_EXCLUDED_DIRS = ["cli"];
5
6
 
@@ -24,7 +25,12 @@ module.exports = (packages, options = {}) => {
24
25
  if (options.script) {
25
26
  result = result.filter((pkg) => {
26
27
  const pkgJson = readPackageJson(pkg.absDir);
27
- return Boolean(pkgJson.scripts?.[options.script]);
28
+ const script = pkgJson.scripts?.[options.script];
29
+
30
+ if (!script) return false;
31
+ if (options.script === "test" && isStubTestScript(script)) return false;
32
+
33
+ return true;
28
34
  });
29
35
  }
30
36
 
@@ -0,0 +1,5 @@
1
+ const STUB_TEST_SCRIPT = 'echo "Error: no test specified" && exit 1';
2
+
3
+ module.exports = (script) => script === STUB_TEST_SCRIPT;
4
+
5
+ module.exports.STUB_TEST_SCRIPT = STUB_TEST_SCRIPT;