@cplieger/deadset-ts 8.0.0-dev.11 → 8.0.0-dev.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/src/build-scripts.js +6 -13
- package/dist/src/commands/read.js +156 -0
- package/dist/src/commands/shell.js +75 -0
- package/dist/src/commands/tools.js +460 -0
- package/dist/src/configuration-files.js +11 -25
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/dependencies.js +67 -115
- package/dist/src/load/synthesize.js +12 -5
- package/dist/src/manifest.js +27 -14
- package/dist/src/roots.js +18 -11
- package/dist/src/text/named-files.js +24 -3
- package/dist/src/text/yaml.js +464 -173
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/workflow-steps.js +111 -133
- package/jsr.json +2 -1
- package/package.json +9 -7
- package/src/build-scripts.ts +6 -13
- package/src/commands/read.ts +230 -0
- package/src/commands/shell.ts +126 -0
- package/src/commands/tools.ts +618 -0
- package/src/configuration-files.ts +10 -26
- package/src/conformance-record.ts +1 -1
- package/src/dependencies.ts +99 -123
- package/src/load/synthesize.ts +18 -5
- package/src/manifest.ts +43 -25
- package/src/roots.ts +20 -13
- package/src/text/named-files.ts +26 -3
- package/src/text/yaml.ts +503 -179
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/workflow-steps.ts +153 -154
- package/dist/src/text/shell.js +0 -159
- package/src/text/named-files.inputs.json +0 -1522
- package/src/text/shell.ts +0 -161
package/dist/src/dependencies.js
CHANGED
|
@@ -13,16 +13,17 @@ import { nodeKey, packageScope } from "./inventory.js";
|
|
|
13
13
|
import { ancestors, dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath, } from "./paths.js";
|
|
14
14
|
import { UNANSWERED } from "./query.js";
|
|
15
15
|
import { sourceFilesOf } from "./source-files.js";
|
|
16
|
-
import { manifestCommands } from "./manifest.js";
|
|
17
|
-
import {
|
|
16
|
+
import { manifestCommands, nodemonTexts } from "./manifest.js";
|
|
17
|
+
import { commandFileTexts, workflowCommands } from "./workflow-steps.js";
|
|
18
|
+
import { pathsNamed, preloadedPackages, readCommands, } from "./commands/read.js";
|
|
19
|
+
import { heldNames } from "./text/named-files.js";
|
|
18
20
|
import { bytewise } from "./text/compare.js";
|
|
19
21
|
import { isRecord } from "./json-document.js";
|
|
20
22
|
import { inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, readDocument } from "./fs/manifest.js";
|
|
21
|
-
import { commandsOf, scriptTokens } from "./text/shell.js";
|
|
22
23
|
const MODULES_SEGMENT = `/${INSTALLED_PACKAGES}/`;
|
|
23
24
|
const TYPES_SCOPE = "@types/";
|
|
24
|
-
/** A
|
|
25
|
-
const SCRIPT_FILE =
|
|
25
|
+
/** A path a command names that is a JavaScript file's. */
|
|
26
|
+
const SCRIPT_FILE = /\.(?:js|mjs|cjs)$/u;
|
|
26
27
|
/** The manifest sections a dependency is declared in, each by the selector its reference spells. */
|
|
27
28
|
const SECTIONS = [
|
|
28
29
|
["dependencies", "dependency"],
|
|
@@ -281,10 +282,10 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
|
|
|
281
282
|
return { uses, at, unanswered };
|
|
282
283
|
}
|
|
283
284
|
/**
|
|
284
|
-
* The JavaScript files no program holds that a
|
|
285
|
-
* project's files runs, each with the directory of that manifest, and those a
|
|
286
|
-
* step or git hook
|
|
287
|
-
* target root and in no `node_modules
|
|
285
|
+
* The JavaScript files no program holds that a command string of a manifest at or above one of
|
|
286
|
+
* the project's files runs or names, each with the directory of that manifest, and those a
|
|
287
|
+
* workflow step or git hook names, with the target root's: a path `pathsNamed` reads, below the
|
|
288
|
+
* target root and in no `node_modules`.
|
|
288
289
|
*/
|
|
289
290
|
function scriptRunFiles(host, targetRoot, files) {
|
|
290
291
|
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
@@ -297,23 +298,28 @@ function scriptRunFiles(host, targetRoot, files) {
|
|
|
297
298
|
dirs.add(dir);
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
|
-
const
|
|
301
|
-
[
|
|
301
|
+
const named = new Map([
|
|
302
|
+
[
|
|
303
|
+
root,
|
|
304
|
+
workflowReadings(host, root)
|
|
305
|
+
.flatMap(pathsNamed)
|
|
306
|
+
.map((one) => one.path),
|
|
307
|
+
],
|
|
302
308
|
]);
|
|
303
309
|
for (const dir of dirs) {
|
|
304
310
|
const read = readDocument(host, joinPath(dir, MANIFEST));
|
|
305
311
|
if (read !== undefined && isRecord(read.value)) {
|
|
306
|
-
const own =
|
|
307
|
-
|
|
312
|
+
const own = manifestReadings(host, dir, read.value)
|
|
313
|
+
.flatMap(pathsNamed)
|
|
314
|
+
.map((one) => one.path);
|
|
315
|
+
named.set(dir, [...own, ...(named.get(dir) ?? [])]);
|
|
308
316
|
}
|
|
309
317
|
}
|
|
310
318
|
const found = [];
|
|
311
|
-
for (const [manifestDir,
|
|
312
|
-
for (const
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
if (path !== undefined &&
|
|
316
|
-
below !== undefined &&
|
|
319
|
+
for (const [manifestDir, paths] of named) {
|
|
320
|
+
for (const path of new Set(paths)) {
|
|
321
|
+
const below = SCRIPT_FILE.test(path) ? relativePath(root, path) : undefined;
|
|
322
|
+
if (below !== undefined &&
|
|
317
323
|
!inInstalledPackages(below) &&
|
|
318
324
|
!files.byName.has(path) &&
|
|
319
325
|
host.kindOf(path) === "file") {
|
|
@@ -323,6 +329,40 @@ function scriptRunFiles(host, targetRoot, files) {
|
|
|
323
329
|
}
|
|
324
330
|
return found;
|
|
325
331
|
}
|
|
332
|
+
/** What the command strings of one manifest, its scripts and nodemon's command, run. */
|
|
333
|
+
function manifestReadings(host, dir, manifest) {
|
|
334
|
+
return manifestCommands(host, dir, manifest).map(({ command }) => readCommands(command, dir));
|
|
335
|
+
}
|
|
336
|
+
/** What one manifest's command strings use, held with the whole text of nodemon's configuration. */
|
|
337
|
+
function manifestUses(host, dir, manifest) {
|
|
338
|
+
const uses = usesOf(manifestReadings(host, dir, manifest));
|
|
339
|
+
const texts = nodemonTexts(host, dir, manifest).map(({ text }) => text);
|
|
340
|
+
return { ...uses, held: [uses.held, ...texts].join("\n") };
|
|
341
|
+
}
|
|
342
|
+
/** What the target root's workflow steps, git hooks and recipes use, held with their files' whole text. */
|
|
343
|
+
function workflowUses(host, targetRoot) {
|
|
344
|
+
const uses = usesOf(workflowReadings(host, targetRoot));
|
|
345
|
+
return { ...uses, held: [uses.held, ...commandFileTexts(host, targetRoot)].join("\n") };
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* What the target root's workflow steps, git hooks, hook managers and recipes run, each held
|
|
349
|
+
* with the directory the file writes for it.
|
|
350
|
+
*/
|
|
351
|
+
function workflowReadings(host, targetRoot) {
|
|
352
|
+
return workflowCommands(host, targetRoot).map(({ text, dir, writtenDirectory }) => {
|
|
353
|
+
const reading = readCommands(text, dir);
|
|
354
|
+
return { ...reading, held: [reading.held, writtenDirectory ?? ""].join("\n") };
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
function usesOf(readings) {
|
|
358
|
+
return {
|
|
359
|
+
words: new Set(readings.flatMap((one) => one.commands.flatMap((command) => command.words.flatMap((word) => word ?? [])))),
|
|
360
|
+
preloads: new Set(readings
|
|
361
|
+
.flatMap((one) => one.runs.flatMap(preloadedPackages))
|
|
362
|
+
.flatMap((specifier) => packageOfSpecifier(specifier) ?? [])),
|
|
363
|
+
held: readings.map((one) => one.held).join("\n"),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
326
366
|
/** The declarations of the inventory a use written at one node belongs to. */
|
|
327
367
|
function ownersOf(file, held, node) {
|
|
328
368
|
const parent = node.parent;
|
|
@@ -633,95 +673,6 @@ function declaredIn(text, manifest, path, scope) {
|
|
|
633
673
|
export function declarationKey(dependency) {
|
|
634
674
|
return `${dependency.position.path}\u0000${dependency.name}`;
|
|
635
675
|
}
|
|
636
|
-
/** Every token of every value of one manifest's `scripts` member. */
|
|
637
|
-
function scriptTokensOf(manifest) {
|
|
638
|
-
const scripts = manifest["scripts"];
|
|
639
|
-
const found = new Set();
|
|
640
|
-
if (isRecord(scripts)) {
|
|
641
|
-
for (const command of Object.values(scripts)) {
|
|
642
|
-
if (typeof command === "string") {
|
|
643
|
-
scriptTokens(command).forEach((token) => found.add(token));
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
return found;
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* The runtime flags whose value is a module loaded before the entry, as `--flag value` or
|
|
651
|
-
* `--flag=value`: https://nodejs.org/api/cli.html#--importmodule,
|
|
652
|
-
* https://nodejs.org/api/cli.html#--experimental-loadermodule,
|
|
653
|
-
* https://nodejs.org/api/cli.html#-r---require-module
|
|
654
|
-
*/
|
|
655
|
-
const PRELOAD_FLAGS = new Set([
|
|
656
|
-
"--experimental-loader",
|
|
657
|
-
"--import",
|
|
658
|
-
"--loader",
|
|
659
|
-
"--require",
|
|
660
|
-
"-r",
|
|
661
|
-
]);
|
|
662
|
-
/**
|
|
663
|
-
* The programs that pass a preload flag to the runtime they start: Node itself, and the
|
|
664
|
-
* runners that forward Node's flags or read the same `--require`:
|
|
665
|
-
* https://mochajs.org/#-require-module-r-module, https://tsx.is/node-enhancement,
|
|
666
|
-
* https://typestrong.org/ts-node/docs/options#require,
|
|
667
|
-
* https://github.com/remy/nodemon#running-non-node-scripts
|
|
668
|
-
*/
|
|
669
|
-
const PRELOADING_PROGRAMS = new Set([
|
|
670
|
-
"mocha",
|
|
671
|
-
"node",
|
|
672
|
-
"nodemon",
|
|
673
|
-
"ts-node",
|
|
674
|
-
"tsx",
|
|
675
|
-
]);
|
|
676
|
-
/** The programs that run the command after them, and an environment assignment before it. */
|
|
677
|
-
const LAUNCHERS = new Set(["cross-env", "env", "npx"]);
|
|
678
|
-
const ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/u;
|
|
679
|
-
/**
|
|
680
|
-
* The packages `scripts` preload by a runtime flag's bare module specifier, a flag
|
|
681
|
-
* counting only in a command whose program passes it to the runtime, and for Node only
|
|
682
|
-
* before the script it runs, whose own arguments come after it.
|
|
683
|
-
*/
|
|
684
|
-
function preloadsOf(scripts) {
|
|
685
|
-
const found = new Set();
|
|
686
|
-
for (const script of scripts) {
|
|
687
|
-
for (const command of commandsOf(script)) {
|
|
688
|
-
const tokens = scriptTokens(command);
|
|
689
|
-
let at = 0;
|
|
690
|
-
while (at < tokens.length &&
|
|
691
|
-
(ASSIGNMENT.test(tokens[at] ?? "") || LAUNCHERS.has(tokens[at] ?? ""))) {
|
|
692
|
-
at += 1;
|
|
693
|
-
}
|
|
694
|
-
const path = tokens[at] ?? "";
|
|
695
|
-
const program = path.slice(path.lastIndexOf("/") + 1);
|
|
696
|
-
if (!PRELOADING_PROGRAMS.has(program)) {
|
|
697
|
-
continue;
|
|
698
|
-
}
|
|
699
|
-
for (at += 1; at < tokens.length; at += 1) {
|
|
700
|
-
const token = tokens[at] ?? "";
|
|
701
|
-
if (!token.startsWith("-")) {
|
|
702
|
-
if (program === "node") {
|
|
703
|
-
break;
|
|
704
|
-
}
|
|
705
|
-
continue;
|
|
706
|
-
}
|
|
707
|
-
const equals = token.indexOf("=");
|
|
708
|
-
const flag = equals < 0 ? token : token.slice(0, equals);
|
|
709
|
-
if (!PRELOAD_FLAGS.has(flag)) {
|
|
710
|
-
continue;
|
|
711
|
-
}
|
|
712
|
-
if (equals < 0) {
|
|
713
|
-
at += 1;
|
|
714
|
-
}
|
|
715
|
-
const value = equals < 0 ? tokens[at] : token.slice(equals + 1);
|
|
716
|
-
const name = value === undefined ? undefined : packageOfSpecifier(value);
|
|
717
|
-
if (name !== undefined) {
|
|
718
|
-
found.add(name);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
return found;
|
|
724
|
-
}
|
|
725
676
|
/** Whether a path below the target root lies in the directory `dir` below it, `""` being the root. */
|
|
726
677
|
function isInside(path, dir) {
|
|
727
678
|
return dir === "" || path.startsWith(`${dir}/`);
|
|
@@ -792,8 +743,7 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
|
|
|
792
743
|
unbuilt.add(path);
|
|
793
744
|
}
|
|
794
745
|
}
|
|
795
|
-
const workflow =
|
|
796
|
-
const workflowPreloads = preloadsOf(workflowCommands(host, targetRoot));
|
|
746
|
+
const workflow = workflowUses(host, targetRoot);
|
|
797
747
|
const declared = [];
|
|
798
748
|
const ran = new Set();
|
|
799
749
|
const peers = new Map();
|
|
@@ -803,23 +753,25 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
|
|
|
803
753
|
if (read === undefined || !isRecord(read.value)) {
|
|
804
754
|
continue;
|
|
805
755
|
}
|
|
806
|
-
const
|
|
807
|
-
const
|
|
756
|
+
const own = manifestUses(host, dir, read.value);
|
|
757
|
+
const held = `${own.held}\n${workflow.held}`;
|
|
808
758
|
for (const dependency of declaredIn(read.text, read.value, path, scopeOf(path))) {
|
|
809
759
|
const found = installedOf(host, dir, dependency.name);
|
|
810
760
|
if (found === undefined && uninstalledHere.has(dir)) {
|
|
811
761
|
continue;
|
|
812
762
|
}
|
|
813
763
|
declared.push(dependency);
|
|
814
|
-
if (preloads.has(dependency.name) ||
|
|
764
|
+
if (own.preloads.has(dependency.name) ||
|
|
765
|
+
workflow.preloads.has(dependency.name) ||
|
|
766
|
+
heldNames(held, [dependency.name]).size > 0) {
|
|
815
767
|
ran.add(declarationKey(dependency));
|
|
816
768
|
}
|
|
817
769
|
if (found === undefined) {
|
|
818
770
|
continue;
|
|
819
771
|
}
|
|
820
772
|
peers.set(declarationKey(dependency), found.peers);
|
|
821
|
-
const runs = (command) =>
|
|
822
|
-
if (found.commands.some(runs)) {
|
|
773
|
+
const runs = (command) => own.words.has(command) || workflow.words.has(command);
|
|
774
|
+
if (found.commands.some(runs) || heldNames(held, found.commands).size > 0) {
|
|
823
775
|
ran.add(declarationKey(dependency));
|
|
824
776
|
}
|
|
825
777
|
}
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* configuration only the snapshot holds, with the module system of the runtime its package
|
|
5
5
|
* is written for.
|
|
6
6
|
*/
|
|
7
|
+
import { readCommands } from "../commands/read.js";
|
|
7
8
|
import { CONVENTION_ROWS } from "../convention-rows.js";
|
|
8
9
|
import { holdsManifest, MANIFEST, readManifestAt } from "../fs/manifest.js";
|
|
9
10
|
import { filesBelow } from "../fs/tree.js";
|
|
10
11
|
import { JAVASCRIPT_FILE, minified, minifiedByName } from "../javascript-file.js";
|
|
11
12
|
import { isRecord } from "../json-document.js";
|
|
13
|
+
import { manifestCommands } from "../manifest.js";
|
|
12
14
|
import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.js";
|
|
13
15
|
import { bytewise } from "../text/compare.js";
|
|
14
16
|
import { writtenPath } from "./workspace-programs.js";
|
|
@@ -89,11 +91,15 @@ const RUNTIME_OPTIONS = {
|
|
|
89
91
|
};
|
|
90
92
|
/** The manifest members that say a package is written for Node. */
|
|
91
93
|
const NODE_MEMBERS = ["main", "exports", "bin", "type"];
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Whether one manifest says its package runs under Node: a Node member, `engines.node`
|
|
96
|
+
* included, or a command string of it that runs a file with `node`, as `commands/read.ts` reads it.
|
|
97
|
+
*/
|
|
98
|
+
function writtenForNode(host, dir, manifest) {
|
|
94
99
|
const { engines } = manifest;
|
|
95
100
|
return (NODE_MEMBERS.some((member) => manifest[member] !== undefined) ||
|
|
96
|
-
(isRecord(engines) && engines["node"] !== undefined)
|
|
101
|
+
(isRecord(engines) && engines["node"] !== undefined) ||
|
|
102
|
+
manifestCommands(host, dir, manifest).some(({ command }) => readCommands(command, dir).runs.some((run) => run.runtime === "node")));
|
|
97
103
|
}
|
|
98
104
|
/**
|
|
99
105
|
* The manifests, by path as `conventions` names them, an applied row of a tool that bundles
|
|
@@ -107,7 +113,8 @@ export function bundlingManifests(conventions) {
|
|
|
107
113
|
/**
|
|
108
114
|
* Each group's program, given the module system of the runtime its package is written for: a
|
|
109
115
|
* bundler's where a row of a tool that bundles applies through the group's manifest or the
|
|
110
|
-
* root's, else Node's where its manifest says the package runs under Node
|
|
116
|
+
* root's, else Node's where its manifest says the package runs under Node or a command string of
|
|
117
|
+
* it runs a file with `node`, under which a file's
|
|
111
118
|
* extension and its package's `type` decide its module format, else a bundler's, which reads a
|
|
112
119
|
* file with no module syntax as a classic script, as a browser loads it.
|
|
113
120
|
*/
|
|
@@ -118,7 +125,7 @@ export function formedPrograms(engine, host, groups, { root, origin, bundling, i
|
|
|
118
125
|
const runtime = !bundling.has(MANIFEST) &&
|
|
119
126
|
(below === undefined || !bundling.has(below)) &&
|
|
120
127
|
group.manifest.kind === "read" &&
|
|
121
|
-
writtenForNode(group.manifest.manifest)
|
|
128
|
+
writtenForNode(host, group.dir, group.manifest.manifest)
|
|
122
129
|
? "node"
|
|
123
130
|
: "bundler";
|
|
124
131
|
const configFile = writtenPath(host, joinPath(group.dir, GROUP_CONFIGURATION));
|
package/dist/src/manifest.js
CHANGED
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
8
|
import { isRecord } from "./json-document.js";
|
|
9
9
|
import { MANIFEST, manifestAt, readJSON } from "./fs/manifest.js";
|
|
10
|
-
import {
|
|
11
|
-
/** The manifest's own name. */
|
|
10
|
+
import { pathsNamed, readCommands } from "./commands/read.js";
|
|
12
11
|
/** The three members that name an entry point beside `exports` and `bin`. */
|
|
13
12
|
const LEGACY_MEMBERS = ["main", "module", "types"];
|
|
14
13
|
/**
|
|
@@ -26,6 +25,25 @@ function isTarget(value, requireDot) {
|
|
|
26
25
|
function below(member, key) {
|
|
27
26
|
return `${member}[${JSON.stringify(key)}]`;
|
|
28
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The whole text of nodemon's configuration, the manifest's `nodemonConfig` member and the
|
|
30
|
+
* `nodemon.json` beside it, by the member each is. Layer 3 holds it whole, because nodemon runs
|
|
31
|
+
* commands from keys besides `exec`, `events` among them: https://github.com/remy/nodemon#config-files
|
|
32
|
+
*/
|
|
33
|
+
export function nodemonTexts(host, dir, manifest) {
|
|
34
|
+
const member = manifest["nodemonConfig"];
|
|
35
|
+
let file;
|
|
36
|
+
try {
|
|
37
|
+
file = host.readFile(joinPath(dir, "nodemon.json"));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
file = undefined;
|
|
41
|
+
}
|
|
42
|
+
return [
|
|
43
|
+
...(member === undefined ? [] : [{ member: "nodemonConfig", text: JSON.stringify(member) }]),
|
|
44
|
+
...(file === undefined ? [] : [{ member: "nodemon.json", text: file }]),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
29
47
|
/**
|
|
30
48
|
* The command strings one manifest runs, each at the member it is written under: each of its
|
|
31
49
|
* `scripts`, and the `exec` command of nodemon's configuration, in the manifest's `nodemonConfig`
|
|
@@ -118,20 +136,15 @@ export function readManifest(host, targetRoot) {
|
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
exportTargets(manifest["exports"], "exports", found);
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
for (const
|
|
124
|
-
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
const member = below("scripts", name);
|
|
128
|
-
for (const path of new Set(scriptTokens(command))) {
|
|
129
|
-
found.push({ member, path, role: "script", published: false });
|
|
130
|
-
}
|
|
139
|
+
for (const { member, command } of manifestCommands(host, targetRoot, manifest)) {
|
|
140
|
+
// Read against ".", so each path stays relative until the entries are resolved below.
|
|
141
|
+
for (const path of new Set(pathsNamed(readCommands(command, ".")).map((one) => one.path))) {
|
|
142
|
+
found.push({ member, path, role: "script", published: false });
|
|
131
143
|
}
|
|
144
|
+
found.push({ member, path: ".", role: "script", published: false, held: command });
|
|
132
145
|
}
|
|
133
|
-
for (const { member,
|
|
134
|
-
found.push({ member, path: ".", role: "script", published: false,
|
|
146
|
+
for (const { member, text } of nodemonTexts(host, targetRoot, manifest)) {
|
|
147
|
+
found.push({ member, path: ".", role: "script", published: false, held: text });
|
|
135
148
|
}
|
|
136
149
|
return {
|
|
137
150
|
entries: found.map((entry) => ({
|
package/dist/src/roots.js
CHANGED
|
@@ -20,7 +20,8 @@ import { bytewise } from "./text/compare.js";
|
|
|
20
20
|
import { holdsManifest } from "./fs/manifest.js";
|
|
21
21
|
import { globExpression } from "./text/glob.js";
|
|
22
22
|
import { spelledFiles } from "./text/named-files.js";
|
|
23
|
-
import {
|
|
23
|
+
import { commandFileTexts, workflowCommands } from "./workflow-steps.js";
|
|
24
|
+
import { readCommands } from "./commands/read.js";
|
|
24
25
|
/** Whether one declaration is written below the directory of a published workspace member. */
|
|
25
26
|
function inPublishedMember(held, id, root, members) {
|
|
26
27
|
const path = held.symbols.find((symbol) => symbol.id === id)?.position.path;
|
|
@@ -174,11 +175,11 @@ function childrenOf(held) {
|
|
|
174
175
|
return byParent;
|
|
175
176
|
}
|
|
176
177
|
/**
|
|
177
|
-
* Per package, the own files its
|
|
178
|
-
* with all they export: a command can use no more of such a file than the root
|
|
179
|
-
* manifest's are its entries'
|
|
180
|
-
* workflow steps, git hooks and makefile recipes beside its own, with the
|
|
181
|
-
*
|
|
178
|
+
* Per package, the own files its held texts name, as `spelledFiles` reads them, but those a
|
|
179
|
+
* root enters with all they export: a command can use no more of such a file than the root
|
|
180
|
+
* keeps live. A manifest's are its entries' held texts, and the target root's package has the
|
|
181
|
+
* workflow steps, git hooks and makefile recipes beside its own, with the whole text of each
|
|
182
|
+
* file `commandFileTexts` reads.
|
|
182
183
|
*/
|
|
183
184
|
function scriptHolds(entries, files, entered, host, targetRoot) {
|
|
184
185
|
const rooted = new Set(entered.filter((one) => one.exports && one.names === undefined).map((one) => one.file.fileName));
|
|
@@ -189,13 +190,19 @@ function scriptHolds(entries, files, entered, host, targetRoot) {
|
|
|
189
190
|
const commands = new Map([
|
|
190
191
|
[
|
|
191
192
|
resolvePath(cwd, targetRoot),
|
|
192
|
-
[
|
|
193
|
+
[
|
|
194
|
+
...workflowCommands(host, targetRoot).flatMap(({ text, dir, writtenDirectory }) => [
|
|
195
|
+
readCommands(text, dir).held,
|
|
196
|
+
...(writtenDirectory === undefined ? [] : [writtenDirectory]),
|
|
197
|
+
]),
|
|
198
|
+
...commandFileTexts(host, targetRoot),
|
|
199
|
+
],
|
|
193
200
|
],
|
|
194
201
|
]);
|
|
195
202
|
for (const entry of entries) {
|
|
196
|
-
if (entry.
|
|
203
|
+
if (entry.held !== undefined) {
|
|
197
204
|
const dir = resolvePath(cwd, entry.dir);
|
|
198
|
-
commands.set(dir, [...(commands.get(dir) ?? []), entry.
|
|
205
|
+
commands.set(dir, [...(commands.get(dir) ?? []), entry.held]);
|
|
199
206
|
}
|
|
200
207
|
}
|
|
201
208
|
const held = [];
|
|
@@ -249,7 +256,7 @@ export function roots(project, held, targetRoot, options) {
|
|
|
249
256
|
(options.publishedAPI || options.publishedMembers?.has(entry.dir) === true),
|
|
250
257
|
})),
|
|
251
258
|
];
|
|
252
|
-
const scripted = entries.flatMap(({ entry }) => entry.role === "script" && entry.
|
|
259
|
+
const scripted = entries.flatMap(({ entry }) => entry.role === "script" && entry.held === undefined ? files.named(entry.path) : []);
|
|
253
260
|
const readBackTo = [
|
|
254
261
|
...scripted,
|
|
255
262
|
...points.filter((point) => READ_BACK_RULES.has(point.rule)).map((point) => point.file),
|
|
@@ -299,7 +306,7 @@ export function roots(project, held, targetRoot, options) {
|
|
|
299
306
|
const unmapped = [];
|
|
300
307
|
const mapped = patterned.map(({ file }) => file);
|
|
301
308
|
for (const { entry } of entries) {
|
|
302
|
-
if (entry.
|
|
309
|
+
if (entry.held !== undefined) {
|
|
303
310
|
continue;
|
|
304
311
|
}
|
|
305
312
|
const named = entryFiles(entry);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* skipped first.
|
|
2
|
+
* Layer 3 of the command reader: the files and the package names a command's text names, read
|
|
3
|
+
* as plain text. The text is searched for each name, which every spelling of what it names
|
|
4
|
+
* contains, so no part of it is split, unquoted or skipped first.
|
|
5
5
|
*/
|
|
6
6
|
import { dirnamePath, normalizePath, relativePath } from "../paths.js";
|
|
7
7
|
/** The extension a source or an emitted file carries: a JavaScript or TypeScript one, or a declaration's. */
|
|
@@ -52,3 +52,24 @@ export function spelledFiles(text, dir, files) {
|
|
|
52
52
|
}
|
|
53
53
|
return [...found];
|
|
54
54
|
}
|
|
55
|
+
/** A character a package's or a command's name may hold, so one beside a name makes it part of a longer one. */
|
|
56
|
+
const NAME_CHARACTER = /[\w.@-]/u;
|
|
57
|
+
/**
|
|
58
|
+
* Each of `names`, a package's or a command's name, that `text` holds with no name character
|
|
59
|
+
* before it and no character after it but one a path or a version may go on with, `/`, `.` or
|
|
60
|
+
* `@` among them: `module-alias/register` holds `module-alias`, and `tsxx` holds no `tsx`.
|
|
61
|
+
*/
|
|
62
|
+
export function heldNames(text, names) {
|
|
63
|
+
const found = new Set();
|
|
64
|
+
for (const name of names) {
|
|
65
|
+
for (let at = text.indexOf(name); at >= 0 && name !== ""; at = text.indexOf(name, at + 1)) {
|
|
66
|
+
const before = text.charAt(at - 1);
|
|
67
|
+
const after = text.charAt(at + name.length);
|
|
68
|
+
if (!NAME_CHARACTER.test(before) && !/[\w-]/u.test(after)) {
|
|
69
|
+
found.add(name);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return found;
|
|
75
|
+
}
|