@atlaspack/bundler-experimental 2.12.1-canary.3624 → 2.12.1-canary.3626

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.
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.EdgeContentGraph = void 0;
7
+ function _graph() {
8
+ const data = require("@atlaspack/graph");
9
+ _graph = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _nullthrows() {
15
+ const data = _interopRequireDefault(require("nullthrows"));
16
+ _nullthrows = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
+ /**
23
+ * A `ContentGraph` that also stores weights on edges.
24
+ *
25
+ * @template N The type of the node weight.
26
+ * @template EW The type of the edge weight.
27
+ */
28
+ class EdgeContentGraph extends _graph().ContentGraph {
29
+ #edgeWeights = new Map();
30
+ clone() {
31
+ const newGraph = new EdgeContentGraph();
32
+ let nodeId = 0;
33
+ for (let node of this.nodes) {
34
+ const contentKey = this._nodeIdToContentKey.get(nodeId);
35
+ if (node == null) {
36
+ // Add null node to preserve node ids
37
+ // $FlowFixMe
38
+ newGraph.addNode(null);
39
+ } else if (contentKey == null) {
40
+ newGraph.addNode(node);
41
+ } else {
42
+ newGraph.addNodeByContentKey(contentKey, node);
43
+ }
44
+ nodeId += 1;
45
+ }
46
+ for (let edge of this.getAllEdges()) {
47
+ const weight = this.getEdgeWeight(edge.from, edge.to);
48
+ newGraph.addWeightedEdge(edge.from, edge.to, edge.type, weight);
49
+ }
50
+ if (this.rootNodeId != null) {
51
+ const rootNodeContentKey = this._nodeIdToContentKey.get(this.rootNodeId);
52
+ const newGraphRootNodeId = newGraph.getNodeIdByContentKey((0, _nullthrows().default)(rootNodeContentKey));
53
+ newGraph.setRootNodeId(newGraphRootNodeId);
54
+ }
55
+ return newGraph;
56
+ }
57
+ addWeightedEdge(from, to, type, weight) {
58
+ this.addEdge(from, to, type);
59
+ if (weight != null) {
60
+ this.#edgeWeights.set([String(from), String(to)].join(','), weight);
61
+ }
62
+ }
63
+ getEdgeWeight(from, to) {
64
+ return this.#edgeWeights.get([String(from), String(to)].join(',')) ?? null;
65
+ }
66
+ }
67
+ exports.EdgeContentGraph = EdgeContentGraph;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/bundler-experimental",
3
- "version": "2.12.1-canary.3624+888b09f09",
3
+ "version": "2.12.1-canary.3626+da1500b0a",
4
4
  "license": "(MIT OR Apache-2.0)",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,19 +16,19 @@
16
16
  "parcel": "^2.12.0"
17
17
  },
18
18
  "dependencies": {
19
- "@atlaspack/core": "2.12.1-canary.3624+888b09f09",
20
- "@atlaspack/diagnostic": "2.12.1-canary.3624+888b09f09",
21
- "@atlaspack/feature-flags": "2.12.1-canary.3624+888b09f09",
22
- "@atlaspack/graph": "3.2.1-canary.3624+888b09f09",
23
- "@atlaspack/logger": "2.12.1-canary.3624+888b09f09",
24
- "@atlaspack/plugin": "2.12.1-canary.3624+888b09f09",
25
- "@atlaspack/rust": "2.12.1-canary.3624+888b09f09",
26
- "@atlaspack/types": "2.12.1-canary.3624+888b09f09",
27
- "@atlaspack/utils": "2.12.1-canary.3624+888b09f09",
19
+ "@atlaspack/core": "2.12.1-canary.3626+da1500b0a",
20
+ "@atlaspack/diagnostic": "2.12.1-canary.3626+da1500b0a",
21
+ "@atlaspack/feature-flags": "2.12.1-canary.3626+da1500b0a",
22
+ "@atlaspack/graph": "3.2.1-canary.3626+da1500b0a",
23
+ "@atlaspack/logger": "2.12.1-canary.3626+da1500b0a",
24
+ "@atlaspack/plugin": "2.12.1-canary.3626+da1500b0a",
25
+ "@atlaspack/rust": "2.12.1-canary.3626+da1500b0a",
26
+ "@atlaspack/types": "2.12.1-canary.3626+da1500b0a",
27
+ "@atlaspack/utils": "2.12.1-canary.3626+da1500b0a",
28
28
  "nullthrows": "^1.1.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@atlaspack/fs": "2.12.1-canary.3624+888b09f09"
31
+ "@atlaspack/fs": "2.12.1-canary.3626+da1500b0a"
32
32
  },
33
- "gitHead": "888b09f09be9a7e0ef6e6416a9a85d19c59fc8bc"
33
+ "gitHead": "da1500b0afb03ecb698c26d71ee0f75a644312aa"
34
34
  }
@@ -0,0 +1,62 @@
1
+ // @flow strict-local
2
+
3
+ import {ContentGraph, type NodeId} from '@atlaspack/graph';
4
+ import nullthrows from 'nullthrows';
5
+
6
+ /**
7
+ * A `ContentGraph` that also stores weights on edges.
8
+ *
9
+ * @template N The type of the node weight.
10
+ * @template EW The type of the edge weight.
11
+ */
12
+ export class EdgeContentGraph<N, EW> extends ContentGraph<N, number> {
13
+ #edgeWeights: Map<string, EW> = new Map();
14
+
15
+ clone(): EdgeContentGraph<N, EW> {
16
+ const newGraph: EdgeContentGraph<N, EW> = new EdgeContentGraph();
17
+ let nodeId = 0;
18
+ for (let node of this.nodes) {
19
+ const contentKey = this._nodeIdToContentKey.get(nodeId);
20
+ if (node == null) {
21
+ // Add null node to preserve node ids
22
+ // $FlowFixMe
23
+ newGraph.addNode(null);
24
+ } else if (contentKey == null) {
25
+ newGraph.addNode(node);
26
+ } else {
27
+ newGraph.addNodeByContentKey(contentKey, node);
28
+ }
29
+ nodeId += 1;
30
+ }
31
+ for (let edge of this.getAllEdges()) {
32
+ const weight = this.getEdgeWeight(edge.from, edge.to);
33
+ newGraph.addWeightedEdge(edge.from, edge.to, edge.type, weight);
34
+ }
35
+
36
+ if (this.rootNodeId != null) {
37
+ const rootNodeContentKey = this._nodeIdToContentKey.get(this.rootNodeId);
38
+ const newGraphRootNodeId = newGraph.getNodeIdByContentKey(
39
+ nullthrows(rootNodeContentKey),
40
+ );
41
+ newGraph.setRootNodeId(newGraphRootNodeId);
42
+ }
43
+
44
+ return newGraph;
45
+ }
46
+
47
+ addWeightedEdge(
48
+ from: NodeId,
49
+ to: NodeId,
50
+ type: number,
51
+ weight: EW | null,
52
+ ): void {
53
+ this.addEdge(from, to, type);
54
+ if (weight != null) {
55
+ this.#edgeWeights.set([String(from), String(to)].join(','), weight);
56
+ }
57
+ }
58
+
59
+ getEdgeWeight(from: NodeId, to: NodeId): EW | null {
60
+ return this.#edgeWeights.get([String(from), String(to)].join(',')) ?? null;
61
+ }
62
+ }
@@ -0,0 +1,58 @@
1
+ // @flow strict-local
2
+
3
+ import assert from 'assert';
4
+ import {EdgeContentGraph} from '../../src/DominatorBundler/EdgeContentGraph';
5
+
6
+ describe('EdgeContentGraph', () => {
7
+ describe('addWeightedEdge', () => {
8
+ it('creates an edge between two nodes', () => {
9
+ const graph = new EdgeContentGraph<string, number>();
10
+ const a = graph.addNode('a');
11
+ const b = graph.addNode('b');
12
+ const edgeType = 1;
13
+ const weight = 10;
14
+ graph.addWeightedEdge(a, b, edgeType, weight);
15
+ const ids = graph.getNodeIdsConnectedFrom(a);
16
+ assert.deepEqual(ids, [b]);
17
+ });
18
+
19
+ it('should add and get edge weights', () => {
20
+ const graph = new EdgeContentGraph<string, number>();
21
+ const a = graph.addNode('a');
22
+ const b = graph.addNode('b');
23
+ const c = graph.addNode('b');
24
+
25
+ const edgeType = 1;
26
+ const weight1 = 10;
27
+ const weight2 = 20;
28
+
29
+ graph.addWeightedEdge(a, b, edgeType, weight1);
30
+ graph.addWeightedEdge(b, c, edgeType, weight2);
31
+
32
+ assert.equal(graph.getEdgeWeight(a, b), weight1);
33
+ assert.equal(graph.getEdgeWeight(b, c), weight2);
34
+ });
35
+ });
36
+
37
+ describe('clone', () => {
38
+ it('clones the graph', () => {
39
+ const graph = new EdgeContentGraph<string, number>();
40
+ const a = graph.addNode('a');
41
+ const b = graph.addNode('b');
42
+ const c = graph.addNode('c');
43
+
44
+ const edgeType = 1;
45
+ const weight1 = 10;
46
+ const weight2 = 20;
47
+
48
+ graph.addWeightedEdge(a, b, edgeType, weight1);
49
+ graph.addWeightedEdge(b, c, edgeType, weight2);
50
+
51
+ const clonedGraph = graph.clone();
52
+ assert.deepEqual(clonedGraph.nodes, graph.nodes);
53
+ assert.deepEqual(clonedGraph.getAllEdges(), graph.getAllEdges());
54
+ assert.equal(clonedGraph.getEdgeWeight(a, b), weight1);
55
+ assert.equal(clonedGraph.getEdgeWeight(b, c), weight2);
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,190 @@
1
+ // @flow strict-local
2
+
3
+ /*!
4
+ * This module provides a way to write fixtures where we don't care about the
5
+ * code within the assets; only the shape of the asset graphs.
6
+ */
7
+ import type {FileSystem} from '@atlaspack/fs';
8
+ import path from 'path';
9
+
10
+ /**
11
+ * A node in the fixture graph
12
+ */
13
+ export type GraphEntry = AssetEntry;
14
+
15
+ /**
16
+ * An asset in the fixture graph. Just a path and dependencies
17
+ */
18
+ export type AssetEntry = {|
19
+ type: 'asset',
20
+ value: {|
21
+ filePath: string,
22
+ dependencies: DependencyEntry[],
23
+ |},
24
+ |};
25
+
26
+ /**
27
+ * Sync or async dependency between assets
28
+ */
29
+ export type DependencyEntry = {|
30
+ type: 'dependency',
31
+ value: {|
32
+ from: string,
33
+ to: string,
34
+ type: 'sync' | 'async',
35
+ |},
36
+ |};
37
+
38
+ export type DependencySpec = {|
39
+ to: string,
40
+ type: 'sync' | 'async',
41
+ |};
42
+
43
+ /**
44
+ * Create an asset node in the fixture graph
45
+ */
46
+ export function asset(
47
+ path: string,
48
+ dependencies?: (string | DependencySpec)[],
49
+ ): GraphEntry {
50
+ return {
51
+ type: 'asset',
52
+ value: {
53
+ filePath: path,
54
+ dependencies:
55
+ dependencies?.map((dependency) => {
56
+ if (typeof dependency === 'string') {
57
+ return {
58
+ type: 'dependency',
59
+ value: {
60
+ from: path,
61
+ to: dependency,
62
+ type: 'sync',
63
+ },
64
+ };
65
+ } else {
66
+ return {
67
+ type: 'dependency',
68
+ value: {
69
+ from: path,
70
+ to: dependency.to,
71
+ type: dependency.type,
72
+ },
73
+ };
74
+ }
75
+ }) ?? [],
76
+ },
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Create the files for a fixture graph over the `fs` filesystem.
82
+ */
83
+ export async function fixtureFromGraph(
84
+ dirname: string,
85
+ fs: FileSystem,
86
+ entries: GraphEntry[],
87
+ ): Promise<string> {
88
+ await fs.mkdirp(dirname);
89
+
90
+ for (let entry of entries) {
91
+ if (entry.type === 'asset') {
92
+ const dependencies = entry.value.dependencies ?? [];
93
+ const symbols = dependencies
94
+ .filter((d) => d.value.type === 'sync')
95
+ .map((_, i) => `d${i}`);
96
+ const asyncDependencies = dependencies
97
+ .filter((d) => d.value.type === 'async')
98
+ .map((d) => `import('./${d.value.to}')`);
99
+ const contents = [
100
+ ...dependencies
101
+ .filter((d) => {
102
+ return d.value.type === 'sync';
103
+ })
104
+ .map((dependency, i) => {
105
+ return `import ${symbols[i]} from './${dependency.value.to}';`;
106
+ }),
107
+ `export default function run() { return [${[
108
+ ...symbols,
109
+ ...asyncDependencies,
110
+ ].join(', ')}] }`,
111
+ ].join('\n');
112
+
113
+ await fs.writeFile(path.join(dirname, entry.value.filePath), contents);
114
+ }
115
+ }
116
+
117
+ return dotFromGraph(entries);
118
+ }
119
+
120
+ /**
121
+ * Create a graphviz dot string from a fixture graph
122
+ *
123
+ * The contents of the GraphViz file will contain (in this order):
124
+ *
125
+ * * the list of all asset nodes
126
+ * * the dependencies between assets
127
+ *
128
+ * Given a graph build with:
129
+ *
130
+ * ```
131
+ * fixtureFromGraph('dir', fs, [
132
+ * asset('a.js', ['b.js', 'c.js']),
133
+ * asset('b.js', ['d.js']),
134
+ * asset('d.js'),
135
+ * ])
136
+ * ```
137
+ *
138
+ * The output will be:
139
+ * ```
140
+ * digraph assets {
141
+ * labelloc="t";
142
+ * label="Assets";
143
+ *
144
+ * "a.js";
145
+ * "b.js";
146
+ * "c.js";
147
+ * "d.js";
148
+ *
149
+ * "a.js" -> "b.js";
150
+ * "a.js" -> "c.js";
151
+ * "b.js" -> "d.js";
152
+ * }
153
+ * ```
154
+ *
155
+ * That is:
156
+ *
157
+ * * iterate all nodes and declare them
158
+ * * iterate all dependencies between nodes and declare them
159
+ *
160
+ */
161
+ export function dotFromGraph(entries: GraphEntry[]): string {
162
+ const contents = [];
163
+
164
+ for (let entry of entries) {
165
+ if (entry.type === 'asset') {
166
+ const asset = entry.value;
167
+ contents.push(`"${asset.filePath}";`);
168
+ }
169
+ }
170
+
171
+ contents.push('');
172
+
173
+ for (let entry of entries) {
174
+ if (entry.type === 'asset') {
175
+ const asset = entry.value;
176
+ for (let dependency of entry.value.dependencies) {
177
+ contents.push(`"${asset.filePath}" -> "${dependency.value.to}";`);
178
+ }
179
+ }
180
+ }
181
+
182
+ return `
183
+ digraph assets {
184
+ labelloc="t";
185
+ label="Assets";
186
+
187
+ ${contents.map((line) => (line.length > 0 ? ` ${line}` : '')).join('\n')}
188
+ }
189
+ `.trim();
190
+ }
@@ -0,0 +1,106 @@
1
+ // @flow strict-local
2
+
3
+ import {MemoryFS} from '@atlaspack/fs';
4
+ import assert from 'assert';
5
+ import {workerFarm} from '@atlaspack/test-utils';
6
+ import {asset, fixtureFromGraph, dotFromGraph} from './fixtureFromGraph';
7
+
8
+ describe('fixtureFromGraph', () => {
9
+ before(async function () {
10
+ this.timeout(10000);
11
+ // Warm up worker farm so that the first test doesn't account for this time.
12
+ await workerFarm.callAllWorkers('ping', []);
13
+ });
14
+
15
+ it('can create fixtures for single files', async () => {
16
+ const fs = new MemoryFS(workerFarm);
17
+ await fixtureFromGraph('dir', fs, [
18
+ asset('file1.js'),
19
+ asset('file2.js'),
20
+ asset('file3.js'),
21
+ ]);
22
+
23
+ assert.deepEqual(await fs.readdir('dir'), [
24
+ 'file1.js',
25
+ 'file2.js',
26
+ 'file3.js',
27
+ ]);
28
+ assert.equal(
29
+ await fs.readFile('dir/file1.js', 'utf8'),
30
+ 'export default function run() { return [] }',
31
+ );
32
+ });
33
+
34
+ it('will create files with imports between themselves', async () => {
35
+ const fs = new MemoryFS(workerFarm);
36
+ await fixtureFromGraph('dir', fs, [
37
+ asset('file1.js', ['file2.js', 'file3.js']),
38
+ asset('file2.js'),
39
+ asset('file3.js'),
40
+ ]);
41
+
42
+ assert.deepEqual(await fs.readdir('dir'), [
43
+ 'file1.js',
44
+ 'file2.js',
45
+ 'file3.js',
46
+ ]);
47
+ assert.equal(
48
+ await fs.readFile('dir/file1.js', 'utf8'),
49
+ `
50
+ import d0 from './file2.js';
51
+ import d1 from './file3.js';
52
+ export default function run() { return [d0, d1] }
53
+ `.trim(),
54
+ );
55
+ });
56
+
57
+ it('will create files with async imports between themselves', async () => {
58
+ const fs = new MemoryFS(workerFarm);
59
+ await fixtureFromGraph('dir', fs, [
60
+ asset('file1.js', ['file2.js', {to: 'file3.js', type: 'async'}]),
61
+ asset('file2.js'),
62
+ asset('file3.js'),
63
+ ]);
64
+
65
+ assert.deepEqual(await fs.readdir('dir'), [
66
+ 'file1.js',
67
+ 'file2.js',
68
+ 'file3.js',
69
+ ]);
70
+ assert.equal(
71
+ await fs.readFile('dir/file1.js', 'utf8'),
72
+ `
73
+ import d0 from './file2.js';
74
+ export default function run() { return [d0, import('./file3.js')] }
75
+ `.trim(),
76
+ );
77
+ });
78
+
79
+ describe('dotFromGraph', () => {
80
+ it('creates a dot string from a graph', () => {
81
+ const graph = [
82
+ asset('file1.js', ['file2.js', 'file3.js']),
83
+ asset('file2.js'),
84
+ asset('file3.js'),
85
+ ];
86
+ const dot = dotFromGraph(graph);
87
+
88
+ assert.equal(
89
+ dot,
90
+ `
91
+ digraph assets {
92
+ labelloc="t";
93
+ label="Assets";
94
+
95
+ "file1.js";
96
+ "file2.js";
97
+ "file3.js";
98
+
99
+ "file1.js" -> "file2.js";
100
+ "file1.js" -> "file3.js";
101
+ }
102
+ `.trim(),
103
+ );
104
+ });
105
+ });
106
+ });