From 9719720d1c987f107dc3f354e6fc4984b7fff472 Mon Sep 17 00:00:00 2001 From: chaoslee Date: Mon, 25 Nov 2024 11:04:39 +0800 Subject: [PATCH] @produck/duck: [ADDED] Utils::throwNotInstalled @produck/duck-log: [FIXED] not allow register() after installed @produck/duck-runner: [FIXED] use Duck::Utils::throwNotInstalled [FIXED] use idiom @produck/duck-web: [FIXED] not allow build application before installed --- .gitignore | 5 ++- package.json | 2 +- packages/duck-log/src/index.mjs | 16 ++++--- packages/duck-log/test/DuckLog.spec.mjs | 60 +++++++++++++++++-------- packages/duck-runner/src/index.mjs | 20 +++------ packages/duck-web/index.d.ts | 9 +++- packages/duck-web/src/index.mjs | 44 +++++++++--------- packages/duck-web/test/DuckWeb.spec.mjs | 5 ++- packages/duck-workspace/index.d.ts | 2 +- packages/duck/index.d.ts | 32 +++++++------ packages/duck/src/Utils.mjs | 5 +++ packages/duck/src/index.mjs | 2 + 12 files changed, 121 insertions(+), 81 deletions(-) create mode 100644 packages/duck/src/Utils.mjs diff --git a/.gitignore b/.gitignore index c1179aa..f1784ea 100644 --- a/.gitignore +++ b/.gitignore @@ -64,8 +64,9 @@ typings/ .vscode # Development debug -.debug.mjs +*.ign* +*.gen* # Duck dist packages/**/index.cjs -packages/**/version.mjs \ No newline at end of file +packages/**/version.mjs diff --git a/package.json b/package.json index ae95695..f4c3186 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "deps:install": "npm -v && npm i", "lint": "eslint --fix packages/**/*.mjs", "test": "npm run build:extract --workspaces && npm run test --workspaces", - "coverage": "c8 --exclude=**/*.spec.mjs --reporter=lcov npm run test", + "coverage": "c8 --exclude=**/*.spec.mjs --reporter=lcov npm test", "publish": "npm run lint && npm test && lerna publish --no-private" }, "devDependencies": { diff --git a/packages/duck-log/src/index.mjs b/packages/duck-log/src/index.mjs index 9cc5b27..0e48134 100644 --- a/packages/duck-log/src/index.mjs +++ b/packages/duck-log/src/index.mjs @@ -22,25 +22,28 @@ const DuckLogComponent = (options = {}) => { ...meta, install: ({ Kit }, next) => { const map = new Map(); + let installed = false; + + const register = Object.freeze((category, options = {}) => { + if (installed) { + Ow.Error.Common('Can NOT register log category after installed.'); + } - const register = (category, options = {}) => { assertCategory(category); if (map.has(category)) { - return Ow.Error.Common(`The category(${category}) is existed.`); + Ow.Error.Common(`The category(${category}) is existed.`); } map.set(category, new Logger.Handler({ label: category, ...options})); - }; - - Object.freeze(register); + }); Kit.Log = new Proxy(register, { get: (_target, category) => { assertCategory(category); if (!map.has(category)) { - return Ow.Error.Common(`Category logger(${category}) is NOT defined.`); + Ow.Error.Common(`Category logger(${category}) is NOT defined.`); } return map.get(category).proxy; @@ -52,6 +55,7 @@ const DuckLogComponent = (options = {}) => { } next(); + installed = true; }, }); }; diff --git a/packages/duck-log/test/DuckLog.spec.mjs b/packages/duck-log/test/DuckLog.spec.mjs index b048f6f..18725d3 100644 --- a/packages/duck-log/test/DuckLog.spec.mjs +++ b/packages/duck-log/test/DuckLog.spec.mjs @@ -42,29 +42,53 @@ describe('DuckLog', function () { }); describe('::register()', function () { - it('should register a new logger.', function () { - const Kit = Duck.define({ - id: 'foo', - components: [DuckLog.Component()], - })(); - - Kit.Log('bar', { label: 'bar' }); - Kit.Log('baz'); + it('should register a new logger.', async function () { + await new Promise((resolve) => { + Duck.define({ + id: 'foo', + components: [DuckLog.Component()], + }, function ({ Log }) { + Log('bar', { label: 'bar' }); + Log('baz'); + resolve(); + })(); + }); }); - it('should throw if bad category.', function () { - const Kit = Duck.define({ - id: 'foo', - components: [DuckLog.Component()], - })(); + it('should throw if bad category.', async function () { + await new Promise(resolve => { + Duck.define({ + id: 'foo', + components: [DuckLog.Component()], + }, function ({ Log }) { + assert.throws(() => Log(1), { + name: 'TypeError', + message: 'Invalid "category", one "string" expected.', + }); + + resolve(); + })(); + }); - assert.throws(() => Kit.Log(1), { - name: 'TypeError', - message: 'Invalid "category", one "string" expected.', + }); + + it('should throw if duplicated category.', async function () { + await new Promise(resolve => { + Duck.define({ + id: 'foo', + components: [DuckLog.Component({ foo: {} })], + }, function ({ Log }) { + assert.throws(() => Log('foo'), { + name: 'Error', + message: 'The category(foo) is existed.', + }); + + resolve(); + })(); }); }); - it('should throw if duplicated category.', function () { + it('should throw if installed.', function () { const Kit = Duck.define({ id: 'foo', components: [DuckLog.Component({ foo: {} })], @@ -72,7 +96,7 @@ describe('DuckLog', function () { assert.throws(() => Kit.Log('foo'), { name: 'Error', - message: 'The category(foo) is existed.', + message: 'Can NOT register log category after installed.', }); }); }); diff --git a/packages/duck-runner/src/index.mjs b/packages/duck-runner/src/index.mjs index 21ffe2e..865dc27 100644 --- a/packages/duck-runner/src/index.mjs +++ b/packages/duck-runner/src/index.mjs @@ -1,7 +1,6 @@ -import * as Ow from '@produck/ow'; import EventEmitter from 'node:events'; -import { defineComponent, defineAny } from '@produck/duck'; -import { T } from '@produck/mold'; +import { Assert } from '@produck/idiom'; +import { defineComponent, defineAny, Utils } from '@produck/duck'; import * as Runner from './Runner/index.mjs'; import * as Options from './Options.mjs'; @@ -21,12 +20,10 @@ const DuckRunnerComponent = (...args) => { ...meta, install: ({ Kit }, next) => { const manager = new Runner.Manager(); - const runner = Kit.Runner = {}; + const runner = Kit.Runner = { start: Utils.throwNotInstalled }; Kit.Bus = new EventEmitter(); - runner.start = () => Ow.Error.Common('Installation not completed.'); - for (const name in modes) { manager.Mode(name, modes[name]); } @@ -38,9 +35,7 @@ const DuckRunnerComponent = (...args) => { const play = roles[name](RoleKit); - if (!T.Native.Function(play)) { - Ow.Invalid('play <= role()', 'function <= role()'); - } + Assert.Type.Function(play, 'play <= role()', 'function <= role()'); manager.Role(name, play); } @@ -48,11 +43,8 @@ const DuckRunnerComponent = (...args) => { next(); runner.start = async function start(mode) { - if (!T.Native.String(mode)) { - Ow.Invalid('mode', 'string'); - } - - return await manager.run(mode, Kit); + Assert.Type.String(mode, 'mode'); + await manager.run(mode, Kit); }; Object.freeze(runner); diff --git a/packages/duck-web/index.d.ts b/packages/duck-web/index.d.ts index 3bb439d..c4dbf62 100644 --- a/packages/duck-web/index.d.ts +++ b/packages/duck-web/index.d.ts @@ -4,7 +4,7 @@ import { Schema } from '@produck/mold'; export interface ApplicationKit extends Duck.ProductKit {} -type Application = (...args: any[]) => RequestListener; +type Application = (...args: T[]) => RequestListener; type Provider = (Kit: ApplicationKit) => Application; interface Descriptor { @@ -13,9 +13,14 @@ interface Descriptor { description?: string; } +interface ApplicationBuilder { + (id: string, ...args: T[]): RequestListener; +} + interface WebRegistry { register: (descriptor: Descriptor) => void; - Application: (id: string, ...args: any[]) => RequestListener; + Application: ApplicationBuilder; + App: ApplicationBuilder; } type Options = Array; diff --git a/packages/duck-web/src/index.mjs b/packages/duck-web/src/index.mjs index 98f96f0..d0263aa 100644 --- a/packages/duck-web/src/index.mjs +++ b/packages/duck-web/src/index.mjs @@ -1,6 +1,6 @@ import * as Ow from '@produck/ow'; -import { defineComponent, defineAny } from '@produck/duck'; -import { T } from '@produck/mold'; +import { Assert } from '@produck/idiom'; +import { defineComponent, defineAny, Utils } from '@produck/duck'; import * as Preset from './Preset.mjs'; import * as Options from './Options.mjs'; @@ -32,22 +32,18 @@ const DuckWebComponent = (options = [DEFAULT_APPLICATION]) => { const { id, provider, description } = finalDescriptor; if (map.has(id)) { - return Ow.Error.Common(`Duplicate Application(${id}).`); + Ow.Error.Common(`Duplicate Application(${id}).`); } const ApplicationKit = Kit(`Application<${id}>`); const Application = provider(ApplicationKit); - if (!T.Native.Function(Application)) { - return Ow.Invalid('.provider()=>', 'function'); - } + Assert.Type.Function(Application, '.provider()=>'); const ApplicationProxy = (...args) => { const requestListener = Application(...args); - if (!T.Native.Function(requestListener)) { - return Ow.Invalid(`Application(${id})=>`, '(req, res) => any'); - } + Assert.Type.Function(requestListener, `Application(${id})=>`); return requestListener; }; @@ -55,25 +51,31 @@ const DuckWebComponent = (options = [DEFAULT_APPLICATION]) => { map.set(id, { id, description, ApplicationProxy }); }; - const Application = function Application(id, ...args) { - if (!T.Native.String(id)) { - return Ow.Invalid('id', 'string'); - } + for (const Application of staticApplicationList) { + register(Application); + } + + const Web = Kit.Web = { + register, + Application: Utils.throwNotInstalled, + get App() { + return this.Application; + }, + }; + + next(); + + Web.Application = function Application(id, ...args) { + Assert.Type.String(id, 'id'); if (!map.has(id)) { - return Ow.Error.Common(`No application(${id}) existed.`); + Ow.Error.Common(`No application(${id}) existed.`); } return map.get(id).ApplicationProxy(...args); }; - Kit.Web = Object.freeze({ register, Application, App: Application }); - - next(); - - for (const Application of staticApplicationList) { - register(Application); - } + Object.freeze(Web); }, }); }; diff --git a/packages/duck-web/test/DuckWeb.spec.mjs b/packages/duck-web/test/DuckWeb.spec.mjs index a87cfa7..b8b09d9 100644 --- a/packages/duck-web/test/DuckWeb.spec.mjs +++ b/packages/duck-web/test/DuckWeb.spec.mjs @@ -150,10 +150,11 @@ describe('DuckWeb', function () { Kit.Web.Application('Foo'); }, { name: 'TypeError', - message: 'Invalid "Application(Foo)=>", one "(req, res) => any" expected.', + message: 'Invalid "Application(Foo)=>", one "function" expected.', }); - }); + + it('should throw if not installed.'); }); }); diff --git a/packages/duck-workspace/index.d.ts b/packages/duck-workspace/index.d.ts index e5a0fd0..189a854 100644 --- a/packages/duck-workspace/index.d.ts +++ b/packages/duck-workspace/index.d.ts @@ -16,7 +16,7 @@ declare module '@produck/duck' { } export namespace Options { - const Schema: Schema; + export const Schema: Schema; export function normalize(options: WorkspaceOptions): WorkspaceOptions; } diff --git a/packages/duck/index.d.ts b/packages/duck/index.d.ts index 7c13701..52deccc 100644 --- a/packages/duck/index.d.ts +++ b/packages/duck/index.d.ts @@ -24,7 +24,7 @@ interface DefinitionKit extends DuckKit { } export interface ProductKit extends DefinitionKit { - ReadyTo: any>(fn: T, message?: string) => T; + [key: string]: unknown; } export interface Component { @@ -32,41 +32,41 @@ export interface Component { * The component unique id. * Example: org.orchange.duck.default */ - id: String, + id: string, /** * The component name for reading. */ - name: String, + name: string, /** * The component version in semver. */ - version?: String; + version?: string; /** * Invoking when Product is called. * Some new functions CAN be set into baseInjection */ - install?: (Kit: ProductKit, next: () => any) => any; + install?: (Kit: ProductKit, next: () => unknown) => unknown; /** * Description of the component. */ - description?: String; + description?: string; } interface ProductOptions { /** * Product id */ - id: String + id: string - name?: String + name?: string - version?: String + version?: string - description?: String + description?: string /** * Duck components list. Use to mixin some function into injection. @@ -74,11 +74,11 @@ interface ProductOptions { components?: Array } -type Product = (...args: any[]) => ProductType +type Product = (...args: unknown[]) => ProductType type Assembler = ( Kit: ProductKit, - ...args: any[] + ...args: unknown[] ) => ProductType export function defineProduct( @@ -86,7 +86,7 @@ export function defineProduct( assembler: Assembler ): Product -export interface AnyDefiner { +export interface AnyDefiner { (any: T): T; } @@ -94,7 +94,7 @@ export const defineAny: AnyDefiner; export const defineComponent: AnyDefiner; export { defineProduct as define }; -type InjectionTarget = (Kit: ProductKit) => T; +type InjectionTarget = (Kit: ProductKit) => T; export const inject: AnyDefiner; @@ -103,3 +103,7 @@ export namespace Options { export const Schema: Schema; export const ComponentSchema: Schema; } + +export namespace Utils { + export function throwNotInstalled(): never; +} diff --git a/packages/duck/src/Utils.mjs b/packages/duck/src/Utils.mjs new file mode 100644 index 0000000..fb2b4b5 --- /dev/null +++ b/packages/duck/src/Utils.mjs @@ -0,0 +1,5 @@ +import * as Ow from '@produck/ow'; + +export function throwNotInstalled() { + Ow.Error.Common('Installation not completed.'); +} diff --git a/packages/duck/src/index.mjs b/packages/duck/src/index.mjs index 8c2c29b..ba483be 100644 --- a/packages/duck/src/index.mjs +++ b/packages/duck/src/index.mjs @@ -48,3 +48,5 @@ export { defineAny as defineComponent, defineAny as inject, }; + +export * as Utils from './Utils.mjs';