Skip to content

Commit 3f33997

Browse files
committed
feat: add machine factory
closes #10
1 parent 2696494 commit 3f33997

File tree

12 files changed

+239
-38
lines changed

12 files changed

+239
-38
lines changed

package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"coveralls_push": "cat ./coverage/lcov.info | coveralls",
2626
"docs": "typedoc src/main --ignoreCompilerErrors || exit 0",
2727
"tsfix": "replace-in-file --configFile=./src/libdef/ts/replace.js",
28-
"flowfix": "replace-in-file --configFile=./src/libdef/flow/replace.js"
28+
"flowfix": "replace-in-file --configFile=./src/libdef/flow/replace.js && yarn flowfix_import",
29+
"flowfix_import": "node -r esm src/libdef/flow/import.js"
2930
},
3031
"files": [
3132
"README.md",
@@ -59,8 +60,10 @@
5960
"coveralls": "^3.0.2",
6061
"dts-generator": "^3.0.0",
6162
"eslint-plugin-typescript": "^0.14.0",
63+
"esm": "^3.1.1",
6264
"flowgen": "^1.3.0",
6365
"jest": "^23.6.0",
66+
"lodash": "^4.17.11",
6467
"semantic-release": "^15.13.3",
6568
"ts-jest": "^23.10.5",
6669
"tslib": "^1.9.3",

src/libdef/flow/append.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
declare module "@qiwi/cyclone/lib/es5/index" {
22
declare export * from '@qiwi/cyclone/lib/es5/machine';
33
declare export * from '@qiwi/cyclone/lib/es5/error';
4+
declare export * from '@qiwi/cyclone/lib/es5/factory';
45
}
56

67
declare module "@qiwi/cyclone" {
78
declare export * from '@qiwi/cyclone/lib/es5/machine';
89
declare export * from '@qiwi/cyclone/lib/es5/error';
10+
declare export * from '@qiwi/cyclone/lib/es5/factory';
911
}

src/libdef/flow/import.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// NOTE flowgen completely ignores module imports
2+
// So we need this dirty hack
3+
4+
import {readFileSync, writeFileSync} from 'fs'
5+
import {resolve} from 'path'
6+
import {each} from 'lodash'
7+
8+
const DTS = resolve(__dirname, '../../../typings/index.d.ts')
9+
const FLOW = resolve(__dirname, '../../../typings/index.flow.js')
10+
11+
const dts = readFileSync(DTS, 'utf-8')
12+
const flow = readFileSync(FLOW, 'utf-8')
13+
let out = flow
14+
15+
const tree = dts
16+
.split('declare module')
17+
.reduce((m, v, k) => {
18+
if (v) {
19+
const [first, ...lines] = v.split('\n')
20+
const name = first.replace(/[^@a-z\d\-\/]/g, '')
21+
const imports = lines
22+
.filter(line => /^\timport/.test(line))
23+
.map(v => {
24+
const [full, rawdeps, name] = /^\timport { (.+) } from \'(.+)\';$/.exec(v)
25+
const deps = rawdeps.split(', ')
26+
27+
const types = deps.filter(d => /^I[A-Z].+/.test(d))
28+
const vars = deps.filter(d => !types.includes(d))
29+
30+
return {
31+
types,
32+
vars,
33+
deps,
34+
name
35+
}
36+
})
37+
const exports = lines.filter(line => /^\texport/.test(line))
38+
39+
m[name] = {
40+
imports,
41+
exports
42+
}
43+
}
44+
45+
return m
46+
}, {})
47+
48+
each(tree, ({imports}, name) => {
49+
if (imports && imports.length) {
50+
each(imports, ({deps, name: from}) => {
51+
out = out.replace(`declare module "${name}" {`, `declare module "${name}" {
52+
import type { ${deps.join(', ')} } from "${from}"
53+
`)
54+
})
55+
}
56+
})
57+
58+
writeFileSync(FLOW, out, 'utf-8')

src/libdef/flow/replace.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
files: 'typings/**/*.js',
2+
files: 'typings/*.js',
33
from: [
44
'this',
55
'mixins IMachine ',

src/libdef/ts/append.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
declare module "@qiwi/cyclone" {
22
export * from '@qiwi/cyclone/lib/es5/error';
33
export * from '@qiwi/cyclone/lib/es5/machine';
4+
export * from '@qiwi/cyclone/lib/es5/factory';
45
}

src/main/factory.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Machine,
3+
IMachine,
4+
IMachineOpts,
5+
DEFAULT_OPTS as DEFAULT_MACHINE_OPTS
6+
} from './machine'
7+
8+
import {
9+
Registry
10+
} from './registry'
11+
12+
export const DEFAULT_TEMPLATE = {}
13+
export const DEFAULT_TEMPLATE_REGISTRY = new Registry()
14+
export const DEFAULT_MACHINE_REGISTRY = new Registry()
15+
16+
type IFactoryOpts = {
17+
machine?: IMachineOpts,
18+
template?: string | Object,
19+
templateRegistry?: Registry,
20+
machineRegistry?: Registry
21+
}
22+
23+
export const factory = (opts: IFactoryOpts): IMachine => {
24+
// NOTE flowgen throws error on typed args destruction
25+
const { machine, template, templateRegistry = DEFAULT_TEMPLATE_REGISTRY, machineRegistry = DEFAULT_MACHINE_REGISTRY } = opts
26+
const _template = getTemplate(template, templateRegistry)
27+
const machineOpts: IMachineOpts = { ...DEFAULT_MACHINE_OPTS, ..._template, ...machine }
28+
const instance = new Machine(machineOpts)
29+
30+
machineRegistry.add(Math.random() + '', instance)
31+
32+
return instance
33+
}
34+
35+
export const getTemplate = (template: string | Object | void, templateRegistry: Registry): any => {
36+
return typeof template === 'string'
37+
? templateRegistry.get(template)
38+
: template
39+
}
40+
41+
export {
42+
IFactoryOpts
43+
}

src/main/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './error'
22
export * from './machine'
3+
export * from './factory'

src/main/registry.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export class Registry {
2+
store: { [key: string]: any }
3+
4+
constructor () {
5+
this.store = {}
6+
}
7+
8+
get (key: string): void {
9+
return this.store[key]
10+
}
11+
12+
add (key: string, value: any): void {
13+
this.store[key] = value
14+
}
15+
16+
remove (key: string): void {
17+
delete this.store[key]
18+
}
19+
}

src/test/factory.ts

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Registry } from '../main/registry'
2+
import { Machine } from '../main/machine'
3+
import {
4+
factory,
5+
getTemplate,
6+
DEFAULT_TEMPLATE,
7+
DEFAULT_MACHINE_REGISTRY,
8+
DEFAULT_TEMPLATE_REGISTRY
9+
} from '../main/factory'
10+
11+
describe('factory', () => {
12+
it('exposes defaults', () => {
13+
expect(DEFAULT_TEMPLATE_REGISTRY).toBeInstanceOf(Registry)
14+
expect(DEFAULT_MACHINE_REGISTRY).toBeInstanceOf(Registry)
15+
expect(DEFAULT_TEMPLATE).not.toBeUndefined()
16+
})
17+
18+
describe('produces a Machine instance', () => {
19+
DEFAULT_TEMPLATE_REGISTRY.add('foo', {
20+
transitions: {
21+
handle: true
22+
}
23+
})
24+
25+
const templateRegistry = new Registry()
26+
const machineRegistry = new Registry()
27+
const machine1 = factory({
28+
machine: { transitions: {} },
29+
template: 'foo'
30+
})
31+
const machine2 = factory({
32+
machine: { transitions: {} },
33+
templateRegistry,
34+
machineRegistry
35+
})
36+
37+
expect(machine1).toBeInstanceOf(Machine)
38+
expect(machine2).toBeInstanceOf(Machine)
39+
expect(Object.keys(machineRegistry.store).length).toBe(1)
40+
expect(Object.keys(DEFAULT_MACHINE_REGISTRY.store).length).toBe(1)
41+
})
42+
})
43+
44+
describe('getTemplate', () => {
45+
const tpl = {}
46+
const registry = new Registry()
47+
registry.add('foo', tpl)
48+
49+
it('returns template literal if passed', () => {
50+
const tpl = {}
51+
expect(getTemplate(tpl, registry)).toBe(tpl)
52+
})
53+
54+
it('searches template by name', () => {
55+
expect(getTemplate('foo', registry)).toBe(tpl)
56+
expect(getTemplate('bar', registry)).toBeUndefined()
57+
})
58+
})

src/test/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
Machine,
3+
factory,
34
DEFAULT_HANDLER,
45
DELIMITER,
56
DEFAULT_OPTS
@@ -8,6 +9,7 @@ import {
89
describe('index', () => {
910
it('properly exposes default and inners', () => {
1011
expect(Machine).toEqual(expect.any(Function))
12+
expect(factory).toEqual(expect.any(Function))
1113
expect(DEFAULT_HANDLER).toEqual(expect.any(Function))
1214
expect(DEFAULT_OPTS).not.toBeUndefined()
1315
expect(DELIMITER).not.toBeUndefined()

src/test/registry.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Registry } from '../main/registry'
2+
3+
describe('Registry', () => {
4+
describe('constructor', () => {
5+
it('returns proper instance', () => {
6+
const registry = new Registry()
7+
8+
expect(registry).toBeInstanceOf(Registry)
9+
expect(registry.store).toEqual({})
10+
})
11+
})
12+
13+
describe('proto', () => {
14+
const registry = new Registry()
15+
16+
describe('#add', () => {
17+
it('saves value', () => {
18+
registry.add('foo', 'bar')
19+
expect(registry.store.foo).toBe('bar')
20+
})
21+
})
22+
23+
describe('#get', () => {
24+
it('gets value by key', () => {
25+
expect(registry.get('foo')).toBe('bar')
26+
})
27+
28+
it('returns undefined if not found', () => {
29+
expect(registry.get('qux')).toBeUndefined()
30+
})
31+
})
32+
33+
describe('#remove', () => {
34+
it('drops value', () => {
35+
expect(registry.store.foo).toBe('bar')
36+
registry.remove('foo')
37+
expect(registry.get('foo')).toBeUndefined()
38+
})
39+
})
40+
})
41+
})

yarn.lock

+9-36
Original file line numberDiff line numberDiff line change
@@ -1443,7 +1443,7 @@ debug@^4.0.0:
14431443
dependencies:
14441444
ms "^2.1.1"
14451445

1446-
debuglog@*, debuglog@^1.0.1:
1446+
debuglog@^1.0.1:
14471447
version "1.0.1"
14481448
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
14491449
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@@ -1764,6 +1764,11 @@ eslint-visitor-keys@^1.0.0:
17641764
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
17651765
integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
17661766

1767+
esm@^3.1.1:
1768+
version "3.1.1"
1769+
resolved "https://registry.yarnpkg.com/esm/-/esm-3.1.1.tgz#810d1144522547801a58a8ea01d6566d61578223"
1770+
integrity sha512-Md2pR4IbR37UqubbgbA4+wiBorOEFB05Oo+g4WJW7W2ajiOhUfjZt77NzzCoQdrCb40GdKcflitm+XHDF053OQ==
1771+
17671772
esprima@^3.1.3:
17681773
version "3.1.3"
17691774
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@@ -2574,7 +2579,7 @@ import-local@^1.0.0:
25742579
pkg-dir "^2.0.0"
25752580
resolve-cwd "^2.0.0"
25762581

2577-
imurmurhash@*, imurmurhash@^0.1.4:
2582+
imurmurhash@^0.1.4:
25782583
version "0.1.4"
25792584
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
25802585
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@@ -3687,11 +3692,6 @@ lockfile@^1.0.4:
36873692
dependencies:
36883693
signal-exit "^3.0.2"
36893694

3690-
lodash._baseindexof@*:
3691-
version "3.1.0"
3692-
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
3693-
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
3694-
36953695
lodash._baseuniq@~4.6.0:
36963696
version "4.6.0"
36973697
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@@ -3700,33 +3700,11 @@ lodash._baseuniq@~4.6.0:
37003700
lodash._createset "~4.0.0"
37013701
lodash._root "~3.0.0"
37023702

3703-
lodash._bindcallback@*:
3704-
version "3.0.1"
3705-
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
3706-
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
3707-
3708-
lodash._cacheindexof@*:
3709-
version "3.0.2"
3710-
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
3711-
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
3712-
3713-
lodash._createcache@*:
3714-
version "3.1.2"
3715-
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
3716-
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
3717-
dependencies:
3718-
lodash._getnative "^3.0.0"
3719-
37203703
lodash._createset@~4.0.0:
37213704
version "4.0.3"
37223705
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
37233706
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
37243707

3725-
lodash._getnative@*, lodash._getnative@^3.0.0:
3726-
version "3.9.1"
3727-
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
3728-
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
3729-
37303708
lodash._root@~3.0.0:
37313709
version "3.0.1"
37323710
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
@@ -3767,11 +3745,6 @@ lodash.pick@^4.4.0:
37673745
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
37683746
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
37693747

3770-
lodash.restparam@*:
3771-
version "3.6.1"
3772-
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
3773-
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
3774-
37753748
lodash.set@^4.3.2:
37763749
version "4.3.2"
37773750
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
@@ -3812,7 +3785,7 @@ lodash.without@~4.4.0:
38123785
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
38133786
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
38143787

3815-
lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.2.1:
3788+
lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.2.1:
38163789
version "4.17.11"
38173790
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
38183791
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
@@ -5362,7 +5335,7 @@ readable-stream@~1.1.10:
53625335
isarray "0.0.1"
53635336
string_decoder "~0.10.x"
53645337

5365-
readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
5338+
readdir-scoped-modules@^1.0.0:
53665339
version "1.0.2"
53675340
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
53685341
integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c=

0 commit comments

Comments
 (0)