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

Commit 63da282

Browse files
authored
Merge pull request #9 from asset-pipe/unstream
refactor: Refactor to remove streams and match js reader api changes
2 parents d6a07f0 + 75a82a9 commit 63da282

File tree

8 files changed

+1784
-1484
lines changed

8 files changed

+1784
-1484
lines changed

.eslintrc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
{
22
"root": true,
3-
"extends": [
4-
"finn",
5-
"finn/node",
6-
"finn-prettier"
7-
],
3+
"extends": ["finn", "finn/node", "finn-prettier"],
84
"parserOptions": {
9-
"ecmaVersion": 2017
5+
"ecmaVersion": 2017,
6+
"ecmaFeatures": {
7+
"experimentalObjectRestSpread": true
8+
}
109
},
1110
"env": {
1211
"node": true,
1312
"jest": true
1413
}
15-
}
14+
}

README.md

Lines changed: 18 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
<!-- TITLE/ -->
22

3-
<h1>asset-pipe-css-reader</h1>
3+
<h1>@asset-pipe/css-reader</h1>
44

55
<!-- /TITLE -->
66

77

88
<!-- BADGES/ -->
99

1010
<span class="badge-travisci"><a href="http://travis-ci.org/asset-pipe/asset-pipe-css-reader" title="Check this project's build status on TravisCI"><img src="https://img.shields.io/travis/asset-pipe/asset-pipe-css-reader/master.svg" alt="Travis CI Build Status" /></a></span>
11-
<span class="badge-npmversion"><a href="https://npmjs.org/package/asset-pipe-css-reader" title="View this project on NPM"><img src="https://img.shields.io/npm/v/asset-pipe-css-reader.svg" alt="NPM version" /></a></span>
11+
<span class="badge-npmversion"><a href="https://npmjs.org/package/@asset-pipe/css-reader" title="View this project on NPM"><img src="https://img.shields.io/npm/v/@asset-pipe/css-reader.svg" alt="NPM version" /></a></span>
1212
<span class="badge-daviddm"><a href="https://david-dm.org/asset-pipe/asset-pipe-css-reader" title="View the status of this project's dependencies on DavidDM"><img src="https://img.shields.io/david/asset-pipe/asset-pipe-css-reader.svg" alt="Dependency Status" /></a></span>
1313
<span class="badge-daviddmdev"><a href="https://david-dm.org/asset-pipe/asset-pipe-css-reader#info=devDependencies" title="View the status of this project's development dependencies on DavidDM"><img src="https://img.shields.io/david/dev/asset-pipe/asset-pipe-css-reader.svg" alt="Dev Dependency Status" /></a></span>
1414

1515
<!-- /BADGES -->
1616

1717

18-
A module that takes any number of css feed streams (provided by asset-pipe sinks) and bundles them into a readable stream of css content.
18+
[![Greenkeeper badge](https://badges.greenkeeper.io/asset-pipe/asset-pipe-css-reader.svg)](https://greenkeeper.io/)
19+
20+
A module that takes any number of css feeds and bundles them into a css bundle.
1921

2022
This is an internal module intended for use by other modules in the [asset-pipe project](https://github.com/asset-pipe).
2123

2224
## Overview
2325

24-
[![Greenkeeper badge](https://badges.greenkeeper.io/asset-pipe/asset-pipe-css-reader.svg)](https://greenkeeper.io/)
25-
26-
Given any number of css feed streams, the reader will:
27-
1. Merge streams into a single stream
26+
Given any number of css feeds, the reader will:
27+
1. Merge feeds into a single feed
2828
2. Dedupe any items with identical id hashes keeping the last occurrence
29-
3. Ensure order of streams given is preserved for the final output CSS
29+
3. Ensure order of feeds given is preserved for the final output CSS
3030

3131
### Input data format
3232

@@ -50,135 +50,42 @@ The following is an example of a feed file:
5050
## Installation
5151

5252
```bash
53-
npm install asset-pipe-css-reader
53+
npm install @asset-pipe/css-reader
5454
```
5555

5656
## Usage
5757

5858
### Require the reader
5959
```js
60-
const CssReader = require('asset-pipe-css-reader')
60+
const cssReader = require('@asset-pipe/css-reader')
6161
```
6262

6363
### Instantiating the reader
6464

65-
Either pass a single stream created by an asset-pipe sink:
66-
```js
67-
const sink = new SinkFs({
68-
path: '/path/to/css/feeds'
69-
});
70-
const feedStream = sink.reader('feed-a.json');
71-
const reader = new CssReader(feedStream)
72-
```
73-
74-
Or pass an array of streams:
65+
Pass feeds created by an asset-pipe sink:
7566
```js
7667
const sink = new SinkFs({
7768
path: '/path/to/css/feeds'
7869
});
79-
const feedStream1 = sink.reader('feed-a.json');
80-
const feedStream2 = sink.reader('feed-b.json');
81-
const reader = new CssReader([feedStream1, feedStream2])
82-
```
83-
84-
### Consuming content from the reader
85-
86-
You should wait for the reader to become ready by listening for the `pipeline ready` event.
87-
88-
The reader is a readable stream so in order to access the data you may register a data handler
89-
and listen for chunks to be passed to the handler:
90-
```js
91-
reader.on('pipeline ready', () => {
92-
reader.on('data', data => {
93-
// ..
94-
})
95-
})
96-
```
97-
98-
You might also pipe the reader into a writeable or transform stream:
99-
```js
100-
const { writeFile } = require('fs')
101-
const consumer = writeFile('/path/to/save/file')
102-
103-
reader.on('pipeline ready', () => {
104-
reader.pipe(consumer)
105-
})
70+
const feed1 = JSON.parse(await sink.get('feed-a.json'));
71+
const feed2 = JSON.parse(await sink.get('feed-b.json'));
72+
const bundle = await cssReader([feed1, feed2])
10673
```
10774

10875
## API
10976

110-
### Methods
111-
112-
#### constructor
113-
114-
Constructor takes a single stream or array of streams. Streams should be produced with an asset-pipe sink such as:
77+
Reader takes an array of feeds. Feeds should be produced with an asset-pipe sink such as:
11578
- [asset-pipe-sink-s3](https://github.com/asset-pipe/asset-pipe-sink-s3`)
11679
- [asset-pipe-sink-fs](https://github.com/asset-pipe/asset-pipe-sink-fs`)
11780
- [asset-pipe-sink-gcs](https://github.com/asset-pipe/asset-pipe-sink-gcs`)
11881
- [asset-pipe-sink-mem](https://github.com/asset-pipe/asset-pipe-sink-mem`)
11982

120-
Examples
121-
```js
122-
new CssReader(stream)
123-
```
124-
```js
125-
new CssReader([stream, ...stream])
126-
```
127-
128-
Returns: `Readable Stream`
129-
130-
### Events
131-
132-
#### file found
133-
134-
Event produced whenever an underlying feed stream successfully reads its feed
135-
file from disk
136-
137-
```js
138-
cssReader.on('file found', file => {})
139-
```
140-
141-
Param: `file`, name of the file given to the feed stream to read from
142-
143-
#### file not found
144-
145-
Event produced whenever an underlying feed stream is unable to read its feed
146-
file from disk
147-
148-
```js
149-
cssReader.on('file not found', file => {})
150-
```
151-
152-
Param: `file`, name of the file given to the feed stream to read from
153-
154-
#### pipeline ready
155-
156-
Event produced once all feed file streams have been successfully merged into
157-
a pipeline
158-
159-
```js
160-
cssReader.on('pipeline ready', () => {})
161-
```
162-
163-
#### data
164-
165-
Event that emits chunks of CSS content to a consumer
166-
167-
```js
168-
cssReader.on('data', chunk => {})
169-
```
170-
171-
Param: `chunk`, a piece of CSS text
172-
173-
#### error
174-
175-
Event produced whenever any of the various stages of the pipeline emit errors
176-
83+
Example
17784
```js
178-
cssReader.on('error', err => {})
85+
cssReader([feed, ...feeds])
17986
```
18087

181-
Param: `err`, Error forwarded from merged streams or otherwise emitted from the pipeline
88+
Returns: `string`
18289

18390
## Contributing
18491

lib/reader.js

Lines changed: 22 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,27 @@
11
'use strict';
22

3-
const { Readable, PassThrough, Stream } = require('readable-stream');
4-
const { parse } = require('JSONStream');
5-
const mergeStream = require('merge-stream');
6-
const { dedupe, sort, setOrder } = require('./util');
73
const assert = require('assert');
84

9-
module.exports = class Reader extends Readable {
10-
constructor(streams) {
11-
super();
12-
13-
assert(
14-
streams instanceof Stream || Array.isArray(streams),
15-
`Expected first argument to new Reader() to be a stream or array of streams.
16-
Instead got ${typeof stream}`
17-
);
18-
19-
if (!Array.isArray(streams)) {
20-
streams = [streams];
21-
}
22-
23-
assert(
24-
streams.every(stream => stream instanceof Stream),
25-
'Expected any/all arguments given to Reader constructor to be subclasses of Stream.'
26-
);
27-
28-
assert(
29-
streams.length,
30-
'Expected at least one stream to be provided to new Reader(). Got none.'
31-
);
32-
33-
const merged = mergeStream();
34-
35-
let count = 0;
36-
streams.forEach((readStream, index) => {
37-
const tmpStream = new PassThrough({ objectMode: true });
38-
merged.add(tmpStream);
39-
40-
readStream.on('file found', file => {
41-
this.emit('file found', file);
42-
readStream
43-
.pipe(parse('*'))
44-
.on('error', err => {
45-
this.emit('error', err);
46-
})
47-
.pipe(setOrder(index))
48-
.pipe(tmpStream);
49-
50-
count++;
51-
if (count === streams.length) {
52-
this.emit('pipeline ready');
53-
}
54-
});
55-
56-
readStream.on('file not found', file => {
57-
this.emit('file not found', file);
58-
tmpStream.end();
59-
60-
count++;
61-
if (count === streams.length) {
62-
this.emit('pipeline ready');
63-
}
64-
});
65-
});
66-
67-
this.data = merged.pipe(sort()).pipe(dedupe());
68-
this.data.pause();
69-
70-
this.data.on('data', chunk => {
71-
this.push(`${chunk.content.trim()}\n\n`);
72-
});
73-
74-
this.data.on('end', () => {
75-
this.push(null);
76-
});
77-
}
78-
79-
_read() {
80-
return this.data.resume();
81-
}
5+
module.exports = async function reader(feeds = []) {
6+
assert(
7+
feeds.length,
8+
`Expected at least 1 feed to be given. Instead got "${feeds.length}"`
9+
);
10+
assert(
11+
feeds.every(Array.isArray),
12+
`Expected every feed to be an array. Instead got "${feeds.join(', ')}"`
13+
);
14+
15+
feeds = [].concat(...feeds);
16+
17+
const feedMap = new Map();
18+
feeds.forEach(feed => {
19+
// because feedMap preserves order, when we get a duplicate we actually
20+
// need to append to the end of the feedMap. We do that by deleting
21+
// first and then adding to the feedMap
22+
feedMap.delete(feed.id);
23+
feedMap.set(feed.id, feed);
24+
});
25+
const dedupedFeeds = Array.from(feedMap.values());
26+
return dedupedFeeds.map(feed => feed.content.trim()).join('\n\n');
8227
};

0 commit comments

Comments
 (0)