├── run_test.sh ├── run_bench.sh ├── .gitignore ├── bench.mod.ts ├── jsmodern ├── extend.ts ├── error.ts ├── object.ts ├── symbol.ts ├── boolean.ts ├── reg-exp.ts ├── promise.ts ├── iterator.ts ├── weak-map.ts ├── weak-set.ts ├── date.ts ├── function.ts ├── error.test.ts ├── object.test.ts ├── symbol.test.ts ├── reg-exp.test.ts ├── boolean.test.ts ├── promise.test.ts ├── weak-map.test.ts ├── weak-set.test.ts ├── iterator.test.ts ├── map.ts ├── function.test.ts ├── date.test.ts ├── number.ts ├── mod.ts ├── set.ts ├── map.test.ts ├── string.ts ├── number.test.ts ├── set.test.ts ├── string.test.ts ├── array.ts ├── array.test.ts └── README.md ├── delay_until ├── mod.ts ├── mod.bench.ts ├── delay_until.test.ts └── README.md ├── polling_observer ├── CONSTANTS.ts ├── mod.ts ├── error.test.ts ├── mod.bench.ts ├── README.md └── polling_observer.test.ts ├── normalize_diacritics ├── mod.ts ├── error.test.ts ├── mod.bench.ts ├── normalize.test.ts └── README.md ├── lit_ntml ├── mod.ts ├── CONSTANTS.ts ├── error.test.ts ├── html_sync.test.ts ├── mod.bench.ts ├── html_fragment_sync.test.ts ├── html_test.ts ├── html_fragment.test.ts └── README.md ├── deep_clone ├── mod.ts ├── error.test.ts ├── CONSTANTS.ts ├── mod.bench.ts ├── deep_clone.test.ts └── README.md ├── bench.ts ├── .editorconfig ├── test.mod.ts ├── .gitattributes ├── tsconfig.json ├── LICENSE ├── .github └── workflows │ └── ci.yml └── README.md /run_test.sh: -------------------------------------------------------------------------------- 1 | deno test --reload 2 | -------------------------------------------------------------------------------- /run_bench.sh: -------------------------------------------------------------------------------- 1 | deno run ./bench.ts --reload 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*cache 2 | .vscode 3 | 4 | node_modules 5 | -------------------------------------------------------------------------------- /bench.mod.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/denoland/deno@0.41.0/std/testing/bench.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/extend.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/extend.ts"; 2 | -------------------------------------------------------------------------------- /delay_until/mod.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/nodemod@2.6.1/src/delay-until/index.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/error.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/error/is-error.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/object.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/object/is-object.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/symbol.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/symbol/is-symbol.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/boolean.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/boolean/is-boolean.ts"; 2 | -------------------------------------------------------------------------------- /jsmodern/reg-exp.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/reg-exp/is-reg-exp.ts"; 2 | -------------------------------------------------------------------------------- /polling_observer/CONSTANTS.ts: -------------------------------------------------------------------------------- 1 | export interface MockData { 2 | items: number[]; 3 | status?: "complete" | "in-progress"; 4 | } 5 | -------------------------------------------------------------------------------- /normalize_diacritics/mod.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/normalize-diacritics@2.11.1/src/normalize-diacritics.ts"; 2 | -------------------------------------------------------------------------------- /lit_ntml/mod.ts: -------------------------------------------------------------------------------- 1 | // @deno-types="https://cdn.jsdelivr.net/npm/lit-ntml@2.16.1/dist/lit-ntml.d.ts" 2 | export * from "https://cdn.jsdelivr.net/npm/lit-ntml@2.16.1/dist/lit-ntml.min.js"; 3 | -------------------------------------------------------------------------------- /deep_clone/mod.ts: -------------------------------------------------------------------------------- 1 | // @deno-types="https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/deep-clone/index.d.ts" 2 | export * from "https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/deep-clone/index.js"; 3 | -------------------------------------------------------------------------------- /lit_ntml/CONSTANTS.ts: -------------------------------------------------------------------------------- 1 | export const helloWorld = `

Hello, World!

`; 2 | export const peopleList = [ 3 | "John Doe", 4 | "Michael CEO", 5 | "Vict Fisherman", 6 | "Cash Black" 7 | ]; 8 | -------------------------------------------------------------------------------- /jsmodern/promise.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/promise/delayed.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/promise/is-promise.ts"; 3 | -------------------------------------------------------------------------------- /jsmodern/iterator.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/iterator/is-async-iterator.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/iterator/is-iterator.ts"; 3 | -------------------------------------------------------------------------------- /jsmodern/weak-map.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-map/from.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-map/is-weak-map.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-map/of.ts"; 4 | -------------------------------------------------------------------------------- /jsmodern/weak-set.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-set/from.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-set/is-weak-set.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/weak-set/of.ts"; 4 | -------------------------------------------------------------------------------- /jsmodern/date.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/date/difference.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/date/is-after.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/date/is-before.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/date/is-date.ts"; 5 | -------------------------------------------------------------------------------- /bench.ts: -------------------------------------------------------------------------------- 1 | import { runBenchmarks } from "./bench.mod.ts"; 2 | 3 | import "./deep_clone/mod.bench.ts"; 4 | import "./delay_until/mod.bench.ts"; 5 | import "./lit_ntml/mod.bench.ts"; 6 | import "./normalize_diacritics/mod.bench.ts"; 7 | import "./polling_observer/mod.bench.ts"; 8 | 9 | async function benchmark() { 10 | await runBenchmarks(); 11 | } 12 | 13 | benchmark(); 14 | -------------------------------------------------------------------------------- /polling_observer/mod.ts: -------------------------------------------------------------------------------- 1 | // @deno-types="https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/polling-observer/index.d.ts" 2 | export * from "https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/polling-observer/index.js"; 3 | 4 | // @deno-types="https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/polling-observer/polling-measure.d.ts" 5 | export * from "https://cdn.jsdelivr.net/npm/nodemod@2.6.1/dist/polling-observer/polling-measure.js"; 6 | -------------------------------------------------------------------------------- /jsmodern/function.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/function/is-async-function.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/function/is-async-generator-function.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/function/is-function.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/function/is-generator-function.ts"; 5 | -------------------------------------------------------------------------------- /delay_until/mod.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, BenchmarkTimer } from "../bench.mod.ts"; 2 | 3 | import { delayUntil } from "./mod.ts"; 4 | 5 | const runs = 3; 6 | const iter = 1e3; 7 | 8 | bench({ 9 | runs, 10 | name: `runs${runs}ForDelayUntilX${iter}s`, 11 | async func(b: BenchmarkTimer) { 12 | b.start(); 13 | for (let i = 0; i < iter; i += 1) { 14 | /** No delay */ 15 | await delayUntil(); 16 | } 17 | b.stop(); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_style = space 10 | indent_size = 2 11 | 12 | # We recommend you to keep these unchanged 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /test.mod.ts: -------------------------------------------------------------------------------- 1 | import { 2 | cyan, 3 | yellow 4 | } from "https://cdn.jsdelivr.net/gh/denoland/deno@0.41.0/std/fmt/colors.ts"; 5 | 6 | export * from "https://cdn.jsdelivr.net/gh/denoland/deno@0.41.0/std/testing/asserts.ts"; 7 | 8 | export function prepareTest( 9 | tests: (() => any)[], 10 | name: string, 11 | prefix: string = "" 12 | ) { 13 | return tests.map(n => 14 | Deno.test({ 15 | name: `${cyan(name)} ${prefix && yellow(prefix) + " "}${n.name}`, 16 | fn: n 17 | }) 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /jsmodern/error.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isError } from "./error.ts"; 6 | 7 | extend({ 8 | error: [isError] 9 | }); 10 | 11 | async function willExtendErrorConstructor() { 12 | const extensions = [["Error.isError", "isError"]]; 13 | const expectation = extensions.every(([_, methodName]) => { 14 | return methodName in Error; 15 | }); 16 | 17 | assertStrictEq(expectation, true); 18 | } 19 | 20 | prepareTest([willExtendErrorConstructor], "jsmodern", "error"); 21 | -------------------------------------------------------------------------------- /jsmodern/object.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isObject } from "./object.ts"; 6 | 7 | extend({ 8 | object: [isObject] 9 | }); 10 | 11 | async function willExtendObjectConstructor() { 12 | const extensions = [["Object.isObject", "isObject"]]; 13 | const expectation = extensions.every(([_, methodName]) => { 14 | return methodName in Object; 15 | }); 16 | 17 | assertStrictEq(expectation, true); 18 | } 19 | 20 | prepareTest([willExtendObjectConstructor], "jsmodern", "object"); 21 | -------------------------------------------------------------------------------- /jsmodern/symbol.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isSymbol } from "./symbol.ts"; 6 | 7 | extend({ 8 | symbol: [isSymbol] 9 | }); 10 | 11 | async function willExtendSymbolConstructor() { 12 | const extensions = [["Symbol.isSymbol", "isSymbol"]]; 13 | const expectation = extensions.every(([_, methodName]) => { 14 | return methodName in Symbol; 15 | }); 16 | 17 | assertStrictEq(expectation, true); 18 | } 19 | 20 | prepareTest([willExtendSymbolConstructor], "jsmodern", "symbol"); 21 | -------------------------------------------------------------------------------- /jsmodern/reg-exp.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isRegExp } from "./reg-exp.ts"; 6 | 7 | extend({ 8 | regExp: [isRegExp] 9 | }); 10 | 11 | async function willExtendRegExpConstructor() { 12 | const extensions = [["RegExp.isRegExp", "isRegExp"]]; 13 | const expectation = extensions.every(([_, methodName]) => { 14 | return methodName in RegExp; 15 | }); 16 | 17 | assertStrictEq(expectation, true); 18 | } 19 | 20 | prepareTest([willExtendRegExpConstructor], "jsmodern", "regExp"); 21 | -------------------------------------------------------------------------------- /jsmodern/boolean.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isBoolean } from "./boolean.ts"; 6 | 7 | extend({ 8 | boolean: [isBoolean] 9 | }); 10 | 11 | async function willExtendBooleanConstructor() { 12 | const extensions = [["Boolean.isBoolean", "isBoolean"]]; 13 | const expectation = extensions.every(([_, methodName]) => { 14 | return methodName in Boolean; 15 | }); 16 | 17 | assertStrictEq(expectation, true); 18 | } 19 | 20 | prepareTest([willExtendBooleanConstructor], "jsmodern", "boolean"); 21 | -------------------------------------------------------------------------------- /jsmodern/promise.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { delayed, isPromise } from "./promise.ts"; 6 | 7 | extend({ 8 | promise: [delayed, isPromise] 9 | }); 10 | 11 | async function willExtendPromiseConstructor() { 12 | const extensions = [ 13 | ["Promise.delayed", "delayed"], 14 | ["Promise.isPromise", "isPromise"] 15 | ]; 16 | const expectation = extensions.every(([_, methodName]) => { 17 | return methodName in Promise; 18 | }); 19 | 20 | assertStrictEq(expectation, true); 21 | } 22 | 23 | prepareTest([willExtendPromiseConstructor], "jsmodern", "promise"); 24 | -------------------------------------------------------------------------------- /delay_until/delay_until.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { delayUntil } from "./mod.ts"; 4 | 5 | async function willDelay() { 6 | const r = await delayUntil(3e3); 7 | 8 | assertStrictEq(r, void 0); 9 | } 10 | 11 | async function willResolveWithOptionalDelay() { 12 | const r = await delayUntil(); 13 | 14 | assertStrictEq(r, void 0); 15 | } 16 | 17 | async function willResolveWithDelayFallbacksTo0() { 18 | const r = await delayUntil(null!); 19 | 20 | assertStrictEq(r, void 0); 21 | } 22 | 23 | prepareTest( 24 | [willDelay, willResolveWithDelayFallbacksTo0, willResolveWithOptionalDelay], 25 | "delay_until" 26 | ); 27 | -------------------------------------------------------------------------------- /jsmodern/weak-map.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { from, isWeakMap, of } from "./weak-map.ts"; 6 | 7 | extend({ 8 | weakMap: [from, isWeakMap, of] 9 | }); 10 | 11 | async function willExtendWeakMapConstructor() { 12 | const extensions = [ 13 | ["WeakMap.from", "from"], 14 | ["WeakMap.isWeakMap", "isWeakMap"], 15 | ["WeakMap.of", "of"] 16 | ]; 17 | const expectation = extensions.every(([_, methodName]) => { 18 | return methodName in WeakMap; 19 | }); 20 | 21 | assertStrictEq(expectation, true); 22 | } 23 | 24 | prepareTest([willExtendWeakMapConstructor], "jsmodern", "weakMap"); 25 | -------------------------------------------------------------------------------- /jsmodern/weak-set.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { from, isWeakSet, of } from "./weak-set.ts"; 6 | 7 | extend({ 8 | weakSet: [from, isWeakSet, of] 9 | }); 10 | 11 | async function willExtendWeakSetConstructor() { 12 | const extensions = [ 13 | ["WeakSet.from", "from"], 14 | ["WeakSet.isWeakSet", "isWeakSet"], 15 | ["WeakSet.of", "of"] 16 | ]; 17 | const expectation = extensions.every(([_, methodName]) => { 18 | return methodName in WeakSet; 19 | }); 20 | 21 | assertStrictEq(expectation, true); 22 | } 23 | 24 | prepareTest([willExtendWeakSetConstructor], "jsmodern", "weakSet"); 25 | -------------------------------------------------------------------------------- /jsmodern/iterator.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { isAsyncIterator, isIterator } from "./iterator.ts"; 6 | 7 | extend({ 8 | iterator: [isAsyncIterator, isIterator] 9 | }); 10 | 11 | async function willExtendIteratorConstructor() { 12 | const extensions = [ 13 | ["Function.isAsyncIterator", "isAsyncIterator"], 14 | ["Function.isIterator", "isIterator"] 15 | ]; 16 | const expectation = extensions.every(([_, methodName]) => { 17 | return methodName in (window || globalThis); 18 | }); 19 | 20 | assertStrictEq(expectation, true); 21 | } 22 | 23 | prepareTest([willExtendIteratorConstructor], "jsmodern", "iterator"); 24 | -------------------------------------------------------------------------------- /deep_clone/error.test.ts: -------------------------------------------------------------------------------- 1 | import { assertThrowsAsync, prepareTest } from "../test.mod.ts"; 2 | 3 | import { deepClone } from "./mod.ts"; 4 | 5 | async function failsWhenDeeplyCloneNull() { 6 | assertThrowsAsync( 7 | async () => { 8 | const nu = null; 9 | await deepClone(nu); 10 | }, 11 | TypeError, 12 | `'target' is not defined` 13 | ); 14 | } 15 | 16 | async function failsWhenDeeplyCloneUndefined() { 17 | assertThrowsAsync( 18 | async () => { 19 | const nu = void 0; 20 | await deepClone(nu); 21 | }, 22 | TypeError, 23 | `'target' is not defined` 24 | ); 25 | } 26 | 27 | prepareTest( 28 | [failsWhenDeeplyCloneNull, failsWhenDeeplyCloneUndefined], 29 | "deep_clone", 30 | "error" 31 | ); 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Automatically normalize line endings for all text-based files 2 | # http://git-scm.com/docs/gitattributes#_end_of_line_conversion 3 | * text=auto 4 | 5 | # For the following file types, normalize line endings to LF on 6 | # checkin and prevent conversion to CRLF when they are checked out 7 | # (this is required in order to prevent newline related issues like, 8 | # for example, after the build script is run) 9 | .* text eol=lf 10 | *.css text eol=lf 11 | *.html text eol=lf 12 | *.js text eol=lf 13 | *.json text eol=lf 14 | *.md text eol=lf 15 | *.scss text eol=lf 16 | *.sh text eol=lf 17 | *.ts text eol=lf 18 | *.tsx text eol=lf 19 | *.txt text eol=lf 20 | *.xml text eol=lf 21 | *.yaml text eol=lf 22 | *.yml text eol=lf 23 | -------------------------------------------------------------------------------- /normalize_diacritics/error.test.ts: -------------------------------------------------------------------------------- 1 | import { assertThrowsAsync, prepareTest } from "../test.mod.ts"; 2 | 3 | import { normalize } from "./mod.ts"; 4 | 5 | async function failsWhenInvalidInput() { 6 | await assertThrowsAsync( 7 | async () => (normalize(null) as unknown) as void, 8 | TypeError, 9 | `Expected 'input' to be of type string, but received 'null'` 10 | ); 11 | } 12 | 13 | async function failsWhenInputIsUndefined() { 14 | await assertThrowsAsync( 15 | async () => (normalize() as unknown) as void, 16 | TypeError, 17 | `Expected 'input' to be of type string, but received 'undefined'` 18 | ); 19 | } 20 | 21 | prepareTest( 22 | [failsWhenInputIsUndefined, failsWhenInvalidInput], 23 | "normalize_diacritics", 24 | "error" 25 | ); 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "experimentalDecorators": true, 6 | "newLine": "LF", 7 | "noFallthroughCasesInSwitch": true, 8 | "noImplicitReturns": true, 9 | "noUnusedLocals": true, 10 | "noUnusedParameters": true, 11 | "resolveJsonModule": true, 12 | "strict": true, 13 | 14 | "lib": [ 15 | "dom", 16 | "dom.iterable", 17 | "esnext", 18 | "esnext.array", 19 | "esnext.asynciterable", 20 | "esnext.intl", 21 | "esnext.symbol" 22 | ], 23 | "baseUrl": ".", 24 | "module": "esnext", 25 | "moduleResolution": "node", 26 | "pretty": true, 27 | "target": "esnext" 28 | }, 29 | "include": ["./**/*.ts"] 30 | } 31 | -------------------------------------------------------------------------------- /lit_ntml/error.test.ts: -------------------------------------------------------------------------------- 1 | import { assertThrowsAsync, prepareTest } from "../test.mod.ts"; 2 | 3 | import { html, htmlFragment } from "./mod.ts"; 4 | 5 | async function failsWhenHtmlThrowsError() { 6 | await assertThrowsAsync( 7 | async () => { 8 | const errorContent = async () => { 9 | throw new Error("error"); 10 | }; 11 | await html`${errorContent}`; 12 | }, 13 | Error, 14 | "error" 15 | ); 16 | } 17 | 18 | async function failsWhenHtmlFragmentThrowsError() { 19 | await assertThrowsAsync( 20 | async () => { 21 | const errorContent = async () => { 22 | throw new Error("error"); 23 | }; 24 | await htmlFragment`${errorContent}`; 25 | }, 26 | Error, 27 | "error" 28 | ); 29 | } 30 | 31 | prepareTest( 32 | [failsWhenHtmlFragmentThrowsError, failsWhenHtmlThrowsError], 33 | "lit_ntml", 34 | "error" 35 | ); 36 | -------------------------------------------------------------------------------- /normalize_diacritics/mod.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, BenchmarkTimer } from "../bench.mod.ts"; 2 | 3 | import { normalize, normalizeSync } from "./mod.ts"; 4 | 5 | const runs = 3; 6 | const iter = 1e3; 7 | 8 | bench({ 9 | runs, 10 | name: `runs${runs}ForNormalizeDiacriticsX${iter}s`, 11 | async func(b: BenchmarkTimer) { 12 | b.start(); 13 | for (let i = 0; i < iter; i += 1) { 14 | await normalize( 15 | `söme stüff with áccènts ${Math.random() 16 | .toString(16) 17 | .slice(-7)}` 18 | ); 19 | } 20 | b.stop(); 21 | } 22 | }); 23 | 24 | bench({ 25 | runs, 26 | name: `runs${runs}ForNormalizeDiacriticsSyncX${iter}s`, 27 | func(b: BenchmarkTimer) { 28 | b.start(); 29 | for (let i = 0; i < iter; i += 1) { 30 | normalizeSync( 31 | `söme stüff with áccènts ${Math.random() 32 | .toString(16) 33 | .slice(-7)}` 34 | ); 35 | } 36 | b.stop(); 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /jsmodern/map.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/entry.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/entry-or-default.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/from.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/get-or-default.ts"; 5 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/is-empty.ts"; 6 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/is-map.ts"; 7 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/iter.ts"; 8 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/len.ts"; 9 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/of.ts"; 10 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/remove-entry.ts"; 11 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/map/to-array.ts"; 12 | -------------------------------------------------------------------------------- /jsmodern/function.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | isAsyncFunction, 7 | isAsyncGeneratorFunction, 8 | isFunction, 9 | isGeneratorFunction 10 | } from "./function.ts"; 11 | 12 | extend({ 13 | function: [ 14 | isAsyncFunction, 15 | isAsyncGeneratorFunction, 16 | isFunction, 17 | isGeneratorFunction 18 | ] 19 | }); 20 | 21 | async function willExtendFunctionConstructor() { 22 | const extensions = [ 23 | ["Function.isAsyncFunction", "isAsyncFunction"], 24 | ["Function.isAsyncGeneratorFunction", "isAsyncGeneratorFunction"], 25 | ["Function.isFunction", "isFunction"], 26 | ["Function.isGeneratorFunction", "isGeneratorFunction"] 27 | ]; 28 | const expectation = extensions.every(([_, methodName]) => { 29 | return methodName in Function; 30 | }); 31 | 32 | assertStrictEq(expectation, true); 33 | } 34 | 35 | prepareTest([willExtendFunctionConstructor], "jsmodern", "function"); 36 | -------------------------------------------------------------------------------- /jsmodern/date.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { difference, isAfter, isBefore, isDate } from "./date.ts"; 6 | 7 | extend({ 8 | date: [difference, isAfter, isBefore, isDate] 9 | }); 10 | 11 | async function willExtendDatePrototype() { 12 | const extensions = [ 13 | ["Date.prototype.difference", "difference"], 14 | ["Date.prototype.isAfter", "isAfter"], 15 | ["Date.prototype.isBefore", "isBefore"] 16 | ]; 17 | const expectation = extensions.every(([_, methodName]) => { 18 | return methodName in Date.prototype; 19 | }); 20 | 21 | assertStrictEq(expectation, true); 22 | } 23 | 24 | async function willExtendDateConstructor() { 25 | const extensions = [["Date.isDate", "isDate"]]; 26 | const expectation = extensions.every(([_, methodName]) => { 27 | return methodName in Date; 28 | }); 29 | 30 | assertStrictEq(expectation, true); 31 | } 32 | 33 | prepareTest( 34 | [willExtendDateConstructor, willExtendDatePrototype], 35 | "jsmodern", 36 | "date" 37 | ); 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2019 Rong Sen Ng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /jsmodern/number.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/div-floor.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/div-mod-floor.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/div-rem.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/gcd.ts"; 5 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/is-between.ts"; 6 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/is-even.ts"; 7 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/is-multiple-of.ts"; 8 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/is-number.ts"; 9 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/is-odd.ts"; 10 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/lcm.ts"; 11 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/mod-floor.ts"; 12 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/number/range.ts"; 13 | -------------------------------------------------------------------------------- /jsmodern/mod.ts: -------------------------------------------------------------------------------- 1 | import * as arrayExtend from "./array.ts"; 2 | import * as booleanExtend from "./boolean.ts"; 3 | import * as dateExtend from "./date.ts"; 4 | import * as errorExtend from "./error.ts"; 5 | import * as functionExtend from "./function.ts"; 6 | import * as iteratorExtend from "./iterator.ts"; 7 | import * as mapExtend from "./map.ts"; 8 | import * as numberExtend from "./number.ts"; 9 | import * as objectExtend from "./object.ts"; 10 | import * as promiseExtend from "./promise.ts"; 11 | import * as regExpExtend from "./reg-exp.ts"; 12 | import * as setExtend from "./set.ts"; 13 | import * as stringExtend from "./string.ts"; 14 | import * as symbolExtend from "./symbol.ts"; 15 | import * as weakMapExtend from "./weak-map.ts"; 16 | import * as weakSetExtend from "./weak-set.ts"; 17 | 18 | export * from "./extend.ts"; 19 | 20 | export { 21 | arrayExtend, 22 | booleanExtend, 23 | dateExtend, 24 | errorExtend, 25 | functionExtend, 26 | iteratorExtend, 27 | mapExtend, 28 | numberExtend, 29 | objectExtend, 30 | promiseExtend, 31 | regExpExtend, 32 | setExtend, 33 | stringExtend, 34 | symbolExtend, 35 | weakMapExtend, 36 | weakSetExtend 37 | }; 38 | -------------------------------------------------------------------------------- /polling_observer/error.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, assertThrowsAsync, prepareTest } from "../test.mod.ts"; 2 | 3 | import { MockData } from "./CONSTANTS.ts"; 4 | import { PollingObserver, OnfinishRejected, OnfinishValue } from "./mod.ts"; 5 | 6 | async function failsWhenConditionCallbackIsUndefined() { 7 | await assertThrowsAsync( 8 | async () => (new PollingObserver(undefined!) as unknown) as void, 9 | TypeError, 10 | `'conditionCallback' is not defined` 11 | ); 12 | } 13 | 14 | async function failsWhenErrorOccurs() { 15 | const obs = new PollingObserver(() => false); 16 | const task = new Promise(yay => { 17 | obs.onfinish = (d: OnfinishValue) => yay(d as OnfinishRejected); 18 | }); 19 | 20 | obs.observe( 21 | async () => { 22 | throw new Error("polling error"); 23 | }, 24 | { interval: 1e3 } 25 | ); 26 | 27 | const { status, reason } = await task; 28 | 29 | assertStrictEq(status, "error"); 30 | assertStrictEq(reason instanceof Error, true); 31 | assertStrictEq(reason.message, "polling error"); 32 | } 33 | 34 | prepareTest( 35 | [failsWhenConditionCallbackIsUndefined, failsWhenErrorOccurs], 36 | "polling_observer", 37 | "error" 38 | ); 39 | -------------------------------------------------------------------------------- /jsmodern/set.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/difference.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/from.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/intersection.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/is-disjoint.ts"; 5 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/is-empty.ts"; 6 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/is-set.ts"; 7 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/is-subset.ts"; 8 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/is-superset.ts"; 9 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/iter.ts"; 10 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/len.ts"; 11 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/of.ts"; 12 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/symmetric-difference.ts"; 13 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/to-array.ts"; 14 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/set/union.ts"; 15 | -------------------------------------------------------------------------------- /lit_ntml/html_sync.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { helloWorld, peopleList } from "./CONSTANTS.ts"; 4 | import { htmlSync as html } from "./mod.ts"; 5 | 6 | function willRender() { 7 | assertStrictEq( 8 | html`${helloWorld}`, 9 | `

Hello, World!

` 10 | ); 11 | } 12 | 13 | function willRenderWithSyncTasks() { 14 | const syncTask = () => helloWorld; 15 | const syncLiteral = "John Doe"; 16 | 17 | assertStrictEq( 18 | html`
${syncTask}

${syncLiteral}

`, 19 | // tslint:disable-next-line: max-line-length 20 | `

Hello, World!

John Doe

` 21 | ); 22 | } 23 | 24 | 25 | function willRenderAListOfSyncTasks() { 26 | assertStrictEq( 27 | html`${helloWorld}
    ${peopleList.map(n => `
  • ${n}
  • `)}
`, 28 | // tslint:disable-next-line: max-line-length 29 | `

Hello, World!

  • John Doe
  • Michael CEO
  • Vict Fisherman
  • Cash Black
` 30 | ); 31 | } 32 | 33 | prepareTest( 34 | [ 35 | willRender, 36 | willRenderAListOfSyncTasks, 37 | willRenderWithSyncTasks 38 | ], 39 | "lit_ntml", 40 | "htmlSync" 41 | ); 42 | -------------------------------------------------------------------------------- /polling_observer/mod.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, BenchmarkTimer } from "../bench.mod.ts"; 2 | 3 | import { PollingObserver } from "./mod.ts"; 4 | 5 | const runs = 3; 6 | const iter = 1e3; 7 | 8 | bench({ 9 | runs, 10 | name: `runs${runs}ForPollingObserverWithSyncConditionCallbackX${iter}s`, 11 | async func(b: BenchmarkTimer) { 12 | let i = iter; 13 | 14 | b.start(); 15 | while (i) { 16 | /** NOTE(motss): Test how long it takes to instantiate, run polling, then disconnect */ 17 | const obs = new PollingObserver(() => true); 18 | const task = new Promise(yay => (obs.onfinish = yay)); 19 | obs.observe(async () => new Promise(yay => setTimeout(yay, 1)), { 20 | interval: 1, 21 | timeout: 1e3 22 | }); 23 | 24 | await task; 25 | obs.disconnect(); 26 | i -= 1; 27 | } 28 | b.stop(); 29 | } 30 | }); 31 | 32 | bench({ 33 | runs, 34 | name: `runs${runs}ForPollingObserverWithAsyncConditionCallbackX${iter}s`, 35 | async func(b: BenchmarkTimer) { 36 | let i = iter; 37 | 38 | b.start(); 39 | while (i) { 40 | /** NOTE(motss): Test how long it takes to instantiate, run polling, then disconnect */ 41 | const obs = new PollingObserver(async () => true); 42 | const task = new Promise(yay => (obs.onfinish = yay)); 43 | obs.observe(async () => new Promise(yay => setTimeout(yay, 1)), { 44 | interval: 1, 45 | timeout: 1e3 46 | }); 47 | 48 | await task; 49 | obs.disconnect(); 50 | i -= 1; 51 | } 52 | b.stop(); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /lit_ntml/mod.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, BenchmarkTimer } from "../bench.mod.ts"; 2 | 3 | import { 4 | html, 5 | htmlFragment, 6 | htmlFragmentSync, 7 | htmlSync 8 | } from "./mod.ts"; 9 | 10 | const runs = 3; 11 | const iter = 1e3; 12 | 13 | bench({ 14 | runs, 15 | name: `runs${runs}ForHtmlX${iter}s`, 16 | async func(b: BenchmarkTimer) { 17 | b.start(); 18 | for (let i = 0; i < iter; i += 1) { 19 | await html`

Hello, World

`; 22 | } 23 | b.stop(); 24 | } 25 | }); 26 | 27 | bench({ 28 | runs, 29 | name: `runs${runs}ForHtmlFragmentX${iter}s`, 30 | async func(b: BenchmarkTimer) { 31 | b.start(); 32 | for (let i = 0; i < iter; i += 1) { 33 | await htmlFragment`

Hello, World

`; 36 | } 37 | b.stop(); 38 | } 39 | }); 40 | 41 | bench({ 42 | runs, 43 | name: `runs${runs}ForHtmlFragmentSyncX${iter}s`, 44 | func(b: BenchmarkTimer) { 45 | b.start(); 46 | for (let i = 0; i < iter; i += 1) { 47 | htmlFragmentSync`

Hello, World

`; 50 | } 51 | b.stop(); 52 | } 53 | }); 54 | 55 | bench({ 56 | runs, 57 | name: `runs${runs}ForHtmlSyncX${iter}s`, 58 | func(b: BenchmarkTimer) { 59 | b.start(); 60 | for (let i = 0; i < iter; i += 1) { 61 | htmlSync`

Hello, World

`; 64 | } 65 | b.stop(); 66 | } 67 | }); 68 | -------------------------------------------------------------------------------- /jsmodern/map.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | entry, 7 | entryOrDefault, 8 | from, 9 | getOrDefault, 10 | isEmpty, 11 | isMap, 12 | iter, 13 | len, 14 | of, 15 | removeEntry, 16 | toArray 17 | } from "./map.ts"; 18 | 19 | extend({ 20 | map: [ 21 | entry, 22 | entryOrDefault, 23 | from, 24 | getOrDefault, 25 | isEmpty, 26 | isMap, 27 | iter, 28 | len, 29 | of, 30 | removeEntry, 31 | toArray 32 | ] 33 | }); 34 | 35 | async function willExtendMapPrototype() { 36 | const extensions = [ 37 | ["Map.prototype.entry", "entry"], 38 | ["Map.prototype.entryOrDefault", "entryOrDefault"], 39 | ["Map.prototype.getOrDefault", "getOrDefault"], 40 | ["Map.prototype.isEmpty", "isEmpty"], 41 | ["Map.prototype.iter", "iter"], 42 | ["Map.prototype.len", "len"], 43 | ["Map.prototype.removeEntry", "removeEntry"], 44 | ["Map.prototype.toArray", "toArray"] 45 | ]; 46 | const expectation = extensions.every(([_, methodName]) => { 47 | return methodName in Map.prototype; 48 | }); 49 | 50 | assertStrictEq(expectation, true); 51 | } 52 | 53 | async function willExtendMapConstructor() { 54 | const extensions = [ 55 | ["Map.from", "from"], 56 | ["Map.isMap", "isMap"], 57 | ["Map.of", "of"] 58 | ]; 59 | const expectation = extensions.every(([_, methodName]) => { 60 | return methodName in Map; 61 | }); 62 | 63 | assertStrictEq(expectation, true); 64 | } 65 | 66 | prepareTest( 67 | [willExtendMapConstructor, willExtendMapPrototype], 68 | "jsmodern", 69 | "map" 70 | ); 71 | -------------------------------------------------------------------------------- /jsmodern/string.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/capitalize.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/contains.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/first-index.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/first-item.ts"; 5 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/insert.ts"; 6 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/is-empty.ts"; 7 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/is-string.ts"; 8 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/last-index.ts"; 9 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/last-item.ts"; 10 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/len.ts"; 11 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/lines.ts"; 12 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/retain.ts"; 13 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/split-whitespace.ts"; 14 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/to-camel-case.ts"; 15 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/to-kebab-case.ts"; 16 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/to-pascal-case.ts"; 17 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/to-snake-case.ts"; 18 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/string/to-start-case.ts"; 19 | -------------------------------------------------------------------------------- /lit_ntml/html_fragment_sync.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { helloWorld, peopleList } from "./CONSTANTS.ts"; 4 | import { htmlFragmentSync as html } from "./mod.ts"; 5 | 6 | function willRender() { 7 | assertStrictEq( 8 | html`${helloWorld}`, 9 | `

Hello, World!

` 10 | ); 11 | } 12 | 13 | function willRenderWithSyncTasks() { 14 | const syncTask = () => helloWorld; 15 | const syncLiteral = "John Doe"; 16 | 17 | assertStrictEq( 18 | html`
${syncTask}

${syncLiteral}

`, 19 | // tslint:disable-next-line: max-line-length 20 | `

Hello, World!

John Doe

` 21 | ); 22 | } 23 | 24 | function willRenderAListOfSyncTasks() { 25 | assertStrictEq( 26 | html`${helloWorld}
    ${peopleList.map(n => `
  • ${n}
  • `)}
`, 27 | // tslint:disable-next-line: max-line-length 28 | `

Hello, World!

  • John Doe
  • Michael CEO
  • Vict Fisherman
  • Cash Black
` 29 | ); 30 | } 31 | 32 | function willRenderExternalStyle() { 33 | // tslint:disable-next-line: max-line-length 34 | const asyncExternalStyleTask = () => 35 | html`body { margin: 0; padding: 0; box-sizing: border-box; }`; 36 | 37 | assertStrictEq( 38 | html`${helloWorld}`, 39 | // tslint:disable-next-line: max-line-length 40 | `

Hello, World!

` 41 | ); 42 | } 43 | 44 | prepareTest( 45 | [ 46 | willRender, 47 | willRenderAListOfSyncTasks, 48 | willRenderExternalStyle, 49 | willRenderWithSyncTasks 50 | ], 51 | "lit_ntml", 52 | "htmlFragmentSync" 53 | ); 54 | -------------------------------------------------------------------------------- /jsmodern/number.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | divFloor, 7 | divModFloor, 8 | divRem, 9 | gcd, 10 | isBetween, 11 | isEven, 12 | isMultipleOf, 13 | isNumber, 14 | isOdd, 15 | lcm, 16 | modFloor, 17 | range 18 | } from "./number.ts"; 19 | 20 | extend({ 21 | number: [ 22 | divFloor, 23 | divModFloor, 24 | divRem, 25 | gcd, 26 | isBetween, 27 | isEven, 28 | isMultipleOf, 29 | isNumber, 30 | isOdd, 31 | lcm, 32 | modFloor, 33 | range 34 | ] 35 | }); 36 | 37 | async function willExtendNumberPrototype() { 38 | const extensions = [ 39 | ["Number.prototype.divFloor", "divFloor"], 40 | ["Number.prototype.divModFloor", "divModFloor"], 41 | ["Number.prototype.divRem", "divRem"], 42 | ["Number.prototype.gcd", "gcd"], 43 | ["Number.prototype.isBetween", "isBetween"], 44 | ["Number.prototype.isEven", "isEven"], 45 | ["Number.prototype.isMultipleOf", "isMultipleOf"], 46 | ["Number.prototype.isOdd", "isOdd"], 47 | ["Number.prototype.lcm", "lcm"], 48 | ["Number.prototype.modFloor", "modFloor"] 49 | ]; 50 | const expectation = extensions.every(([_, methodName]) => { 51 | return methodName in Number.prototype; 52 | }); 53 | 54 | assertStrictEq(expectation, true); 55 | } 56 | 57 | async function willExtendNumberConstructor() { 58 | const extensions = [ 59 | ["Number.isNumber", "isNumber"], 60 | ["Number.range", "range"] 61 | ]; 62 | const expectation = extensions.every(([_, methodName]) => { 63 | return methodName in Number; 64 | }); 65 | 66 | assertStrictEq(expectation, true); 67 | } 68 | 69 | prepareTest( 70 | [willExtendNumberConstructor, willExtendNumberPrototype], 71 | "jsmodern", 72 | "number" 73 | ); 74 | -------------------------------------------------------------------------------- /jsmodern/set.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | difference, 7 | from, 8 | intersection, 9 | isDisjoint, 10 | isEmpty, 11 | isSet, 12 | isSubset, 13 | isSuperset, 14 | iter, 15 | len, 16 | of, 17 | symmetricDifference, 18 | toArray, 19 | union 20 | } from "./set.ts"; 21 | 22 | extend({ 23 | set: [ 24 | difference, 25 | from, 26 | intersection, 27 | isDisjoint, 28 | isEmpty, 29 | isSet, 30 | isSubset, 31 | isSuperset, 32 | iter, 33 | len, 34 | of, 35 | symmetricDifference, 36 | toArray, 37 | union 38 | ] 39 | }); 40 | 41 | async function willExtendSetPrototype() { 42 | const extensions = [ 43 | ["Set.prototype.difference", "difference"], 44 | ["Set.prototype.intersection", "intersection"], 45 | ["Set.prototype.isDisjoint", "isDisjoint"], 46 | ["Set.prototype.isEmpty", "isEmpty"], 47 | ["Set.prototype.isSubset", "isSubset"], 48 | ["Set.prototype.isSuperset", "isSuperset"], 49 | ["Set.prototype.iter", "iter"], 50 | ["Set.prototype.len", "len"], 51 | ["Set.prototype.symmetricDifference", "symmetricDifference"], 52 | ["Set.prototype.toArray", "toArray"], 53 | ["Set.prototype.union", "union"] 54 | ]; 55 | const expectation = extensions.every(([_, methodName]) => { 56 | return methodName in Set.prototype; 57 | }); 58 | 59 | assertStrictEq(expectation, true); 60 | } 61 | 62 | async function willExtendSetConstructor() { 63 | const extensions = [ 64 | ["Set.from", "from"], 65 | ["Set.isSet", "isSet"], 66 | ["Set.of", "of"] 67 | ]; 68 | const expectation = extensions.every(([_, methodName]) => { 69 | return methodName in Set; 70 | }); 71 | 72 | assertStrictEq(expectation, true); 73 | } 74 | 75 | prepareTest( 76 | [willExtendSetConstructor, willExtendSetPrototype], 77 | "jsmodern", 78 | "set" 79 | ); 80 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | tags-ignore: 8 | - '*' 9 | pull_request: 10 | branches: 11 | - '*' 12 | tags-ignore: 13 | - '*' 14 | 15 | env: 16 | CI_SKIP: false 17 | 18 | jobs: 19 | test: 20 | if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, 'doc:')" 21 | name: ${{ matrix.os }} ${{ matrix.target }} 22 | runs-on: ${{ matrix.os }} 23 | strategy: 24 | matrix: 25 | os: [macos-latest, ubuntu-18.04, windows-2019] 26 | target: [0.41] 27 | timeout-minutes: 120 28 | 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v2 32 | 33 | - name: Git log 34 | shell: bash 35 | run: | 36 | if [ -n "$(git log --format=%B -n 1 | grep -iE '^[0-9]+[.]{1,}[0-9]+[.]{1,}[0-9]+')" ]; then 37 | echo '::set-env name=CI_SKIP::true' 38 | fi 39 | 40 | - name: Setup deno@${{ matrix.target }} 41 | if: "env.CI_SKIP == 'false'" 42 | uses: denolib/setup-deno@master 43 | with: 44 | deno-version: ${{ matrix.target }} 45 | 46 | - name: List versions 47 | if: "env.CI_SKIP == 'false'" 48 | continue-on-error: true 49 | shell: bash 50 | run: | 51 | deno --version && which deno && pwd && npx envinfo 52 | 53 | - name: Test 54 | if: "env.CI_SKIP == 'false'" 55 | run: | 56 | deno test --reload 57 | 58 | - name: Benchmark 59 | if: "env.CI_SKIP == 'false' && success()" 60 | run: | 61 | deno run ./bench.ts --reload 62 | 63 | # - name: Upload coverage to codecov 64 | # uses: codecov/codecov-action@v1 65 | # if: success() 66 | # with: 67 | # token: ${{ secrets.CODECOV_TOKEN }} 68 | # file: ./coverage/lcov.info 69 | # flags: unit_tests 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Deno Modules

3 | 4 |

Modules for deno

5 |
6 | 7 |
8 | 9 | [![Version][version-badge]][version-url] 10 | [![MIT License][mit-license-badge]][mit-license-url] 11 | 12 | [![ci][ga-badge]][ga-url] 13 | 14 | > A collection of [deno] modules written in TypeScript. 15 | 16 | ## Table of contents 17 | 18 | - [Pre-requisite](#pre-requisite) 19 | - [Available modules](#available-modules) 20 | - [Node.js equivalent](#nodejs-equivalent) 21 | - [License](#license) 22 | 23 | ## Pre-requisite 24 | 25 | - [deno] >= 0.41.0 26 | 27 | ## Available modules 28 | 29 | - [deep_clone] - Simple and fast deep cloning 30 | - [delay_until] - A typical delay function but Promise based 31 | - [jsmodern] - An extension to existing JavaScript, influenced by other great languages such as Rust, Dart, Java, Golang, etc. 32 | - [lit_ntml] - Expressive HTML Templates 33 | - [normalize_diacritics] - Remove accents/ diacritics in string 34 | - [polling_observer] - A new way of running polling function with observer pattern 35 | 36 | ## Node.js equivalent 37 | 38 | Check out [nodemod] for equivalent modules for Node.js. 39 | 40 | ## License 41 | 42 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 43 | 44 | 45 | 46 | [deno]: https://github.com/denoland/deno 47 | [nodemod]: https://github.com/motss/nodemod 48 | 49 | 50 | 51 | [deep_clone]: /deep_clone 52 | [lit_ntml]: /lit_ntml 53 | [normalize_diacritics]: /normalize_diacritics 54 | [polling_observer]: /polling_observer 55 | [delay_until]: /delay_until 56 | [jsmodern]: /jsmodern 57 | 58 | 59 | 60 | [version-badge]: https://flat.badgen.net/github/release/motss/deno_mod?icon=github 61 | [mit-license-badge]: https://flat.badgen.net/github/license/motss/deno_mod 62 | 63 | [ga-badge]: https://github.com/motss/deno_mod/workflows/ci/badge.svg?branch=master 64 | 65 | 66 | 67 | [version-url]: https://github.com/motss/deno_mod/releases 68 | [mit-license-url]: /LICENSE 69 | 70 | [ga-url]: https://github.com/motss/deno_mod/actions?query=workflow%3Aci 71 | -------------------------------------------------------------------------------- /normalize_diacritics/normalize.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, assertEquals, prepareTest } from "../test.mod.ts"; 2 | 3 | import { normalize } from "./mod.ts"; 4 | 5 | async function willSkipNormalizationForEmptyCharacter() { 6 | assertStrictEq(await normalize(""), ""); 7 | } 8 | 9 | async function willNormalizeAccentedCharacters() { 10 | const strs = [ 11 | "Åland Islands", 12 | "Saint Barthélemy", 13 | "Cocos (Keeling) Islands", 14 | "Côte d'Ivoire", 15 | "Curaçao", 16 | "Réunion" 17 | ]; 18 | 19 | assertEquals(await Promise.all(strs.map(async n => normalize(n))), [ 20 | "Aland Islands", 21 | "Saint Barthelemy", 22 | "Cocos (Keeling) Islands", 23 | "Cote d'Ivoire", 24 | "Curacao", 25 | "Reunion" 26 | ]); 27 | } 28 | 29 | async function willNormalizeAccentedCharactersWithoutUsingNativeFunction() { 30 | const cachedFn = String.prototype.normalize; 31 | String.prototype.normalize = null!; 32 | 33 | try { 34 | assertStrictEq(await normalize("Réunion"), "Reunion"); 35 | } catch (e) { 36 | throw e; 37 | } finally { 38 | String.prototype.normalize = cachedFn; 39 | } 40 | } 41 | 42 | async function willReturnOriginalCharacterWhenNoMatchFound() { 43 | assertStrictEq(await normalize("2 ÷ 2 = 1"), "2 ÷ 2 = 1"); 44 | } 45 | 46 | async function willNormalizeSingleCharacter() { 47 | assertStrictEq(await normalize("ô"), "o"); 48 | } 49 | 50 | async function willNormalizeNonAccentedCharacter() { 51 | assertStrictEq(await normalize("tromsø"), "tromso"); 52 | assertStrictEq(await normalize("\u00d8"), "O"); 53 | } 54 | 55 | async function willNormalizeRepeatedCharacters() { 56 | assertStrictEq(await normalize("éééé"), "eeee"); 57 | assertStrictEq(await normalize("åååå"), "aaaa"); 58 | assertStrictEq(await normalize("éåéåéåéå"), "eaeaeaea"); 59 | assertStrictEq(await normalize("åéåéåéåé"), "aeaeaeae"); 60 | } 61 | 62 | prepareTest( 63 | [ 64 | willSkipNormalizationForEmptyCharacter, 65 | willNormalizeSingleCharacter, 66 | willNormalizeAccentedCharacters, 67 | willNormalizeAccentedCharactersWithoutUsingNativeFunction, 68 | willReturnOriginalCharacterWhenNoMatchFound, 69 | willNormalizeNonAccentedCharacter, 70 | willNormalizeRepeatedCharacters 71 | ], 72 | "normalize_diacritics" 73 | ); 74 | -------------------------------------------------------------------------------- /lit_ntml/html_test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { helloWorld, peopleList } from "./CONSTANTS.ts"; 4 | import { html } from "./mod.ts"; 5 | 6 | async function willRender() { 7 | const d = await html`${helloWorld}`; 8 | 9 | assertStrictEq( 10 | d, 11 | `

Hello, World!

` 12 | ); 13 | } 14 | 15 | async function willRenderWithSyncTasks() { 16 | const syncTask = () => helloWorld; 17 | const syncLiteral = "John Doe"; 18 | const d = await html`
${syncTask}

${syncLiteral}

`; 19 | 20 | assertStrictEq( 21 | d, 22 | // tslint:disable-next-line: max-line-length 23 | `

Hello, World!

John Doe

` 24 | ); 25 | } 26 | 27 | async function willRenderWithAsyncTasks() { 28 | const asyncTask = async () => helloWorld; 29 | const asyncLiteral = Promise.resolve("John Doe"); 30 | const d = await html`
${asyncTask}

${asyncLiteral}

`; 31 | 32 | assertStrictEq( 33 | d, 34 | // tslint:disable-next-line: max-line-length 35 | `

Hello, World!

John Doe

` 36 | ); 37 | } 38 | 39 | async function willRenderWithSyncAndAsyncTasks() { 40 | const asyncTask = async () => helloWorld; 41 | const syncLiteral = await "John Doe"; 42 | const d = await html`
${asyncTask}

${syncLiteral}

`; 43 | 44 | assertStrictEq( 45 | d, 46 | // tslint:disable-next-line: max-line-length 47 | `

Hello, World!

John Doe

` 48 | ); 49 | } 50 | 51 | async function willRenderAListofSyncTasks() { 52 | const d = await html`${helloWorld}
    ${peopleList.map( 53 | n => `
  • ${n}
  • ` 54 | )}
`; 55 | 56 | assertStrictEq( 57 | d, 58 | // tslint:disable-next-line: max-line-length 59 | `

Hello, World!

  • John Doe
  • Michael CEO
  • Vict Fisherman
  • Cash Black
` 60 | ); 61 | } 62 | 63 | prepareTest( 64 | [ 65 | willRender, 66 | willRenderAListofSyncTasks, 67 | willRenderWithAsyncTasks, 68 | willRenderWithSyncAndAsyncTasks, 69 | willRenderWithSyncTasks 70 | ], 71 | "lit_ntml", 72 | "html" 73 | ); 74 | -------------------------------------------------------------------------------- /deep_clone/CONSTANTS.ts: -------------------------------------------------------------------------------- 1 | export const towno = { 2 | a: { 3 | b: { 4 | c: { 5 | d: { 6 | e: [1, 2, 3], 7 | f: "random-string", 8 | g: () => null, 9 | re: /haha/gi, 10 | createdAt: new Date() 11 | } 12 | } 13 | }, 14 | j: 999, 15 | k: [ 16 | { 17 | l: { 18 | m: { 19 | n: 0 20 | } 21 | } 22 | }, 23 | { 24 | o: 999 25 | }, 26 | { 27 | p: [ 28 | { 29 | q: 999, 30 | r: [ 31 | { 32 | s: { 33 | t: { 34 | u: "deep-string" 35 | } 36 | } 37 | }, 38 | { 39 | v: null 40 | }, 41 | Symbol( 42 | Math.random() 43 | .toString(16) 44 | .slice(-7) 45 | ) 46 | ] 47 | }, 48 | { 49 | w: () => null, 50 | re: /^hello\sworld/gi 51 | }, 52 | { 53 | x: { 54 | y: { 55 | z: [1, 2] 56 | } 57 | } 58 | } 59 | ] 60 | } 61 | ] 62 | }, 63 | h: [1, 2], 64 | i: "random-string-depth-0", 65 | j: Symbol("haha") 66 | }; 67 | 68 | export const owno = { 69 | a: { 70 | b: { 71 | c: { 72 | d: [1, 2, 3] 73 | } 74 | }, 75 | e: { 76 | f: 111, 77 | g: "deep-string", 78 | h: [ 79 | { i: 999 }, 80 | { 81 | j: [ 82 | { 83 | k: { 84 | l: "deep-string" 85 | } 86 | } 87 | ] 88 | } 89 | ] 90 | }, 91 | m: null 92 | }, 93 | n: 999 94 | }; 95 | 96 | export const awno = [ 97 | [ 98 | [ 99 | { 100 | a: { 101 | b: [ 102 | { 103 | c: [ 104 | [ 105 | { 106 | d: 999 107 | } 108 | ] 109 | ] 110 | } 111 | ] 112 | }, 113 | e: [[1, 2, 3]] 114 | } 115 | ], 116 | "deep-string", 117 | 1, 118 | 2 119 | ], 120 | null, 121 | "deep-string", 122 | [1, 2] 123 | ]; 124 | -------------------------------------------------------------------------------- /deep_clone/mod.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, BenchmarkTimer } from "../bench.mod.ts"; 2 | 3 | import { deepClone, deepCloneSync } from "./mod.ts"; 4 | 5 | const runs = 3; 6 | const iter = 1e3; 7 | 8 | bench({ 9 | runs, 10 | name: `runs${runs}ForDeepCloneX${iter}s`, 11 | async func(b: BenchmarkTimer) { 12 | b.start(); 13 | for (let i = 0; i < iter; i += 1) { 14 | await deepClone({ 15 | a: { 16 | b: { c: [1, 2, 3] }, 17 | e: [{ f: null }] 18 | }, 19 | d: "deep", 20 | [Math.random() 21 | .toString(16) 22 | .slice(-7)]: "e", 23 | f: Symbol("haha") 24 | }); 25 | } 26 | b.stop(); 27 | } 28 | }); 29 | 30 | bench({ 31 | runs, 32 | name: `runs${runs}ForDeepCloneAbsoluteX${iter}s`, 33 | async func(b: BenchmarkTimer) { 34 | b.start(); 35 | for (let i = 0; i < iter; i += 1) { 36 | await deepClone( 37 | { 38 | a: () => {}, 39 | b: /test/gi, 40 | c: [1, 2], 41 | d: new Date(), 42 | e: { f: 111 }, 43 | [Math.random() 44 | .toString(16) 45 | .slice(-7)]: "f", 46 | g: Symbol("haha") 47 | }, 48 | { absolute: true } 49 | ); 50 | } 51 | b.stop(); 52 | } 53 | }); 54 | 55 | bench({ 56 | runs, 57 | name: `runs${runs}ForDeepCloneSyncX${iter}s`, 58 | func(b: BenchmarkTimer) { 59 | b.start(); 60 | for (let i = 0; i < iter; i += 1) { 61 | deepCloneSync({ 62 | a: { 63 | b: { c: [1, 2, 3] }, 64 | e: [{ f: null }] 65 | }, 66 | d: "deep", 67 | [Math.random() 68 | .toString(16) 69 | .slice(-7)]: "e", 70 | f: Symbol("haha") 71 | }); 72 | } 73 | b.stop(); 74 | } 75 | }); 76 | 77 | bench({ 78 | runs, 79 | name: `runs${runs}ForDeepCloneSyncAbsoluteX${iter}s`, 80 | func(b: BenchmarkTimer) { 81 | b.start(); 82 | for (let i = 0; i < iter; i += 1) { 83 | deepCloneSync( 84 | { 85 | a: () => {}, 86 | b: /test/gi, 87 | c: [1, 2], 88 | d: new Date(), 89 | e: { f: 111 }, 90 | [Math.random() 91 | .toString(16) 92 | .slice(-7)]: "f", 93 | g: Symbol("haha") 94 | }, 95 | { absolute: true } 96 | ); 97 | } 98 | b.stop(); 99 | } 100 | }); 101 | -------------------------------------------------------------------------------- /jsmodern/string.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | capitalize, 7 | contains, 8 | firstIndex, 9 | firstItem, 10 | insert, 11 | isEmpty, 12 | isString, 13 | lastIndex, 14 | lastItem, 15 | len, 16 | lines, 17 | retain, 18 | splitWhitespace, 19 | toCamelCase, 20 | toKebabCase, 21 | toPascalCase, 22 | toSnakeCase, 23 | toStartCase 24 | } from "./string.ts"; 25 | 26 | extend({ 27 | string: [ 28 | capitalize, 29 | contains, 30 | firstIndex, 31 | firstItem, 32 | insert, 33 | isEmpty, 34 | isString, 35 | lastIndex, 36 | lastItem, 37 | len, 38 | lines, 39 | retain, 40 | splitWhitespace, 41 | toCamelCase, 42 | toKebabCase, 43 | toPascalCase, 44 | toSnakeCase, 45 | toStartCase 46 | ] 47 | }); 48 | 49 | async function willExtendStringPrototype() { 50 | const extensions = [ 51 | ["String.prototype.capitalize", "capitalize"], 52 | ["String.prototype.contains", "contains"], 53 | ["String.prototype.firstIndex", "firstIndex"], 54 | ["String.prototype.firstItem", "firstItem"], 55 | ["String.prototype.insert", "insert"], 56 | ["String.prototype.isEmpty", "isEmpty"], 57 | ["String.prototype.lastIndex", "lastIndex"], 58 | ["String.prototype.isEmpty", "isEmpty"], 59 | ["String.prototype.lastIndex", "lastIndex"], 60 | ["String.prototype.lastItem", "lastItem"], 61 | ["String.prototype.len", "len"], 62 | ["String.prototype.lines", "lines"], 63 | ["String.prototype.retain", "retain"], 64 | ["String.prototype.splitWhitespace", "splitWhitespace"], 65 | ["String.prototype.toCamelCase", "toCamelCase"], 66 | ["String.prototype.toKebabCase", "toKebabCase"], 67 | ["String.prototype.toPascalCase", "toPascalCase"], 68 | ["String.prototype.toSnakeCase", "toSnakeCase"], 69 | ["String.prototype.toStartCase", "toStartCase"] 70 | ]; 71 | const expectation = extensions.every(([_, methodName]) => { 72 | return methodName in String.prototype; 73 | }); 74 | 75 | assertStrictEq(expectation, true); 76 | } 77 | 78 | async function willExtendStringConstructor() { 79 | const extensions = [["String.isString", "isString"]]; 80 | const expectation = extensions.every(([_, methodName]) => { 81 | return methodName in String; 82 | }); 83 | 84 | assertStrictEq(expectation, true); 85 | } 86 | 87 | prepareTest( 88 | [willExtendStringConstructor, willExtendStringPrototype], 89 | "jsmodern", 90 | "string" 91 | ); 92 | -------------------------------------------------------------------------------- /normalize_diacritics/README.md: -------------------------------------------------------------------------------- 1 |
2 |

normalize_diacritics

3 | 4 |

Remove accents/ diacritics in string

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > Simple [deno] module to remove any accents/ diacritics found in a string. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [API Reference](#api-reference) 17 | - [normalize([input])](#normalizeinput) 18 | - [normalizeSync([input])](#normalizesyncinput) 19 | - [License](#license) 20 | 21 | ## Usage 22 | 23 | ```ts 24 | /** Import from GH via `denopkg` */ 25 | import { normalize } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/normalize_diacritics/mod.ts"; 26 | 27 | (async () => { 28 | const str = "söme stüff with áccènts"; 29 | 30 | await normalize(str); // 'some stuff with accents' 31 | })(); 32 | ``` 33 | 34 | ## API Reference 35 | 36 | ### normalize([input]) 37 | 38 | - `input` Optional input string that contains accents/ diacritics. 39 | - returns: <[Promise][promise-mdn-url]<[string][string-mdn-url]>> Promise which resolves with normalized input string. 40 | 41 | This method normalizes any accents/ diacritics found in a given input string and output a normalized string as a result. 42 | 43 | ### normalizeSync([input]) 44 | 45 | This methods works the same as `normalize([input])` except that this is the synchronous version. 46 | 47 | ## License 48 | 49 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 50 | 51 | 52 | 53 | [deno]: https://github.com/denoland/deno 54 | 55 | 56 | 57 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 58 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 59 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 60 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 61 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 62 | [html-style-element-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement 63 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 64 | 65 | 66 | 67 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 68 | 69 | 70 | 71 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 72 | -------------------------------------------------------------------------------- /delay_until/README.md: -------------------------------------------------------------------------------- 1 |
2 |

delay_until

3 | 4 |

A typical delay function but Promise based

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > Unlike thread sleep, this is achieved by wrapping a [setTimeout] inside [Promise][promise-mdn-url]. It's best to use with [async...await] syntax. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [API Reference](#api-reference) 17 | - [delayUntil([delay])](#delayuntildelay) 18 | - [License](#license) 19 | 20 | ## Usage 21 | 22 | ```ts 23 | /** Import from GH via `denopkg` */ 24 | import { delayUntil } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/delay_until/mod.ts"; 25 | 26 | (async () => { 27 | await delayUntil(3e3); 28 | 29 | console.log("This message prints out after 3 seconds"); 30 | })(); 31 | ``` 32 | 33 | ## API Reference 34 | 35 | ### delayUntil([delay]) 36 | 37 | - `delay` The delay, in milliseconds, the function should wait for before any code after where the delay function is called can be executed. This does not affect code execution in other thread, module, or even file. 38 | - returns: <[Promise][promise-mdn-url]<`undefined`>> Promise which resolves with no return value. 39 | 40 | ## License 41 | 42 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 43 | 44 | 45 | 46 | [settimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout 47 | [async...await]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await 48 | 49 | 50 | 51 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 52 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 53 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 54 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 55 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 56 | [html-style-element-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement 57 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 58 | 59 | 60 | 61 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 62 | 63 | 64 | 65 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 66 | -------------------------------------------------------------------------------- /lit_ntml/html_fragment.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { helloWorld, peopleList } from "./CONSTANTS.ts"; 4 | import { htmlFragment as html } from "./mod.ts"; 5 | 6 | async function willRender() { 7 | const d = await html`${helloWorld}`; 8 | 9 | assertStrictEq(d, `

Hello, World!

`); 10 | } 11 | 12 | async function willRenderWithSyncTasks() { 13 | const syncTask = () => helloWorld; 14 | const syncLiteral = "John Doe"; 15 | const d = await html`
${syncTask}

${syncLiteral}

`; 16 | 17 | assertStrictEq( 18 | d, 19 | // tslint:disable-next-line: max-line-length 20 | `

Hello, World!

John Doe

` 21 | ); 22 | } 23 | 24 | async function willRenderWithAsyncTasks() { 25 | const asyncTask = async () => helloWorld; 26 | const asyncLiteral = Promise.resolve("John Doe"); 27 | const d = await html`
${asyncTask}

${asyncLiteral}

`; 28 | 29 | assertStrictEq( 30 | d, 31 | // tslint:disable-next-line: max-line-length 32 | `

Hello, World!

John Doe

` 33 | ); 34 | } 35 | 36 | async function willRenderWithSyncAndAsyncTasks() { 37 | const asyncTask = async () => helloWorld; 38 | const syncLiteral = await "John Doe"; 39 | const d = await html`
${asyncTask}

${syncLiteral}

`; 40 | 41 | assertStrictEq( 42 | d, 43 | // tslint:disable-next-line: max-line-length 44 | `

Hello, World!

John Doe

` 45 | ); 46 | } 47 | 48 | async function willRenderAListOfSyncTasks() { 49 | const d = await html`${helloWorld}
    ${peopleList.map( 50 | n => `
  • ${n}
  • ` 51 | )}
`; 52 | 53 | assertStrictEq( 54 | d, 55 | // tslint:disable-next-line: max-line-length 56 | `

Hello, World!

  • John Doe
  • Michael CEO
  • Vict Fisherman
  • Cash Black
` 57 | ); 58 | } 59 | 60 | async function willRenderExternalStyle() { 61 | // tslint:disable-next-line: max-line-length 62 | const asyncExternalStyleTask = async () => 63 | html/* css */ `body { margin: 0; padding: 0; box-sizing: border-box; }`; 64 | const d = await html`${helloWorld}`; 65 | 66 | assertStrictEq( 67 | d, 68 | // tslint:disable-next-line: max-line-length 69 | `

Hello, World!

` 70 | ); 71 | } 72 | 73 | prepareTest( 74 | [ 75 | willRender, 76 | willRenderAListOfSyncTasks, 77 | willRenderExternalStyle, 78 | willRenderWithAsyncTasks, 79 | willRenderWithSyncAndAsyncTasks, 80 | willRenderWithSyncTasks 81 | ], 82 | "lit_ntml", 83 | "htmlFragment" 84 | ); 85 | -------------------------------------------------------------------------------- /jsmodern/array.ts: -------------------------------------------------------------------------------- 1 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/all.ts"; 2 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/any.ts"; 3 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/binary-search.ts"; 4 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/chunks.ts"; 5 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/clear.ts"; 6 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/contains.ts"; 7 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/ends-with.ts"; 8 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/enumerate.ts"; 9 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/filled.ts"; 10 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/first-item.ts"; 11 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/fold.ts"; 12 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/insert.ts"; 13 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/is-empty.ts"; 14 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/is-sorted.ts"; 15 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/iter.ts"; 16 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/last-index.ts"; 17 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/last-item.ts"; 18 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/len.ts"; 19 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/max.ts"; 20 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/min.ts"; 21 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/partition.ts"; 22 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/product.ts"; 23 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/reject.ts"; 24 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/remove.ts"; 25 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/repeat.ts"; 26 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/retain.ts"; 27 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/select.ts"; 28 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/shuffle.ts"; 29 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/split.ts"; 30 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/split-at.ts"; 31 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/starts-with.ts"; 32 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/sum.ts"; 33 | export * from "https://cdn.jsdelivr.net/gh/motss/jsmodern@deno.0/src/array/truncate.ts"; 34 | -------------------------------------------------------------------------------- /deep_clone/deep_clone.test.ts: -------------------------------------------------------------------------------- 1 | import { equal, assert, assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { deepClone } from "./mod.ts"; 4 | import { owno, awno, towno } from "./CONSTANTS.ts"; 5 | 6 | async function willDeeplyCloneNestedObject() { 7 | assert(equal(await deepClone(owno), owno)); 8 | } 9 | 10 | async function willTrulyDeepCloneNestedObject() { 11 | const dc = await deepClone(owno); 12 | 13 | dc.a.b.c = {}; 14 | dc.e = {}; 15 | 16 | assert(!equal(dc, owno)); 17 | } 18 | 19 | async function willDeeplyCloneNestedArray() { 20 | assert(equal(await deepClone(awno), awno)); 21 | } 22 | 23 | async function willTrulyDeepCloneNestedArray() { 24 | const dc = await deepClone(awno); 25 | 26 | dc[0][0][0].a = {}; 27 | 28 | assert(!equal(dc, awno)); 29 | } 30 | 31 | async function willDeeplyCloneNonNestedObject() { 32 | const shallowObj = { 33 | a: "shallow-string", 34 | b: [1, 2, 3], 35 | c: 999, 36 | d: null 37 | }; 38 | const dc = await deepClone(shallowObj); 39 | 40 | assert(equal(dc, shallowObj)); 41 | } 42 | 43 | async function willTrulyDeepCloneNonNestedObject() { 44 | const shallowObj = { 45 | a: "shallow-string", 46 | b: [1, 2, 3], 47 | c: 999, 48 | d: null 49 | }; 50 | const dc = await deepClone(shallowObj); 51 | 52 | delete dc.a; 53 | delete dc.b; 54 | delete dc.c; 55 | delete dc.d; 56 | 57 | assert(!equal(dc, shallowObj)); 58 | } 59 | 60 | async function willDeeplyCloneNonNestedArray() { 61 | const shallowArr = [null, 1, 2, { a: 1 }, "shallow-string"]; 62 | const dc = await deepClone(shallowArr); 63 | 64 | assert(equal(dc, shallowArr)); 65 | } 66 | 67 | async function willTrulyDeepCloneNonNestedArray() { 68 | const shallowArr = [null, 1, 2, { a: 1 }, "shallow-string"]; 69 | const dc = await deepClone(shallowArr); 70 | 71 | dc[3] = {}; 72 | 73 | assert(!equal(dc, shallowArr)); 74 | } 75 | 76 | async function willDeepCloneString() { 77 | const str = "just a string"; 78 | const dc = await deepClone(str); 79 | 80 | assertStrictEq(dc, str); 81 | } 82 | 83 | async function willDeepCloneNumber() { 84 | const num = 999; 85 | const dc = await deepClone(num); 86 | 87 | assertStrictEq(dc, num); 88 | } 89 | 90 | async function willDeepCloneBoolean() { 91 | const bool = !0; 92 | const dc = await deepClone(bool); 93 | 94 | assertStrictEq(dc, bool); 95 | } 96 | 97 | async function willDeepCloningWithAbsoluteFlag() { 98 | const dc = await deepClone(towno, { absolute: true }); 99 | 100 | assert(equal(dc, towno)); 101 | } 102 | 103 | async function willDeepCloningWithAbsoluteFlagBeforeMutatingClonedObject() { 104 | const dc = await deepClone(towno, { absolute: true }); 105 | 106 | dc.a.b = {}; 107 | 108 | assert(!equal(dc, towno)); 109 | } 110 | 111 | prepareTest( 112 | [ 113 | willDeeplyCloneNestedObject, 114 | willTrulyDeepCloneNestedObject, 115 | 116 | willDeeplyCloneNestedArray, 117 | willTrulyDeepCloneNestedArray, 118 | 119 | willDeeplyCloneNonNestedObject, 120 | willTrulyDeepCloneNonNestedObject, 121 | 122 | willDeeplyCloneNonNestedArray, 123 | willTrulyDeepCloneNonNestedArray, 124 | 125 | willDeepCloneString, 126 | willDeepCloneNumber, 127 | willDeepCloneBoolean, 128 | 129 | willDeepCloningWithAbsoluteFlag, 130 | willDeepCloningWithAbsoluteFlagBeforeMutatingClonedObject 131 | ], 132 | "deep_clone" 133 | ); 134 | -------------------------------------------------------------------------------- /jsmodern/array.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, prepareTest } from "../test.mod.ts"; 2 | 3 | import { extend } from "./extend.ts"; 4 | 5 | import { 6 | all, 7 | any, 8 | binarySearch, 9 | chunks, 10 | clear, 11 | contains, 12 | endsWith, 13 | enumerate, 14 | filled, 15 | firstItem, 16 | fold, 17 | insert, 18 | isEmpty, 19 | isSorted, 20 | iter, 21 | lastIndex, 22 | lastItem, 23 | len, 24 | max, 25 | min, 26 | partition, 27 | product, 28 | reject, 29 | remove, 30 | repeat, 31 | retain, 32 | select, 33 | shuffle, 34 | split, 35 | splitAt, 36 | startsWith, 37 | sum, 38 | truncate 39 | } from "./array.ts"; 40 | 41 | extend({ 42 | array: [ 43 | all, 44 | any, 45 | binarySearch, 46 | chunks, 47 | clear, 48 | contains, 49 | endsWith, 50 | enumerate, 51 | filled, 52 | firstItem, 53 | fold, 54 | insert, 55 | isEmpty, 56 | isSorted, 57 | iter, 58 | lastIndex, 59 | lastItem, 60 | len, 61 | max, 62 | min, 63 | partition, 64 | product, 65 | reject, 66 | remove, 67 | repeat, 68 | retain, 69 | select, 70 | shuffle, 71 | split, 72 | splitAt, 73 | startsWith, 74 | sum, 75 | truncate 76 | ] 77 | }); 78 | 79 | async function willExtendArrayPrototype() { 80 | const extensions = [ 81 | ["Array.prototype.all", "all"], 82 | ["Array.prototype.any", "any"], 83 | ["Array.prototype.binarySearch", "binarySearch"], 84 | ["Array.prototype.chunks", "chunks"], 85 | ["Array.prototype.clear", "clear"], 86 | ["Array.prototype.contains", "contains"], 87 | ["Array.prototype.endsWith", "endsWith"], 88 | ["Array.prototype.enumerate", "enumerate"], 89 | ["Array.prototype.firstItem", "firstItem"], 90 | ["Array.prototype.fold", "fold"], 91 | ["Array.prototype.insert", "insert"], 92 | ["Array.prototype.isEmpty", "isEmpty"], 93 | ["Array.prototype.isSorted", "isSorted"], 94 | ["Array.prototype.iter", "iter"], 95 | ["Array.prototype.lastIndex", "lastIndex"], 96 | ["Array.prototype.lastItem", "lastItem"], 97 | ["Array.prototype.len", "len"], 98 | ["Array.prototype.max", "max"], 99 | ["Array.prototype.min", "min"], 100 | ["Array.prototype.partition", "partition"], 101 | ["Array.prototype.product", "product"], 102 | ["Array.prototype.reject", "reject"], 103 | ["Array.prototype.remove", "remove"], 104 | ["Array.prototype.repeat", "repeat"], 105 | ["Array.prototype.retain", "retain"], 106 | ["Array.prototype.select", "select"], 107 | ["Array.prototype.shuffle", "shuffle"], 108 | ["Array.prototype.splitAt", "splitAt"], 109 | ["Array.prototype.split", "split"], 110 | ["Array.prototype.startsWith", "startsWith"], 111 | ["Array.prototype.sum", "sum"], 112 | ["Array.prototype.truncate", "truncate"] 113 | ]; 114 | const expectation = extensions.every(([_, methodName]) => { 115 | return methodName in Array.prototype; 116 | }); 117 | 118 | assertStrictEq(expectation, true); 119 | } 120 | 121 | async function willExtendArrayConstructor() { 122 | const extensions = [["Array.filled", "filled"]]; 123 | const expectation = extensions.every(([_, methodName]) => { 124 | return methodName in Array; 125 | }); 126 | 127 | assertStrictEq(expectation, true); 128 | } 129 | 130 | prepareTest( 131 | [willExtendArrayConstructor, willExtendArrayPrototype], 132 | "jsmodern", 133 | "array" 134 | ); 135 | -------------------------------------------------------------------------------- /deep_clone/README.md: -------------------------------------------------------------------------------- 1 |
2 |

deep_clone

3 | 4 |

Simple and fast deep cloning

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > Simple [deno] module to do simple and fast deep cloning. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [API Reference](#api-reference) 17 | - [deepClone<T>(target[, options])](#deepclonettarget-options) 18 | - [deepCloneSync(target[, options])](#deepclonesynctarget-options) 19 | - [License](#license) 20 | 21 | ## Usage 22 | 23 | ```ts 24 | /** Import from GH via `denopkg` */ 25 | import { deepClone } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/deep_clone/mod.ts"; 26 | 27 | (async () => { 28 | const simpleObject = { 29 | a: { 30 | b: { c: [1, 2, 3] }, 31 | e: [{ f: null }] 32 | }, 33 | d: "deep" 34 | }; 35 | const complexObject = { 36 | a: () => {}, 37 | b: /test/gi, 38 | c: [1, 2], 39 | d: new Date(), 40 | e: { f: 111 } 41 | }; 42 | 43 | await deepClone(simpleObject); 44 | await deepClone(complexObject, { absolute: true }); 45 | })(); 46 | ``` 47 | 48 | ## API Reference 49 | 50 | ### deepClone<T>(target[, options]) 51 | 52 | - `target` <`T`> Target to be cloned. 53 | - `options` Optionally set `absolute: true` for deep cloning complex objects that are not possible with `JSON.parse` + `JSON.stringify`. 54 | - `absolute` <[boolean][boolean-mdn-url]> If true, deep clone complex objects. 55 | - returns: <[Promise][promise-mdn-url]<`T`>> Promise which resolves with the deeply cloned target. 56 | 57 | This method deeply clones a given target with `JSON.parse` + `JSON.stringify` asynchronously by default. Set `absolute: true` for deep cloning complex objects that contain [Date][date-mdn-url], [RegExp][reg-exp-mdn-url], [Function][function-mdn-url], etc. 58 | 59 | ### deepCloneSync(target[, options]) 60 | 61 | This methods works the same as `deepClone(target[, options])` except that this is the synchronous version. 62 | 63 | ## License 64 | 65 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 66 | 67 | 68 | 69 | [deno]: https://github.com/denoland/deno 70 | 71 | 72 | 73 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 74 | [date-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date 75 | [function-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function 76 | [html-style-element-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement 77 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 78 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 79 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 80 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 81 | [reg-exp-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp 82 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 83 | 84 | 85 | 86 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 87 | 88 | 89 | 90 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 91 | -------------------------------------------------------------------------------- /jsmodern/README.md: -------------------------------------------------------------------------------- 1 |
2 |

jsmodern

3 | 4 |

An extension to existing JavaScript, influenced by other great languages such as Rust, Dart, Java, Golang, etc.

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > A collections of extensions for JavaScript that borrow some of the useful features from other programming languages. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [API Reference](#api-reference) 17 | - [License](#license) 18 | 19 | ## Usage 20 | 21 | ```ts 22 | // It is recommended to only import those extensions you need instead of everything. 23 | import { extend } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/jsmodern/extend.ts"; 24 | import { sum } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/jsmodern/array.ts"; 25 | 26 | extend({ array: [sum] }); 27 | 28 | const total = [1, 2, 3].sum(); 29 | 30 | console.log(total === 6); // true 31 | ``` 32 | 33 | ## API Reference 34 | 35 | - [x] [Array extensions] 36 | - [x] [Boolean extensions] 37 | - [x] [Date extensions] 38 | - [x] [Error extensions] 39 | - [x] [Function extensions] 40 | - [x] [Iterator extensions] 41 | - [x] [Map extensions] 42 | - [x] [Number extensions] 43 | - [x] [Object extensions] 44 | - [x] [Promise extensions] 45 | - [x] [RegExp extensions] 46 | - [x] [Set extensions] 47 | - [x] [String extensions] 48 | - [x] [Symbol extensions] 49 | - [x] [WeakMap extensions] 50 | - [x] [WeakSet extensions] 51 | 52 | ## License 53 | 54 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 55 | 56 | 57 | 58 | [array extensions]: https://github.com/motss/jsmodern/tree/master/src/array 59 | [boolean extensions]: https://github.com/motss/jsmodern/tree/master/src/boolean 60 | [date extensions]: https://github.com/motss/jsmodern/tree/master/src/date 61 | [error extensions]: https://github.com/motss/jsmodern/tree/master/src/error 62 | [function extensions]: https://github.com/motss/jsmodern/tree/master/src/function 63 | [iterator extensions]: https://github.com/motss/jsmodern/tree/master/src/iterator 64 | [map extensions]: https://github.com/motss/jsmodern/tree/master/src/map 65 | [number extensions]: https://github.com/motss/jsmodern/tree/master/src/number 66 | [object extensions]: https://github.com/motss/jsmodern/tree/master/src/object 67 | [promise extensions]: https://github.com/motss/jsmodern/tree/master/src/promise 68 | [reg-exp extensions]: https://github.com/motss/jsmodern/tree/master/src/reg-exp 69 | [set extensions]: https://github.com/motss/jsmodern/tree/master/src/set 70 | [string extensions]: https://github.com/motss/jsmodern/tree/master/src/string 71 | [symbol extensions]: https://github.com/motss/jsmodern/tree/master/src/symbol 72 | [weakmap extensions]: https://github.com/motss/jsmodern/tree/master/src/weak-map 73 | [weakset extensions]: https://github.com/motss/jsmodern/tree/master/src/weak-set 74 | 75 | 76 | 77 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 78 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 79 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 80 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 81 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 82 | [html-style-element-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement 83 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 84 | 85 | 86 | 87 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 88 | 89 | 90 | 91 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 92 | -------------------------------------------------------------------------------- /lit_ntml/README.md: -------------------------------------------------------------------------------- 1 |
2 |

lit_ntml

3 | 4 |

Expressive HTML Templates

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > Lightweight, expressive, and modern templating for SSR in [deno], inspired by [lit-html]. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [html()](#html) 17 | - [htmlSync()](#htmlsync) 18 | - [htmlFragment()](#htmlfragment) 19 | - [htmlFragmentSync()](#htmlfragmentsync) 20 | - [API Reference](#api-reference) 21 | - [html()](#html-1) 22 | - [htmlSync()](#htmlsync-1) 23 | - [htmlFragment()](#htmlfragment-1) 24 | - [htmlFragmentSync()](#htmlfragmentsync-1) 25 | - [License](#license) 26 | 27 | ## Usage 28 | 29 | ### html() 30 | 31 | ```ts 32 | import { html } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/lit_ntml/mod.ts"; 33 | 34 | const peopleList = ["Cash Black", "Vict Fisherman"]; 35 | const syncTask = () => `

Hello, World!

`; 36 | const asyncLiteral = Promise.resolve("

John Doe

"); 37 | const asyncListTask = async () => 38 | `
    ${peopleList.map(n => `
  • ${n}
  • `)}
`; 39 | 40 | /** Assuming top-level await is enabled... */ 41 | await html`${syncTask}${asyncLiteral}${asyncListTask}`; /**

Hello, World!

John Doe

  • Cash Black
  • Vict Fisherman
*/ 42 | ``` 43 | 44 | ### htmlSync() 45 | 46 | ```ts 47 | import { htmlSync as html } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/lit_ntml/mod.ts"; 48 | 49 | const peopleList = ['Cash Black', 'Vict Fisherman']; 50 | const syncTask = () => `

Hello, World!

`; 51 | 52 | html`${syncTask}${peopleList}`; 53 | /**

Hello, World!

Cash BlackVictFisherman */ 54 | ``` 55 | 56 | ### htmlFragment() 57 | 58 | ```ts 59 | import { htmlFragment as html } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/lit_ntml/mod.ts"; 60 | 61 | const syncTask = () => `

Hello, World!

`; 62 | const externalStyleLiteral = ``; 63 | 64 | /** Assuming top-level await is enabled... */ 65 | await html`${externalStyleLiteral}${syncTask}`; /**

Hello, World!

*/ 66 | ``` 67 | 68 | ### htmlFragmentSync() 69 | 70 | ```ts 71 | import { htmlFragmentSync as html } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/lit_ntml/mod.ts"; 72 | 73 | const peopleList = ['Cash Black', 'Vict Fisherman']; 74 | const syncTask = () => `

Hello, World!

`; 75 | const asyncTask = Promise.resolve(1); 76 | 77 | html`${syncTask}${peopleList}${asyncTask}`; 78 | /**

Hello, World!

Cash BlackVictFisherman[object Promise] */ 79 | ``` 80 | 81 | ## API Reference 82 | 83 | ### html() 84 | 85 | - returns: <[Promise][promise-mdn-url]<[string][string-mdn-url]>> Promise which resolves with rendered HTML document string. 86 | 87 | ### htmlSync() 88 | 89 | This method works the same as `html()` except that this is the synchronous version. 90 | 91 | ### htmlFragment() 92 | 93 | - returns: <[Promise][promise-mdn-url]<[string][string-mdn-url]>> Promise which resolves with rendered HTML document fragment string. 94 | 95 | ### htmlFragmentSync() 96 | 97 | This method works the same as `htmlFragment()` except that this is the synchronous version. 98 | 99 | ## License 100 | 101 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 102 | 103 | 104 | 105 | [deno]: https://github.com/denoland/deno 106 | [lit-html]: https://github.com/PolymerLabs/lit-html 107 | 108 | 109 | 110 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 111 | [date-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date 112 | [function-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function 113 | [html-style-element-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement 114 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 115 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 116 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 117 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 118 | [reg-exp-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp 119 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 120 | 121 | 122 | 123 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 124 | 125 | 126 | 127 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 128 | -------------------------------------------------------------------------------- /polling_observer/README.md: -------------------------------------------------------------------------------- 1 |
2 |

polling_observer

3 | 4 |

A new way of running polling function with observer pattern

5 |
6 | 7 |
8 | 9 | [![MIT License][mit-license-badge]][mit-license-url] 10 | 11 | > Like PerformanceObserver or any other observer APIs you could find in a browser, but this is for polling. Not only does it run polling with defined parameters but also collect polling metrics for each run until timeout or a defined condition fulfills. 12 | 13 | ## Table of contents 14 | 15 | - [Usage](#usage) 16 | - [API Reference](#api-reference) 17 | - [OnfinishFulfilled<T>](#onfinishfulfilledt) 18 | - [OnfinishRejected](#onfinishrejected) 19 | - [PollingMeasure](#pollingmeasure) 20 | - [Methods](#methods) 21 | - [PollingMeasure.toJSON()](#pollingmeasuretojson) 22 | - [PollingObserver<T>](#pollingobservert) 23 | - [Methods](#methods-1) 24 | - [PollingObserver.observe(callback[, options])](#pollingobserverobservecallback-options) 25 | - [PollingObserver.disconnect()](#pollingobserverdisconnect) 26 | - [PollingObserver.takeRecords()](#pollingobservertakerecords) 27 | - [Event handler](#event-handler) 28 | - [PollingObserver.onfinish](#pollingobserveronfinish) 29 | - [Events](#events) 30 | - [finish](#finish) 31 | - [License](#license) 32 | 33 | ## Usage 34 | 35 | ```ts 36 | interface DataType { 37 | status: "complete" | "in-progress"; 38 | items: Record[]; 39 | } 40 | 41 | import { PollingObserver } from "https://cdn.jsdelivr.net/gh/motss/deno_mod@v0.10.0/polling_observer/mod.ts"; 42 | 43 | const obs = new PollingObserver((data /** list, observer */) => { 44 | const { status, items } = data || {}; 45 | const itemsLen = (items && items.length) || 0; 46 | 47 | /** Stop polling when any of the conditions fulfills */ 48 | return "complete" === status || itemsLen > 99; 49 | }); 50 | 51 | /** 52 | * When polling finishes, it will either fulfill or reject depending on the status: 53 | * 54 | * | Status | Returns | 55 | * | ------- | --------- | 56 | * | finish | | 57 | * | timeout | | 58 | * | error | | 59 | * 60 | */ 61 | obs.onfinish = (data, records /**, observer */) => { 62 | const { status, value, reason } = data || {}; 63 | 64 | switch (status) { 65 | case "error": { 66 | console.error(`Polling fails due to: `, reason); 67 | break; 68 | } 69 | case "timeout": { 70 | console.log(`Polling timeouts after 30 seconds: `, value); 71 | break; 72 | } 73 | case "finish": 74 | default: { 75 | console.log(`Polling finishes: `, value); 76 | } 77 | } 78 | 79 | console.log(`Formatted polling records: `, records.map(n => n.toJSON())); 80 | /** 81 | * [ 82 | * { 83 | * duration: 100, 84 | * entryType: 'polling-measure', 85 | * name: 'polling:0', 86 | * startTime: 100, 87 | * }, 88 | * ... 89 | * ] 90 | */ 91 | 92 | obs.disconnect(); /** Disconnect to clean up */ 93 | }; 94 | 95 | obs.observe( 96 | async () => { 97 | /** Polling callback - fetch resources */ 98 | const r = await fetch("https://example.com/api?key=123"); 99 | const d = await r.json(); 100 | 101 | return d; 102 | }, 103 | /** Run polling (at least) every 2 seconds and timeout if it exceeds 30 seconds */ 104 | { 105 | interval: 2e3, 106 | timeout: 30e3 107 | } 108 | ); 109 | ``` 110 | 111 | ## API Reference 112 | 113 | ### OnfinishFulfilled<T> 114 | 115 | ```ts 116 | interface OnfinishFulfilled { 117 | status: "finish" | "timeout"; 118 | value: T; 119 | } 120 | ``` 121 | 122 | ### OnfinishRejected 123 | 124 | ```ts 125 | interface OnfinishRejected { 126 | status: "error"; 127 | reason: Error; 128 | } 129 | ``` 130 | 131 | ### PollingMeasure 132 | 133 | ```ts 134 | interface PollingMeasure { 135 | duration: number; 136 | entryType: "polling-measure"; 137 | name: string; 138 | startTime: number; 139 | } 140 | ``` 141 | 142 | - `duration` <[number][number-mdn-url]> Duration of the polling takes in milliseconds. 143 | - `entryType` <[string][string-mdn-url]> Entry type, defaults to `polling-measure`. 144 | - `name` <[string][string-mdn-url]> Polling name in the format of `polling:` where `` starts from `0` and increments on each polling. 145 | - `startTime` <[string][string-mdn-url]> Relative timestamp (in milliseconds ) indicates when the polling starts at. 146 | 147 | #### Methods 148 | 149 | ##### PollingMeasure.toJSON() 150 | 151 | - <[Function][function-mdn-url]> Returns a JSON representation of the polling object's properties. 152 | 153 | --- 154 | 155 | ### PollingObserver<T> 156 | 157 | - `conditionCallback` <[Function][function-mdn-url]> Condition callback to be executed in each polling and return the condition result in the type of boolean, e.g. return `true` to stop next poll. 158 | - `data` <`T`> Polling data returned by `callback` in the type of `T` which defined in the [PollingObserver.observe()] method. 159 | - `entries` <[Array][array-mdn-url]<[PollingMeasure]>> A list of [PollingMeasure] objects. 160 | - `observer` <[PollingObserver]<`T`>> Created [PollingObserver] object. 161 | - returns: <[boolean][boolean-mdn-url]> If `true`, the polling stops. Returning `false` will result in an infinite polling as the condition will never meet. 162 | - returns: <[PollingObserver]<`T`>> [PollingObserver] object. 163 | 164 | #### Methods 165 | 166 | ##### PollingObserver.observe(callback[, options]) 167 | 168 | The method is used to initiate polling with a polling callback and optional configuration. 169 | 170 | - `callback` <[Function][function-mdn-url]> Callback to be executed in each polling and return the result so that it will be passed as the first argument in `conditionCallback`. 171 | - returns: <`T` | [Promise][promise-mdn-url]<`T`>> Return polling result in the type of `T` or `Promise` in each polling. 172 | - `options` <[Object][object-mdn-url]> Optional configuration to run the polling. 173 | - `interval` <[number][number-mdn-url]> Optional interval in milliseconds. This is the minimum delay before starting the next polling. 174 | - `timeout` <[number][number-mdn-url]> Optional timeout in milliseconds. Polling ends when it reaches the defined timeout even though the condition has not been met yet. _As long as `timeout` is not a number or it has a value that is less than 1, it indicates an infinite polling. The polling needs to be stopped manually by calling [PollingObserver.disconnect()] method._ 175 | 176 | ##### PollingObserver.disconnect() 177 | 178 | Once a `PollingObserver` disconnects, the polling stops and all polling metrics will be cleared. Calling [PollingObserver.takeRecords()] after the disconnection will always return an empty record. 179 | 180 | A `onfinish` event handler can be used to retrieve polling records after a disconnection but it has to be attached before disconnecting the observer. 181 | 182 | ##### PollingObserver.takeRecords() 183 | 184 | The method returns a list of [PollingMeasure] object containing the metrics of each polling. 185 | 186 | - returns: <[Array][array-mdn-url]<[PollingMeasure]>> A list of [PollingMeasure] objects. 187 | 188 | #### Event handler 189 | 190 | ##### PollingObserver.onfinish 191 | 192 | _Alternatively, an event handler can be setup to listen for the `finish` event. See [finish]._ 193 | 194 | Event handler for when a polling finishes. When a polling finishes, it can either be fulfilled with a `value` or rejected with a `reason`. Any one of which contains a `status` field to tell the state of the finished polling. 195 | 196 | - `onfinishCallback` <[Function][function-mdn-url]> Callback to be executed when a polling finishes. 197 | 198 | - `data` <[OnfinishFulfilled<T>]|[OnfinishRejected]> When a polling fulfills, it returns an [OnfinishFulfilled<T>] object with `status` set to `finish` or `timeout` and a `value` in the type of `T`. Whereas a polling rejects, it returns an [OnfinishRejected] object with `status` set to `error` and a `reason` in the type of [Error][error-mdn-url]. 199 | 200 | | Status | Returns | 201 | | --------- | -------------- | 202 | | `finish` | <value> | 203 | | `timeout` | <value> | 204 | | `error` | <reason> | 205 | 206 | - `entries` <[Array][array-mdn-url]<[PollingMeasure]>> A list of [PollingMeasure] objects. 207 | - `observer` <[PollingObserver]<`T`>> Created [PollingObserver] object. 208 | 209 | #### Events 210 | 211 | ##### finish 212 | 213 | `finish` event fires when a polling finishes. 214 | 215 | ```ts 216 | const obs = new PollingObserver(/** --snip */); 217 | // --snip 218 | ``` 219 | 220 | ## License 221 | 222 | [MIT License](http://motss.mit-license.org/) © Rong Sen Ng 223 | 224 | 225 | 226 | [deno]: https://github.com/denoland/deno 227 | [pollingobserver]: #pollingobservert 228 | [pollingobserver.observe()]: #pollingobserverobservecallback-options 229 | [pollingobserver.disconnect()]: #pollingobserverdisconnect 230 | [pollingobserver.takerecords()]: #pollingobservertakerecords 231 | [pollingmeasure]: #pollingmeasure 232 | [pollingmeasure.tojson()]: #pollingmeasuretojson 233 | [onfinishfulfilled<t>]: #onfinishfulfilledt 234 | [onfinishrejected]: #onfinishrejected 235 | [finish]: #finish 236 | 237 | 238 | 239 | [array-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 240 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 241 | [function-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function 242 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 243 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 244 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 245 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 246 | [reg-exp-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp 247 | [set-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set 248 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 249 | [void-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void 250 | [error-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error 251 | 252 | 253 | 254 | [mit-license-badge]: https://flat.badgen.net/badge/license/MIT/blue 255 | 256 | 257 | 258 | [mit-license-url]: https://github.com/motss/deno_mod/blob/master/LICENSE 259 | -------------------------------------------------------------------------------- /polling_observer/polling_observer.test.ts: -------------------------------------------------------------------------------- 1 | import { assertStrictEq, assertEquals, prepareTest } from "../test.mod.ts"; 2 | 3 | import { MockData } from "./CONSTANTS.ts"; 4 | import { PollingObserver, OnfinishFulfilled, OnfinishValue, PollingMeasure } from "./mod.ts"; 5 | 6 | async function willFinishPollingWithConditionFulfills() { 7 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 8 | const obs = new PollingObserver(d => Boolean(d && d.items.length > 0)); 9 | const task = new Promise>(yay => { 10 | obs.onfinish = (d: OnfinishValue) => yay(d as unknown as OnfinishFulfilled); 11 | }); 12 | 13 | obs.observe( 14 | async () => { 15 | return new Promise(yay => setTimeout(() => yay(data), 2e3)); 16 | }, 17 | { interval: 1e3, timeout: 5e3 } 18 | ); 19 | 20 | const { status, value } = await task; 21 | 22 | assertStrictEq(status, "finish"); 23 | assertEquals(value, { ...data }); 24 | } 25 | 26 | async function willTimeoutAPolling() { 27 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 28 | const obs = new PollingObserver(() => false); 29 | const task = new Promise>(yay => { 30 | obs.onfinish = (d: OnfinishValue) => yay(d as unknown as OnfinishFulfilled); 31 | }); 32 | 33 | obs.observe( 34 | async () => { 35 | return new Promise(yay => setTimeout(() => yay(data), 7e3)); 36 | }, 37 | { interval: 1e3, timeout: 5e3 } 38 | ); 39 | 40 | const { status, value } = await task; 41 | 42 | assertStrictEq(status, "timeout"); 43 | assertEquals(value, { ...data }); 44 | } 45 | 46 | async function willTimeoutAPollingWithMoreThanOneRepeat() { 47 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 48 | const obs = new PollingObserver(() => false); 49 | const task = new Promise>(yay => { 50 | obs.onfinish = (d: OnfinishValue) => yay(d as unknown as OnfinishFulfilled); 51 | }); 52 | 53 | obs.observe( 54 | async () => { 55 | /** 56 | * NOTE(motss): The promise resolves after 1s timeout and the next run will be 57 | * scheduled to happen in roughly (1e3 - 1) milliseconds. 58 | */ 59 | return new Promise(yay => setTimeout(() => yay(data), 1)); 60 | }, 61 | { interval: 1e3, timeout: 5e3 } 62 | ); 63 | 64 | const { status, value } = await task; 65 | 66 | assertStrictEq(status, "timeout"); 67 | assertEquals(value, { ...data }); 68 | } 69 | 70 | async function willReadRecordsWhenPollingFinishes() { 71 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 72 | const obs = new PollingObserver(() => false); 73 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 74 | yay => { 75 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 76 | yay([d as unknown as OnfinishFulfilled, r]); 77 | } 78 | ); 79 | 80 | obs.observe( 81 | async () => { 82 | return new Promise(yay => setTimeout(() => yay(data), 1)); 83 | }, 84 | { interval: 1e3, timeout: 5e3 } 85 | ); 86 | 87 | const [{ status, value }, records] = await task; 88 | 89 | assertStrictEq(status, "timeout"); 90 | assertEquals(value, { ...data }); 91 | 92 | assertStrictEq(records.length > 1, true); 93 | 94 | const firstRecord = records[0].toJSON(); 95 | assertStrictEq( 96 | "number" === typeof firstRecord.duration && 97 | !Number.isNaN(firstRecord.duration), 98 | true 99 | ); 100 | assertStrictEq( 101 | "string" === typeof firstRecord.entryType && 102 | "polling-measure" === firstRecord.entryType, 103 | true 104 | ); 105 | assertStrictEq( 106 | "string" === typeof firstRecord.name && 107 | /^polling:\d+/gi.test(firstRecord.name), 108 | true 109 | ); 110 | assertStrictEq( 111 | "number" === typeof firstRecord.startTime && 112 | !Number.isNaN(firstRecord.startTime), 113 | true 114 | ); 115 | 116 | assertStrictEq(obs.takeRecords().length > 1, true); 117 | 118 | const firstRecordTaken = obs.takeRecords()[0].toJSON(); 119 | assertStrictEq( 120 | "number" === typeof firstRecordTaken.duration && 121 | !Number.isNaN(firstRecordTaken.duration), 122 | true 123 | ); 124 | assertStrictEq( 125 | "string" === typeof firstRecordTaken.entryType && 126 | "polling-measure" === firstRecordTaken.entryType, 127 | true 128 | ); 129 | assertStrictEq( 130 | "string" === typeof firstRecordTaken.name && 131 | /^polling:\d+/gi.test(firstRecordTaken.name), 132 | true 133 | ); 134 | assertStrictEq( 135 | "number" === typeof firstRecordTaken.startTime && 136 | !Number.isNaN(firstRecordTaken.startTime), 137 | true 138 | ); 139 | } 140 | 141 | async function willClearRecordsWhenObserverDisconnects() { 142 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 143 | const obs = new PollingObserver(() => false); 144 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 145 | yay => { 146 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 147 | yay([d as unknown as OnfinishFulfilled, r]); 148 | } 149 | ); 150 | 151 | obs.observe( 152 | async () => { 153 | return new Promise(yay => setTimeout(() => yay(data), 1)); 154 | }, 155 | { interval: 1e3, timeout: 5e3 } 156 | ); 157 | 158 | const [{ status, value }, records] = await task; 159 | 160 | assertStrictEq(status, "timeout"); 161 | assertEquals(value, { ...data }); 162 | assertStrictEq(records.length > 1, true); 163 | assertStrictEq(obs.takeRecords().length > 1, true); 164 | 165 | obs.disconnect(); 166 | 167 | assertStrictEq(obs.takeRecords().length < 1, true); 168 | } 169 | 170 | async function willForcePollingToStopByDisconnecting() { 171 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 172 | const obs = new PollingObserver(() => { 173 | /** 174 | * NOTE(motss): Disconnect observer after 1st polling. 175 | */ 176 | obs.disconnect(); 177 | return false; 178 | }); 179 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 180 | yay => { 181 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 182 | yay([d as unknown as OnfinishFulfilled, r]); 183 | } 184 | ); 185 | 186 | obs.observe( 187 | async () => { 188 | return new Promise(yay => setTimeout(() => yay(data), 1)); 189 | }, 190 | { interval: 2e3, timeout: 5e3 } 191 | ); 192 | 193 | const [{ status, value }, records] = await task; 194 | 195 | assertStrictEq(status, "finish"); 196 | assertEquals(value, { ...data }); 197 | assertStrictEq(records.length === 1, true); 198 | assertStrictEq(!obs.takeRecords().length, true); 199 | } 200 | 201 | async function willDisconnectBeforeFirstPollingInitiates() { 202 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 203 | const obs = new PollingObserver(() => false); 204 | 205 | obs.observe( 206 | async () => { 207 | return new Promise(yay => setTimeout(() => yay(data), 1)); 208 | }, 209 | { interval: 2e3, timeout: 5e3 } 210 | ); 211 | obs.onfinish = (d, records) => { 212 | const { status, value } = d as unknown as OnfinishFulfilled; 213 | 214 | assertStrictEq(status, "finish"); 215 | assertStrictEq(value, void 0); 216 | assertStrictEq(records.length, 0); 217 | assertStrictEq(obs.takeRecords().length, 0); 218 | }; 219 | obs.disconnect(); 220 | } 221 | 222 | async function willReobserveAfterDisconnected() { 223 | const getMockData = (): MockData => ({ 224 | items: [Math.floor(Math.random() * Math.PI)] 225 | }); 226 | const pollingFn = (d: MockData) => async () => { 227 | return new Promise( 228 | yay => setTimeout(() => yay(d as unknown as MockData), 1) 229 | ); 230 | }; 231 | 232 | const obs = new PollingObserver(() => false); 233 | const pollingOpts = { interval: 1e3, timeout: 3e3 }; 234 | 235 | const mockData = getMockData(); 236 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 237 | yay => { 238 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 239 | yay([d as unknown as OnfinishFulfilled, r]); 240 | } 241 | ); 242 | 243 | obs.observe(pollingFn(mockData), pollingOpts); 244 | 245 | const [{ status, value }, records] = await task; 246 | 247 | assertStrictEq(status, "timeout"); 248 | assertEquals(value, { ...mockData }); 249 | assertStrictEq(records.length > 1, true); 250 | assertStrictEq(obs.takeRecords().length > 1, true); 251 | 252 | obs.disconnect(); 253 | assertStrictEq(obs.takeRecords().length < 1, true); 254 | 255 | { 256 | const mockData2 = getMockData(); 257 | const task2 = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 258 | yay => { 259 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 260 | yay([d as unknown as OnfinishFulfilled, r]); 261 | } 262 | ); 263 | 264 | obs.observe(pollingFn(mockData2), pollingOpts); 265 | 266 | const [{ status, value }, records] = await task2; 267 | 268 | assertStrictEq(status, "timeout"); 269 | assertEquals(value, { ...mockData2 }); 270 | assertStrictEq(records.length > 1, true); 271 | assertStrictEq(obs.takeRecords().length > 1, true); 272 | } 273 | } 274 | 275 | async function willPollWithOptionalInterval() { 276 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 277 | const obs = new PollingObserver(() => false); 278 | const task = new Promise>(yay => { 279 | obs.onfinish = (d: OnfinishValue) => yay(d as unknown as OnfinishFulfilled); 280 | }); 281 | 282 | obs.observe( 283 | async () => { 284 | return new Promise(yay => setTimeout(() => yay(data), 1)); 285 | }, 286 | { timeout: 5e3 } 287 | ); 288 | 289 | const { status, value } = await task; 290 | 291 | assertStrictEq(status, "timeout"); 292 | assertEquals(value, { ...data }); 293 | assertStrictEq(obs.takeRecords().length > 1, true); 294 | } 295 | 296 | async function willPollWithOptionalTimeout() { 297 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 298 | const startsAt = +new Date(); 299 | const obs = new PollingObserver(() => { 300 | /** NOTE(motss): It still needs to be stopped to pass the test */ 301 | const endsAt = +new Date(); 302 | return Math.floor(endsAt - startsAt) > 5e3; 303 | }); 304 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 305 | yay => { 306 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 307 | yay([d as unknown as OnfinishFulfilled, r]); 308 | } 309 | ); 310 | 311 | obs.observe( 312 | async () => { 313 | return new Promise(yay => setTimeout(() => yay(data), 1)); 314 | }, 315 | { interval: 2e3 } 316 | ); 317 | 318 | const [{ status, value }, records] = await task; 319 | 320 | assertStrictEq(status, "finish"); 321 | assertEquals(value, { ...data }); 322 | assertStrictEq(records.length > 1, true); 323 | assertStrictEq(obs.takeRecords().length > 1, true); 324 | } 325 | 326 | async function willPollWithOptionalOptions() { 327 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 328 | const startsAt = +new Date(); 329 | const obs = new PollingObserver(() => { 330 | /** NOTE(motss): It still needs to be stopped to pass the test */ 331 | const endsAt = +new Date(); 332 | return Math.floor(endsAt - startsAt) > 5e3; 333 | }); 334 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 335 | yay => { 336 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 337 | yay([d as unknown as OnfinishFulfilled, r]); 338 | } 339 | ); 340 | 341 | obs.observe(async () => { 342 | return new Promise(yay => setTimeout(() => yay(data), 1)); 343 | }); 344 | 345 | const [{ status, value }, records] = await task; 346 | 347 | assertStrictEq(status, "finish"); 348 | assertEquals(value, { ...data }); 349 | assertStrictEq(records.length > 1, true); 350 | assertStrictEq(obs.takeRecords().length > 1, true); 351 | } 352 | 353 | async function willPollWithAsyncConditionCallback() { 354 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 355 | const obs = new PollingObserver(async () => false); 356 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 357 | yay => { 358 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 359 | yay([d as unknown as OnfinishFulfilled, r]); 360 | } 361 | ); 362 | 363 | obs.observe( 364 | async () => { 365 | return new Promise(yay => setTimeout(() => yay(data), 1)); 366 | }, 367 | { interval: 2e3, timeout: 5e3 } 368 | ); 369 | 370 | const [{ status, value }, records] = await task; 371 | 372 | assertStrictEq(status, "timeout"); 373 | assertEquals(value, { ...data }); 374 | assertStrictEq(records.length > 1, true); 375 | assertStrictEq(obs.takeRecords().length > 1, true); 376 | } 377 | 378 | async function willPollWithSyncCallback() { 379 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 380 | const obs = new PollingObserver(async () => false); 381 | const task = new Promise<[OnfinishFulfilled, PollingMeasure[]]>( 382 | yay => { 383 | obs.onfinish = (d: OnfinishValue, r: PollingMeasure[]) => 384 | yay([d as unknown as OnfinishFulfilled, r]); 385 | } 386 | ); 387 | 388 | obs.observe(() => data, { interval: 2e3, timeout: 5e3 }); 389 | 390 | const [{ status, value }, records] = await task; 391 | 392 | assertStrictEq(status, "timeout"); 393 | assertEquals(value, { ...data }); 394 | assertStrictEq(records.length > 1, true); 395 | assertStrictEq(obs.takeRecords().length > 1, true); 396 | } 397 | 398 | async function willPollWithoutOnfinishCallback() { 399 | const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 400 | const obs = new PollingObserver(async () => false); 401 | const task = new Promise(yay => 402 | setTimeout(() => { 403 | yay(obs.takeRecords()); 404 | }, 8e3) 405 | ); 406 | 407 | obs.observe(() => data, { interval: 2e3, timeout: 5e3 }); 408 | 409 | assertEquals(obs.takeRecords().length < 1, true); 410 | assertEquals((await task).length > 1, true); 411 | } 412 | 413 | // async function willFireFinishEvent() { 414 | // const data: MockData = { items: [Math.floor(Math.random() * Math.PI)] }; 415 | // const obs = new PollingObserver(async () => false); 416 | // const task = new Promise(yay => { 417 | // obs.addEventListener( 418 | // "finish", 419 | // // (ev: CustomEvent<[OnfinishFulfilled, PollingMeasure[]]>) => yay(ev.detail) 420 | // (ev: CustomEvent) => yay(ev) 421 | // ); 422 | // }); 423 | 424 | // obs.observe(() => data, { interval: 2e3, timeout: 5e3 }); 425 | 426 | // const { 427 | // detail: [{ status, value }, records] 428 | // // [OnfinishFulfilled, PollingMeasure[]] 429 | // } = await task; 430 | 431 | // assertStrictEq(status, "timeout"); 432 | // assertEquals(value, { ...data }); 433 | // assertStrictEq(records.length > 1, true); 434 | // assertStrictEq(obs.takeRecords().length > 1, true); 435 | // } 436 | 437 | prepareTest( 438 | [ 439 | willFinishPollingWithConditionFulfills, 440 | willTimeoutAPolling, 441 | willTimeoutAPollingWithMoreThanOneRepeat, 442 | willReadRecordsWhenPollingFinishes, 443 | willClearRecordsWhenObserverDisconnects, 444 | willForcePollingToStopByDisconnecting, 445 | willDisconnectBeforeFirstPollingInitiates, 446 | willReobserveAfterDisconnected, 447 | willPollWithOptionalInterval, 448 | willPollWithOptionalTimeout, 449 | willPollWithOptionalOptions, 450 | willPollWithAsyncConditionCallback, 451 | willPollWithSyncCallback, 452 | willPollWithoutOnfinishCallback 453 | // willFireFinishEvent 454 | ], 455 | "polling_observer" 456 | ); 457 | --------------------------------------------------------------------------------