@vltpkg/graph 0.0.0-13 → 0.0.0-15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/esm/actual/load.d.ts +7 -0
  2. package/dist/esm/actual/load.d.ts.map +1 -1
  3. package/dist/esm/actual/load.js +22 -6
  4. package/dist/esm/actual/load.js.map +1 -1
  5. package/dist/esm/graph.d.ts +2 -2
  6. package/dist/esm/graph.d.ts.map +1 -1
  7. package/dist/esm/graph.js +11 -4
  8. package/dist/esm/graph.js.map +1 -1
  9. package/dist/esm/ideal/add-nodes.d.ts +3 -1
  10. package/dist/esm/ideal/add-nodes.d.ts.map +1 -1
  11. package/dist/esm/ideal/add-nodes.js +3 -2
  12. package/dist/esm/ideal/add-nodes.js.map +1 -1
  13. package/dist/esm/ideal/append-nodes.d.ts +2 -1
  14. package/dist/esm/ideal/append-nodes.d.ts.map +1 -1
  15. package/dist/esm/ideal/append-nodes.js +18 -4
  16. package/dist/esm/ideal/append-nodes.js.map +1 -1
  17. package/dist/esm/ideal/build-ideal-from-starting-graph.d.ts +2 -0
  18. package/dist/esm/ideal/build-ideal-from-starting-graph.d.ts.map +1 -1
  19. package/dist/esm/ideal/build-ideal-from-starting-graph.js +3 -0
  20. package/dist/esm/ideal/build-ideal-from-starting-graph.js.map +1 -1
  21. package/dist/esm/ideal/build.d.ts +5 -0
  22. package/dist/esm/ideal/build.d.ts.map +1 -1
  23. package/dist/esm/ideal/build.js.map +1 -1
  24. package/dist/esm/ideal/check-nodes.d.ts +33 -0
  25. package/dist/esm/ideal/check-nodes.d.ts.map +1 -0
  26. package/dist/esm/ideal/check-nodes.js +42 -0
  27. package/dist/esm/ideal/check-nodes.js.map +1 -0
  28. package/dist/esm/ideal/get-importer-specs.d.ts +8 -2
  29. package/dist/esm/ideal/get-importer-specs.d.ts.map +1 -1
  30. package/dist/esm/ideal/get-importer-specs.js +15 -5
  31. package/dist/esm/ideal/get-importer-specs.js.map +1 -1
  32. package/dist/esm/index.d.ts +1 -0
  33. package/dist/esm/index.d.ts.map +1 -1
  34. package/dist/esm/index.js +1 -0
  35. package/dist/esm/index.js.map +1 -1
  36. package/dist/esm/install.d.ts.map +1 -1
  37. package/dist/esm/install.js +3 -0
  38. package/dist/esm/install.js.map +1 -1
  39. package/dist/esm/lockfile/load.d.ts.map +1 -1
  40. package/dist/esm/lockfile/load.js +3 -1
  41. package/dist/esm/lockfile/load.js.map +1 -1
  42. package/dist/esm/lockfile/save.d.ts +1 -1
  43. package/dist/esm/lockfile/save.d.ts.map +1 -1
  44. package/dist/esm/lockfile/save.js +5 -3
  45. package/dist/esm/lockfile/save.js.map +1 -1
  46. package/dist/esm/modifiers.d.ts +199 -0
  47. package/dist/esm/modifiers.d.ts.map +1 -0
  48. package/dist/esm/modifiers.js +342 -0
  49. package/dist/esm/modifiers.js.map +1 -0
  50. package/dist/esm/node.d.ts +7 -0
  51. package/dist/esm/node.d.ts.map +1 -1
  52. package/dist/esm/node.js +7 -0
  53. package/dist/esm/node.js.map +1 -1
  54. package/dist/esm/reify/add-edge.d.ts.map +1 -1
  55. package/dist/esm/reify/add-edge.js +18 -7
  56. package/dist/esm/reify/add-edge.js.map +1 -1
  57. package/dist/esm/reify/index.d.ts.map +1 -1
  58. package/dist/esm/reify/index.js +3 -1
  59. package/dist/esm/reify/index.js.map +1 -1
  60. package/dist/esm/reify/internal-hoist.d.ts +9 -0
  61. package/dist/esm/reify/internal-hoist.d.ts.map +1 -0
  62. package/dist/esm/reify/internal-hoist.js +121 -0
  63. package/dist/esm/reify/internal-hoist.js.map +1 -0
  64. package/dist/esm/visualization/human-readable-output.d.ts.map +1 -1
  65. package/dist/esm/visualization/human-readable-output.js +1 -4
  66. package/dist/esm/visualization/human-readable-output.js.map +1 -1
  67. package/package.json +23 -20
@@ -0,0 +1,199 @@
1
+ import { Spec } from '@vltpkg/spec';
2
+ import type { ModifierBreadcrumb, ModifierInteractiveBreadcrumb } from '@vltpkg/dss-breadcrumb';
3
+ import type { SpecOptions } from '@vltpkg/spec';
4
+ import type { Manifest } from '@vltpkg/types';
5
+ import type { Edge } from './edge.ts';
6
+ import type { Node } from './node.ts';
7
+ import type { Dependency } from './dependencies.ts';
8
+ /**
9
+ * Loaded modifiers configuration as described in the `vlt.json` file.
10
+ */
11
+ export type GraphModifierLoadedConfig = {
12
+ modifiers: GraphModifierConfigObject;
13
+ };
14
+ /**
15
+ * Type definition for the modifiers configuration object
16
+ */
17
+ export type GraphModifierConfigObject = Record<string, string>;
18
+ /**
19
+ * Info needed to define a graph modifier.
20
+ */
21
+ export type BaseModifierEntry = {
22
+ type: 'edge' | 'node';
23
+ query: string;
24
+ breadcrumb: ModifierBreadcrumb;
25
+ value: string | Manifest;
26
+ refs: Set<{
27
+ name: string;
28
+ from: Node;
29
+ }>;
30
+ };
31
+ /**
32
+ * Extra info to define specifically a graph edge modifier.
33
+ */
34
+ export type EdgeModifierEntry = BaseModifierEntry & {
35
+ type: 'edge';
36
+ spec: Spec;
37
+ value: string;
38
+ };
39
+ /**
40
+ * Extra info to define the graph node modifier.
41
+ */
42
+ export type NodeModifierEntry = BaseModifierEntry & {
43
+ type: 'node';
44
+ manifest: Manifest;
45
+ };
46
+ /**
47
+ * A graph modifier entry, which can be either an edge or a node modifier.
48
+ */
49
+ export type ModifierEntry = EdgeModifierEntry | NodeModifierEntry;
50
+ /**
51
+ * An object to track modifiers that have matched an initial part of the
52
+ * breadcrumb. It holds pointers to both nodes and edges matched in the
53
+ * current traversed graph on top of the modifier info and the breadcrumb
54
+ * state that is used to track the current state of the parsing.
55
+ */
56
+ export type ModifierActiveEntry = {
57
+ /**
58
+ * The modifier this active entry is working with.
59
+ */
60
+ modifier: ModifierEntry;
61
+ /**
62
+ * The breadcrumb that is used to track the current state of the parsing.
63
+ */
64
+ interactiveBreadcrumb: ModifierInteractiveBreadcrumb;
65
+ /**
66
+ * The first node to be affected by this modifier.
67
+ */
68
+ originalFrom: Node;
69
+ /**
70
+ * The original edge that is being replaced with this entry.
71
+ */
72
+ originalEdge?: Edge;
73
+ /**
74
+ * The modified edge that is being used to replace the original edge.
75
+ */
76
+ modifiedEdge?: Edge;
77
+ };
78
+ /**
79
+ * Class representing loaded modifiers configuration for a project.
80
+ *
81
+ * Instances of this class can be used as a helper to modify the graph
82
+ * during the graph build ideal traversal time.
83
+ *
84
+ * ```
85
+ * const modifier = new GraphModifier(options)
86
+ * modifier.load(options)
87
+ * ```
88
+ *
89
+ * The `tryImporter` method can be used to register the initial importer
90
+ * node along with any modifier that includes an importer selector, e.g:
91
+ * `modifier.tryImporter(graph.mainImporter)`
92
+ *
93
+ * When traversing the graph, use the `tryNewDependency` method to check
94
+ * if a given dependency name to the current traversed node has matching
95
+ * registered modifiers, e.g:
96
+ * `const entries = modifier.tryNewDependency(fromNode, depName)`
97
+ *
98
+ * Use `updateActiveEntry` to update a given active modifier entry state
99
+ * with the current node of the graph being traversed. e.g:
100
+ * ```
101
+ * for (const entry of entries)
102
+ * modifier.updateActiveEntry(fromNode, entry)
103
+ * ```
104
+ */
105
+ export declare class GraphModifier {
106
+ #private;
107
+ /**
108
+ * A set of currently active modifiers, which are being parsed.
109
+ */
110
+ activeModifiers: Set<ModifierActiveEntry>;
111
+ constructor(options: SpecOptions);
112
+ /**
113
+ * Load the modifiers definitions from vlt.json,
114
+ * converting the result into a GraphModifierConfigObject
115
+ */
116
+ get config(): GraphModifierConfigObject;
117
+ /**
118
+ * Loads the modifiers defined in `vlt.json` into memory.
119
+ */
120
+ load(options: SpecOptions): void;
121
+ /**
122
+ * Check if a given importer dependency name has potentially a registered
123
+ * modifier. In case of an ambiguous modifier, the method will always
124
+ * return `true`, it only returns `false` in the case that only fully
125
+ * qualified modifiers are registered and none are targeting the given
126
+ * top-level dependency name.
127
+ *
128
+ * This method is useful to help avoiding traversing the sub graph of
129
+ * a direct dependency when we know that it's impossible to ever match
130
+ * beforehand.
131
+ */
132
+ maybeHasModifier(depName: string): boolean;
133
+ /**
134
+ * Try matching the provided node against the top-level selectors. In case
135
+ * a match is found it will also register the active entry modifier and
136
+ * update the active entry to the current importer node.
137
+ */
138
+ tryImporter(importer: Node): void;
139
+ /**
140
+ * Try matching the provided node and dependency name to the current
141
+ * active parsing modifier entries along with possible starting-level
142
+ * modifiers.
143
+ *
144
+ * Any entries in which the breachcrumb have already reached its last
145
+ * element will be prioritized, along with checking for specificity,
146
+ * the complete entry with the highest specificity will be returned or just
147
+ * the entry with the highest specificity if no complete entry is found.
148
+ * Returns `undefined` if no matching entry is found.
149
+ *
150
+ * This method works with the assumption that it's going to be called
151
+ * during a graph traversal, such that any ascendent has been checked
152
+ * and the active modifier entry state has been updated in the previous
153
+ * iteration.
154
+ */
155
+ tryNewDependency(from: Node, name: string): ModifierActiveEntry | undefined;
156
+ /**
157
+ * Returns the set of {@link ModifierActiveEntry} instances that matches
158
+ * the provided {@link Dependency} specs for a given node.
159
+ *
160
+ * This method is mostly a helper to {@link GraphModifier.tryNewDependency}
161
+ * that handles the registered modifiers traversal lookup.
162
+ */
163
+ tryDependencies(from: Node, dependencies: Dependency[]): Map<string, ModifierActiveEntry>;
164
+ /**
165
+ * Updates an active entry state keeping track of items in the multi-level
166
+ * active entries map. If the current breadcrumb state shows there's no more
167
+ * items left, then we deregister the modifier.
168
+ */
169
+ updateActiveEntry(from: Node, active: ModifierActiveEntry): void;
170
+ /**
171
+ * Creates a new active modifier.
172
+ */
173
+ newModifier(from: Node, modifier: ModifierEntry): ModifierActiveEntry;
174
+ /**
175
+ * Removes a previously registered modifier from the active entries.
176
+ */
177
+ deregisterModifier(modifier: ModifierEntry): void;
178
+ /**
179
+ * Operates in previously registered nodes and edges in order to put
180
+ * back in place any of the original edges that were referenced to in
181
+ * active (ongoing) breadcrumb parsing entries that were never completed.
182
+ *
183
+ * This method can be used to easily rollback any pending operations
184
+ * once the graph traversal is done.
185
+ */
186
+ rollbackActiveEntries(): void;
187
+ /**
188
+ * Convenience method to instantiate and load in one call.
189
+ * Returns undefined if the project does not have a vlt.json file,
190
+ * otherwise returns the loaded Modifiers instance.
191
+ */
192
+ static maybeLoad(options: SpecOptions): GraphModifier | undefined;
193
+ /**
194
+ * Convenience method to instantiate and load in one call.
195
+ * Throws if called on a directory that does not have a vlt.json file.
196
+ */
197
+ static load(options: SpecOptions): GraphModifier;
198
+ }
199
+ //# sourceMappingURL=modifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifiers.d.ts","sourceRoot":"","sources":["../../src/modifiers.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAGnC,OAAO,KAAK,EACV,kBAAkB,EAClB,6BAA6B,EAC9B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,yBAAyB,CAAA;CACrC,CAAA;AAED;;GAEG;AAEH,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,kBAAkB,CAAA;IAC9B,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAA;IACxB,IAAI,EAAE,GAAG,CAAC;QACR,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,IAAI,CAAA;KACX,CAAC,CAAA;CACH,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,iBAAiB,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,QAAQ,EAAE,aAAa,CAAA;IACvB;;OAEG;IACH,qBAAqB,EAAE,6BAA6B,CAAA;IACpD;;OAEG;IACH,YAAY,EAAE,IAAI,CAAA;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,IAAI,CAAA;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,IAAI,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,aAAa;;IA2BxB;;OAEG;IACH,eAAe,2BAAiC;gBAEpC,OAAO,EAAE,WAAW;IAIhC;;;OAGG;IACH,IAAI,MAAM,IAAI,yBAAyB,CAItC;IAED;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,WAAW;IA+CzB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAa1C;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,IAAI;IAwB1B;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,GACX,mBAAmB,GAAG,SAAS;IAsDlC;;;;;;OAMG;IACH,eAAe,CACb,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,UAAU,EAAE,GACzB,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAWnC;;;;OAIG;IACH,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI;IA6BhE;;OAEG;IACH,WAAW,CACT,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,aAAa,GACtB,mBAAmB;IAQtB;;OAEG;IACH,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAmBjD;;;;;;;OAOG;IACH,qBAAqB,IAAI,IAAI;IAc7B;;;;OAIG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW;IAMrC;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW;CAGjC"}
@@ -0,0 +1,342 @@
1
+ import { parseBreadcrumb, specificitySort, } from '@vltpkg/dss-breadcrumb';
2
+ import { error } from '@vltpkg/error-cause';
3
+ import { Spec } from '@vltpkg/spec';
4
+ import { asManifest, assertRecordStringString } from '@vltpkg/types';
5
+ import { load } from '@vltpkg/vlt-json';
6
+ /**
7
+ * Class representing loaded modifiers configuration for a project.
8
+ *
9
+ * Instances of this class can be used as a helper to modify the graph
10
+ * during the graph build ideal traversal time.
11
+ *
12
+ * ```
13
+ * const modifier = new GraphModifier(options)
14
+ * modifier.load(options)
15
+ * ```
16
+ *
17
+ * The `tryImporter` method can be used to register the initial importer
18
+ * node along with any modifier that includes an importer selector, e.g:
19
+ * `modifier.tryImporter(graph.mainImporter)`
20
+ *
21
+ * When traversing the graph, use the `tryNewDependency` method to check
22
+ * if a given dependency name to the current traversed node has matching
23
+ * registered modifiers, e.g:
24
+ * `const entries = modifier.tryNewDependency(fromNode, depName)`
25
+ *
26
+ * Use `updateActiveEntry` to update a given active modifier entry state
27
+ * with the current node of the graph being traversed. e.g:
28
+ * ```
29
+ * for (const entry of entries)
30
+ * modifier.updateActiveEntry(fromNode, entry)
31
+ * ```
32
+ */
33
+ export class GraphModifier {
34
+ /** The loaded modifiers configuration */
35
+ #config;
36
+ /** A set of all modifiers loaded from vlt.json */
37
+ #modifiers = new Set();
38
+ /** A set of all edge modifiers loaded from vlt.json */
39
+ #edgeModifiers = new Set();
40
+ /** A set of all node modifiers loaded from vlt.json */
41
+ #nodeModifiers = new Set();
42
+ /**
43
+ * A map of initial entries, keyed by the name of the first breadcrumb
44
+ * item to its modifier entry. Useful for checking for non-importer
45
+ * starting breadcrumbs, e.g: `#a > #b`
46
+ */
47
+ #initialEntries = new Map();
48
+ /**
49
+ * A multi-level map of active entries, keyed by:
50
+ * - modifiers
51
+ * - edge name
52
+ * - from node
53
+ * that allows for retrieving seen {@link ModifierActiveEntry} instances
54
+ * in constant time.
55
+ */
56
+ #activeEntries = new Map();
57
+ /**
58
+ * A set of currently active modifiers, which are being parsed.
59
+ */
60
+ activeModifiers = new Set();
61
+ constructor(options) {
62
+ this.load(options);
63
+ }
64
+ /**
65
+ * Load the modifiers definitions from vlt.json,
66
+ * converting the result into a GraphModifierConfigObject
67
+ */
68
+ get config() {
69
+ if (this.#config)
70
+ return this.#config;
71
+ return (this.#config =
72
+ load('modifiers', assertRecordStringString) ?? {});
73
+ }
74
+ /**
75
+ * Loads the modifiers defined in `vlt.json` into memory.
76
+ */
77
+ load(options) {
78
+ for (const [key, value] of Object.entries(this.config)) {
79
+ const breadcrumb = parseBreadcrumb(key);
80
+ /* c8 ignore start - should not be possible */
81
+ if (!breadcrumb.last.name) {
82
+ throw error('Could not find name in breadcrumb', {
83
+ found: key,
84
+ });
85
+ }
86
+ /* c8 ignore stop */
87
+ let mod;
88
+ if (typeof value === 'string') {
89
+ mod = {
90
+ breadcrumb,
91
+ query: key,
92
+ refs: new Set(),
93
+ spec: Spec.parse(breadcrumb.last.name, value, options),
94
+ type: 'edge',
95
+ value,
96
+ };
97
+ this.#edgeModifiers.add(mod);
98
+ /* c8 ignore start - TODO */
99
+ }
100
+ else {
101
+ const manifest = asManifest(value);
102
+ mod = {
103
+ breadcrumb,
104
+ query: key,
105
+ manifest,
106
+ refs: new Set(),
107
+ type: 'node',
108
+ value: manifest,
109
+ };
110
+ this.#nodeModifiers.add(mod);
111
+ }
112
+ /* c8 ignore end */
113
+ this.#modifiers.add(mod);
114
+ // if the breadcrumb starts with an id, then add it to the
115
+ // map of initial entries, so that we can use it to match
116
+ if (breadcrumb.first.name) {
117
+ const initialSet = this.#initialEntries.get(breadcrumb.first.name) ?? new Set();
118
+ initialSet.add(mod);
119
+ this.#initialEntries.set(breadcrumb.first.name, initialSet);
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Check if a given importer dependency name has potentially a registered
125
+ * modifier. In case of an ambiguous modifier, the method will always
126
+ * return `true`, it only returns `false` in the case that only fully
127
+ * qualified modifiers are registered and none are targeting the given
128
+ * top-level dependency name.
129
+ *
130
+ * This method is useful to help avoiding traversing the sub graph of
131
+ * a direct dependency when we know that it's impossible to ever match
132
+ * beforehand.
133
+ */
134
+ maybeHasModifier(depName) {
135
+ for (const mod of this.#modifiers) {
136
+ const matchingName = mod.breadcrumb.first.importer &&
137
+ mod.breadcrumb.first.next?.name === depName;
138
+ const rootlessBreadcrumb = !mod.breadcrumb.first.importer;
139
+ if (rootlessBreadcrumb || matchingName) {
140
+ return true;
141
+ }
142
+ }
143
+ return false;
144
+ }
145
+ /**
146
+ * Try matching the provided node against the top-level selectors. In case
147
+ * a match is found it will also register the active entry modifier and
148
+ * update the active entry to the current importer node.
149
+ */
150
+ tryImporter(importer) {
151
+ for (const modifier of this.#modifiers) {
152
+ // if the first item in the breadcrumb is an importer and it matches
153
+ // any of the valid top-level selectors, then register the modifier
154
+ const { first } = modifier.breadcrumb;
155
+ const matchRoot = first.value === ':root' && importer.mainImporter;
156
+ const matchWorkspace = first.value === ':workspace' && importer.importer;
157
+ const matchAny = first.value === ':project' || matchRoot || matchWorkspace;
158
+ if (first.importer && matchAny) {
159
+ const active = this.newModifier(importer, modifier);
160
+ const single = active.modifier.breadcrumb.single;
161
+ // only the importers will update the active entry right after
162
+ // registering it since tryImporter doesn't try to match from
163
+ // active dependencies
164
+ if (!single) {
165
+ this.updateActiveEntry(importer, active);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ /**
171
+ * Try matching the provided node and dependency name to the current
172
+ * active parsing modifier entries along with possible starting-level
173
+ * modifiers.
174
+ *
175
+ * Any entries in which the breachcrumb have already reached its last
176
+ * element will be prioritized, along with checking for specificity,
177
+ * the complete entry with the highest specificity will be returned or just
178
+ * the entry with the highest specificity if no complete entry is found.
179
+ * Returns `undefined` if no matching entry is found.
180
+ *
181
+ * This method works with the assumption that it's going to be called
182
+ * during a graph traversal, such that any ascendent has been checked
183
+ * and the active modifier entry state has been updated in the previous
184
+ * iteration.
185
+ */
186
+ tryNewDependency(from, name) {
187
+ // here we use a map instead of a set so that we can associate each
188
+ // modifier active entry with its breadcrumb so that it's easier to
189
+ // pick the correct entry when we sort breadcrbumbs by specificity
190
+ const all = new Map();
191
+ for (const modifier of this.#modifiers) {
192
+ // if an active entry is found then returns that
193
+ const entry = this.#activeEntries
194
+ .get(modifier)
195
+ ?.get(name)
196
+ ?.get(from);
197
+ if (entry) {
198
+ all.set(entry.modifier.breadcrumb, entry);
199
+ }
200
+ }
201
+ // matches the name against the initial entries, this will make it so
202
+ // that modifier queries that start with a name (e.g: #a > #b) can
203
+ // match at any point of the graph traversal
204
+ const initialSet = this.#initialEntries.get(name) ?? new Set();
205
+ for (const initial of initialSet) {
206
+ const initialEntry =
207
+ /* c8 ignore next - difficult to test branch */
208
+ this.#activeEntries.get(initial)?.get(name)?.get(from) ??
209
+ this.newModifier(from, initial);
210
+ all.set(initialEntry.modifier.breadcrumb, initialEntry);
211
+ }
212
+ // selects the active entry that should apply to this dependency,
213
+ // any active entry that is done parsing has the priority, if we
214
+ // find multiple entries then we use css specificity to pick a winner
215
+ // if we have multiple matches but no active entry is complete, then
216
+ // we pick the one with the highest specificity breadcrumb
217
+ const arr = [...all.values()];
218
+ const completeEntries = arr.filter(active => active.interactiveBreadcrumb.current ===
219
+ active.modifier.breadcrumb.last);
220
+ // deregister completed entries
221
+ for (const entry of completeEntries) {
222
+ this.deregisterModifier(entry.modifier);
223
+ }
224
+ // returns the highest specificity entry from either the complete entries
225
+ // if any were found or from any of the entries if available, otherwise
226
+ // it will return undefined as no entry is found in the `all` map
227
+ const entries = completeEntries.length ? completeEntries : arr;
228
+ return all.get(specificitySort(entries.map(i => i.modifier.breadcrumb))[0]);
229
+ }
230
+ /**
231
+ * Returns the set of {@link ModifierActiveEntry} instances that matches
232
+ * the provided {@link Dependency} specs for a given node.
233
+ *
234
+ * This method is mostly a helper to {@link GraphModifier.tryNewDependency}
235
+ * that handles the registered modifiers traversal lookup.
236
+ */
237
+ tryDependencies(from, dependencies) {
238
+ const modifierRefs = new Map();
239
+ for (const { spec } of dependencies) {
240
+ const active = this.tryNewDependency(from, spec.name);
241
+ if (active) {
242
+ modifierRefs.set(spec.name, active);
243
+ }
244
+ }
245
+ return modifierRefs;
246
+ }
247
+ /**
248
+ * Updates an active entry state keeping track of items in the multi-level
249
+ * active entries map. If the current breadcrumb state shows there's no more
250
+ * items left, then we deregister the modifier.
251
+ */
252
+ updateActiveEntry(from, active) {
253
+ const { modifier } = active;
254
+ const interactiveBreadcrumb = active.interactiveBreadcrumb.next();
255
+ const name = interactiveBreadcrumb.current?.name;
256
+ // if there's no name, or we're done parsing then we
257
+ // deregister the modifier instead of updating the entry
258
+ if (interactiveBreadcrumb.done || !name) {
259
+ this.deregisterModifier(modifier);
260
+ return;
261
+ }
262
+ // register the active modifier
263
+ this.activeModifiers.add(active);
264
+ active.modifier.refs.add({ from, name });
265
+ // optionally read or create the nested maps
266
+ const nameMap = this.#activeEntries.get(modifier) ??
267
+ new Map();
268
+ this.#activeEntries.set(modifier, nameMap);
269
+ const nodeMap = nameMap.get(name) ?? new Map();
270
+ nameMap.set(name, nodeMap);
271
+ // sets the active entry in the map
272
+ nodeMap.set(from, active);
273
+ }
274
+ /**
275
+ * Creates a new active modifier.
276
+ */
277
+ newModifier(from, modifier) {
278
+ return {
279
+ modifier,
280
+ interactiveBreadcrumb: modifier.breadcrumb.interactive(),
281
+ originalFrom: from,
282
+ };
283
+ }
284
+ /**
285
+ * Removes a previously registered modifier from the active entries.
286
+ */
287
+ deregisterModifier(modifier) {
288
+ for (const { from, name } of modifier.refs) {
289
+ const nodeMap = this.#activeEntries.get(modifier)?.get(name);
290
+ if (nodeMap) {
291
+ // if an entry is found, we remove it from the active set
292
+ const entry = nodeMap.get(from);
293
+ if (entry) {
294
+ this.activeModifiers.delete(entry);
295
+ }
296
+ // then we remove the entry from the map
297
+ nodeMap.delete(from);
298
+ // if the map is empty, we remove it from the active entries map
299
+ if (!nodeMap.size) {
300
+ this.#activeEntries.get(modifier)?.delete(name);
301
+ }
302
+ }
303
+ }
304
+ }
305
+ /**
306
+ * Operates in previously registered nodes and edges in order to put
307
+ * back in place any of the original edges that were referenced to in
308
+ * active (ongoing) breadcrumb parsing entries that were never completed.
309
+ *
310
+ * This method can be used to easily rollback any pending operations
311
+ * once the graph traversal is done.
312
+ */
313
+ rollbackActiveEntries() {
314
+ for (const modifier of this.activeModifiers) {
315
+ // if the modifier has an original edge, we can put it back in place
316
+ if (modifier.originalEdge) {
317
+ modifier.originalFrom.edgesOut.set(modifier.originalEdge.spec.name, modifier.originalEdge);
318
+ }
319
+ // then we deregister the modifier
320
+ this.deregisterModifier(modifier.modifier);
321
+ }
322
+ }
323
+ /**
324
+ * Convenience method to instantiate and load in one call.
325
+ * Returns undefined if the project does not have a vlt.json file,
326
+ * otherwise returns the loaded Modifiers instance.
327
+ */
328
+ static maybeLoad(options) {
329
+ const config = load('modifiers', assertRecordStringString);
330
+ if (!config)
331
+ return;
332
+ return new GraphModifier(options);
333
+ }
334
+ /**
335
+ * Convenience method to instantiate and load in one call.
336
+ * Throws if called on a directory that does not have a vlt.json file.
337
+ */
338
+ static load(options) {
339
+ return new GraphModifier(options);
340
+ }
341
+ }
342
+ //# sourceMappingURL=modifiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifiers.js","sourceRoot":"","sources":["../../src/modifiers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n parseBreadcrumb,\n specificitySort,\n} from '@vltpkg/dss-breadcrumb'\nimport { error } from '@vltpkg/error-cause'\nimport { Spec } from '@vltpkg/spec'\nimport { asManifest, assertRecordStringString } from '@vltpkg/types'\nimport { load } from '@vltpkg/vlt-json'\nimport type {\n ModifierBreadcrumb,\n ModifierInteractiveBreadcrumb,\n} from '@vltpkg/dss-breadcrumb'\nimport type { SpecOptions } from '@vltpkg/spec'\nimport type { Manifest } from '@vltpkg/types'\nimport type { Edge } from './edge.ts'\nimport type { Node } from './node.ts'\nimport type { Dependency } from './dependencies.ts'\n\n/**\n * Loaded modifiers configuration as described in the `vlt.json` file.\n */\nexport type GraphModifierLoadedConfig = {\n modifiers: GraphModifierConfigObject\n}\n\n/**\n * Type definition for the modifiers configuration object\n */\n// TODO: subtype string into a more specific type for Queries\nexport type GraphModifierConfigObject = Record<string, string>\n\n/**\n * Info needed to define a graph modifier.\n */\nexport type BaseModifierEntry = {\n type: 'edge' | 'node'\n query: string\n breadcrumb: ModifierBreadcrumb\n value: string | Manifest\n refs: Set<{\n name: string\n from: Node\n }>\n}\n\n/**\n * Extra info to define specifically a graph edge modifier.\n */\nexport type EdgeModifierEntry = BaseModifierEntry & {\n type: 'edge'\n spec: Spec\n value: string\n}\n\n/**\n * Extra info to define the graph node modifier.\n */\nexport type NodeModifierEntry = BaseModifierEntry & {\n type: 'node'\n manifest: Manifest\n}\n\n/**\n * A graph modifier entry, which can be either an edge or a node modifier.\n */\nexport type ModifierEntry = EdgeModifierEntry | NodeModifierEntry\n\n/**\n * An object to track modifiers that have matched an initial part of the\n * breadcrumb. It holds pointers to both nodes and edges matched in the\n * current traversed graph on top of the modifier info and the breadcrumb\n * state that is used to track the current state of the parsing.\n */\nexport type ModifierActiveEntry = {\n /**\n * The modifier this active entry is working with.\n */\n modifier: ModifierEntry\n /**\n * The breadcrumb that is used to track the current state of the parsing.\n */\n interactiveBreadcrumb: ModifierInteractiveBreadcrumb\n /**\n * The first node to be affected by this modifier.\n */\n originalFrom: Node\n /**\n * The original edge that is being replaced with this entry.\n */\n originalEdge?: Edge\n /**\n * The modified edge that is being used to replace the original edge.\n */\n modifiedEdge?: Edge\n}\n\n/**\n * Class representing loaded modifiers configuration for a project.\n *\n * Instances of this class can be used as a helper to modify the graph\n * during the graph build ideal traversal time.\n *\n * ```\n * const modifier = new GraphModifier(options)\n * modifier.load(options)\n * ```\n *\n * The `tryImporter` method can be used to register the initial importer\n * node along with any modifier that includes an importer selector, e.g:\n * `modifier.tryImporter(graph.mainImporter)`\n *\n * When traversing the graph, use the `tryNewDependency` method to check\n * if a given dependency name to the current traversed node has matching\n * registered modifiers, e.g:\n * `const entries = modifier.tryNewDependency(fromNode, depName)`\n *\n * Use `updateActiveEntry` to update a given active modifier entry state\n * with the current node of the graph being traversed. e.g:\n * ```\n * for (const entry of entries)\n * modifier.updateActiveEntry(fromNode, entry)\n * ```\n */\nexport class GraphModifier {\n /** The loaded modifiers configuration */\n #config?: GraphModifierConfigObject\n /** A set of all modifiers loaded from vlt.json */\n #modifiers = new Set<ModifierEntry>()\n /** A set of all edge modifiers loaded from vlt.json */\n #edgeModifiers = new Set<EdgeModifierEntry>()\n /** A set of all node modifiers loaded from vlt.json */\n #nodeModifiers = new Set<NodeModifierEntry>()\n /**\n * A map of initial entries, keyed by the name of the first breadcrumb\n * item to its modifier entry. Useful for checking for non-importer\n * starting breadcrumbs, e.g: `#a > #b`\n */\n #initialEntries = new Map<string, Set<ModifierEntry>>()\n /**\n * A multi-level map of active entries, keyed by:\n * - modifiers\n * - edge name\n * - from node\n * that allows for retrieving seen {@link ModifierActiveEntry} instances\n * in constant time.\n */\n #activeEntries = new Map<\n ModifierEntry,\n Map<string, Map<Node, ModifierActiveEntry>>\n >()\n /**\n * A set of currently active modifiers, which are being parsed.\n */\n activeModifiers = new Set<ModifierActiveEntry>()\n\n constructor(options: SpecOptions) {\n this.load(options)\n }\n\n /**\n * Load the modifiers definitions from vlt.json,\n * converting the result into a GraphModifierConfigObject\n */\n get config(): GraphModifierConfigObject {\n if (this.#config) return this.#config\n return (this.#config =\n load('modifiers', assertRecordStringString) ?? {})\n }\n\n /**\n * Loads the modifiers defined in `vlt.json` into memory.\n */\n load(options: SpecOptions) {\n for (const [key, value] of Object.entries(this.config)) {\n const breadcrumb = parseBreadcrumb(key)\n /* c8 ignore start - should not be possible */\n if (!breadcrumb.last.name) {\n throw error('Could not find name in breadcrumb', {\n found: key,\n })\n }\n /* c8 ignore stop */\n let mod: ModifierEntry\n if (typeof value === 'string') {\n mod = {\n breadcrumb,\n query: key,\n refs: new Set(),\n spec: Spec.parse(breadcrumb.last.name, value, options),\n type: 'edge',\n value,\n } satisfies EdgeModifierEntry\n this.#edgeModifiers.add(mod)\n /* c8 ignore start - TODO */\n } else {\n const manifest = asManifest(value)\n mod = {\n breadcrumb,\n query: key,\n manifest,\n refs: new Set(),\n type: 'node',\n value: manifest,\n } satisfies NodeModifierEntry\n this.#nodeModifiers.add(mod)\n }\n /* c8 ignore end */\n this.#modifiers.add(mod)\n // if the breadcrumb starts with an id, then add it to the\n // map of initial entries, so that we can use it to match\n if (breadcrumb.first.name) {\n const initialSet =\n this.#initialEntries.get(breadcrumb.first.name) ?? new Set()\n initialSet.add(mod)\n this.#initialEntries.set(breadcrumb.first.name, initialSet)\n }\n }\n }\n\n /**\n * Check if a given importer dependency name has potentially a registered\n * modifier. In case of an ambiguous modifier, the method will always\n * return `true`, it only returns `false` in the case that only fully\n * qualified modifiers are registered and none are targeting the given\n * top-level dependency name.\n *\n * This method is useful to help avoiding traversing the sub graph of\n * a direct dependency when we know that it's impossible to ever match\n * beforehand.\n */\n maybeHasModifier(depName: string): boolean {\n for (const mod of this.#modifiers) {\n const matchingName =\n mod.breadcrumb.first.importer &&\n mod.breadcrumb.first.next?.name === depName\n const rootlessBreadcrumb = !mod.breadcrumb.first.importer\n if (rootlessBreadcrumb || matchingName) {\n return true\n }\n }\n return false\n }\n\n /**\n * Try matching the provided node against the top-level selectors. In case\n * a match is found it will also register the active entry modifier and\n * update the active entry to the current importer node.\n */\n tryImporter(importer: Node) {\n for (const modifier of this.#modifiers) {\n // if the first item in the breadcrumb is an importer and it matches\n // any of the valid top-level selectors, then register the modifier\n const { first } = modifier.breadcrumb\n const matchRoot =\n first.value === ':root' && importer.mainImporter\n const matchWorkspace =\n first.value === ':workspace' && importer.importer\n const matchAny =\n first.value === ':project' || matchRoot || matchWorkspace\n if (first.importer && matchAny) {\n const active = this.newModifier(importer, modifier)\n const single = active.modifier.breadcrumb.single\n // only the importers will update the active entry right after\n // registering it since tryImporter doesn't try to match from\n // active dependencies\n if (!single) {\n this.updateActiveEntry(importer, active)\n }\n }\n }\n }\n\n /**\n * Try matching the provided node and dependency name to the current\n * active parsing modifier entries along with possible starting-level\n * modifiers.\n *\n * Any entries in which the breachcrumb have already reached its last\n * element will be prioritized, along with checking for specificity,\n * the complete entry with the highest specificity will be returned or just\n * the entry with the highest specificity if no complete entry is found.\n * Returns `undefined` if no matching entry is found.\n *\n * This method works with the assumption that it's going to be called\n * during a graph traversal, such that any ascendent has been checked\n * and the active modifier entry state has been updated in the previous\n * iteration.\n */\n tryNewDependency(\n from: Node,\n name: string,\n ): ModifierActiveEntry | undefined {\n // here we use a map instead of a set so that we can associate each\n // modifier active entry with its breadcrumb so that it's easier to\n // pick the correct entry when we sort breadcrbumbs by specificity\n const all = new Map<\n ModifierBreadcrumb | undefined,\n ModifierActiveEntry\n >()\n for (const modifier of this.#modifiers) {\n // if an active entry is found then returns that\n const entry = this.#activeEntries\n .get(modifier)\n ?.get(name)\n ?.get(from)\n if (entry) {\n all.set(entry.modifier.breadcrumb, entry)\n }\n }\n // matches the name against the initial entries, this will make it so\n // that modifier queries that start with a name (e.g: #a > #b) can\n // match at any point of the graph traversal\n const initialSet =\n this.#initialEntries.get(name) ?? new Set<ModifierEntry>()\n for (const initial of initialSet) {\n const initialEntry =\n /* c8 ignore next - difficult to test branch */\n this.#activeEntries.get(initial)?.get(name)?.get(from) ??\n this.newModifier(from, initial)\n all.set(initialEntry.modifier.breadcrumb, initialEntry)\n }\n // selects the active entry that should apply to this dependency,\n // any active entry that is done parsing has the priority, if we\n // find multiple entries then we use css specificity to pick a winner\n // if we have multiple matches but no active entry is complete, then\n // we pick the one with the highest specificity breadcrumb\n const arr = [...all.values()]\n const completeEntries = arr.filter(\n active =>\n active.interactiveBreadcrumb.current ===\n active.modifier.breadcrumb.last,\n )\n // deregister completed entries\n for (const entry of completeEntries) {\n this.deregisterModifier(entry.modifier)\n }\n // returns the highest specificity entry from either the complete entries\n // if any were found or from any of the entries if available, otherwise\n // it will return undefined as no entry is found in the `all` map\n const entries = completeEntries.length ? completeEntries : arr\n return all.get(\n specificitySort(entries.map(i => i.modifier.breadcrumb))[0],\n )\n }\n\n /**\n * Returns the set of {@link ModifierActiveEntry} instances that matches\n * the provided {@link Dependency} specs for a given node.\n *\n * This method is mostly a helper to {@link GraphModifier.tryNewDependency}\n * that handles the registered modifiers traversal lookup.\n */\n tryDependencies(\n from: Node,\n dependencies: Dependency[],\n ): Map<string, ModifierActiveEntry> {\n const modifierRefs = new Map<string, ModifierActiveEntry>()\n for (const { spec } of dependencies) {\n const active = this.tryNewDependency(from, spec.name)\n if (active) {\n modifierRefs.set(spec.name, active)\n }\n }\n return modifierRefs\n }\n\n /**\n * Updates an active entry state keeping track of items in the multi-level\n * active entries map. If the current breadcrumb state shows there's no more\n * items left, then we deregister the modifier.\n */\n updateActiveEntry(from: Node, active: ModifierActiveEntry): void {\n const { modifier } = active\n const interactiveBreadcrumb = active.interactiveBreadcrumb.next()\n const name = interactiveBreadcrumb.current?.name\n\n // if there's no name, or we're done parsing then we\n // deregister the modifier instead of updating the entry\n if (interactiveBreadcrumb.done || !name) {\n this.deregisterModifier(modifier)\n return\n }\n\n // register the active modifier\n this.activeModifiers.add(active)\n active.modifier.refs.add({ from, name })\n\n // optionally read or create the nested maps\n const nameMap =\n this.#activeEntries.get(modifier) ??\n new Map<string, Map<Node, ModifierActiveEntry>>()\n this.#activeEntries.set(modifier, nameMap)\n const nodeMap =\n nameMap.get(name) ?? new Map<Node, ModifierActiveEntry>()\n nameMap.set(name, nodeMap)\n\n // sets the active entry in the map\n nodeMap.set(from, active)\n }\n\n /**\n * Creates a new active modifier.\n */\n newModifier(\n from: Node,\n modifier: ModifierEntry,\n ): ModifierActiveEntry {\n return {\n modifier,\n interactiveBreadcrumb: modifier.breadcrumb.interactive(),\n originalFrom: from,\n }\n }\n\n /**\n * Removes a previously registered modifier from the active entries.\n */\n deregisterModifier(modifier: ModifierEntry): void {\n for (const { from, name } of modifier.refs) {\n const nodeMap = this.#activeEntries.get(modifier)?.get(name)\n if (nodeMap) {\n // if an entry is found, we remove it from the active set\n const entry = nodeMap.get(from)\n if (entry) {\n this.activeModifiers.delete(entry)\n }\n // then we remove the entry from the map\n nodeMap.delete(from)\n // if the map is empty, we remove it from the active entries map\n if (!nodeMap.size) {\n this.#activeEntries.get(modifier)?.delete(name)\n }\n }\n }\n }\n\n /**\n * Operates in previously registered nodes and edges in order to put\n * back in place any of the original edges that were referenced to in\n * active (ongoing) breadcrumb parsing entries that were never completed.\n *\n * This method can be used to easily rollback any pending operations\n * once the graph traversal is done.\n */\n rollbackActiveEntries(): void {\n for (const modifier of this.activeModifiers) {\n // if the modifier has an original edge, we can put it back in place\n if (modifier.originalEdge) {\n modifier.originalFrom.edgesOut.set(\n modifier.originalEdge.spec.name,\n modifier.originalEdge,\n )\n }\n // then we deregister the modifier\n this.deregisterModifier(modifier.modifier)\n }\n }\n\n /**\n * Convenience method to instantiate and load in one call.\n * Returns undefined if the project does not have a vlt.json file,\n * otherwise returns the loaded Modifiers instance.\n */\n static maybeLoad(options: SpecOptions) {\n const config = load('modifiers', assertRecordStringString)\n if (!config) return\n return new GraphModifier(options)\n }\n\n /**\n * Convenience method to instantiate and load in one call.\n * Throws if called on a directory that does not have a vlt.json file.\n */\n static load(options: SpecOptions) {\n return new GraphModifier(options)\n }\n}\n"]}
@@ -81,6 +81,12 @@ export declare class Node implements NodeLike {
81
81
  * the same registry, if it's not the default.
82
82
  */
83
83
  registry?: string;
84
+ /**
85
+ * If this node has been modified as part of applying a {@link GraphModifier}
86
+ * then this field will contain the modifier query that was applied.
87
+ * Otherwise, it will be `undefined`.
88
+ */
89
+ modifier: string | undefined;
84
90
  get name(): string;
85
91
  /**
86
92
  * The version of the package represented by this node, this is usually
@@ -157,6 +163,7 @@ export declare class Node implements NodeLike {
157
163
  dev: boolean;
158
164
  optional: boolean;
159
165
  confused: boolean;
166
+ modifier: string | undefined;
160
167
  };
161
168
  toString(): string;
162
169
  }
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/node.ts"],"names":[],"mappings":"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"}
package/dist/esm/node.js CHANGED
@@ -105,6 +105,12 @@ export class Node {
105
105
  * the same registry, if it's not the default.
106
106
  */
107
107
  registry;
108
+ /**
109
+ * If this node has been modified as part of applying a {@link GraphModifier}
110
+ * then this field will contain the modifier query that was applied.
111
+ * Otherwise, it will be `undefined`.
112
+ */
113
+ modifier;
108
114
  /**
109
115
  * The name of the package represented by this node, this is usually
110
116
  * equivalent to `manifest.name` but in a few ways it may differ such as
@@ -294,6 +300,7 @@ export class Node {
294
300
  dev: this.dev,
295
301
  optional: this.optional,
296
302
  confused: this.confused,
303
+ modifier: this.modifier,
297
304
  ...(this.confused ?
298
305
  { rawManifest: this.#rawManifest }
299
306
  : undefined),