From 89dcffbed7cd911553efd4cb434caf629f09d371 Mon Sep 17 00:00:00 2001 From: ryuever Date: Mon, 27 May 2024 08:10:48 +0800 Subject: [PATCH 1/2] feat: add createDeferred --- packages/promise/deferred/README.md | 19 ++++++++++++++ packages/promise/deferred/package.json | 24 +++++++++++++++++ packages/promise/deferred/src/index.ts | 21 +++++++++++++++ packages/promise/deferred/test/test.spec.ts | 11 ++++++++ packages/promise/deferred/tsconfig.build.json | 12 +++++++++ packages/promise/deferred/tsconfig.json | 7 +++++ packages/promise/deferred/vitest.config.ts | 26 +++++++++++++++++++ 7 files changed, 120 insertions(+) create mode 100644 packages/promise/deferred/README.md create mode 100644 packages/promise/deferred/package.json create mode 100644 packages/promise/deferred/src/index.ts create mode 100644 packages/promise/deferred/test/test.spec.ts create mode 100644 packages/promise/deferred/tsconfig.build.json create mode 100644 packages/promise/deferred/tsconfig.json create mode 100644 packages/promise/deferred/vitest.config.ts diff --git a/packages/promise/deferred/README.md b/packages/promise/deferred/README.md new file mode 100644 index 0000000..ff37840 --- /dev/null +++ b/packages/promise/deferred/README.md @@ -0,0 +1,19 @@ +# @x-oasis/deferred + +## Installation + +```bash +$ npm i @x-oasis/deferred +``` + +## How to use + +```typescript +import deferred from '@x-oasis/deferred' +``` + +## How to run test + +```bash +$ pnpm test +``` \ No newline at end of file diff --git a/packages/promise/deferred/package.json b/packages/promise/deferred/package.json new file mode 100644 index 0000000..8c1992e --- /dev/null +++ b/packages/promise/deferred/package.json @@ -0,0 +1,24 @@ +{ + "name": "@x-oasis/deferred", + "version": "0.1.34", + "description": "deferred function", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "module": "dist/deferred.esm.js", + "files": [ + "dist", + "index.ts", + "src" + ], + "scripts": { + "build": "tsdx build --tsconfig tsconfig.build.json", + "clean": "rimraf ./dist", + "test": "vitest", + "compile": "tsc -p tsconfig.build.json" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "tsdx": "^0.14.1" + } +} diff --git a/packages/promise/deferred/src/index.ts b/packages/promise/deferred/src/index.ts new file mode 100644 index 0000000..ea831eb --- /dev/null +++ b/packages/promise/deferred/src/index.ts @@ -0,0 +1,21 @@ +export type Deferred = { + resolve: (value: T | PromiseLike) => void; + reject: (err?: unknown) => void; + promise: PromiseLike; +}; + +export function createDeferred(): Deferred { + let resolve: (value: T | PromiseLike) => void = null; + let reject: (err?: unknown) => void = null; + + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + + return { + promise, + resolve, + reject, + }; +} diff --git a/packages/promise/deferred/test/test.spec.ts b/packages/promise/deferred/test/test.spec.ts new file mode 100644 index 0000000..0825a4f --- /dev/null +++ b/packages/promise/deferred/test/test.spec.ts @@ -0,0 +1,11 @@ +import { expect, test } from 'vitest'; + +import { createDeferred } from '../src'; + +test('vitest', async () => { + const deferred = createDeferred(); + + expect(deferred.resolve).toBeTypeOf('function'); + expect(deferred.promise.then).toBeTypeOf('function'); + expect(deferred.reject).toBeTypeOf('function'); +}); diff --git a/packages/promise/deferred/tsconfig.build.json b/packages/promise/deferred/tsconfig.build.json new file mode 100644 index 0000000..c8613f0 --- /dev/null +++ b/packages/promise/deferred/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist", + "esModuleInterop": true + }, + + "include": [ + "index.ts", + "src/**/*" + ] +} \ No newline at end of file diff --git a/packages/promise/deferred/tsconfig.json b/packages/promise/deferred/tsconfig.json new file mode 100644 index 0000000..a5aa7cc --- /dev/null +++ b/packages/promise/deferred/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/packages/promise/deferred/vitest.config.ts b/packages/promise/deferred/vitest.config.ts new file mode 100644 index 0000000..31d7ded --- /dev/null +++ b/packages/promise/deferred/vitest.config.ts @@ -0,0 +1,26 @@ +// import path from 'path'; +// import tsPath from 'vite-tsconfig-paths'; +import { defineConfig } from 'vitest/config'; + +// const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf('/')); + +export default defineConfig({ + test: { + globals: true, + include: ['test/**/*.(spec|test).ts'], + exclude: ['node_modules/**'], + threads: false, + + coverage: { + provider: 'istanbul', // or 'c8' + }, + }, + + // plugins: [tsPath()], + resolve: { + alias: {}, + }, + define: { + __DEV__: false, + }, +}); From ba97c4ca77a9f6947e59c5a6bde84b4df8a826e4 Mon Sep 17 00:00:00 2001 From: ryuever Date: Fri, 12 Jul 2024 19:23:33 +0800 Subject: [PATCH 2/2] feat: add city module --- packages/event/disposable/README.md | 13 +++ packages/event/disposable/package.json | 25 +++++ packages/event/disposable/src/Disposable.ts | 34 +++++++ .../event/disposable/src/DisposableStore.ts | 99 +++++++++++++++++++ packages/event/disposable/src/index.ts | 3 + .../event/disposable/src/types/disposable.ts | 3 + packages/event/disposable/src/types/index.ts | 1 + packages/event/disposable/test/test.spec.ts | 7 ++ packages/event/disposable/tsconfig.build.json | 12 +++ packages/event/disposable/tsconfig.json | 7 ++ packages/event/disposable/vitest.config.ts | 26 +++++ packages/event/emitter/README.md | 13 +++ packages/event/emitter/package.json | 27 +++++ packages/event/emitter/src/index.ts | 20 ++++ packages/event/emitter/test/test.spec.ts | 9 ++ packages/event/emitter/tsconfig.build.json | 12 +++ packages/event/emitter/tsconfig.json | 7 ++ packages/event/emitter/vitest.config.ts | 26 +++++ packages/functional/each/test/test.spec.ts | 2 +- packages/hypertext/README.md | 2 + 20 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 packages/event/disposable/README.md create mode 100644 packages/event/disposable/package.json create mode 100644 packages/event/disposable/src/Disposable.ts create mode 100644 packages/event/disposable/src/DisposableStore.ts create mode 100644 packages/event/disposable/src/index.ts create mode 100644 packages/event/disposable/src/types/disposable.ts create mode 100644 packages/event/disposable/src/types/index.ts create mode 100644 packages/event/disposable/test/test.spec.ts create mode 100644 packages/event/disposable/tsconfig.build.json create mode 100644 packages/event/disposable/tsconfig.json create mode 100644 packages/event/disposable/vitest.config.ts create mode 100644 packages/event/emitter/README.md create mode 100644 packages/event/emitter/package.json create mode 100644 packages/event/emitter/src/index.ts create mode 100644 packages/event/emitter/test/test.spec.ts create mode 100644 packages/event/emitter/tsconfig.build.json create mode 100644 packages/event/emitter/tsconfig.json create mode 100644 packages/event/emitter/vitest.config.ts create mode 100644 packages/hypertext/README.md diff --git a/packages/event/disposable/README.md b/packages/event/disposable/README.md new file mode 100644 index 0000000..85a623b --- /dev/null +++ b/packages/event/disposable/README.md @@ -0,0 +1,13 @@ +# @x-oasis/disposable + +## Installation + +```bash +$ npm i @x-oasis/disposable +``` + +## How to use + +```typescript +import disposable from '@x-oasis/disposable' +``` \ No newline at end of file diff --git a/packages/event/disposable/package.json b/packages/event/disposable/package.json new file mode 100644 index 0000000..ca9d5d2 --- /dev/null +++ b/packages/event/disposable/package.json @@ -0,0 +1,25 @@ +{ + "name": "@x-oasis/disposable", + "version": "0.1.34", + "description": "disposable function", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "module": "dist/disposable.esm.js", + "files": [ + "dist", + "index.ts", + "src" + ], + "scripts": { + "build": "tsdx build --tsconfig tsconfig.build.json", + "clean": "rimraf ./dist", + "test": "vitest", + "compile": "tsc -p tsconfig.build.json" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "tsdx": "^0.14.1" + }, + "dependencies": {} +} diff --git a/packages/event/disposable/src/Disposable.ts b/packages/event/disposable/src/Disposable.ts new file mode 100644 index 0000000..d6a74df --- /dev/null +++ b/packages/event/disposable/src/Disposable.ts @@ -0,0 +1,34 @@ +import isObject from '@x-oasis/is-object'; +import { IDisposable } from './types/disposable'; +import DisposableStore from './DisposableStore'; + +const isFunction = (o) => typeof o === 'function'; + +export function isDisposable( + thing: T +): thing is T & IDisposable { + return isObject(thing) && isFunction((thing as IDisposable).dispose); +} + +export function toDisposable(fn: Function): IDisposable { + return { + dispose: () => fn(), + }; +} + +export class Disposable implements IDisposable { + static readonly None = Object.freeze({ dispose() {} }); + + private readonly _store = new DisposableStore(); + + public dispose(): void { + this._store.dispose(); + } + + registerDisposable(disposable: T) { + if ((disposable as any) === this) { + throw new Error('Can not register itself'); + } + this._store.add(disposable); + } +} diff --git a/packages/event/disposable/src/DisposableStore.ts b/packages/event/disposable/src/DisposableStore.ts new file mode 100644 index 0000000..07b1077 --- /dev/null +++ b/packages/event/disposable/src/DisposableStore.ts @@ -0,0 +1,99 @@ +import { isArray } from '@redcity/core/common/assertion/types'; +import { Iterable } from '@redcity/core/common/assertion/iterable'; +import { IDisposable } from './types/disposable'; +import { isDisposable } from './Disposable'; + +export function dispose(disposable: T): T; +export function dispose( + disposable: T | undefined +): T | undefined; +export function dispose( + arg: T | Iterable | undefined +): any; +export function dispose( + disposables: T[] +): T | T[] | undefined { + const errors = []; + if (isArray(disposables)) { + disposables.forEach((disposable) => { + try { + disposable?.dispose(); + } catch (err) { + errors.push(err); + } + }); + return []; + } + if (isDisposable(disposables)) { + try { + disposables.dispose(); + } catch (err) { + errors.push(err); + } + return disposables; + } + if (Iterable.is(disposables)) { + for (const disposable of disposables) { + try { + disposable?.dispose(); + } catch (err) { + errors.push(err); + } + } + } +} + +export default class DisposableStore implements IDisposable { + private readonly _toDispose = new Set(); + + private _isDisposed = false; + + public dispose(): void { + if (this._isDisposed) { + return; + } + + this._isDisposed = true; + this.clear(); + } + + public get isDisposed(): boolean { + return this._isDisposed; + } + + public clear(): void { + if (this._toDispose.size === 0) { + return; + } + + dispose(this._toDispose); + + this._toDispose.clear(); + } + + public add(thing: T): T { + if (!thing) return thing; + if ((thing as unknown as DisposableStore) === this) { + throw new Error('Cannot register a disposable on itself!'); + } + + if (this._isDisposed) { + // ... + } else { + this._toDispose.add(thing); + } + + return thing; + } + + public delete(thing: T): void { + if (!thing) { + return; + } + if ((thing as unknown as DisposableStore) === this) { + throw new Error('Cannot dispose a disposable on itself!'); + } + this._toDispose.delete(thing); + thing.dispose(); + } +} diff --git a/packages/event/disposable/src/index.ts b/packages/event/disposable/src/index.ts new file mode 100644 index 0000000..2ac289c --- /dev/null +++ b/packages/event/disposable/src/index.ts @@ -0,0 +1,3 @@ +export { Disposable } from './Disposable'; +export { default as DisposableStore } from './DisposableStore'; +export * from './types'; diff --git a/packages/event/disposable/src/types/disposable.ts b/packages/event/disposable/src/types/disposable.ts new file mode 100644 index 0000000..ab3e3f1 --- /dev/null +++ b/packages/event/disposable/src/types/disposable.ts @@ -0,0 +1,3 @@ +export interface IDisposable { + dispose(): void; +} diff --git a/packages/event/disposable/src/types/index.ts b/packages/event/disposable/src/types/index.ts new file mode 100644 index 0000000..23fc48c --- /dev/null +++ b/packages/event/disposable/src/types/index.ts @@ -0,0 +1 @@ +export * from './disposable'; diff --git a/packages/event/disposable/test/test.spec.ts b/packages/event/disposable/test/test.spec.ts new file mode 100644 index 0000000..042a31e --- /dev/null +++ b/packages/event/disposable/test/test.spec.ts @@ -0,0 +1,7 @@ +import { expect, test } from 'vitest'; +import { Disposable } from '../src'; + +test('disposable', async () => { + const disposable = new Disposable(); + expect(disposable).toBe(Disposable); +}); diff --git a/packages/event/disposable/tsconfig.build.json b/packages/event/disposable/tsconfig.build.json new file mode 100644 index 0000000..c8613f0 --- /dev/null +++ b/packages/event/disposable/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist", + "esModuleInterop": true + }, + + "include": [ + "index.ts", + "src/**/*" + ] +} \ No newline at end of file diff --git a/packages/event/disposable/tsconfig.json b/packages/event/disposable/tsconfig.json new file mode 100644 index 0000000..a5aa7cc --- /dev/null +++ b/packages/event/disposable/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/packages/event/disposable/vitest.config.ts b/packages/event/disposable/vitest.config.ts new file mode 100644 index 0000000..31d7ded --- /dev/null +++ b/packages/event/disposable/vitest.config.ts @@ -0,0 +1,26 @@ +// import path from 'path'; +// import tsPath from 'vite-tsconfig-paths'; +import { defineConfig } from 'vitest/config'; + +// const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf('/')); + +export default defineConfig({ + test: { + globals: true, + include: ['test/**/*.(spec|test).ts'], + exclude: ['node_modules/**'], + threads: false, + + coverage: { + provider: 'istanbul', // or 'c8' + }, + }, + + // plugins: [tsPath()], + resolve: { + alias: {}, + }, + define: { + __DEV__: false, + }, +}); diff --git a/packages/event/emitter/README.md b/packages/event/emitter/README.md new file mode 100644 index 0000000..ccfbb6d --- /dev/null +++ b/packages/event/emitter/README.md @@ -0,0 +1,13 @@ +# @x-oasis/each + +## Installation + +```bash +$ npm i @x-oasis/each +``` + +## How to use + +```typescript +import each from '@x-oasis/each' +``` \ No newline at end of file diff --git a/packages/event/emitter/package.json b/packages/event/emitter/package.json new file mode 100644 index 0000000..90186bb --- /dev/null +++ b/packages/event/emitter/package.json @@ -0,0 +1,27 @@ +{ + "name": "@x-oasis/each", + "version": "0.1.34", + "description": "each function", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "module": "dist/each.esm.js", + "files": [ + "dist", + "index.ts", + "src" + ], + "scripts": { + "build": "tsdx build --tsconfig tsconfig.build.json", + "clean": "rimraf ./dist", + "test": "vitest", + "compile": "tsc -p tsconfig.build.json" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "tsdx": "^0.14.1" + }, + "dependencies": { + "@x-oasis/is-object": "workspace:*" + } +} diff --git a/packages/event/emitter/src/index.ts b/packages/event/emitter/src/index.ts new file mode 100644 index 0000000..602e595 --- /dev/null +++ b/packages/event/emitter/src/index.ts @@ -0,0 +1,20 @@ +import isObject from '@x-oasis/is-object'; + +type EachArray = (index: number, entry: any, obj: T) => void; +type EachObject = (key: K, entry: T[K], obj: T) => number; +type Iter | { [key: string]: any }> = T extends Array + ? EachArray + : T extends { [key: string]: any } + ? EachObject + : never; + +export default function each(obj: T, iter: Iter) { + if (Array.isArray(obj)) { + (obj as Array).forEach((entry, index) => + (iter as EachArray)(index, entry, obj) + ); + } else if (isObject(obj)) { + // @ts-ignore + ownKeys(obj).forEach((key) => (iter as EachObject)(key, obj[key], obj)); + } +} diff --git a/packages/event/emitter/test/test.spec.ts b/packages/event/emitter/test/test.spec.ts new file mode 100644 index 0000000..963a9d5 --- /dev/null +++ b/packages/event/emitter/test/test.spec.ts @@ -0,0 +1,9 @@ +import { expect, test } from 'vitest'; +import each from '../'; + +test('each', async () => { + const array = [6.1, 4.2, 6.3]; + const actual = each(array, Math.floor); + + expect(actual).toEqual({ '4': [4.2], '6': [6.1, 6.3] }); +}); diff --git a/packages/event/emitter/tsconfig.build.json b/packages/event/emitter/tsconfig.build.json new file mode 100644 index 0000000..c8613f0 --- /dev/null +++ b/packages/event/emitter/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist", + "esModuleInterop": true + }, + + "include": [ + "index.ts", + "src/**/*" + ] +} \ No newline at end of file diff --git a/packages/event/emitter/tsconfig.json b/packages/event/emitter/tsconfig.json new file mode 100644 index 0000000..a5aa7cc --- /dev/null +++ b/packages/event/emitter/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/packages/event/emitter/vitest.config.ts b/packages/event/emitter/vitest.config.ts new file mode 100644 index 0000000..31d7ded --- /dev/null +++ b/packages/event/emitter/vitest.config.ts @@ -0,0 +1,26 @@ +// import path from 'path'; +// import tsPath from 'vite-tsconfig-paths'; +import { defineConfig } from 'vitest/config'; + +// const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf('/')); + +export default defineConfig({ + test: { + globals: true, + include: ['test/**/*.(spec|test).ts'], + exclude: ['node_modules/**'], + threads: false, + + coverage: { + provider: 'istanbul', // or 'c8' + }, + }, + + // plugins: [tsPath()], + resolve: { + alias: {}, + }, + define: { + __DEV__: false, + }, +}); diff --git a/packages/functional/each/test/test.spec.ts b/packages/functional/each/test/test.spec.ts index 963a9d5..6f0904d 100644 --- a/packages/functional/each/test/test.spec.ts +++ b/packages/functional/each/test/test.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from 'vitest'; -import each from '../'; +import each from '../src'; test('each', async () => { const array = [6.1, 4.2, 6.3]; diff --git a/packages/hypertext/README.md b/packages/hypertext/README.md new file mode 100644 index 0000000..5c932fa --- /dev/null +++ b/packages/hypertext/README.md @@ -0,0 +1,2 @@ +# @x-oasis/hypertext +