Skip to content
This repository was archived by the owner on Jun 24, 2024. It is now read-only.

Commit 0012a0a

Browse files
author
Walker
committed
Add writer implementation and tests
1 parent 379916c commit 0012a0a

File tree

10 files changed

+229
-0
lines changed

10 files changed

+229
-0
lines changed

lib/util.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const { promisify } = require('util');
5+
const fs = require('fs');
6+
const readFile = promisify(fs.readFile);
7+
const { hasher } = require('asset-pipe-common');
8+
const readPkgUp = require('read-pkg-up');
9+
const postcss = require('postcss');
10+
const atImport = require('postcss-import');
11+
12+
module.exports.identifyCssModule = function identifyCssModule (filePath) {
13+
return readPkgUp({
14+
normalize: false,
15+
cwd: path.dirname(filePath),
16+
}).then(result => {
17+
const { name, version } = result.pkg;
18+
const ref = filePath.replace(path.dirname(result.path), name);
19+
20+
return {
21+
id: hasher(`${name}|${version}|${ref}`),
22+
name,
23+
version,
24+
file: ref,
25+
};
26+
});
27+
};
28+
29+
module.exports.bundleCssModule = function bundleCssModule (filePath) {
30+
return readFile(filePath, 'utf8').then(css =>
31+
postcss()
32+
.use(atImport())
33+
.process(css, {
34+
from: filePath,
35+
})
36+
.then(({ css }) => css)
37+
);
38+
};

lib/writer.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
const { Readable } = require('stream');
4+
const { identifyCssModule, bundleCssModule } = require('./util');
5+
const { existsSync } = require('fs');
6+
const assert = require('assert');
7+
8+
module.exports = class Writer extends Readable {
9+
constructor (files = []) {
10+
assert(Array.isArray(files), `Expected 'files' to be of type 'Array', instead got '${typeof files}'`);
11+
for (const file of files) {
12+
assert(typeof file === 'string', `Expected 'file' (${file}) to be of type 'string', instead got '${typeof file}'`);
13+
assert(existsSync(file), `Expected 'file' (${file}) to exist on file system but it did not`);
14+
}
15+
16+
super({ objectMode: true });
17+
this.files = files;
18+
}
19+
20+
_read () {
21+
const file = this.files.shift();
22+
if (!file) {
23+
this.push(null);
24+
return;
25+
}
26+
Promise.all([bundleCssModule(file), identifyCssModule(file)])
27+
.then(([css, meta]) => {
28+
meta.content = css;
29+
this.push(meta);
30+
})
31+
.catch(err => {
32+
process.nextTick(() => this.emit('error', err));
33+
});
34+
}
35+
};

test/test-assets/my-module-1/main.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* my-module-1/main.css */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "my-module-1",
3+
"version": "1.0.1"
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* my-module-2/main.css */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "my-module-2",
3+
"version": "1.0.1"
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* my-module-3/dep.css */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* my-module-3/main.css */
2+
3+
@import url('./dep.css');
4+
@import url('dep/main.css');
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "my-module-3",
3+
"version": "1.0.1"
4+
}

test/writer.test.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const { hasher } = require('asset-pipe-common');
5+
const { identifyCssModule, bundleCssModule } = require('../lib/util.js');
6+
const Writer = require('..');
7+
8+
test('identifyCssModule(filePath)', async () => {
9+
const filePath = path.join(__dirname, 'test-assets/my-module-1/main.css');
10+
const fileRef = 'my-module-1/main.css';
11+
12+
const result = await identifyCssModule(filePath);
13+
14+
const identifier = {
15+
id: hasher(`my-module-1|1.0.1|${fileRef}`),
16+
name: 'my-module-1',
17+
version: '1.0.1',
18+
file: fileRef
19+
};
20+
expect(result).toEqual(identifier);
21+
});
22+
23+
test('identifyCssModule(filePath) css in nested directory', async () => {
24+
const filePath = path.join(__dirname, 'test-assets/my-module-2/css/main.css');
25+
const fileRef = 'my-module-2/css/main.css';
26+
27+
const result = await identifyCssModule(filePath);
28+
29+
const identifier = {
30+
id: hasher(`my-module-2|1.0.1|${fileRef}`),
31+
name: 'my-module-2',
32+
version: '1.0.1',
33+
file: fileRef
34+
};
35+
expect(result).toEqual(identifier);
36+
});
37+
38+
test('bundleCssModule(filePath)', async () => {
39+
const filePath = path.join(__dirname, 'test-assets/my-module-3/css/main.css');
40+
41+
const result = await bundleCssModule(filePath);
42+
43+
expect(result).toMatch('my-module-3/main.css');
44+
expect(result).toMatch('my-module-3/dep.css');
45+
expect(result).toMatch('dep/main.css');
46+
});
47+
48+
test('new Writer([filePath])', () => {
49+
const filePath = path.join(__dirname, 'test-assets/my-module-1/main.css');
50+
const fileRef = 'my-module-1/main.css';
51+
52+
const writer = new Writer([filePath]);
53+
const items = [];
54+
55+
writer.on('data', item => {
56+
items.push(item);
57+
});
58+
59+
writer.on('end', () => {
60+
const result1 = items[0];
61+
const result2 = items[1];
62+
63+
expect(result1.id).toBe(hasher(`my-module-1|1.0.1|${fileRef}`));
64+
expect(result2).toBeFalsy();
65+
});
66+
});
67+
68+
test('Writer processes @import statements', () => {
69+
const filePath = path.join(__dirname, 'test-assets/my-module-3/css/main.css');
70+
const fileRef = 'my-module-3/css/main.css';
71+
72+
const writer = new Writer([filePath]);
73+
const items = [];
74+
75+
writer.on('data', item => {
76+
items.push(item);
77+
});
78+
79+
writer.on('end', () => {
80+
const result1 = items[0];
81+
const result2 = items[1];
82+
83+
expect(result1.id).toBe(hasher(`my-module-3|1.0.1|${fileRef}`));
84+
expect(result1.content).toMatch('my-module-3/main.css');
85+
expect(result1.content).toMatch('my-module-3/dep.css');
86+
expect(result1.content).toMatch('dep/main.css');
87+
expect(result2).toBeFalsy();
88+
});
89+
});
90+
91+
test('new Writer([filePath1, filePath2]) ensures correct order', () => {
92+
const filePath1 = path.join(__dirname, 'test-assets/my-module-1/main.css');
93+
const fileRef1 = 'my-module-1/main.css';
94+
const filePath2 = path.join(__dirname, 'test-assets/my-module-2/css/main.css');
95+
const fileRef2 = 'my-module-2/css/main.css';
96+
97+
const writer = new Writer([filePath1, filePath2]);
98+
const items = [];
99+
100+
writer.on('data', item => {
101+
items.push(item);
102+
});
103+
104+
writer.on('end', () => {
105+
const result1 = items[0];
106+
const result2 = items[1];
107+
const result3 = items[2];
108+
109+
expect(result1.id).toBe(hasher(`my-module-1|1.0.1|${fileRef1}`));
110+
expect(result2.id).toBe(hasher(`my-module-2|1.0.1|${fileRef2}`));
111+
expect(result3).toBeFalsy();
112+
});
113+
});
114+
115+
test('new Writer([filePath]) ensures filePath[] is an array', () => {
116+
const filePath = null;
117+
118+
const result = () => new Writer(filePath);
119+
120+
expect(result).toThrow();
121+
});
122+
123+
test('new Writer([filePath]) ensures filePath[] is an array of strings', () => {
124+
const filePath = null;
125+
126+
const result = () => new Writer([filePath]);
127+
128+
expect(result).toThrow();
129+
});
130+
131+
test('new Writer([filePath]) ensures valid filePaths provided', () => {
132+
const filePath = 'fake.css';
133+
134+
const result = () => new Writer([filePath]);
135+
136+
expect(result).toThrow();
137+
});

0 commit comments

Comments
 (0)