-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: reset types definitions and dependencies for Application class (#…
…183)
- Loading branch information
Showing
66 changed files
with
1,266 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,14 @@ | ||
import { Runtime } from '@shuvi/types'; | ||
|
||
export const create: Runtime.ApplicationCreater; | ||
import { IAppRenderFn, IApplication } from '@shuvi/runtime-core' | ||
export interface IApplicationCreaterContext { | ||
routeProps?: { [x: string]: any }; | ||
[x: string]: any; | ||
} | ||
export interface ApplicationCreater { | ||
( | ||
context: IApplicationCreaterContext, | ||
options: { | ||
render: IAppRenderFn; | ||
} | ||
): IApplication; | ||
} | ||
export const create: ApplicationCreater; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.log | ||
.DS_Store | ||
node_modules | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# @shuvi/hook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "@shuvi/hook", | ||
"version": "0.0.1-rc.32", | ||
"license": "MIT", | ||
"main": "lib/index.js", | ||
"module": "esm/index.js", | ||
"types": "lib/index.d.ts", | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"engines": { | ||
"node": ">= 12.0.0" | ||
}, | ||
"scripts": { | ||
"dev": "run-p watch:*", | ||
"watch:esm": "tsc -p tsconfig.build.esm.json -w", | ||
"watch:cjs": "tsc -p tsconfig.build.cjs.json -w", | ||
"prebuild": "rimraf lib esm", | ||
"build": "run-p build:*", | ||
"build:esm": "tsc -p tsconfig.build.esm.json", | ||
"build:cjs": "tsc -p tsconfig.build.cjs.json" | ||
}, | ||
"author": "Zheng Yu Tay", | ||
"dependencies": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { IHookOpts } from './types'; | ||
|
||
export const executeAsyncParallelHook = async ( | ||
tapFns: IHookOpts['fn'][], | ||
...args: any[] | ||
) => { | ||
const results = await Promise.all(tapFns.map(fn => fn(...args))); | ||
return results; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { IHookOpts } from './types'; | ||
|
||
export const executeAsyncSeriesBailHook = async ( | ||
tapFns: IHookOpts['fn'][], | ||
...args: any[] | ||
) => { | ||
let result: unknown = []; | ||
|
||
for (let i = 0; i < tapFns.length; i++) { | ||
result = tapFns[i](...args); | ||
|
||
if (Promise.resolve(result) === result) { | ||
result = await result; | ||
} | ||
|
||
if (result) { | ||
break; | ||
} | ||
} | ||
return result; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { IHookOpts } from './types'; | ||
|
||
export const executeAsyncSeriesHook = async ( | ||
tapFns: IHookOpts['fn'][], | ||
...args: any[] | ||
) => { | ||
let results: unknown[] = []; | ||
|
||
for (let i = 0; i < tapFns.length; i++) { | ||
results.push(await tapFns[i](...args)); | ||
} | ||
|
||
return results; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { IHookOpts } from './types'; | ||
|
||
export const executeAsyncSeriesWaterfallHook = async ( | ||
tapFns: IHookOpts['fn'][], | ||
...args: any[] | ||
) => { | ||
for (let i = 0; i < tapFns.length; i++) { | ||
let fn = tapFns[i]; | ||
let promiseResult = await fn(...args); | ||
if (typeof args[0] !== 'undefined') { | ||
if (typeof promiseResult !== 'undefined') { | ||
args[0] = promiseResult; | ||
} else { | ||
console.warn( | ||
`Expected return value from hook "${fn.hookName}" but is undefined` | ||
); | ||
} | ||
} | ||
} | ||
|
||
return args[0]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { executeAsyncParallelHook } from './AsyncParallelHook'; | ||
import { executeAsyncSeriesHook } from './AsyncSeriesHook'; | ||
import { executeAsyncSeriesBailHook } from './AsyncSeriesBailHook'; | ||
import { executeAsyncSeriesWaterfallHook } from './AsyncSeriesWaterfallHook'; | ||
|
||
import { IHookOpts, ICallHookOpts, IHookable, IHookConfig } from './types'; | ||
import { insertHook, getHooksFunctions, removeHook } from './utils'; | ||
|
||
async function callSerailWithInitialValue<R = unknown>( | ||
hooks: IHookOpts[], | ||
args: any[], | ||
initialValue: R | ||
): Promise<R> { | ||
const fns = getHooksFunctions(hooks); | ||
|
||
return executeAsyncSeriesWaterfallHook(fns, initialValue, ...args); | ||
} | ||
|
||
async function callSerail<R = unknown>( | ||
hooks: IHookOpts[], | ||
args: any[], | ||
bail: boolean | ||
): Promise<R> { | ||
const thookFn = bail ? executeAsyncSeriesBailHook : executeAsyncSeriesHook; | ||
const fns = getHooksFunctions(hooks); | ||
return thookFn(fns, ...args) as Promise<R>; | ||
} | ||
|
||
async function callParallel<R = unknown>( | ||
hooks: IHookOpts[], | ||
args: any[] | ||
): Promise<R> { | ||
const fns = getHooksFunctions(hooks); | ||
|
||
return (await (executeAsyncParallelHook(fns, ...args) as any)) as Promise<R>; | ||
} | ||
|
||
export class Hookable implements IHookable { | ||
private _hooks = new Map<string, IHookOpts[]>(); | ||
|
||
tap<Config extends IHookConfig = IHookConfig>( | ||
name: Config['name'], | ||
hook: IHookOpts<Config['initialValue'], Config['args']> | ||
) { | ||
let hooks = this._hooks.get(name); | ||
if (!hooks) { | ||
hooks = []; | ||
this._hooks.set(name, hooks); | ||
} | ||
|
||
insertHook(hooks, hook); | ||
|
||
return () => { | ||
removeHook(hooks!, hook); | ||
}; | ||
} | ||
|
||
callHook<Config extends IHookConfig = IHookConfig>( | ||
name: Config['name'], | ||
...args: Config['args'] | ||
): Promise<unknown[]>; | ||
callHook<Config extends IHookConfig = IHookConfig>( | ||
options: ICallHookOpts<Config['name'], Config['initialValue']>, | ||
...args: Config['args'] | ||
): Promise<Config['initialValue']>; | ||
// implement | ||
async callHook( | ||
options: string | ICallHookOpts<string>, | ||
...args: any[] | ||
): Promise<any> { | ||
const defaultOpts = { | ||
bail: false, | ||
parallel: false, | ||
initialValue: undefined | ||
}; | ||
let opts: Required<ICallHookOpts>; | ||
if (typeof options === 'object') { | ||
opts = { | ||
...defaultOpts, | ||
...options | ||
}; | ||
} else { | ||
opts = { | ||
...defaultOpts, | ||
name: options | ||
}; | ||
} | ||
|
||
const hasInitialValue = typeof opts.initialValue !== 'undefined'; | ||
|
||
const hooks = this._hooks.get(opts.name); | ||
if (!hooks || hooks.length <= 0) { | ||
// @ts-ignore no return value | ||
return hasInitialValue ? opts.initialValue : []; | ||
} | ||
|
||
if (opts.parallel) { | ||
return await callParallel(hooks, args); | ||
} else if (hasInitialValue) { | ||
return await callSerailWithInitialValue(hooks, args, opts.initialValue); | ||
} else { | ||
return await callSerail(hooks, args, opts.bail); | ||
} | ||
} | ||
|
||
on<Config extends IHookConfig = IHookConfig>( | ||
event: Config['name'], | ||
listener: (...args: Config['args']) => void | ||
) { | ||
return this.tap<any>(event, { name: 'listener', fn: listener }); | ||
} | ||
|
||
emitEvent<Config extends IHookConfig = IHookConfig>( | ||
name: Config['name'], | ||
...args: Config['args'] | ||
) { | ||
this.callHook({ name, parallel: true }, ...args); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { Hookable } from './Hookable'; | ||
export { Hookable }; | ||
export * from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
export type NoInitValue = '$$no-initial-value'; | ||
|
||
export interface ICallHookOpts<Name extends string = string, InitV = unknown> { | ||
name: Name; | ||
bail?: boolean; | ||
parallel?: boolean; | ||
initialValue?: InitV; | ||
} | ||
|
||
export interface IHookOpts< | ||
InitValue = NoInitValue, | ||
Args extends any[] = any[] | ||
> { | ||
name: string; | ||
fn: (InitValue extends NoInitValue | ||
? (...args: Args) => void | Promise<void> | ||
: (init: InitValue, ...args: Args) => InitValue | Promise<InitValue>) & { | ||
hookName?: string; | ||
}; | ||
before?: string; | ||
stage?: number; | ||
} | ||
|
||
export interface IHookConfig { | ||
name: string; | ||
args: any[]; | ||
initialValue: any; | ||
} | ||
|
||
export interface IHookable { | ||
tap<Config extends IHookConfig>( | ||
hook: Config['name'], | ||
opts: IHookOpts<Config['initialValue'], Config['args']> | ||
): void; | ||
callHook<Config extends IHookConfig>( | ||
name: Config['name'], | ||
...args: Config['args'] | ||
): Promise<unknown[]>; | ||
callHook<Config extends IHookConfig>( | ||
options: ICallHookOpts<Config['name'], Config['initialValue']>, | ||
...args: Config['args'] | ||
): Promise<Config['initialValue']>; | ||
|
||
on<Config extends IHookConfig>( | ||
event: Config['name'], | ||
listener: (...args: Config['args']) => void | ||
): void; | ||
emitEvent<Config extends IHookConfig>( | ||
name: Config['name'], | ||
...args: Config['args'] | ||
): void; | ||
} | ||
|
||
type IDefaultHookConfig = { | ||
args: []; | ||
initialValue: NoInitValue; | ||
}; | ||
|
||
export type defineHook< | ||
Name extends string, | ||
Config extends Partial<IHookConfig> = {} | ||
> = { | ||
name: Name; | ||
} & { | ||
[K in keyof Config]: Config[K]; | ||
} & | ||
{ | ||
[K in Exclude< | ||
keyof IDefaultHookConfig, | ||
keyof Config | ||
>]: IDefaultHookConfig[K]; | ||
}; | ||
|
||
export type defineEvent<Name extends string, Args = []> = { | ||
name: Name; | ||
args: Args; | ||
initialValue: NoInitValue; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { IHookOpts } from './types'; | ||
|
||
export const getHooksFunctions = (hooks: IHookOpts[]) => { | ||
return hooks.map(({ fn, name }) => { | ||
fn.hookName = name; | ||
return fn; | ||
}); | ||
}; | ||
|
||
// mutable sort | ||
export const insertHook = (hooks: IHookOpts[], hook: IHookOpts) => { | ||
let before; | ||
|
||
if (typeof hook.before === 'string') { | ||
before = new Set([hook.before]); | ||
} | ||
|
||
let stage = 0; | ||
if (typeof hook.stage === 'number') { | ||
stage = hook.stage; | ||
} | ||
|
||
const originalHooksLength = hooks.length; | ||
|
||
if (hooks.length > 1) { | ||
for (let i = 1; i < originalHooksLength; i++) { | ||
const tap = hooks[i]; | ||
const tapStage = tap.stage || 0; | ||
|
||
if (before) { | ||
if (before.has(tap.name)) { | ||
hooks.splice(i, 0, hook); | ||
break; | ||
} | ||
} | ||
if (tapStage > stage) { | ||
hooks.splice(i, 0, hook); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (hooks.length === originalHooksLength) { | ||
hooks.push(hook); | ||
} | ||
|
||
return hooks; | ||
}; | ||
|
||
// mutable way | ||
export const removeHook = (hooks: IHookOpts[], hookToRemove: IHookOpts) => { | ||
const indexToRemove = hooks.findIndex(hook => hook === hookToRemove); | ||
if (indexToRemove >= 0) { | ||
hooks.splice(indexToRemove, 1); | ||
} | ||
}; |
Oops, something went wrong.