Skip to content

Commit a78eb44

Browse files
committed
feat: add FileSource to process file data
1 parent a9e82cf commit a78eb44

File tree

13 files changed

+166
-15
lines changed

13 files changed

+166
-15
lines changed

src/event/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import {isBrowser} from '../base'
44
import type {IEventEmitter} from '../interface'
5-
import eventEmitterPolyfill from './eventEmitterPolyfill'
5+
import eventEmitterPolyfill from './polyfill'
66

77
export function eventEmitterFactory (): IEventEmitter {
88
const Constructor = isBrowser()
File renamed without changes.

src/parser/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @flow
2+
3+
import {echo} from '../base'
4+
import json from './json'
5+
6+
export {
7+
echo,
8+
json
9+
}

src/parser/json.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @flow
2+
3+
import type {IAny} from '../interface'
4+
5+
export default function (data: string): IAny {
6+
return JSON.parse(data)
7+
}

src/source/abstractSource.js src/source/abstract.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export default class AbstractSource implements ISource {
100100
}
101101
}
102102

103-
static finalize(source: ISource, expression: Function | Promise): IAny {
103+
static finalize (source: ISource, expression: Function | Promise<IAny>): IAny {
104104
let res
105105
if (typeof expression === 'function') {
106106
try {

src/source/fileSource.js src/source/file.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// @flow
22

3-
import {get, has, echo} from '../base'
3+
import {get, has} from '../base'
4+
import {json} from '../parser'
45
import {file as fileApi} from '../api'
5-
import AbstractSource, {SYNC, PROCESSING, FAILURE, READY} from './abstractSource'
6+
import AbstractSource, {SYNC, PROCESSING} from './abstract'
67
import type {
78
ISource,
89
ISourceStatus,
@@ -27,7 +28,7 @@ export default class FileSource extends AbstractSource implements ISource {
2728
super(opts)
2829
this.type = 'file'
2930
this.api = fileApi
30-
this.parser = echo
31+
this.parser = json
3132

3233
return this
3334
}
@@ -36,9 +37,7 @@ export default class FileSource extends AbstractSource implements ISource {
3637
this.setStatus(PROCESSING)
3738

3839
const expression = mode === SYNC
39-
? () => {
40-
this.data = this.parser(this.api.readSync(target, api))
41-
}
40+
? () => { this.data = this.parser(this.api.readSync(target, api)) }
4241
: this.api.read(target, api)
4342
.then(this.parser)
4443
.then((data: IAny): void => { this.data = data })

src/source/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @flow
2+
3+
import AbstractSource from './abstract'
4+
import FileSource from './file'
5+
6+
export {
7+
AbstractSource,
8+
FileSource
9+
}

test/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Config, {DEFAULT_OPTS} from '../src/config'
22
import {MISSED_VALUE_PATH} from '../src/error'
3-
import EventEmitterPolyfill from '../src/event/eventEmitterPolyfill'
3+
import EventEmitterPolyfill from '../src/event/polyfill'
44

55
describe('Config', () => {
66
describe('constructor', () => {

test/event/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import EventEmitter from 'events'
2-
import EventEmitterPolyfill from '../../src/event/eventEmitterPolyfill'
2+
import EventEmitterPolyfill from '../../src/event/polyfill'
33
import {eventEmitterFactory} from '../../src/event'
44

55
describe('event', () => {

test/event/eePolyfill.js test/event/polyfill.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Emitter from '../../src/event/eventEmitterPolyfill'
1+
import Emitter from '../../src/event/polyfill'
22

33
describe('eventEmitterPolyfill', () => {
44
describe('constructor', () => {

test/parser/index.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {json, echo} from '../../src/parser'
2+
3+
describe('parser', () => {
4+
describe('json', () => {
5+
const value = {foo: 'bar', baz: 1}
6+
const str = JSON.stringify(value)
7+
8+
expect(json(str)).toEqual(value)
9+
expect(json('null')).toBeNull()
10+
})
11+
12+
describe('echo', () => {
13+
it('translates value as is', () => {
14+
const value = {}
15+
16+
expect(echo(value)).toBe(value)
17+
})
18+
})
19+
})

test/source/abstract.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import AbstractSource, {INITIAL, READY, FAILURE} from '../../src/source/abstractSource'
1+
import AbstractSource, {INITIAL, READY, FAILURE} from '../../src/source/abstract'
22
import EventEmitter from 'events'
33

44
describe('source/abstract', () => {
@@ -75,9 +75,9 @@ describe('source/abstract', () => {
7575
const emitter = new EventEmitter()
7676
const cases = [
7777
['fn succeeds', () => {}, READY],
78-
['fn fails', () => { throw new Error }, FAILURE],
79-
['promise resolved', new Promise(res => res()), READY],
80-
['promise rejected', new Promise((res, rej) => rej()), FAILURE]
78+
['fn fails', () => { throw new Error() }, FAILURE],
79+
['promise resolved', new Promise((resolve) => resolve()), READY],
80+
['promise rejected', new Promise((resolve, reject) => reject(new Error())), FAILURE]
8181
]
8282

8383
cases.forEach(([descr, expression, status]) => {

test/source/file.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import path from 'path'
2+
import {FileSource, AbstractSource} from '../../src/source'
3+
import EventEmitter from 'events'
4+
import {ASYNC, FAILURE, INITIAL, READY, SYNC} from '../../src/source/abstract'
5+
6+
const FOOBAR = path.resolve(__dirname, '../stub/foobar.json')
7+
8+
describe('source/file', () => {
9+
describe('constructor', () => {
10+
it('returns proper instance', () => {
11+
const target = 'foo'
12+
const emitter = new EventEmitter()
13+
const api = { encoding: 'utf' }
14+
const opts = {emitter, target, api}
15+
const source = new FileSource(opts)
16+
17+
expect(source).toBeInstanceOf(AbstractSource)
18+
expect(source.status).toBe(INITIAL)
19+
expect(source.type).toBe('file')
20+
expect(source.id).toEqual(expect.any(String))
21+
expect(source.target).toBe(target)
22+
expect(source.opts).toBe(opts)
23+
expect(source.emitter).toBe(emitter)
24+
})
25+
})
26+
27+
describe('proto', () => {
28+
describe('inherited from AbstractSource', () => {
29+
const cases = ['open', 'emit', 'on', 'setStatus']
30+
31+
cases.forEach(method => {
32+
it(method, () => {
33+
expect(FileSource.prototype[method]).toBe(AbstractSource.prototype[method])
34+
})
35+
})
36+
})
37+
38+
const emitter = new EventEmitter()
39+
const target = FOOBAR
40+
41+
describe('connect', () => {
42+
it('fetches file synchronously', () => {
43+
const source = new FileSource({emitter, target, mode: SYNC})
44+
45+
expect(source.connect()).toBe(source)
46+
expect(source.data).toEqual({foo: 'bar'})
47+
expect(source.status).toBe(READY)
48+
})
49+
50+
it('fetches file asynchronously', done => {
51+
const source = new FileSource({emitter, target, mode: ASYNC})
52+
expect(source.connect()).toBe(source)
53+
54+
source.on(READY, () => {
55+
expect(source.data).toEqual({foo: 'bar'})
56+
expect(source.status).toBe(READY)
57+
done()
58+
})
59+
})
60+
61+
it('switches status to failed on any error', () => {
62+
const source = new FileSource({emitter, target: null, mode: SYNC})
63+
source.connect()
64+
65+
expect(source.status).toBe(FAILURE)
66+
})
67+
})
68+
69+
describe('getters', () => {
70+
const source = new FileSource({emitter, target, mode: SYNC})
71+
source.data = {foo: 'bar'}
72+
73+
describe('has', () => {
74+
it('asserts status', () => {
75+
source.status = INITIAL
76+
expect(() => source.has('foo')).toThrow('Invalid source status: initial')
77+
})
78+
79+
it('returns value if path exists', () => {
80+
source.status = READY
81+
expect(source.has('foo')).toBeTruthy()
82+
})
83+
84+
it('returns false otherwise', () => {
85+
source.status = READY
86+
expect(source.has('baz')).toBeFalsy()
87+
})
88+
})
89+
90+
describe('get', () => {
91+
it('asserts status', () => {
92+
source.status = FAILURE
93+
expect(() => source.get('foo')).toThrow('Invalid source status: failure')
94+
})
95+
96+
it('returns value if path exists', () => {
97+
source.status = READY
98+
expect(source.get('foo')).toBe('bar')
99+
})
100+
101+
it('returns undefined ithrwise', () => {
102+
source.status = READY
103+
expect(source.get('baz')).toBeUndefined()
104+
})
105+
})
106+
})
107+
})
108+
})

0 commit comments

Comments
 (0)