>
33 |
34 | export default (name: string, pluginCallback: StartPluginCallback
): StartPlugin
=> (reporter) => async (inProps?: P): Promise => {
35 | try {
36 | reporter.emit('start', name)
37 |
38 | const outProps = await pluginCallback({
39 | reporter,
40 | logPath: (path) => reporter.emit('path', name, path),
41 | logMessage: (message) => reporter.emit('message', name, message)
42 | })(inProps as P)
43 |
44 | reporter.emit('done', name)
45 |
46 | return outProps
47 | } catch (error) {
48 | reporter.emit('error', name, error)
49 |
50 | throw null
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/plugin/test/index.ts:
--------------------------------------------------------------------------------
1 | import EventEmitter from 'events'
2 | import test from 'blue-tape'
3 | import { createSpy, getSpyCalls } from 'spyfn'
4 |
5 | import plugin from '../src'
6 |
7 | test('plugin: export', async (t) => {
8 | t.equals(
9 | typeof plugin,
10 | 'function',
11 | 'must be a function'
12 | )
13 | })
14 |
15 | test('plugin: utils and props', async (t) => {
16 | const reporter = new EventEmitter()
17 | const pluginCallbackSpy = createSpy(() => ({ bar: true }))
18 | const pluginSpy = createSpy(() => pluginCallbackSpy)
19 | const pluginRunner = await plugin('plugin', pluginSpy)
20 | const result = await pluginRunner(reporter)({ foo: true })
21 |
22 | t.deepEqual(
23 | getSpyCalls(pluginSpy)[0][0].reporter,
24 | reporter,
25 | 'should pass reporter to plugin utils'
26 | )
27 |
28 | t.deepEqual(
29 | getSpyCalls(pluginCallbackSpy),
30 | [[{ foo: true }]],
31 | 'should pass props to plugin'
32 | )
33 |
34 | t.deepEqual(
35 | result,
36 | { bar: true },
37 | 'should return output props'
38 | )
39 | })
40 |
41 | test('plugin: done', async (t) => {
42 | const reporter = new EventEmitter()
43 | const pluginRunner = await plugin('plugin', () => () => {})
44 | const eventStartSpy = createSpy(() => {})
45 | const eventDoneSpy = createSpy(() => {})
46 |
47 | await pluginRunner(reporter)()
48 |
49 | reporter.on('start', eventStartSpy)
50 | reporter.on('done', eventDoneSpy)
51 |
52 | await pluginRunner(reporter)()
53 |
54 | t.deepEqual(
55 | getSpyCalls(eventStartSpy),
56 | [[ 'plugin' ]],
57 | 'should emit `start` event'
58 | )
59 |
60 | t.deepEqual(
61 | getSpyCalls(eventDoneSpy),
62 | [[ 'plugin' ]],
63 | 'should emit `done` event'
64 | )
65 | })
66 |
67 | test('plugin: hard error', async (t) => {
68 | const reporter = new EventEmitter()
69 | const pluginRunner = await plugin('plugin', () => () => {
70 | throw 'oops'
71 | })
72 | const eventStartSpy = createSpy(() => {})
73 | const eventErrorSpy = createSpy(() => {})
74 |
75 | reporter.on('start', eventStartSpy)
76 | reporter.on('error', eventErrorSpy)
77 |
78 | try {
79 | await pluginRunner(reporter)()
80 |
81 | t.fail('should not get here')
82 | } catch (e) {
83 | t.deepEqual(
84 | getSpyCalls(eventStartSpy),
85 | [[ 'plugin' ]],
86 | 'should emit `start` event'
87 | )
88 |
89 | t.deepEqual(
90 | getSpyCalls(eventErrorSpy),
91 | [[ 'plugin', 'oops' ]],
92 | 'should emit `done` event'
93 | )
94 | }
95 | })
96 |
97 | test('plugin: reject', async (t) => {
98 | const reporter = new EventEmitter()
99 | const pluginRunner = await plugin('plugin', () => () => Promise.reject('oops'))
100 | const eventStartSpy = createSpy(() => {})
101 | const eventErrorSpy = createSpy(() => {})
102 |
103 | reporter.on('start', eventStartSpy)
104 | reporter.on('error', eventErrorSpy)
105 |
106 | try {
107 | await pluginRunner(reporter)()
108 |
109 | t.fail('should not get here')
110 | } catch (e) {
111 | t.deepEqual(
112 | getSpyCalls(eventStartSpy),
113 | [[ 'plugin' ]],
114 | 'should emit `start` event'
115 | )
116 |
117 | t.deepEqual(
118 | getSpyCalls(eventErrorSpy),
119 | [[ 'plugin', 'oops' ]],
120 | 'should emit `done` event'
121 | )
122 | }
123 | })
124 |
125 | test('plugin: log message', async (t) => {
126 | const reporter = new EventEmitter()
127 | const pluginRunner = await plugin('plugin', ({ logMessage }) => () => {
128 | logMessage('hi')
129 | })
130 | const eventMessageSpy = createSpy(() => {})
131 |
132 | await pluginRunner(reporter)()
133 |
134 | reporter.on('message', eventMessageSpy)
135 |
136 | await pluginRunner(reporter)()
137 |
138 | t.deepEqual(
139 | getSpyCalls(eventMessageSpy),
140 | [[ 'plugin', 'hi' ]],
141 | 'should emit `message` event'
142 | )
143 | })
144 |
145 | test('plugin: log path', async (t) => {
146 | const reporter = new EventEmitter()
147 | const pluginRunner = await plugin('plugin', ({ logPath }) => () => {
148 | logPath('path/to/file')
149 | })
150 | const eventPathSpy = createSpy(() => {})
151 |
152 | await pluginRunner(reporter)()
153 |
154 | reporter.on('path', eventPathSpy)
155 |
156 | await pluginRunner(reporter)()
157 |
158 | t.deepEqual(
159 | getSpyCalls(eventPathSpy),
160 | [[ 'plugin', 'path/to/file' ]],
161 | 'should emit `path` event'
162 | )
163 | })
164 |
--------------------------------------------------------------------------------
/packages/reporter-verbose/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@start/reporter-verbose",
3 | "version": "0.2.1",
4 | "description": "📃 Verbose reporter",
5 | "keywords": "tasks, runner, start, start-reporter",
6 | "repository": "deepsweet/start",
7 | "homepage": "https://github.com/deepsweet/start/tree/master/packages/reporter-verbose",
8 | "author": "Kir Belevich (https://twitter.com/deepsweet)",
9 | "license": "MIT",
10 | "main": "build/index.js",
11 | "types": "build/index.d.ts",
12 | "files": [
13 | "build/"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "engines": {
19 | "node": ">=8.6.0"
20 | },
21 | "dependencies": {
22 | "@babel/runtime": "^7.4.2",
23 | "chalk": "^2.4.2",
24 | "stack-utils": "^1.0.2"
25 | },
26 | "devDependencies": {
27 | "@types/stack-utils": "^1.0.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/reporter-verbose/readme.md:
--------------------------------------------------------------------------------
1 | # 📃 reporter-verbose
2 |
3 | [](https://www.npmjs.com/package/@start/reporter-verbose) [](https://travis-ci.org/deepsweet/start) [](https://ci.appveyor.com/project/deepsweet/start) [](https://codecov.io/github/deepsweet/start) [](https://david-dm.org/deepsweet/start?path=packages/reporter-verbose)
4 |
5 | Verbose reporter.
6 |
7 | ## Install
8 |
9 | ```sh
10 | $ yarn add --dev @start/reporter-verbose
11 | # or
12 | $ npm install --save-dev @start/reporter-verbose
13 | ```
14 |
15 | ## Usage
16 |
17 | ### Example
18 |
19 | ```ts
20 | export default (taskName: string) => {
21 | const emitter = new EventEmitter()
22 |
23 | emitter.on('start', (pluginName: string) => {})
24 | emitter.on('message', (pluginName: string, message: string) => {})
25 | emitter.on('file', (pluginName: string, file: string) => {})
26 | emitter.on('done', (pluginName: string) => {})
27 | emitter.on('error', (pluginName: string, error: Error | string[] | string | null) => {})
28 |
29 | return emitter
30 | }
31 | ```
32 |
--------------------------------------------------------------------------------
/packages/reporter-verbose/src/index.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import EventEmitter from 'events'
3 | import chalk from 'chalk'
4 | import StackUtils from 'stack-utils'
5 |
6 | type StartError = Error | string[] | string | null
7 |
8 | export default (taskName: string) => {
9 | const emitter = new EventEmitter()
10 |
11 | emitter.on('start', (pluginName: string) => {
12 | console.log(`${chalk.yellow(`${taskName}.${pluginName}`)}: start`)
13 | })
14 |
15 | emitter.on('message', (pluginName: string, message: string) => {
16 | console.log(`${chalk.cyan(`${taskName}.${pluginName}`)}: ${message}`)
17 | })
18 |
19 | emitter.on('path', (pluginName: string, pathToLog: string) => {
20 | const relativeFile = path.relative(process.cwd(), pathToLog)
21 |
22 | console.log(`${chalk.blue(`${taskName}.${pluginName}`)}: ${relativeFile}`)
23 | })
24 |
25 | emitter.on('done', (pluginName: string) => {
26 | console.log(`${chalk.green(`${taskName}.${pluginName}`)}: done`)
27 | })
28 |
29 | emitter.on('error', (pluginName: string, error: StartError) => {
30 | // hard error
31 | if (error instanceof Error) {
32 | const stackUtils = new StackUtils({
33 | cwd: process.cwd(),
34 | internals: StackUtils.nodeInternals()
35 | })
36 | const stack = stackUtils.clean(error.stack!)
37 |
38 | console.error(`${chalk.red(`${taskName}.${pluginName}`)}: ${error.message}`)
39 | console.error(`\n${chalk.red(stack)}`)
40 | // array of "soft" errors
41 | } else if (Array.isArray(error)) {
42 | error.forEach((message) => {
43 | console.error(`${chalk.red(`${taskName}.${pluginName}`)}: ${message}`)
44 | })
45 | // "soft" error
46 | } else if (typeof error === 'string') {
47 | console.error(`${chalk.red(`${taskName}.${pluginName}`)}: ${error}`)
48 | }
49 |
50 | console.error(`${chalk.red(`${taskName}.${pluginName}`)}: error`)
51 | })
52 |
53 | return emitter
54 | }
55 |
--------------------------------------------------------------------------------
/packages/reporter-verbose/test/index.ts:
--------------------------------------------------------------------------------
1 | import test from 'blue-tape'
2 |
3 | import reporterVerbose from '../src'
4 |
5 | test('reporter-verbose: export', async (t) => {
6 | t.equals(
7 | typeof reporterVerbose,
8 | 'function',
9 | 'must be a function'
10 | )
11 | })
12 |
--------------------------------------------------------------------------------
/tasks/config/auto.ts:
--------------------------------------------------------------------------------
1 | import { TGitOptions } from '@auto/git'
2 | import { TBumpOptions } from '@auto/bump'
3 | import { TGithubOptions } from '@auto/log'
4 | import { TPrefixes, TWorkspacesOptions } from '@auto/utils'
5 |
6 | export const prefixes: TPrefixes = {
7 | required: {
8 | major: {
9 | title: 'Breaking change',
10 | value: '💥'
11 | },
12 | minor: {
13 | title: 'New feature',
14 | value: '➕'
15 | },
16 | patch: {
17 | title: 'Bugfix',
18 | value: '✔️'
19 | },
20 | publish: {
21 | title: 'New version',
22 | value: '📦'
23 | },
24 | dependencies: {
25 | title: 'Dependencies',
26 | value: '♻️'
27 | },
28 | initial: {
29 | title: 'Initial',
30 | value: '🐣'
31 | }
32 | },
33 | custom: [
34 | {
35 | title: 'Dependencies',
36 | value: '♻️'
37 | },
38 | {
39 | title: 'Lint',
40 | value: '🚷'
41 | },
42 | {
43 | title: 'Test',
44 | value: '👾'
45 | },
46 | {
47 | title: 'Docs',
48 | value: '📝'
49 | },
50 | {
51 | title: 'Demo',
52 | value: '📺'
53 | },
54 | {
55 | title: 'Refactor',
56 | value: '🛠'
57 | },
58 | {
59 | title: 'WIP',
60 | value: '🚧'
61 | },
62 | {
63 | title: 'Other',
64 | value: '🛠'
65 | }
66 | ]
67 | }
68 |
69 | export const gitOptions: TGitOptions = { initialType: 'minor' }
70 |
71 | export const bumpOptions: TBumpOptions = {
72 | zeroBreakingChangeType: 'minor',
73 | shouldAlwaysBumpDependents: true
74 | }
75 |
76 | export const githubOptions: TGithubOptions = {
77 | username: 'deepsweet',
78 | repo: 'start',
79 | token: process.env.GITHUB_RELEASE_TOKEN || ''
80 | }
81 |
82 | export const workspacesOptions: TWorkspacesOptions = { autoNamePrefix: '@start/' }
83 |
--------------------------------------------------------------------------------
/tasks/config/babel.ts:
--------------------------------------------------------------------------------
1 | const babelConfigCommon = {
2 | babelrc: false,
3 | presets: [
4 | [
5 | '@babel/preset-env',
6 | {
7 | targets: {
8 | node: '8.6.0'
9 | }
10 | }
11 | ]
12 | ],
13 | plugins: [
14 | [
15 | '@babel/plugin-transform-runtime',
16 | {
17 | regenerator: false
18 | }
19 | ],
20 | '@babel/plugin-syntax-dynamic-import',
21 | 'babel-plugin-dynamic-import-node',
22 | [
23 | 'module-resolver', {
24 | 'alias': {
25 | '@start/plugin/src/': '@start/plugin'
26 | }
27 | }
28 | ]
29 | ]
30 | }
31 |
32 | export const babelConfigBuild = {
33 | ...babelConfigCommon,
34 | presets: [
35 | ...babelConfigCommon.presets,
36 | '@babel/preset-typescript'
37 | ]
38 | }
39 |
40 | export const babelConfigDts = {
41 | ...babelConfigCommon,
42 | plugins: [
43 | ...babelConfigCommon.plugins,
44 | '@babel/plugin-syntax-typescript'
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/tasks/index.ts:
--------------------------------------------------------------------------------
1 | import plugin, { StartDataFilesProps, StartDataFile } from '@start/plugin/src'
2 | import sequence from '@start/plugin-sequence/src/'
3 | import parallel from '@start/plugin-parallel/src/'
4 | import xargs from '@start/plugin-xargs/src/'
5 | import assert from '@start/plugin-assert/src/'
6 | import env from '@start/plugin-env/src/'
7 | import find from '@start/plugin-find/src/'
8 | import findGitStaged from '@start/plugin-find-git-staged/src/'
9 | import remove from '@start/plugin-remove/src/'
10 | import read from '@start/plugin-read/src/'
11 | import babel from '@start/plugin-lib-babel/src/'
12 | import rename from '@start/plugin-rename/src/'
13 | import write from '@start/plugin-write/src/'
14 | import overwrite from '@start/plugin-overwrite/src/'
15 | import watch from '@start/plugin-watch/src/'
16 | import eslint from '@start/plugin-lib-eslint/src/'
17 | import { istanbulInstrument, istanbulReport } from '@start/plugin-lib-istanbul/src/'
18 | import tape from '@start/plugin-lib-tape/src/'
19 | import typescriptGenerate from '@start/plugin-lib-typescript-generate/src/'
20 | import typescriptCheck from '@start/plugin-lib-typescript-check/src/'
21 | import codecov from '@start/plugin-lib-codecov/src/'
22 | import {
23 | makeWorkspacesCommit,
24 | buildBumpedPackages,
25 | getWorkspacesPackagesBumps,
26 | publishWorkspacesPrompt,
27 | writeWorkspacesPackagesDependencies,
28 | writeWorkspacesDependenciesCommit,
29 | writeWorkspacesPackageVersions,
30 | writeWorkspacesPublishCommit,
31 | publishWorkspacesPackagesBumps,
32 | pushCommitsAndTags,
33 | writeWorkspacesPublishTags,
34 | makeWorkspacesGithubReleases
35 | } from '@auto/start-plugin'
36 | // @ts-ignore
37 | import tapDiff from 'tap-diff'
38 |
39 | export const build = async (packageName: string) => {
40 | const { babelConfigBuild } = await import('./config/babel')
41 |
42 | return sequence(
43 | find(`packages/${packageName}/src/**/*.+(js|ts)`),
44 | read,
45 | babel(babelConfigBuild),
46 | rename((file) => file.replace(/\.ts$/, '.js')),
47 | write(`packages/${packageName}/build/`)
48 | )
49 | }
50 |
51 | export const dts = (packageName: string) =>
52 | sequence(
53 | find(`packages/${packageName}/src/*.ts`),
54 | typescriptGenerate(`packages/${packageName}/build/`),
55 | find(`packages/${packageName}/build/**/*.d.ts`),
56 | read,
57 | // https://github.com/babel/babel/issues/7749
58 | // babel(babelConfigDts)
59 | plugin('modifyImports', () => ({ files }: StartDataFilesProps) => ({
60 | files: files.map((file): StartDataFile => ({
61 | ...file,
62 | data: file.data.replace(/(@.+?)\/src\/?/g, '$1')
63 | }))
64 | })),
65 | write(`packages/${packageName}/build/`)
66 | )
67 |
68 | export const pack = (packageName: string) =>
69 | sequence(
70 | assert(packageName, 'package name is required'),
71 | env({ NODE_ENV: 'production' }),
72 | find(`packages/${packageName}/build/`),
73 | remove,
74 | parallel(['build', 'dts'])(packageName)
75 | )
76 |
77 | export const packs = xargs('pack')
78 |
79 | export const dev = async (packageName: string) => {
80 | const { babelConfigBuild } = await import('./config/babel')
81 |
82 | return watch(`packages/${packageName}/src/**/*.ts`)(
83 | sequence(
84 | read,
85 | babel(babelConfigBuild),
86 | rename((file) => file.replace(/\.ts$/, '.js')),
87 | write(`packages/${packageName}/build/`)
88 | )
89 | )
90 | }
91 |
92 | export const lint = () =>
93 | sequence(
94 | findGitStaged(['packages/*/+(src|test)/**/*.ts', 'tasks/**/*.ts']),
95 | read,
96 | eslint(),
97 | typescriptCheck()
98 | )
99 |
100 | export const lintAll = () =>
101 | sequence(
102 | find(['packages/*/+(src|test)/**/*.+(ts|js)', 'tasks/**/*.ts']),
103 | read,
104 | eslint(),
105 | typescriptCheck()
106 | )
107 |
108 | export const fix = () =>
109 | sequence(
110 | find(['packages/*/+(src|test)/**/*.+(js|ts)', 'tasks/**/*.ts']),
111 | read,
112 | eslint({ fix: true }),
113 | overwrite
114 | )
115 |
116 | export const test = (packageName: string = '*') =>
117 | sequence(
118 | env({ NODE_ENV: 'test' }),
119 | find(`coverage/`),
120 | remove,
121 | find(`packages/${packageName}/src/**/*.ts`),
122 | istanbulInstrument({ esModules: true }, ['.ts']),
123 | find(`packages/${packageName}/test/**/*.ts`),
124 | tape(tapDiff),
125 | istanbulReport(['lcovonly', 'html', 'text-summary'])
126 | )
127 |
128 | export const ci = () =>
129 | sequence(
130 | lintAll(),
131 | test()
132 | )
133 |
134 | export const ciCoverage = () =>
135 | sequence(
136 | ci(),
137 | find('coverage/lcov.info'),
138 | read,
139 | codecov
140 | )
141 |
142 | export const commit = async () => {
143 | const { prefixes, workspacesOptions } = await import('./config/auto')
144 |
145 | return makeWorkspacesCommit(prefixes, workspacesOptions)
146 | }
147 |
148 | export const publish = async () => {
149 | const { prefixes, workspacesOptions, gitOptions, bumpOptions, githubOptions } = await import('./config/auto')
150 |
151 | return sequence(
152 | getWorkspacesPackagesBumps(prefixes, gitOptions, bumpOptions, workspacesOptions),
153 | publishWorkspacesPrompt(prefixes),
154 | buildBumpedPackages(pack),
155 | writeWorkspacesPackagesDependencies,
156 | writeWorkspacesDependenciesCommit(prefixes),
157 | writeWorkspacesPackageVersions,
158 | writeWorkspacesPublishCommit(prefixes, workspacesOptions),
159 | writeWorkspacesPublishTags(workspacesOptions),
160 | publishWorkspacesPackagesBumps(),
161 | pushCommitsAndTags,
162 | makeWorkspacesGithubReleases(prefixes, workspacesOptions, githubOptions)
163 | )
164 | }
165 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "allowSyntheticDefaultImports": true,
5 | "noEmit": true,
6 | "pretty": true,
7 | "lib": ["esnext"],
8 | "moduleResolution": "node",
9 | "skipLibCheck": true
10 | },
11 | "include": [
12 | "packages/*/src/",
13 | "packages/*/test/",
14 | "tasks/"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------