@willbooster/shared-lib 10.17.0 → 10.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.cjs +2 -0
- package/dist/array.cjs.map +1 -0
- package/dist/array.d.ts +2 -0
- package/dist/array.js +2 -0
- package/dist/array.js.map +1 -0
- package/dist/concurrency.cjs +1 -1
- package/dist/concurrency.cjs.map +1 -1
- package/dist/concurrency.d.ts +5 -1
- package/dist/concurrency.js +1 -1
- package/dist/concurrency.js.map +1 -1
- package/dist/crypto.cjs +2 -0
- package/dist/crypto.cjs.map +1 -0
- package/dist/crypto.d.ts +11 -0
- package/dist/crypto.js +2 -0
- package/dist/crypto.js.map +1 -0
- package/dist/error.cjs +2 -2
- package/dist/error.cjs.map +1 -1
- package/dist/error.d.ts +9 -0
- package/dist/error.js +2 -2
- package/dist/error.js.map +1 -1
- package/dist/filePath.cjs +2 -0
- package/dist/filePath.cjs.map +1 -0
- package/dist/filePath.d.ts +5 -0
- package/dist/filePath.js +2 -0
- package/dist/filePath.js.map +1 -0
- package/dist/foreignCjk.cjs +1 -1
- package/dist/foreignCjk.cjs.map +1 -1
- package/dist/foreignCjk.js +1 -1
- package/dist/foreignCjk.js.map +1 -1
- package/dist/formatIsoDate.cjs +2 -0
- package/dist/formatIsoDate.cjs.map +1 -0
- package/dist/formatIsoDate.d.ts +7 -0
- package/dist/formatIsoDate.js +2 -0
- package/dist/formatIsoDate.js.map +1 -0
- package/dist/github.cjs +2 -0
- package/dist/github.cjs.map +1 -0
- package/dist/github.d.ts +8 -0
- package/dist/github.js +2 -0
- package/dist/github.js.map +1 -0
- package/dist/http.cjs +2 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.js +2 -0
- package/dist/http.js.map +1 -0
- package/dist/humanize.cjs +1 -1
- package/dist/humanize.cjs.map +1 -1
- package/dist/humanize.d.ts +5 -0
- package/dist/humanize.js +1 -1
- package/dist/humanize.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.js +1 -1
- package/dist/markdown.cjs +1 -1
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.js +1 -1
- package/dist/markdown.js.map +1 -1
- package/dist/number.cjs +2 -0
- package/dist/number.cjs.map +1 -0
- package/dist/number.d.ts +7 -0
- package/dist/number.js +2 -0
- package/dist/number.js.map +1 -0
- package/dist/object.cjs +2 -0
- package/dist/object.cjs.map +1 -0
- package/dist/object.d.ts +16 -0
- package/dist/object.js +2 -0
- package/dist/object.js.map +1 -0
- package/dist/parseIsoDate.cjs +1 -1
- package/dist/parseIsoDate.cjs.map +1 -1
- package/dist/parseIsoDate.js +1 -1
- package/dist/parseIsoDate.js.map +1 -1
- package/dist/prompt.cjs +2 -2
- package/dist/prompt.cjs.map +1 -1
- package/dist/prompt.js +10 -10
- package/dist/prompt.js.map +1 -1
- package/dist/promptFormatters.cjs +1 -1
- package/dist/promptFormatters.cjs.map +1 -1
- package/dist/promptFormatters.js +1 -1
- package/dist/promptFormatters.js.map +1 -1
- package/dist/recoverJson.cjs +2 -2
- package/dist/recoverJson.cjs.map +1 -1
- package/dist/recoverJson.js +2 -1
- package/dist/recoverJson.js.map +1 -1
- package/dist/sqlite.cjs +1 -1
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.ts +7 -0
- package/dist/sqlite.js +1 -1
- package/dist/sqlite.js.map +1 -1
- package/dist/text.cjs +1 -1
- package/dist/text.cjs.map +1 -1
- package/dist/text.d.ts +12 -0
- package/dist/text.js +1 -1
- package/dist/text.js.map +1 -1
- package/dist/timeout.cjs +2 -0
- package/dist/timeout.cjs.map +1 -0
- package/dist/timeout.d.ts +12 -0
- package/dist/timeout.js +2 -0
- package/dist/timeout.js.map +1 -0
- package/dist/yaml.cjs +2 -0
- package/dist/yaml.cjs.map +1 -0
- package/dist/yaml.d.ts +8 -0
- package/dist/yaml.js +2 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +3 -3
package/dist/array.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.cjs","names":[],"sources":["../src/array.ts"],"sourcesContent":["/** Splits items into consecutive chunks of `size` items; the last chunk holds the remainder. */\nexport function chunk<T>(items: readonly T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) {\n throw new RangeError(`size must be a positive integer: ${size}`);\n }\n return Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>\n items.slice(index * size, (index + 1) * size)\n );\n}\n"],"mappings":"aACA,SAAgB,EAAS,EAAqB,EAAqB,CACjE,GAAI,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,EACpC,MAAU,WAAW,oCAAoC,GAAM,EAEjE,OAAO,MAAM,KAAK,CAAE,OAAQ,KAAK,KAAK,EAAM,OAAS,CAAI,CAAE,GAAI,EAAG,IAChE,EAAM,MAAM,EAAQ,GAAO,EAAQ,GAAK,CAAI,CAC9C,CACF"}
|
package/dist/array.d.ts
ADDED
package/dist/array.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.js","names":[],"sources":["../src/array.ts"],"sourcesContent":["/** Splits items into consecutive chunks of `size` items; the last chunk holds the remainder. */\nexport function chunk<T>(items: readonly T[], size: number): T[][] {\n if (!Number.isInteger(size) || size < 1) {\n throw new RangeError(`size must be a positive integer: ${size}`);\n }\n return Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>\n items.slice(index * size, (index + 1) * size)\n );\n}\n"],"mappings":"AACA,SAAgB,EAAS,EAAqB,EAAqB,CACjE,GAAI,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,EACpC,MAAU,WAAW,oCAAoC,GAAM,EAEjE,OAAO,MAAM,KAAK,CAAE,OAAQ,KAAK,KAAK,EAAM,OAAS,CAAI,CAAE,GAAI,EAAG,IAChE,EAAM,MAAM,EAAQ,GAAO,EAAQ,GAAK,CAAI,CAC9C,CACF"}
|
package/dist/concurrency.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";async function e(e,t,n){if(!Number.isInteger(t)||t<1)throw RangeError(`concurrency must be a positive integer: ${t}`);let r=0,i;if(await Promise.all(Array.from({length:t},async()=>{for(;!i&&r<e
|
|
1
|
+
"use strict";async function e(e,t,r){await n(e.length,t,t=>r(e[t],t))}async function t(e,t,r){let i=Array.from({length:e.length});return await n(e.length,t,async t=>{i[t]=await r(e[t],t)}),i}async function n(e,t,n){if(!Number.isInteger(t)||t<1)throw RangeError(`concurrency must be a positive integer: ${t}`);let r=0,i;if(await Promise.all(Array.from({length:Math.min(t,e)},async()=>{for(;!i&&r<e;)try{await n(r++)}catch(e){i??={error:e}}})),i)throw i.error}exports.forEachConcurrently=e,exports.mapConcurrently=t;
|
|
2
2
|
//# sourceMappingURL=concurrency.cjs.map
|
package/dist/concurrency.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concurrency.cjs","names":[],"sources":["../src/concurrency.ts"],"sourcesContent":["/**\n * Runs `action` for every item with at most `concurrency` actions in flight, starting the next item as soon as any\n * action settles, so one slow item does not hold back a whole batch. After an action rejects, no further item is\n * started, and once every started action has settled, the returned promise rejects with the first error.\n * The returned promise rejects with a `RangeError` when `concurrency` is not a positive integer.\n */\nexport async function forEachConcurrently<T>(\n items: readonly T[],\n concurrency: number,\n action: (item: T) => Promise<unknown>\n): Promise<void> {\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new RangeError(`concurrency must be a positive integer: ${concurrency}`);\n }\n let nextIndex = 0;\n let failure: { error: unknown } | undefined;\n await Promise.all(\n Array.from({ length: concurrency }, async () => {\n while (!failure && nextIndex <
|
|
1
|
+
{"version":3,"file":"concurrency.cjs","names":[],"sources":["../src/concurrency.ts"],"sourcesContent":["/**\n * Runs `action` for every item with at most `concurrency` actions in flight, starting the next item as soon as any\n * action settles, so one slow item does not hold back a whole batch. After an action rejects, no further item is\n * started, and once every started action has settled, the returned promise rejects with the first error.\n * The returned promise rejects with a `RangeError` when `concurrency` is not a positive integer.\n */\nexport async function forEachConcurrently<T>(\n items: readonly T[],\n concurrency: number,\n action: (item: T, index: number) => Promise<unknown>\n): Promise<void> {\n await runConcurrently(items.length, concurrency, (index) => action(items[index] as T, index));\n}\n\n/**\n * Like `forEachConcurrently`, but resolves with the results of `mapper` in the order of `items`.\n */\nexport async function mapConcurrently<T, R>(\n items: readonly T[],\n concurrency: number,\n mapper: (item: T, index: number) => Promise<R>\n): Promise<R[]> {\n const results = Array.from<R>({ length: items.length });\n await runConcurrently(items.length, concurrency, async (index) => {\n results[index] = await mapper(items[index] as T, index);\n });\n return results;\n}\n\nasync function runConcurrently(\n length: number,\n concurrency: number,\n run: (index: number) => Promise<unknown>\n): Promise<void> {\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new RangeError(`concurrency must be a positive integer: ${concurrency}`);\n }\n let nextIndex = 0;\n let failure: { error: unknown } | undefined;\n // Workers beyond the item count would find nothing to take, so they are not created.\n await Promise.all(\n Array.from({ length: Math.min(concurrency, length) }, async () => {\n while (!failure && nextIndex < length) {\n try {\n await run(nextIndex++);\n } catch (error) {\n failure ??= { error };\n }\n }\n })\n );\n if (failure) throw failure.error;\n}\n"],"mappings":"aAMA,eAAsB,EACpB,EACA,EACA,EACe,CACf,MAAM,EAAgB,EAAM,OAAQ,EAAc,GAAU,EAAO,EAAM,GAAa,CAAK,CAAC,CAC9F,CAKA,eAAsB,EACpB,EACA,EACA,EACc,CACd,IAAM,EAAU,MAAM,KAAQ,CAAE,OAAQ,EAAM,MAAO,CAAC,EAItD,OAHA,MAAM,EAAgB,EAAM,OAAQ,EAAa,KAAO,IAAU,CAChE,EAAQ,GAAS,MAAM,EAAO,EAAM,GAAa,CAAK,CACxD,CAAC,EACM,CACT,CAEA,eAAe,EACb,EACA,EACA,EACe,CACf,GAAI,CAAC,OAAO,UAAU,CAAW,GAAK,EAAc,EAClD,MAAU,WAAW,2CAA2C,GAAa,EAE/E,IAAI,EAAY,EACZ,EAaJ,GAXA,MAAM,QAAQ,IACZ,MAAM,KAAK,CAAE,OAAQ,KAAK,IAAI,EAAa,CAAM,CAAE,EAAG,SAAY,CAChE,KAAO,CAAC,GAAW,EAAY,GAC7B,GAAI,CACF,MAAM,EAAI,GAAW,CACvB,OAAS,EAAO,CACd,IAAY,CAAE,OAAM,CACtB,CAEJ,CAAC,CACH,EACI,EAAS,MAAM,EAAQ,KAC7B"}
|
package/dist/concurrency.d.ts
CHANGED
|
@@ -4,4 +4,8 @@
|
|
|
4
4
|
* started, and once every started action has settled, the returned promise rejects with the first error.
|
|
5
5
|
* The returned promise rejects with a `RangeError` when `concurrency` is not a positive integer.
|
|
6
6
|
*/
|
|
7
|
-
export declare function forEachConcurrently<T>(items: readonly T[], concurrency: number, action: (item: T) => Promise<unknown>): Promise<void>;
|
|
7
|
+
export declare function forEachConcurrently<T>(items: readonly T[], concurrency: number, action: (item: T, index: number) => Promise<unknown>): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Like `forEachConcurrently`, but resolves with the results of `mapper` in the order of `items`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mapConcurrently<T, R>(items: readonly T[], concurrency: number, mapper: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
package/dist/concurrency.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
async function e(e,t,n){if(!Number.isInteger(t)||t<1)throw RangeError(`concurrency must be a positive integer: ${t}`);let r=0,i;if(await Promise.all(Array.from({length:t},async()=>{for(;!i&&r<e
|
|
1
|
+
async function e(e,t,r){await n(e.length,t,t=>r(e[t],t))}async function t(e,t,r){let i=Array.from({length:e.length});return await n(e.length,t,async t=>{i[t]=await r(e[t],t)}),i}async function n(e,t,n){if(!Number.isInteger(t)||t<1)throw RangeError(`concurrency must be a positive integer: ${t}`);let r=0,i;if(await Promise.all(Array.from({length:Math.min(t,e)},async()=>{for(;!i&&r<e;)try{await n(r++)}catch(e){i??={error:e}}})),i)throw i.error}export{e as forEachConcurrently,t as mapConcurrently};
|
|
2
2
|
//# sourceMappingURL=concurrency.js.map
|
package/dist/concurrency.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concurrency.js","names":[],"sources":["../src/concurrency.ts"],"sourcesContent":["/**\n * Runs `action` for every item with at most `concurrency` actions in flight, starting the next item as soon as any\n * action settles, so one slow item does not hold back a whole batch. After an action rejects, no further item is\n * started, and once every started action has settled, the returned promise rejects with the first error.\n * The returned promise rejects with a `RangeError` when `concurrency` is not a positive integer.\n */\nexport async function forEachConcurrently<T>(\n items: readonly T[],\n concurrency: number,\n action: (item: T) => Promise<unknown>\n): Promise<void> {\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new RangeError(`concurrency must be a positive integer: ${concurrency}`);\n }\n let nextIndex = 0;\n let failure: { error: unknown } | undefined;\n await Promise.all(\n Array.from({ length: concurrency }, async () => {\n while (!failure && nextIndex <
|
|
1
|
+
{"version":3,"file":"concurrency.js","names":[],"sources":["../src/concurrency.ts"],"sourcesContent":["/**\n * Runs `action` for every item with at most `concurrency` actions in flight, starting the next item as soon as any\n * action settles, so one slow item does not hold back a whole batch. After an action rejects, no further item is\n * started, and once every started action has settled, the returned promise rejects with the first error.\n * The returned promise rejects with a `RangeError` when `concurrency` is not a positive integer.\n */\nexport async function forEachConcurrently<T>(\n items: readonly T[],\n concurrency: number,\n action: (item: T, index: number) => Promise<unknown>\n): Promise<void> {\n await runConcurrently(items.length, concurrency, (index) => action(items[index] as T, index));\n}\n\n/**\n * Like `forEachConcurrently`, but resolves with the results of `mapper` in the order of `items`.\n */\nexport async function mapConcurrently<T, R>(\n items: readonly T[],\n concurrency: number,\n mapper: (item: T, index: number) => Promise<R>\n): Promise<R[]> {\n const results = Array.from<R>({ length: items.length });\n await runConcurrently(items.length, concurrency, async (index) => {\n results[index] = await mapper(items[index] as T, index);\n });\n return results;\n}\n\nasync function runConcurrently(\n length: number,\n concurrency: number,\n run: (index: number) => Promise<unknown>\n): Promise<void> {\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new RangeError(`concurrency must be a positive integer: ${concurrency}`);\n }\n let nextIndex = 0;\n let failure: { error: unknown } | undefined;\n // Workers beyond the item count would find nothing to take, so they are not created.\n await Promise.all(\n Array.from({ length: Math.min(concurrency, length) }, async () => {\n while (!failure && nextIndex < length) {\n try {\n await run(nextIndex++);\n } catch (error) {\n failure ??= { error };\n }\n }\n })\n );\n if (failure) throw failure.error;\n}\n"],"mappings":"AAMA,eAAsB,EACpB,EACA,EACA,EACe,CACf,MAAM,EAAgB,EAAM,OAAQ,EAAc,GAAU,EAAO,EAAM,GAAa,CAAK,CAAC,CAC9F,CAKA,eAAsB,EACpB,EACA,EACA,EACc,CACd,IAAM,EAAU,MAAM,KAAQ,CAAE,OAAQ,EAAM,MAAO,CAAC,EAItD,OAHA,MAAM,EAAgB,EAAM,OAAQ,EAAa,KAAO,IAAU,CAChE,EAAQ,GAAS,MAAM,EAAO,EAAM,GAAa,CAAK,CACxD,CAAC,EACM,CACT,CAEA,eAAe,EACb,EACA,EACA,EACe,CACf,GAAI,CAAC,OAAO,UAAU,CAAW,GAAK,EAAc,EAClD,MAAU,WAAW,2CAA2C,GAAa,EAE/E,IAAI,EAAY,EACZ,EAaJ,GAXA,MAAM,QAAQ,IACZ,MAAM,KAAK,CAAE,OAAQ,KAAK,IAAI,EAAa,CAAM,CAAE,EAAG,SAAY,CAChE,KAAO,CAAC,GAAW,EAAY,GAC7B,GAAI,CACF,MAAM,EAAI,GAAW,CACvB,OAAS,EAAO,CACd,IAAY,CAAE,OAAM,CACtB,CAEJ,CAAC,CACH,EACI,EAAS,MAAM,EAAQ,KAC7B"}
|
package/dist/crypto.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";async function e(e){let t=typeof e==`string`?new TextEncoder().encode(e):new Uint8Array(e),n=new Uint8Array(await crypto.subtle.digest(`SHA-256`,t));return Array.from(n,e=>e.toString(16).padStart(2,`0`)).join(``)}async function t(e,t){let[r,i]=await Promise.all([n(e),n(t)]),a=0;for(let e=0;e<r.length;e++)a|=(r[e]??0)^(i[e]??0);return a===0}async function n(e){let t=new Uint16Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Uint8Array(await crypto.subtle.digest(`SHA-256`,t))}exports.sha256HexAsync=e,exports.timingSafeEqualStringAsync=t;
|
|
2
|
+
//# sourceMappingURL=crypto.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.cjs","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["/**\n * Answers the SHA-256 hex digest of `data` (a string is encoded as UTF-8) with WebCrypto, so it runs in browsers and\n * Cloudflare Workers; the result equals Node.js's `createHash('sha256').update(data).digest('hex')`.\n */\nexport async function sha256HexAsync(data: string | Uint8Array): Promise<string> {\n // Copying into a fresh `ArrayBuffer` also accepts a `SharedArrayBuffer`-backed view, which WebCrypto rejects.\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n return Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Compares strings, e.g. a received API key against the expected one, with WebCrypto, so it runs in browsers and\n * Cloudflare Workers. Neither a length check nor an early exit reveals where they differ; only hashing each string\n * takes time proportional to its length, as in `shared-lib-node`'s `timingSafeEqualString`.\n */\nexport async function timingSafeEqualStringAsync(actual: string, expected: string): Promise<boolean> {\n // Hashing gives equal-length inputs, so the loop below needs no length check and never exits early.\n const [actualDigest, expectedDigest] = await Promise.all([digestCodeUnits(actual), digestCodeUnits(expected)]);\n let difference = 0;\n for (let i = 0; i < actualDigest.length; i++) {\n difference |= (actualDigest[i] ?? 0) ^ (expectedDigest[i] ?? 0);\n }\n return difference === 0;\n}\n\nasync function digestCodeUnits(text: string): Promise<Uint8Array> {\n // UTF-16 keeps every code unit, while UTF-8 would turn distinct lone surrogates into the same U+FFFD.\n const codeUnits = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n // oxlint-disable-next-line unicorn/prefer-code-point -- a code point would merge a surrogate pair into one value.\n codeUnits[i] = text.charCodeAt(i);\n }\n return new Uint8Array(await crypto.subtle.digest('SHA-256', codeUnits));\n}\n"],"mappings":"aAIA,eAAsB,EAAe,EAA4C,CAE/E,IAAM,EAAQ,OAAO,GAAS,SAAW,IAAI,YAAY,CAAC,CAAC,OAAO,CAAI,EAAI,IAAI,WAAW,CAAI,EACvF,EAAS,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,UAAW,CAAK,CAAC,EAC1E,OAAO,MAAM,KAAK,EAAS,GAAS,EAAK,SAAS,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CACjF,CAOA,eAAsB,EAA2B,EAAgB,EAAoC,CAEnG,GAAM,CAAC,EAAc,GAAkB,MAAM,QAAQ,IAAI,CAAC,EAAgB,CAAM,EAAG,EAAgB,CAAQ,CAAC,CAAC,EACzG,EAAa,EACjB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,IAAe,EAAa,IAAM,IAAM,EAAe,IAAM,GAE/D,OAAO,IAAe,CACxB,CAEA,eAAe,EAAgB,EAAmC,CAEhE,IAAM,EAAY,IAAI,YAAY,EAAK,MAAM,EAC7C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAE/B,EAAU,GAAK,EAAK,WAAW,CAAC,EAElC,OAAO,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,UAAW,CAAS,CAAC,CACxE"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Answers the SHA-256 hex digest of `data` (a string is encoded as UTF-8) with WebCrypto, so it runs in browsers and
|
|
3
|
+
* Cloudflare Workers; the result equals Node.js's `createHash('sha256').update(data).digest('hex')`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function sha256HexAsync(data: string | Uint8Array): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Compares strings, e.g. a received API key against the expected one, with WebCrypto, so it runs in browsers and
|
|
8
|
+
* Cloudflare Workers. Neither a length check nor an early exit reveals where they differ; only hashing each string
|
|
9
|
+
* takes time proportional to its length, as in `shared-lib-node`'s `timingSafeEqualString`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function timingSafeEqualStringAsync(actual: string, expected: string): Promise<boolean>;
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
async function e(e){let t=typeof e==`string`?new TextEncoder().encode(e):new Uint8Array(e),n=new Uint8Array(await crypto.subtle.digest(`SHA-256`,t));return Array.from(n,e=>e.toString(16).padStart(2,`0`)).join(``)}async function t(e,t){let[r,i]=await Promise.all([n(e),n(t)]),a=0;for(let e=0;e<r.length;e++)a|=(r[e]??0)^(i[e]??0);return a===0}async function n(e){let t=new Uint16Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Uint8Array(await crypto.subtle.digest(`SHA-256`,t))}export{e as sha256HexAsync,t as timingSafeEqualStringAsync};
|
|
2
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["/**\n * Answers the SHA-256 hex digest of `data` (a string is encoded as UTF-8) with WebCrypto, so it runs in browsers and\n * Cloudflare Workers; the result equals Node.js's `createHash('sha256').update(data).digest('hex')`.\n */\nexport async function sha256HexAsync(data: string | Uint8Array): Promise<string> {\n // Copying into a fresh `ArrayBuffer` also accepts a `SharedArrayBuffer`-backed view, which WebCrypto rejects.\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n return Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Compares strings, e.g. a received API key against the expected one, with WebCrypto, so it runs in browsers and\n * Cloudflare Workers. Neither a length check nor an early exit reveals where they differ; only hashing each string\n * takes time proportional to its length, as in `shared-lib-node`'s `timingSafeEqualString`.\n */\nexport async function timingSafeEqualStringAsync(actual: string, expected: string): Promise<boolean> {\n // Hashing gives equal-length inputs, so the loop below needs no length check and never exits early.\n const [actualDigest, expectedDigest] = await Promise.all([digestCodeUnits(actual), digestCodeUnits(expected)]);\n let difference = 0;\n for (let i = 0; i < actualDigest.length; i++) {\n difference |= (actualDigest[i] ?? 0) ^ (expectedDigest[i] ?? 0);\n }\n return difference === 0;\n}\n\nasync function digestCodeUnits(text: string): Promise<Uint8Array> {\n // UTF-16 keeps every code unit, while UTF-8 would turn distinct lone surrogates into the same U+FFFD.\n const codeUnits = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n // oxlint-disable-next-line unicorn/prefer-code-point -- a code point would merge a surrogate pair into one value.\n codeUnits[i] = text.charCodeAt(i);\n }\n return new Uint8Array(await crypto.subtle.digest('SHA-256', codeUnits));\n}\n"],"mappings":"AAIA,eAAsB,EAAe,EAA4C,CAE/E,IAAM,EAAQ,OAAO,GAAS,SAAW,IAAI,YAAY,CAAC,CAAC,OAAO,CAAI,EAAI,IAAI,WAAW,CAAI,EACvF,EAAS,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,UAAW,CAAK,CAAC,EAC1E,OAAO,MAAM,KAAK,EAAS,GAAS,EAAK,SAAS,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CACjF,CAOA,eAAsB,EAA2B,EAAgB,EAAoC,CAEnG,GAAM,CAAC,EAAc,GAAkB,MAAM,QAAQ,IAAI,CAAC,EAAgB,CAAM,EAAG,EAAgB,CAAQ,CAAC,CAAC,EACzG,EAAa,EACjB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,IAAe,EAAa,IAAM,IAAM,EAAe,IAAM,GAE/D,OAAO,IAAe,CACxB,CAEA,eAAe,EAAgB,EAAmC,CAEhE,IAAM,EAAY,IAAI,YAAY,EAAK,MAAM,EAC7C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAE/B,EAAU,GAAK,EAAK,WAAW,CAAC,EAElC,OAAO,IAAI,WAAW,MAAM,OAAO,OAAO,OAAO,UAAW,CAAS,CAAC,CACxE"}
|
package/dist/error.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const e=require("./sleep.cjs");function t(e){return e instanceof Error?e:Error(typeof e==`string`?e:
|
|
1
|
+
"use strict";const e=require("./sleep.cjs");function t(e){return e instanceof Error?e:Error(typeof e==`string`?e:i(()=>JSON.stringify(e))??i(()=>String(e)))}function n(e,t){return i(()=>e instanceof Error?e.message:t??String(e))??t??i(()=>Object.prototype.toString.call(e))??`Unknown error`}function r(e,t){return typeof e==`object`&&!!e&&`code`in e&&e.code===t}function i(e){try{return e()}catch{}}function a(e){try{return e()}catch(e){if(r(e,`ENOENT`))return;throw e}}async function o(e){try{return await e()}catch{}}async function s(e){try{return await e()}catch(e){if(r(e,`ENOENT`))return;throw e}}async function c(t,{beforeRetry:n,handleError:r,retryCount:i=3,retryLogger:a,shouldRetry:o,getSleepMilliseconds:s,sleepMilliseconds:c=0,updateSleepMilliseconds:l}={}){let u=0;for(;;)try{return await t(u)}catch(t){if(await r?.(t),u++,u>=i||o&&!o(t))throw t;let d=s?.(t,c)??c;d>0&&await e.sleep(d),l&&(c=l(c)),a?.(`Retry due to: ${t}
|
|
2
2
|
${t instanceof Error?`---
|
|
3
|
-
`+(t.stack??``):``}`),await n?.(t)}}exports.errorify=t,exports.
|
|
3
|
+
`+(t.stack??``):``}`),await n?.(t)}}exports.errorify=t,exports.getErrorMessage=n,exports.hasErrorCode=r,exports.ignoreEnoent=a,exports.ignoreEnoentAsync=s,exports.ignoreError=i,exports.ignoreErrorAsync=o,exports.withRetry=c;
|
|
4
4
|
//# sourceMappingURL=error.cjs.map
|
package/dist/error.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.cjs","names":["sleep"],"sources":["../src/error.ts"],"sourcesContent":["import { sleep } from './sleep.js';\n\n/**\n * Convert an object to an error.\n * @param obj The object to convert.\n */\nexport function errorify(obj: unknown): Error {\n if (obj instanceof Error) return obj;\n if (typeof obj === 'string') return new Error(obj);\n // `JSON.stringify` answers `undefined` for `undefined`, a symbol and a function, and throws\n // on a bigint or a cycle; `new Error(undefined)` has an empty message, which would drop the\n // only diagnostic a caller has about such a thrown value. Neither representation may throw\n // out of here: this runs in a catch block, where it would replace the error it converts.\n return new Error(ignoreError(() => JSON.stringify(obj)) ?? ignoreError(() => String(obj)));\n}\n\nexport function ignoreError<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch {\n // do nothing\n }\n}\n\nexport function ignoreEnoent<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch (error) {\n if (
|
|
1
|
+
{"version":3,"file":"error.cjs","names":["sleep"],"sources":["../src/error.ts"],"sourcesContent":["import { sleep } from './sleep.js';\n\n/**\n * Convert an object to an error.\n * @param obj The object to convert.\n */\nexport function errorify(obj: unknown): Error {\n if (obj instanceof Error) return obj;\n if (typeof obj === 'string') return new Error(obj);\n // `JSON.stringify` answers `undefined` for `undefined`, a symbol and a function, and throws\n // on a bigint or a cycle; `new Error(undefined)` has an empty message, which would drop the\n // only diagnostic a caller has about such a thrown value. Neither representation may throw\n // out of here: this runs in a catch block, where it would replace the error it converts.\n return new Error(ignoreError(() => JSON.stringify(obj)) ?? ignoreError(() => String(obj)));\n}\n\n/**\n * Returns the message of a thrown `Error`; for any other thrown value, `fallback` if given, or else its string form.\n * `fallback` is also returned when reading the message throws. Never throws, so it is safe to call in a catch block.\n */\nexport function getErrorMessage(error: unknown, fallback?: string): string {\n // `String` throws for an object without a prototype, and even `instanceof`, a `message` getter, and\n // `Object.prototype.toString` throw for a proxy or object whose traps or getters throw.\n return (\n ignoreError(() => (error instanceof Error ? error.message : (fallback ?? String(error)))) ??\n fallback ??\n ignoreError(() => Object.prototype.toString.call(error)) ??\n 'Unknown error'\n );\n}\n\n/** Whether a thrown value carries the given `code`, such as a Node.js errno code (`ENOENT`, `EEXIST`, ...). */\nexport function hasErrorCode<C extends string>(error: unknown, code: C): error is { code: C } {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code;\n}\n\nexport function ignoreError<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch {\n // do nothing\n }\n}\n\nexport function ignoreEnoent<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return;\n throw error;\n }\n}\n\nexport async function ignoreErrorAsync<T>(fn: () => Promise<T>): Promise<T | undefined> {\n try {\n return await fn();\n } catch {\n // do nothing\n }\n}\n\nexport async function ignoreEnoentAsync<T>(fn: () => Promise<T>): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return;\n throw error;\n }\n}\n\nexport interface RetryOptions {\n beforeRetry?: (error: unknown) => Promise<void>;\n handleError?: (error: unknown) => Promise<void>;\n /**\n * The maximum number of total attempts, including the initial attempt.\n * For example, `retryCount: 3` runs the function at most 3 times: 1 initial attempt and up to 2 retries.\n */\n retryCount?: number;\n retryLogger?: (message: string) => void;\n shouldRetry?: (error: unknown) => boolean;\n /**\n * Decides how long to wait before retrying after `error`, given the backoff `sleepMilliseconds` it would otherwise wait,\n * e.g. `(error, ms) => Math.max(ms, retryAtOf(error) - Date.now())` to honor a retry time sent by a server.\n * It does not affect the backoff that `updateSleepMilliseconds` advances.\n */\n getSleepMilliseconds?: (error: unknown, sleepMilliseconds: number) => number;\n sleepMilliseconds?: number;\n updateSleepMilliseconds?: (sleepMilliseconds: number) => number;\n}\n\n/**\n * Retry the given function.\n * @param func The function to retry.\n * @param beforeRetry The function to call immediately before retrying.\n * @param handleError The function to call when an error occurs.\n * @param retryCount The maximum number of total attempts, including the initial attempt.\n * @param retryLogger The function to log retrying.\n * @param sleepMilliseconds The number of milliseconds to sleep before retrying.\n * @param updateSleepMilliseconds The function to update sleep milliseconds after each retry.\n */\nexport async function withRetry<T>(\n func: (failedCount: number) => T | Promise<T>,\n {\n beforeRetry,\n handleError,\n retryCount = 3,\n retryLogger,\n shouldRetry,\n getSleepMilliseconds,\n sleepMilliseconds = 0,\n updateSleepMilliseconds,\n }: RetryOptions = {}\n): Promise<T> {\n let failedCount = 0;\n for (;;) {\n try {\n return await func(failedCount);\n } catch (error) {\n await handleError?.(error);\n failedCount++;\n if (failedCount >= retryCount) {\n throw error;\n }\n if (shouldRetry && !shouldRetry(error)) {\n throw error;\n }\n const currentSleepMilliseconds = getSleepMilliseconds?.(error, sleepMilliseconds) ?? sleepMilliseconds;\n if (currentSleepMilliseconds > 0) {\n await sleep(currentSleepMilliseconds);\n }\n if (updateSleepMilliseconds) {\n sleepMilliseconds = updateSleepMilliseconds(sleepMilliseconds);\n }\n retryLogger?.(`Retry due to: ${error}\n${error instanceof Error ? '---\\n' + (error.stack ?? '') : ''}`);\n await beforeRetry?.(error);\n }\n }\n}\n"],"mappings":"4CAMA,SAAgB,EAAS,EAAqB,CAO5C,OANI,aAAe,MAAc,EACO,MAApC,OAAO,GAAQ,SAA2B,EAK7B,MAAkB,KAAK,UAAU,CAAG,CAAC,GAAK,MAAkB,OAAO,CAAG,CAAC,CALvC,CAMnD,CAMA,SAAgB,EAAgB,EAAgB,EAA2B,CAGzE,OACE,MAAmB,aAAiB,MAAQ,EAAM,QAAW,GAAY,OAAO,CAAK,CAAG,GACxF,GACA,MAAkB,OAAO,UAAU,SAAS,KAAK,CAAK,CAAC,GACvD,eAEJ,CAGA,SAAgB,EAA+B,EAAgB,EAA+B,CAC5F,OAAO,OAAO,GAAU,YAAY,GAAkB,SAAU,GAAS,EAAM,OAAS,CAC1F,CAEA,SAAgB,EAAe,EAA4B,CACzD,GAAI,CACF,OAAO,EAAG,CACZ,MAAQ,CAER,CACF,CAEA,SAAgB,EAAgB,EAA4B,CAC1D,GAAI,CACF,OAAO,EAAG,CACZ,OAAS,EAAO,CACd,GAAI,EAAa,EAAO,QAAQ,EAAG,OACnC,MAAM,CACR,CACF,CAEA,eAAsB,EAAoB,EAA8C,CACtF,GAAI,CACF,OAAO,MAAM,EAAG,CAClB,MAAQ,CAER,CACF,CAEA,eAAsB,EAAqB,EAA8C,CACvF,GAAI,CACF,OAAO,MAAM,EAAG,CAClB,OAAS,EAAO,CACd,GAAI,EAAa,EAAO,QAAQ,EAAG,OACnC,MAAM,CACR,CACF,CAgCA,eAAsB,EACpB,EACA,CACE,cACA,cACA,aAAa,EACb,cACA,cACA,uBACA,oBAAoB,EACpB,2BACgB,CAAC,EACP,CACZ,IAAI,EAAc,EAClB,OACE,GAAI,CACF,OAAO,MAAM,EAAK,CAAW,CAC/B,OAAS,EAAO,CAMd,GALA,MAAM,IAAc,CAAK,EACzB,IACI,GAAe,GAGf,GAAe,CAAC,EAAY,CAAK,EACnC,MAAM,EAER,IAAM,EAA2B,IAAuB,EAAO,CAAiB,GAAK,EACjF,EAA2B,GAC7B,MAAMA,EAAAA,MAAM,CAAwB,EAElC,IACF,EAAoB,EAAwB,CAAiB,GAE/D,IAAc,iBAAiB,EAAM;EACzC,aAAiB,MAAQ;GAAW,EAAM,OAAS,IAAM,IAAI,EACzD,MAAM,IAAc,CAAK,CAC3B,CAEJ"}
|
package/dist/error.d.ts
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
* @param obj The object to convert.
|
|
4
4
|
*/
|
|
5
5
|
export declare function errorify(obj: unknown): Error;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the message of a thrown `Error`; for any other thrown value, `fallback` if given, or else its string form.
|
|
8
|
+
* `fallback` is also returned when reading the message throws. Never throws, so it is safe to call in a catch block.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getErrorMessage(error: unknown, fallback?: string): string;
|
|
11
|
+
/** Whether a thrown value carries the given `code`, such as a Node.js errno code (`ENOENT`, `EEXIST`, ...). */
|
|
12
|
+
export declare function hasErrorCode<C extends string>(error: unknown, code: C): error is {
|
|
13
|
+
code: C;
|
|
14
|
+
};
|
|
6
15
|
export declare function ignoreError<T>(fn: () => T): T | undefined;
|
|
7
16
|
export declare function ignoreEnoent<T>(fn: () => T): T | undefined;
|
|
8
17
|
export declare function ignoreErrorAsync<T>(fn: () => Promise<T>): Promise<T | undefined>;
|
package/dist/error.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{sleep as e}from"./sleep.js";function t(e){return e instanceof Error?e:Error(typeof e==`string`?e:
|
|
1
|
+
import{sleep as e}from"./sleep.js";function t(e){return e instanceof Error?e:Error(typeof e==`string`?e:i(()=>JSON.stringify(e))??i(()=>String(e)))}function n(e,t){return i(()=>e instanceof Error?e.message:t??String(e))??t??i(()=>Object.prototype.toString.call(e))??`Unknown error`}function r(e,t){return typeof e==`object`&&!!e&&`code`in e&&e.code===t}function i(e){try{return e()}catch{}}function a(e){try{return e()}catch(e){if(r(e,`ENOENT`))return;throw e}}async function o(e){try{return await e()}catch{}}async function s(e){try{return await e()}catch(e){if(r(e,`ENOENT`))return;throw e}}async function c(t,{beforeRetry:n,handleError:r,retryCount:i=3,retryLogger:a,shouldRetry:o,getSleepMilliseconds:s,sleepMilliseconds:c=0,updateSleepMilliseconds:l}={}){let u=0;for(;;)try{return await t(u)}catch(t){if(await r?.(t),u++,u>=i||o&&!o(t))throw t;let d=s?.(t,c)??c;d>0&&await e(d),l&&(c=l(c)),a?.(`Retry due to: ${t}
|
|
2
2
|
${t instanceof Error?`---
|
|
3
|
-
`+(t.stack??``):``}`),await n?.(t)}}export{t as errorify,r as
|
|
3
|
+
`+(t.stack??``):``}`),await n?.(t)}}export{t as errorify,n as getErrorMessage,r as hasErrorCode,a as ignoreEnoent,s as ignoreEnoentAsync,i as ignoreError,o as ignoreErrorAsync,c as withRetry};
|
|
4
4
|
//# sourceMappingURL=error.js.map
|
package/dist/error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","names":[],"sources":["../src/error.ts"],"sourcesContent":["import { sleep } from './sleep.js';\n\n/**\n * Convert an object to an error.\n * @param obj The object to convert.\n */\nexport function errorify(obj: unknown): Error {\n if (obj instanceof Error) return obj;\n if (typeof obj === 'string') return new Error(obj);\n // `JSON.stringify` answers `undefined` for `undefined`, a symbol and a function, and throws\n // on a bigint or a cycle; `new Error(undefined)` has an empty message, which would drop the\n // only diagnostic a caller has about such a thrown value. Neither representation may throw\n // out of here: this runs in a catch block, where it would replace the error it converts.\n return new Error(ignoreError(() => JSON.stringify(obj)) ?? ignoreError(() => String(obj)));\n}\n\nexport function ignoreError<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch {\n // do nothing\n }\n}\n\nexport function ignoreEnoent<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch (error) {\n if (
|
|
1
|
+
{"version":3,"file":"error.js","names":[],"sources":["../src/error.ts"],"sourcesContent":["import { sleep } from './sleep.js';\n\n/**\n * Convert an object to an error.\n * @param obj The object to convert.\n */\nexport function errorify(obj: unknown): Error {\n if (obj instanceof Error) return obj;\n if (typeof obj === 'string') return new Error(obj);\n // `JSON.stringify` answers `undefined` for `undefined`, a symbol and a function, and throws\n // on a bigint or a cycle; `new Error(undefined)` has an empty message, which would drop the\n // only diagnostic a caller has about such a thrown value. Neither representation may throw\n // out of here: this runs in a catch block, where it would replace the error it converts.\n return new Error(ignoreError(() => JSON.stringify(obj)) ?? ignoreError(() => String(obj)));\n}\n\n/**\n * Returns the message of a thrown `Error`; for any other thrown value, `fallback` if given, or else its string form.\n * `fallback` is also returned when reading the message throws. Never throws, so it is safe to call in a catch block.\n */\nexport function getErrorMessage(error: unknown, fallback?: string): string {\n // `String` throws for an object without a prototype, and even `instanceof`, a `message` getter, and\n // `Object.prototype.toString` throw for a proxy or object whose traps or getters throw.\n return (\n ignoreError(() => (error instanceof Error ? error.message : (fallback ?? String(error)))) ??\n fallback ??\n ignoreError(() => Object.prototype.toString.call(error)) ??\n 'Unknown error'\n );\n}\n\n/** Whether a thrown value carries the given `code`, such as a Node.js errno code (`ENOENT`, `EEXIST`, ...). */\nexport function hasErrorCode<C extends string>(error: unknown, code: C): error is { code: C } {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code;\n}\n\nexport function ignoreError<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch {\n // do nothing\n }\n}\n\nexport function ignoreEnoent<T>(fn: () => T): T | undefined {\n try {\n return fn();\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return;\n throw error;\n }\n}\n\nexport async function ignoreErrorAsync<T>(fn: () => Promise<T>): Promise<T | undefined> {\n try {\n return await fn();\n } catch {\n // do nothing\n }\n}\n\nexport async function ignoreEnoentAsync<T>(fn: () => Promise<T>): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return;\n throw error;\n }\n}\n\nexport interface RetryOptions {\n beforeRetry?: (error: unknown) => Promise<void>;\n handleError?: (error: unknown) => Promise<void>;\n /**\n * The maximum number of total attempts, including the initial attempt.\n * For example, `retryCount: 3` runs the function at most 3 times: 1 initial attempt and up to 2 retries.\n */\n retryCount?: number;\n retryLogger?: (message: string) => void;\n shouldRetry?: (error: unknown) => boolean;\n /**\n * Decides how long to wait before retrying after `error`, given the backoff `sleepMilliseconds` it would otherwise wait,\n * e.g. `(error, ms) => Math.max(ms, retryAtOf(error) - Date.now())` to honor a retry time sent by a server.\n * It does not affect the backoff that `updateSleepMilliseconds` advances.\n */\n getSleepMilliseconds?: (error: unknown, sleepMilliseconds: number) => number;\n sleepMilliseconds?: number;\n updateSleepMilliseconds?: (sleepMilliseconds: number) => number;\n}\n\n/**\n * Retry the given function.\n * @param func The function to retry.\n * @param beforeRetry The function to call immediately before retrying.\n * @param handleError The function to call when an error occurs.\n * @param retryCount The maximum number of total attempts, including the initial attempt.\n * @param retryLogger The function to log retrying.\n * @param sleepMilliseconds The number of milliseconds to sleep before retrying.\n * @param updateSleepMilliseconds The function to update sleep milliseconds after each retry.\n */\nexport async function withRetry<T>(\n func: (failedCount: number) => T | Promise<T>,\n {\n beforeRetry,\n handleError,\n retryCount = 3,\n retryLogger,\n shouldRetry,\n getSleepMilliseconds,\n sleepMilliseconds = 0,\n updateSleepMilliseconds,\n }: RetryOptions = {}\n): Promise<T> {\n let failedCount = 0;\n for (;;) {\n try {\n return await func(failedCount);\n } catch (error) {\n await handleError?.(error);\n failedCount++;\n if (failedCount >= retryCount) {\n throw error;\n }\n if (shouldRetry && !shouldRetry(error)) {\n throw error;\n }\n const currentSleepMilliseconds = getSleepMilliseconds?.(error, sleepMilliseconds) ?? sleepMilliseconds;\n if (currentSleepMilliseconds > 0) {\n await sleep(currentSleepMilliseconds);\n }\n if (updateSleepMilliseconds) {\n sleepMilliseconds = updateSleepMilliseconds(sleepMilliseconds);\n }\n retryLogger?.(`Retry due to: ${error}\n${error instanceof Error ? '---\\n' + (error.stack ?? '') : ''}`);\n await beforeRetry?.(error);\n }\n }\n}\n"],"mappings":"mCAMA,SAAgB,EAAS,EAAqB,CAO5C,OANI,aAAe,MAAc,EACO,MAApC,OAAO,GAAQ,SAA2B,EAK7B,MAAkB,KAAK,UAAU,CAAG,CAAC,GAAK,MAAkB,OAAO,CAAG,CAAC,CALvC,CAMnD,CAMA,SAAgB,EAAgB,EAAgB,EAA2B,CAGzE,OACE,MAAmB,aAAiB,MAAQ,EAAM,QAAW,GAAY,OAAO,CAAK,CAAG,GACxF,GACA,MAAkB,OAAO,UAAU,SAAS,KAAK,CAAK,CAAC,GACvD,eAEJ,CAGA,SAAgB,EAA+B,EAAgB,EAA+B,CAC5F,OAAO,OAAO,GAAU,YAAY,GAAkB,SAAU,GAAS,EAAM,OAAS,CAC1F,CAEA,SAAgB,EAAe,EAA4B,CACzD,GAAI,CACF,OAAO,EAAG,CACZ,MAAQ,CAER,CACF,CAEA,SAAgB,EAAgB,EAA4B,CAC1D,GAAI,CACF,OAAO,EAAG,CACZ,OAAS,EAAO,CACd,GAAI,EAAa,EAAO,QAAQ,EAAG,OACnC,MAAM,CACR,CACF,CAEA,eAAsB,EAAoB,EAA8C,CACtF,GAAI,CACF,OAAO,MAAM,EAAG,CAClB,MAAQ,CAER,CACF,CAEA,eAAsB,EAAqB,EAA8C,CACvF,GAAI,CACF,OAAO,MAAM,EAAG,CAClB,OAAS,EAAO,CACd,GAAI,EAAa,EAAO,QAAQ,EAAG,OACnC,MAAM,CACR,CACF,CAgCA,eAAsB,EACpB,EACA,CACE,cACA,cACA,aAAa,EACb,cACA,cACA,uBACA,oBAAoB,EACpB,2BACgB,CAAC,EACP,CACZ,IAAI,EAAc,EAClB,OACE,GAAI,CACF,OAAO,MAAM,EAAK,CAAW,CAC/B,OAAS,EAAO,CAMd,GALA,MAAM,IAAc,CAAK,EACzB,IACI,GAAe,GAGf,GAAe,CAAC,EAAY,CAAK,EACnC,MAAM,EAER,IAAM,EAA2B,IAAuB,EAAO,CAAiB,GAAK,EACjF,EAA2B,GAC7B,MAAM,EAAM,CAAwB,EAElC,IACF,EAAoB,EAAwB,CAAiB,GAE/D,IAAc,iBAAiB,EAAM;EACzC,aAAiB,MAAQ;GAAW,EAAM,OAAS,IAAM,IAAI,EACzD,MAAM,IAAc,CAAK,CAC3B,CAEJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filePath.cjs","names":[],"sources":["../src/filePath.ts"],"sourcesContent":["/**\n * Returns the lower-cased extension of the last path segment without the dot, or an empty string when the segment\n * has none. As with `path.extname`, a leading dot (e.g. `.gitignore`) does not start an extension.\n */\nexport function getFileExtension(filePath: string): string {\n const dotIndex = filePath.lastIndexOf('.');\n return dotIndex > filePath.lastIndexOf('/') + 1 ? filePath.slice(dotIndex + 1).toLowerCase() : '';\n}\n"],"mappings":"aAIA,SAAgB,EAAiB,EAA0B,CACzD,IAAM,EAAW,EAAS,YAAY,GAAG,EACzC,OAAO,EAAW,EAAS,YAAY,GAAG,EAAI,EAAI,EAAS,MAAM,EAAW,CAAC,CAAC,CAAC,YAAY,EAAI,EACjG"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the lower-cased extension of the last path segment without the dot, or an empty string when the segment
|
|
3
|
+
* has none. As with `path.extname`, a leading dot (e.g. `.gitignore`) does not start an extension.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getFileExtension(filePath: string): string;
|
package/dist/filePath.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filePath.js","names":[],"sources":["../src/filePath.ts"],"sourcesContent":["/**\n * Returns the lower-cased extension of the last path segment without the dot, or an empty string when the segment\n * has none. As with `path.extname`, a leading dot (e.g. `.gitignore`) does not start an extension.\n */\nexport function getFileExtension(filePath: string): string {\n const dotIndex = filePath.lastIndexOf('.');\n return dotIndex > filePath.lastIndexOf('/') + 1 ? filePath.slice(dotIndex + 1).toLowerCase() : '';\n}\n"],"mappings":"AAIA,SAAgB,EAAiB,EAA0B,CACzD,IAAM,EAAW,EAAS,YAAY,GAAG,EACzC,OAAO,EAAW,EAAS,YAAY,GAAG,EAAI,EAAI,EAAS,MAAM,EAAW,CAAC,CAAC,CAAC,YAAY,EAAI,EACjG"}
|
package/dist/foreignCjk.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e=/\p{Script=Hangul}/u,t=/\p{Script=Han}/u,n
|
|
1
|
+
"use strict";const e=/\p{Script=Hangul}/u,t=/\p{Script=Han}/u,n=/* @__PURE__ */ new Set(`个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜`);let r;function i(t,n){let r=a(t,n),i=[];return r.some(t=>!e.test(t))&&i.push(`chinese`),r.some(t=>e.test(t))&&i.push(`korean`),i}function a(i,a=``){let s=new Set(a.normalize(`NFKC`)),c=r??=o(),l=/* @__PURE__ */ new Set;for(let r of i.normalize(`NFKC`))s.has(r)||(e.test(r)||t.test(r)&&(!c.has(r)||n.has(r)))&&l.add(r);return[...l]}function o(){let e=new TextDecoder(`shift_jis`),t=/* @__PURE__ */ new Set(`𠮟塡剝頰仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷`);for(let n=129;n<=234;n++)if(!(n>=160&&n<=223))for(let r=64;r<=252;r++)t.add(e.decode(new Uint8Array([n,r])));return t}exports.detectForeignCjkInJapanese=i,exports.findForeignCjkCharactersInJapanese=a;
|
|
2
2
|
//# sourceMappingURL=foreignCjk.cjs.map
|
package/dist/foreignCjk.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foreignCjk.cjs","names":[],"sources":["../src/foreignCjk.ts"],"sourcesContent":["export type ForeignCjkLanguage = 'chinese' | 'korean';\n\nconst HANGUL_REGEX = /\\p{Script=Hangul}/u;\nconst HAN_REGEX = /\\p{Script=Han}/u;\n// JIS X 0208 cannot encode these Jōyō kanji, which were added in 2010.\nconst JOYO_KANJI_OUTSIDE_JIS_X_0208 = '𠮟塡剝頰';\n// Kanji for Japanese names (e.g., 髙, 﨑, 濵, 栁) that Chinese prose rarely contains: the NFKC forms of the\n// Windows-31J NEC-selected IBM and IBM extension kanji that neither JIS X 0208, Big5, nor GB2312 encodes, plus 𠮷 from\n// JIS X 0213. NFKC forms are listed because the lookup runs after NFKC normalization (e.g., U+FA20 becomes U+8612).\n// Some also appear in Chinese names (e.g., 喆), but prose that mixes Chinese into Japanese hardly contains them.\n// Extension kanji that Big5 or GB2312 encodes (e.g., 德, 瀨) stay Chinese because Chinese prose uses them.\nconst JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208 =\n '仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷';\n// Characters JIS X 0208 can encode but modern Japanese prose does not use:\n// - old forms (kyūjitai) of Jōyō kanji, from the `kyujitai` npm package and Unihan's kJapaneseOldVariant,\n// except those still common in Japanese words or names (e.g., 應 in 慶應, 澤, 邊, 龍, 藝 in 東京藝術大学, 糺す)\n// - Chinese function words that Japanese writes in kana (e.g., 們, 這, 麼, 很, 怎, 跟, 嘛) and stray simplified forms (e.g., 个)\n// - traditional Chinese characters that neither table covers but Japanese never uses: 碼, 舉, 鏈, 雖\n// Other Chinese-only content characters (e.g., 媽, 豬) are not listed because separating them from rare kanji\n// that Japanese prose does use (e.g., 乖離, 瑕疵, 齟齬, 俯瞰) needs Japanese usage frequencies.\nconst CHINESE_CHARACTERS_IN_JIS_X_0208 = new Set(\n '个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜'\n);\n\nlet japaneseKanji: Set<string> | undefined;\n\n/**\n * Detects Chinese or Korean characters mixed into Japanese text, such as LLM-generated Japanese prose.\n * See {@link findForeignCjkCharactersInJapanese} for which characters count and how `allowedText` works.\n * Returns the detected languages, or an empty array if none are found.\n */\nexport function detectForeignCjkInJapanese(text: string, allowedText?: string): ForeignCjkLanguage[] {\n const characters = findForeignCjkCharactersInJapanese(text, allowedText);\n const languages: ForeignCjkLanguage[] = [];\n if (characters.some((char) => !HANGUL_REGEX.test(char))) languages.push('chinese');\n if (characters.some((char) => HANGUL_REGEX.test(char))) languages.push('korean');\n return languages;\n}\n\n/**\n * Returns the distinct Chinese or Korean characters mixed into Japanese text, NFKC-normalized, in order of appearance.\n * A kanji is treated as Chinese when it is outside JIS X 0208 (except the four Jōyō kanji 𠮟塡剝頰 and Japanese name\n * kanji that neither Big5 nor GB2312 encodes, e.g., 髙, 﨑, 𠮷) or is one of the listed old forms, Chinese function\n * words, or other Chinese-only characters that modern Japanese prose does not use (e.g., 對, 國, 這, 們, 很, 碼).\n * Old forms in names that Chinese prose also uses (e.g., 國, 與, 德) are therefore also reported, while Chinese\n * containing none of these characters (e.g., 最后返回答案, 豬肉) is not.\n * Characters that also occur in `allowedText` are not reported, so passing the input that an LLM may quote\n * (e.g., the prompt, a question, or an error message) keeps quoted names and code from being reported.\n */\nexport function findForeignCjkCharactersInJapanese(text: string, allowedText = ''): string[] {\n const allowedCharacters = new Set(allowedText.normalize('NFKC'));\n const kanjiSet = (japaneseKanji ??= buildJapaneseKanjiSet());\n const characters = new Set<string>();\n for (const char of text.normalize('NFKC')) {\n if (allowedCharacters.has(char)) continue;\n if (\n HANGUL_REGEX.test(char) ||\n (HAN_REGEX.test(char) && (!kanjiSet.has(char) || CHINESE_CHARACTERS_IN_JIS_X_0208.has(char)))\n ) {\n characters.add(char);\n }\n }\n return [...characters];\n}\n\nfunction buildJapaneseKanjiSet(): Set<string> {\n // The WHATWG `shift_jis` decoder is Windows-31J, so skip its vendor-extension lead bytes (0xED-0xFC) to keep JIS X 0208 only.\n const decoder = new TextDecoder('shift_jis');\n const kanjiSet = new Set(JOYO_KANJI_OUTSIDE_JIS_X_0208 + JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208);\n for (let lead = 0x81; lead <= 0xEA; lead++) {\n if (lead >= 0xA0 && lead <= 0xDF) continue;\n for (let trail = 0x40; trail <= 0xFC; trail++) {\n kanjiSet.add(decoder.decode(new Uint8Array([lead, trail])));\n }\n }\n return kanjiSet;\n}\n"],"mappings":"aAEA,MAAM,EAAe,qBACf,EAAY,kBAiBZ,
|
|
1
|
+
{"version":3,"file":"foreignCjk.cjs","names":[],"sources":["../src/foreignCjk.ts"],"sourcesContent":["export type ForeignCjkLanguage = 'chinese' | 'korean';\n\nconst HANGUL_REGEX = /\\p{Script=Hangul}/u;\nconst HAN_REGEX = /\\p{Script=Han}/u;\n// JIS X 0208 cannot encode these Jōyō kanji, which were added in 2010.\nconst JOYO_KANJI_OUTSIDE_JIS_X_0208 = '𠮟塡剝頰';\n// Kanji for Japanese names (e.g., 髙, 﨑, 濵, 栁) that Chinese prose rarely contains: the NFKC forms of the\n// Windows-31J NEC-selected IBM and IBM extension kanji that neither JIS X 0208, Big5, nor GB2312 encodes, plus 𠮷 from\n// JIS X 0213. NFKC forms are listed because the lookup runs after NFKC normalization (e.g., U+FA20 becomes U+8612).\n// Some also appear in Chinese names (e.g., 喆), but prose that mixes Chinese into Japanese hardly contains them.\n// Extension kanji that Big5 or GB2312 encodes (e.g., 德, 瀨) stay Chinese because Chinese prose uses them.\nconst JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208 =\n '仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷';\n// Characters JIS X 0208 can encode but modern Japanese prose does not use:\n// - old forms (kyūjitai) of Jōyō kanji, from the `kyujitai` npm package and Unihan's kJapaneseOldVariant,\n// except those still common in Japanese words or names (e.g., 應 in 慶應, 澤, 邊, 龍, 藝 in 東京藝術大学, 糺す)\n// - Chinese function words that Japanese writes in kana (e.g., 們, 這, 麼, 很, 怎, 跟, 嘛) and stray simplified forms (e.g., 个)\n// - traditional Chinese characters that neither table covers but Japanese never uses: 碼, 舉, 鏈, 雖\n// Other Chinese-only content characters (e.g., 媽, 豬) are not listed because separating them from rare kanji\n// that Japanese prose does use (e.g., 乖離, 瑕疵, 齟齬, 俯瞰) needs Japanese usage frequencies.\nconst CHINESE_CHARACTERS_IN_JIS_X_0208 = new Set(\n '个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜'\n);\n\nlet japaneseKanji: Set<string> | undefined;\n\n/**\n * Detects Chinese or Korean characters mixed into Japanese text, such as LLM-generated Japanese prose.\n * See {@link findForeignCjkCharactersInJapanese} for which characters count and how `allowedText` works.\n * Returns the detected languages, or an empty array if none are found.\n */\nexport function detectForeignCjkInJapanese(text: string, allowedText?: string): ForeignCjkLanguage[] {\n const characters = findForeignCjkCharactersInJapanese(text, allowedText);\n const languages: ForeignCjkLanguage[] = [];\n if (characters.some((char) => !HANGUL_REGEX.test(char))) languages.push('chinese');\n if (characters.some((char) => HANGUL_REGEX.test(char))) languages.push('korean');\n return languages;\n}\n\n/**\n * Returns the distinct Chinese or Korean characters mixed into Japanese text, NFKC-normalized, in order of appearance.\n * A kanji is treated as Chinese when it is outside JIS X 0208 (except the four Jōyō kanji 𠮟塡剝頰 and Japanese name\n * kanji that neither Big5 nor GB2312 encodes, e.g., 髙, 﨑, 𠮷) or is one of the listed old forms, Chinese function\n * words, or other Chinese-only characters that modern Japanese prose does not use (e.g., 對, 國, 這, 們, 很, 碼).\n * Old forms in names that Chinese prose also uses (e.g., 國, 與, 德) are therefore also reported, while Chinese\n * containing none of these characters (e.g., 最后返回答案, 豬肉) is not.\n * Characters that also occur in `allowedText` are not reported, so passing the input that an LLM may quote\n * (e.g., the prompt, a question, or an error message) keeps quoted names and code from being reported.\n */\nexport function findForeignCjkCharactersInJapanese(text: string, allowedText = ''): string[] {\n const allowedCharacters = new Set(allowedText.normalize('NFKC'));\n const kanjiSet = (japaneseKanji ??= buildJapaneseKanjiSet());\n const characters = new Set<string>();\n for (const char of text.normalize('NFKC')) {\n if (allowedCharacters.has(char)) continue;\n if (\n HANGUL_REGEX.test(char) ||\n (HAN_REGEX.test(char) && (!kanjiSet.has(char) || CHINESE_CHARACTERS_IN_JIS_X_0208.has(char)))\n ) {\n characters.add(char);\n }\n }\n return [...characters];\n}\n\nfunction buildJapaneseKanjiSet(): Set<string> {\n // The WHATWG `shift_jis` decoder is Windows-31J, so skip its vendor-extension lead bytes (0xED-0xFC) to keep JIS X 0208 only.\n const decoder = new TextDecoder('shift_jis');\n const kanjiSet = new Set(JOYO_KANJI_OUTSIDE_JIS_X_0208 + JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208);\n for (let lead = 0x81; lead <= 0xEA; lead++) {\n if (lead >= 0xA0 && lead <= 0xDF) continue;\n for (let trail = 0x40; trail <= 0xFC; trail++) {\n kanjiSet.add(decoder.decode(new Uint8Array([lead, trail])));\n }\n }\n return kanjiSet;\n}\n"],"mappings":"aAEA,MAAM,EAAe,qBACf,EAAY,kBAiBZ,kBAAmC,IAAI,IAC3C,+RACF,EAEA,IAAI,EAOJ,SAAgB,EAA2B,EAAc,EAA4C,CACnG,IAAM,EAAa,EAAmC,EAAM,CAAW,EACjE,EAAkC,CAAC,EAGzC,OAFI,EAAW,KAAM,GAAS,CAAC,EAAa,KAAK,CAAI,CAAC,GAAG,EAAU,KAAK,SAAS,EAC7E,EAAW,KAAM,GAAS,EAAa,KAAK,CAAI,CAAC,GAAG,EAAU,KAAK,QAAQ,EACxE,CACT,CAYA,SAAgB,EAAmC,EAAc,EAAc,GAAc,CAC3F,IAAM,EAAoB,IAAI,IAAI,EAAY,UAAU,MAAM,CAAC,EACzD,EAAY,IAAkB,EAAsB,EACpD,kBAAa,IAAI,IACvB,IAAK,IAAM,KAAQ,EAAK,UAAU,MAAM,EAClC,EAAkB,IAAI,CAAI,IAE5B,EAAa,KAAK,CAAI,GACrB,EAAU,KAAK,CAAI,IAAM,CAAC,EAAS,IAAI,CAAI,GAAK,EAAiC,IAAI,CAAI,KAE1F,EAAW,IAAI,CAAI,EAGvB,MAAO,CAAC,GAAG,CAAU,CACvB,CAEA,SAAS,GAAqC,CAE5C,IAAM,EAAU,IAAI,YAAY,WAAW,EACrC,kBAAW,IAAI,IAAI,qIAAsE,EAC/F,IAAK,IAAI,EAAO,IAAM,GAAQ,IAAM,IAC9B,QAAQ,KAAQ,GAAQ,KAC5B,IAAK,IAAI,EAAQ,GAAM,GAAS,IAAM,IACpC,EAAS,IAAI,EAAQ,OAAO,IAAI,WAAW,CAAC,EAAM,CAAK,CAAC,CAAC,CAAC,EAG9D,OAAO,CACT"}
|
package/dist/foreignCjk.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=/\p{Script=Hangul}/u,t=/\p{Script=Han}/u,n
|
|
1
|
+
const e=/\p{Script=Hangul}/u,t=/\p{Script=Han}/u,n=/* @__PURE__ */ new Set(`个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜`);let r;function i(t,n){let r=a(t,n),i=[];return r.some(t=>!e.test(t))&&i.push(`chinese`),r.some(t=>e.test(t))&&i.push(`korean`),i}function a(i,a=``){let s=new Set(a.normalize(`NFKC`)),c=r??=o(),l=/* @__PURE__ */ new Set;for(let r of i.normalize(`NFKC`))s.has(r)||(e.test(r)||t.test(r)&&(!c.has(r)||n.has(r)))&&l.add(r);return[...l]}function o(){let e=new TextDecoder(`shift_jis`),t=/* @__PURE__ */ new Set(`𠮟塡剝頰仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷`);for(let n=129;n<=234;n++)if(!(n>=160&&n<=223))for(let r=64;r<=252;r++)t.add(e.decode(new Uint8Array([n,r])));return t}export{i as detectForeignCjkInJapanese,a as findForeignCjkCharactersInJapanese};
|
|
2
2
|
//# sourceMappingURL=foreignCjk.js.map
|
package/dist/foreignCjk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foreignCjk.js","names":[],"sources":["../src/foreignCjk.ts"],"sourcesContent":["export type ForeignCjkLanguage = 'chinese' | 'korean';\n\nconst HANGUL_REGEX = /\\p{Script=Hangul}/u;\nconst HAN_REGEX = /\\p{Script=Han}/u;\n// JIS X 0208 cannot encode these Jōyō kanji, which were added in 2010.\nconst JOYO_KANJI_OUTSIDE_JIS_X_0208 = '𠮟塡剝頰';\n// Kanji for Japanese names (e.g., 髙, 﨑, 濵, 栁) that Chinese prose rarely contains: the NFKC forms of the\n// Windows-31J NEC-selected IBM and IBM extension kanji that neither JIS X 0208, Big5, nor GB2312 encodes, plus 𠮷 from\n// JIS X 0213. NFKC forms are listed because the lookup runs after NFKC normalization (e.g., U+FA20 becomes U+8612).\n// Some also appear in Chinese names (e.g., 喆), but prose that mixes Chinese into Japanese hardly contains them.\n// Extension kanji that Big5 or GB2312 encodes (e.g., 德, 瀨) stay Chinese because Chinese prose uses them.\nconst JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208 =\n '仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷';\n// Characters JIS X 0208 can encode but modern Japanese prose does not use:\n// - old forms (kyūjitai) of Jōyō kanji, from the `kyujitai` npm package and Unihan's kJapaneseOldVariant,\n// except those still common in Japanese words or names (e.g., 應 in 慶應, 澤, 邊, 龍, 藝 in 東京藝術大学, 糺す)\n// - Chinese function words that Japanese writes in kana (e.g., 們, 這, 麼, 很, 怎, 跟, 嘛) and stray simplified forms (e.g., 个)\n// - traditional Chinese characters that neither table covers but Japanese never uses: 碼, 舉, 鏈, 雖\n// Other Chinese-only content characters (e.g., 媽, 豬) are not listed because separating them from rare kanji\n// that Japanese prose does use (e.g., 乖離, 瑕疵, 齟齬, 俯瞰) needs Japanese usage frequencies.\nconst CHINESE_CHARACTERS_IN_JIS_X_0208 = new Set(\n '个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜'\n);\n\nlet japaneseKanji: Set<string> | undefined;\n\n/**\n * Detects Chinese or Korean characters mixed into Japanese text, such as LLM-generated Japanese prose.\n * See {@link findForeignCjkCharactersInJapanese} for which characters count and how `allowedText` works.\n * Returns the detected languages, or an empty array if none are found.\n */\nexport function detectForeignCjkInJapanese(text: string, allowedText?: string): ForeignCjkLanguage[] {\n const characters = findForeignCjkCharactersInJapanese(text, allowedText);\n const languages: ForeignCjkLanguage[] = [];\n if (characters.some((char) => !HANGUL_REGEX.test(char))) languages.push('chinese');\n if (characters.some((char) => HANGUL_REGEX.test(char))) languages.push('korean');\n return languages;\n}\n\n/**\n * Returns the distinct Chinese or Korean characters mixed into Japanese text, NFKC-normalized, in order of appearance.\n * A kanji is treated as Chinese when it is outside JIS X 0208 (except the four Jōyō kanji 𠮟塡剝頰 and Japanese name\n * kanji that neither Big5 nor GB2312 encodes, e.g., 髙, 﨑, 𠮷) or is one of the listed old forms, Chinese function\n * words, or other Chinese-only characters that modern Japanese prose does not use (e.g., 對, 國, 這, 們, 很, 碼).\n * Old forms in names that Chinese prose also uses (e.g., 國, 與, 德) are therefore also reported, while Chinese\n * containing none of these characters (e.g., 最后返回答案, 豬肉) is not.\n * Characters that also occur in `allowedText` are not reported, so passing the input that an LLM may quote\n * (e.g., the prompt, a question, or an error message) keeps quoted names and code from being reported.\n */\nexport function findForeignCjkCharactersInJapanese(text: string, allowedText = ''): string[] {\n const allowedCharacters = new Set(allowedText.normalize('NFKC'));\n const kanjiSet = (japaneseKanji ??= buildJapaneseKanjiSet());\n const characters = new Set<string>();\n for (const char of text.normalize('NFKC')) {\n if (allowedCharacters.has(char)) continue;\n if (\n HANGUL_REGEX.test(char) ||\n (HAN_REGEX.test(char) && (!kanjiSet.has(char) || CHINESE_CHARACTERS_IN_JIS_X_0208.has(char)))\n ) {\n characters.add(char);\n }\n }\n return [...characters];\n}\n\nfunction buildJapaneseKanjiSet(): Set<string> {\n // The WHATWG `shift_jis` decoder is Windows-31J, so skip its vendor-extension lead bytes (0xED-0xFC) to keep JIS X 0208 only.\n const decoder = new TextDecoder('shift_jis');\n const kanjiSet = new Set(JOYO_KANJI_OUTSIDE_JIS_X_0208 + JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208);\n for (let lead = 0x81; lead <= 0xEA; lead++) {\n if (lead >= 0xA0 && lead <= 0xDF) continue;\n for (let trail = 0x40; trail <= 0xFC; trail++) {\n kanjiSet.add(decoder.decode(new Uint8Array([lead, trail])));\n }\n }\n return kanjiSet;\n}\n"],"mappings":"AAEA,MAAM,EAAe,qBACf,EAAY,kBAiBZ,
|
|
1
|
+
{"version":3,"file":"foreignCjk.js","names":[],"sources":["../src/foreignCjk.ts"],"sourcesContent":["export type ForeignCjkLanguage = 'chinese' | 'korean';\n\nconst HANGUL_REGEX = /\\p{Script=Hangul}/u;\nconst HAN_REGEX = /\\p{Script=Han}/u;\n// JIS X 0208 cannot encode these Jōyō kanji, which were added in 2010.\nconst JOYO_KANJI_OUTSIDE_JIS_X_0208 = '𠮟塡剝頰';\n// Kanji for Japanese names (e.g., 髙, 﨑, 濵, 栁) that Chinese prose rarely contains: the NFKC forms of the\n// Windows-31J NEC-selected IBM and IBM extension kanji that neither JIS X 0208, Big5, nor GB2312 encodes, plus 𠮷 from\n// JIS X 0213. NFKC forms are listed because the lookup runs after NFKC normalization (e.g., U+FA20 becomes U+8612).\n// Some also appear in Chinese names (e.g., 喆), but prose that mixes Chinese into Japanese hardly contains them.\n// Extension kanji that Big5 or GB2312 encodes (e.g., 德, 瀨) stay Chinese because Chinese prose uses them.\nconst JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208 =\n '仼伃伹侊俿偂僘僴兊兤冝凬刕劜劯匇匤厓叝咊咜喆坙坥垬埈墲夋奛奝奣尞岺峵嵓嵭嶹巐弡弴彅惞愑愰憘戓抦敎昞昻晳暿曺曻朎杦栁桒棏樰橳櫢櫤涖淸澵濵焏犱犾猤玽甁硺礰竧箞絈緖罇荢葈蓜蘒蠇裵褜訷贒郞鄕釞釥鈼鉙鉷鍈鏆隝隯霳霻靍靏靑靕髙魲鮏鮱鮻鰀﨎﨏﨑﨓﨔﨟﨡﨣﨤﨧﨨﨩𠮷';\n// Characters JIS X 0208 can encode but modern Japanese prose does not use:\n// - old forms (kyūjitai) of Jōyō kanji, from the `kyujitai` npm package and Unihan's kJapaneseOldVariant,\n// except those still common in Japanese words or names (e.g., 應 in 慶應, 澤, 邊, 龍, 藝 in 東京藝術大学, 糺す)\n// - Chinese function words that Japanese writes in kana (e.g., 們, 這, 麼, 很, 怎, 跟, 嘛) and stray simplified forms (e.g., 个)\n// - traditional Chinese characters that neither table covers but Japanese never uses: 碼, 舉, 鏈, 雖\n// Other Chinese-only content characters (e.g., 媽, 豬) are not listed because separating them from rare kanji\n// that Japanese prose does use (e.g., 乖離, 瑕疵, 齟齬, 俯瞰) needs Japanese usage frequencies.\nconst CHINESE_CHARACTERS_IN_JIS_X_0208 = new Set(\n '个乘亂亞从佛來們假傳僞價儉兒兩册刄剩劍劑勞勳勵勸區卷參听呀咯哇哦唔單嘛嚴囑囘圈國圍圓圖團墮壓壘壞壤壯壹壻壽奧奬姙孃學寢實寫寶將專對屆屬峽巖帶广廢廣廳彈很徑從怎恆惡惱愼慘懷戀戰戲拂拔拜挾插搖搜擇擔據擧擴攜攝收效敍敕數斷晝曉會條棧榮樂樓樞樣檢權歐歡歸殘殼毆氣沒淨淺滯滿潛澁濕濟灣燈燒營爐爭爲犧狹獨獵獸獻瓣畫當疊癡發盜盡碎碼祕禪禮稱稻穗穩竊竝粹絲經縣縱總繩繪繼續纖缺罐聲聽肅腦膽臟臺與舉舊舍舖艷莊莖萬藏藥處號螢蟲蠶蠻衞裝襃覺覽觀觸謠證譯譽讀變讓讚豐豫貳賣贊跟踐輕轉辨辭辯這遙遞遲鄰醉醫釀釋錢鎭鏈鐵鑄鑛關陷隨險隱隸雖雙雜霸靈靜顏顯飜飮餘餠騷驅驗驛髓體髮鬪鷄鹽麥麼黏默點黨齊齒齡龜'\n);\n\nlet japaneseKanji: Set<string> | undefined;\n\n/**\n * Detects Chinese or Korean characters mixed into Japanese text, such as LLM-generated Japanese prose.\n * See {@link findForeignCjkCharactersInJapanese} for which characters count and how `allowedText` works.\n * Returns the detected languages, or an empty array if none are found.\n */\nexport function detectForeignCjkInJapanese(text: string, allowedText?: string): ForeignCjkLanguage[] {\n const characters = findForeignCjkCharactersInJapanese(text, allowedText);\n const languages: ForeignCjkLanguage[] = [];\n if (characters.some((char) => !HANGUL_REGEX.test(char))) languages.push('chinese');\n if (characters.some((char) => HANGUL_REGEX.test(char))) languages.push('korean');\n return languages;\n}\n\n/**\n * Returns the distinct Chinese or Korean characters mixed into Japanese text, NFKC-normalized, in order of appearance.\n * A kanji is treated as Chinese when it is outside JIS X 0208 (except the four Jōyō kanji 𠮟塡剝頰 and Japanese name\n * kanji that neither Big5 nor GB2312 encodes, e.g., 髙, 﨑, 𠮷) or is one of the listed old forms, Chinese function\n * words, or other Chinese-only characters that modern Japanese prose does not use (e.g., 對, 國, 這, 們, 很, 碼).\n * Old forms in names that Chinese prose also uses (e.g., 國, 與, 德) are therefore also reported, while Chinese\n * containing none of these characters (e.g., 最后返回答案, 豬肉) is not.\n * Characters that also occur in `allowedText` are not reported, so passing the input that an LLM may quote\n * (e.g., the prompt, a question, or an error message) keeps quoted names and code from being reported.\n */\nexport function findForeignCjkCharactersInJapanese(text: string, allowedText = ''): string[] {\n const allowedCharacters = new Set(allowedText.normalize('NFKC'));\n const kanjiSet = (japaneseKanji ??= buildJapaneseKanjiSet());\n const characters = new Set<string>();\n for (const char of text.normalize('NFKC')) {\n if (allowedCharacters.has(char)) continue;\n if (\n HANGUL_REGEX.test(char) ||\n (HAN_REGEX.test(char) && (!kanjiSet.has(char) || CHINESE_CHARACTERS_IN_JIS_X_0208.has(char)))\n ) {\n characters.add(char);\n }\n }\n return [...characters];\n}\n\nfunction buildJapaneseKanjiSet(): Set<string> {\n // The WHATWG `shift_jis` decoder is Windows-31J, so skip its vendor-extension lead bytes (0xED-0xFC) to keep JIS X 0208 only.\n const decoder = new TextDecoder('shift_jis');\n const kanjiSet = new Set(JOYO_KANJI_OUTSIDE_JIS_X_0208 + JAPANESE_NAME_KANJI_OUTSIDE_JIS_X_0208);\n for (let lead = 0x81; lead <= 0xEA; lead++) {\n if (lead >= 0xA0 && lead <= 0xDF) continue;\n for (let trail = 0x40; trail <= 0xFC; trail++) {\n kanjiSet.add(decoder.decode(new Uint8Array([lead, trail])));\n }\n }\n return kanjiSet;\n}\n"],"mappings":"AAEA,MAAM,EAAe,qBACf,EAAY,kBAiBZ,kBAAmC,IAAI,IAC3C,+RACF,EAEA,IAAI,EAOJ,SAAgB,EAA2B,EAAc,EAA4C,CACnG,IAAM,EAAa,EAAmC,EAAM,CAAW,EACjE,EAAkC,CAAC,EAGzC,OAFI,EAAW,KAAM,GAAS,CAAC,EAAa,KAAK,CAAI,CAAC,GAAG,EAAU,KAAK,SAAS,EAC7E,EAAW,KAAM,GAAS,EAAa,KAAK,CAAI,CAAC,GAAG,EAAU,KAAK,QAAQ,EACxE,CACT,CAYA,SAAgB,EAAmC,EAAc,EAAc,GAAc,CAC3F,IAAM,EAAoB,IAAI,IAAI,EAAY,UAAU,MAAM,CAAC,EACzD,EAAY,IAAkB,EAAsB,EACpD,kBAAa,IAAI,IACvB,IAAK,IAAM,KAAQ,EAAK,UAAU,MAAM,EAClC,EAAkB,IAAI,CAAI,IAE5B,EAAa,KAAK,CAAI,GACrB,EAAU,KAAK,CAAI,IAAM,CAAC,EAAS,IAAI,CAAI,GAAK,EAAiC,IAAI,CAAI,KAE1F,EAAW,IAAI,CAAI,EAGvB,MAAO,CAAC,GAAG,CAAU,CACvB,CAEA,SAAS,GAAqC,CAE5C,IAAM,EAAU,IAAI,YAAY,WAAW,EACrC,kBAAW,IAAI,IAAI,qIAAsE,EAC/F,IAAK,IAAI,EAAO,IAAM,GAAQ,IAAM,IAC9B,QAAQ,KAAQ,GAAQ,KAC5B,IAAK,IAAI,EAAQ,GAAM,GAAS,IAAM,IACpC,EAAS,IAAI,EAAQ,OAAO,IAAI,WAAW,CAAC,EAAM,CAAK,CAAC,CAAC,CAAC,EAG9D,OAAO,CACT"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const e=/* @__PURE__ */ new Map;function t(t,n){let r=e.get(n);r||(r=new Intl.DateTimeFormat(`en-US`,{timeZone:n,era:`short`,year:`numeric`,month:`2-digit`,day:`2-digit`}),e.set(n,r));let i=0,a=!1,o=``,s=``;for(let e of r.formatToParts(t))e.type===`year`?i=Number(e.value):e.type===`era`?a=e.value===`BC`:e.type===`month`?o=e.value:e.type===`day`&&(s=e.value);let c=a?1-i:i;if(c<0||c>9999)throw RangeError(`The year ${c} in ${n} is outside 0000–9999`);return`${String(c).padStart(4,`0`)}-${o}-${s}`}exports.formatIsoDateInTimeZone=t;
|
|
2
|
+
//# sourceMappingURL=formatIsoDate.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatIsoDate.cjs","names":[],"sources":["../src/formatIsoDate.ts"],"sourcesContent":["const formatters = new Map<string, Intl.DateTimeFormat>();\n\n/**\n * Formats the calendar date of `date` in an IANA `timeZone` (e.g. `Asia/Tokyo`) as YYYY-MM-DD, independent of the\n * runtime's local time zone, which is UTC on Cloudflare Workers and most servers.\n * Supports ISO years 0000–9999, like `parseIsoDate`. Throws a `RangeError` for a date outside them in `timeZone` and\n * for an unknown time zone.\n */\nexport function formatIsoDateInTimeZone(date: Date, timeZone: string): string {\n let formatter = formatters.get(timeZone);\n if (!formatter) {\n // Constructing a formatter costs far more than formatting, so one is kept per time zone.\n formatter = new Intl.DateTimeFormat('en-US', {\n timeZone,\n era: 'short',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n formatters.set(timeZone, formatter);\n }\n let year = 0;\n let isBeforeCommonEra = false;\n let month = '';\n let day = '';\n // `formatToParts` is used instead of a locale whose format happens to be YYYY-MM-DD (e.g. `en-CA`), since such\n // formats follow CLDR updates.\n for (const part of formatter.formatToParts(date)) {\n if (part.type === 'year') year = Number(part.value);\n else if (part.type === 'era') isBeforeCommonEra = part.value === 'BC';\n else if (part.type === 'month') month = part.value;\n else if (part.type === 'day') day = part.value;\n }\n // The Gregorian calendar has no year 0: ISO year 0000 is 1 BC.\n const isoYear = isBeforeCommonEra ? 1 - year : year;\n if (isoYear < 0 || isoYear > 9999) throw new RangeError(`The year ${isoYear} in ${timeZone} is outside 0000–9999`);\n return `${String(isoYear).padStart(4, '0')}-${month}-${day}`;\n}\n"],"mappings":"aAAA,MAAM,kBAAa,IAAI,IAQvB,SAAgB,EAAwB,EAAY,EAA0B,CAC5E,IAAI,EAAY,EAAW,IAAI,CAAQ,EAClC,IAEH,EAAY,IAAI,KAAK,eAAe,QAAS,CAC3C,WACA,IAAK,QACL,KAAM,UACN,MAAO,UACP,IAAK,SACP,CAAC,EACD,EAAW,IAAI,EAAU,CAAS,GAEpC,IAAI,EAAO,EACP,EAAoB,GACpB,EAAQ,GACR,EAAM,GAGV,IAAK,IAAM,KAAQ,EAAU,cAAc,CAAI,EACzC,EAAK,OAAS,OAAQ,EAAO,OAAO,EAAK,KAAK,EACzC,EAAK,OAAS,MAAO,EAAoB,EAAK,QAAU,KACxD,EAAK,OAAS,QAAS,EAAQ,EAAK,MACpC,EAAK,OAAS,QAAO,EAAM,EAAK,OAG3C,IAAM,EAAU,EAAoB,EAAI,EAAO,EAC/C,GAAI,EAAU,GAAK,EAAU,KAAM,MAAU,WAAW,YAAY,EAAQ,MAAM,EAAS,sBAAsB,EACjH,MAAO,GAAG,OAAO,CAAO,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAAG,EAAM,GAAG,GACzD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats the calendar date of `date` in an IANA `timeZone` (e.g. `Asia/Tokyo`) as YYYY-MM-DD, independent of the
|
|
3
|
+
* runtime's local time zone, which is UTC on Cloudflare Workers and most servers.
|
|
4
|
+
* Supports ISO years 0000–9999, like `parseIsoDate`. Throws a `RangeError` for a date outside them in `timeZone` and
|
|
5
|
+
* for an unknown time zone.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatIsoDateInTimeZone(date: Date, timeZone: string): string;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=/* @__PURE__ */ new Map;function t(t,n){let r=e.get(n);r||(r=new Intl.DateTimeFormat(`en-US`,{timeZone:n,era:`short`,year:`numeric`,month:`2-digit`,day:`2-digit`}),e.set(n,r));let i=0,a=!1,o=``,s=``;for(let e of r.formatToParts(t))e.type===`year`?i=Number(e.value):e.type===`era`?a=e.value===`BC`:e.type===`month`?o=e.value:e.type===`day`&&(s=e.value);let c=a?1-i:i;if(c<0||c>9999)throw RangeError(`The year ${c} in ${n} is outside 0000–9999`);return`${String(c).padStart(4,`0`)}-${o}-${s}`}export{t as formatIsoDateInTimeZone};
|
|
2
|
+
//# sourceMappingURL=formatIsoDate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatIsoDate.js","names":[],"sources":["../src/formatIsoDate.ts"],"sourcesContent":["const formatters = new Map<string, Intl.DateTimeFormat>();\n\n/**\n * Formats the calendar date of `date` in an IANA `timeZone` (e.g. `Asia/Tokyo`) as YYYY-MM-DD, independent of the\n * runtime's local time zone, which is UTC on Cloudflare Workers and most servers.\n * Supports ISO years 0000–9999, like `parseIsoDate`. Throws a `RangeError` for a date outside them in `timeZone` and\n * for an unknown time zone.\n */\nexport function formatIsoDateInTimeZone(date: Date, timeZone: string): string {\n let formatter = formatters.get(timeZone);\n if (!formatter) {\n // Constructing a formatter costs far more than formatting, so one is kept per time zone.\n formatter = new Intl.DateTimeFormat('en-US', {\n timeZone,\n era: 'short',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n formatters.set(timeZone, formatter);\n }\n let year = 0;\n let isBeforeCommonEra = false;\n let month = '';\n let day = '';\n // `formatToParts` is used instead of a locale whose format happens to be YYYY-MM-DD (e.g. `en-CA`), since such\n // formats follow CLDR updates.\n for (const part of formatter.formatToParts(date)) {\n if (part.type === 'year') year = Number(part.value);\n else if (part.type === 'era') isBeforeCommonEra = part.value === 'BC';\n else if (part.type === 'month') month = part.value;\n else if (part.type === 'day') day = part.value;\n }\n // The Gregorian calendar has no year 0: ISO year 0000 is 1 BC.\n const isoYear = isBeforeCommonEra ? 1 - year : year;\n if (isoYear < 0 || isoYear > 9999) throw new RangeError(`The year ${isoYear} in ${timeZone} is outside 0000–9999`);\n return `${String(isoYear).padStart(4, '0')}-${month}-${day}`;\n}\n"],"mappings":"AAAA,MAAM,kBAAa,IAAI,IAQvB,SAAgB,EAAwB,EAAY,EAA0B,CAC5E,IAAI,EAAY,EAAW,IAAI,CAAQ,EAClC,IAEH,EAAY,IAAI,KAAK,eAAe,QAAS,CAC3C,WACA,IAAK,QACL,KAAM,UACN,MAAO,UACP,IAAK,SACP,CAAC,EACD,EAAW,IAAI,EAAU,CAAS,GAEpC,IAAI,EAAO,EACP,EAAoB,GACpB,EAAQ,GACR,EAAM,GAGV,IAAK,IAAM,KAAQ,EAAU,cAAc,CAAI,EACzC,EAAK,OAAS,OAAQ,EAAO,OAAO,EAAK,KAAK,EACzC,EAAK,OAAS,MAAO,EAAoB,EAAK,QAAU,KACxD,EAAK,OAAS,QAAS,EAAQ,EAAK,MACpC,EAAK,OAAS,QAAO,EAAM,EAAK,OAG3C,IAAM,EAAU,EAAoB,EAAI,EAAO,EAC/C,GAAI,EAAU,GAAK,EAAU,KAAM,MAAU,WAAW,YAAY,EAAQ,MAAM,EAAS,sBAAsB,EACjH,MAAO,GAAG,OAAO,CAAO,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAAG,EAAM,GAAG,GACzD"}
|
package/dist/github.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.cjs","names":[],"sources":["../src/github.ts"],"sourcesContent":["/**\n * Parses a GitHub repository full name such as `WillBooster/shared`. Returns undefined unless the owner consists of\n * alphanumerics and hyphens and the repository name of alphanumerics, `-`, `_`, and `.` other than `.` and `..`.\n */\nexport function parseGitHubRepositoryFullName(fullName: string): { owner: string; repo: string } | undefined {\n const match = /^([\\dA-Za-z-]+)\\/([\\w.-]+)$/u.exec(fullName);\n if (!match) return undefined;\n const [, owner, repo] = match as unknown as [string, string, string];\n return repo === '.' || repo === '..' ? undefined : { owner, repo };\n}\n"],"mappings":"aAIA,SAAgB,EAA8B,EAA+D,CAC3G,IAAM,EAAQ,+BAA+B,KAAK,CAAQ,EAC1D,GAAI,CAAC,EAAO,OACZ,GAAM,EAAG,EAAO,GAAQ,EACxB,OAAO,IAAS,KAAO,IAAS,KAAO,IAAA,GAAY,CAAE,QAAO,MAAK,CACnE"}
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a GitHub repository full name such as `WillBooster/shared`. Returns undefined unless the owner consists of
|
|
3
|
+
* alphanumerics and hyphens and the repository name of alphanumerics, `-`, `_`, and `.` other than `.` and `..`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseGitHubRepositoryFullName(fullName: string): {
|
|
6
|
+
owner: string;
|
|
7
|
+
repo: string;
|
|
8
|
+
} | undefined;
|
package/dist/github.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","names":[],"sources":["../src/github.ts"],"sourcesContent":["/**\n * Parses a GitHub repository full name such as `WillBooster/shared`. Returns undefined unless the owner consists of\n * alphanumerics and hyphens and the repository name of alphanumerics, `-`, `_`, and `.` other than `.` and `..`.\n */\nexport function parseGitHubRepositoryFullName(fullName: string): { owner: string; repo: string } | undefined {\n const match = /^([\\dA-Za-z-]+)\\/([\\w.-]+)$/u.exec(fullName);\n if (!match) return undefined;\n const [, owner, repo] = match as unknown as [string, string, string];\n return repo === '.' || repo === '..' ? undefined : { owner, repo };\n}\n"],"mappings":"AAIA,SAAgB,EAA8B,EAA+D,CAC3G,IAAM,EAAQ,+BAA+B,KAAK,CAAQ,EAC1D,GAAI,CAAC,EAAO,OACZ,GAAM,EAAG,EAAO,GAAQ,EACxB,OAAO,IAAS,KAAO,IAAS,KAAO,IAAA,GAAY,CAAE,QAAO,MAAK,CACnE"}
|
package/dist/http.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";function e(e){if(!e)return;let t=/^(\S+) +([\w+./~-]+=*) *$/u.exec(e);return t?.[1]?.toLowerCase()===`bearer`?t[2]:void 0}function t(e,t){let n=e.get(t);return typeof n==`string`?n:void 0}exports.getFormString=t,exports.parseBearerToken=e;
|
|
2
|
+
//# sourceMappingURL=http.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.cjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * Extracts the token from an `Authorization` header value of the Bearer scheme (RFC 6750), whose scheme name is\n * case-insensitive. Returns undefined for a missing header, another scheme, or a malformed value.\n */\nexport function parseBearerToken(authorization: string | null | undefined): string | undefined {\n if (!authorization) return undefined;\n // The scheme is compared after lowercasing instead of with the `i` flag, which together with `u` would let the token\n // class match non-ASCII case variants such as U+212A KELVIN SIGN for `k`.\n const match = /^(\\S+) +([\\w+./~-]+=*) *$/u.exec(authorization);\n return match?.[1]?.toLowerCase() === 'bearer' ? match[2] : undefined;\n}\n\n/** Returns a text field of `FormData`, or undefined when the field is missing or holds a file. */\nexport function getFormString(formData: FormData, name: string): string | undefined {\n const value = formData.get(name);\n return typeof value === 'string' ? value : undefined;\n}\n"],"mappings":"aAIA,SAAgB,EAAiB,EAA8D,CAC7F,GAAI,CAAC,EAAe,OAGpB,IAAM,EAAQ,6BAA6B,KAAK,CAAa,EAC7D,OAAO,IAAQ,EAAE,EAAE,YAAY,IAAM,SAAW,EAAM,GAAK,IAAA,EAC7D,CAGA,SAAgB,EAAc,EAAoB,EAAkC,CAClF,IAAM,EAAQ,EAAS,IAAI,CAAI,EAC/B,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,EAC7C"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the token from an `Authorization` header value of the Bearer scheme (RFC 6750), whose scheme name is
|
|
3
|
+
* case-insensitive. Returns undefined for a missing header, another scheme, or a malformed value.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseBearerToken(authorization: string | null | undefined): string | undefined;
|
|
6
|
+
/** Returns a text field of `FormData`, or undefined when the field is missing or holds a file. */
|
|
7
|
+
export declare function getFormString(formData: FormData, name: string): string | undefined;
|
package/dist/http.js
ADDED
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * Extracts the token from an `Authorization` header value of the Bearer scheme (RFC 6750), whose scheme name is\n * case-insensitive. Returns undefined for a missing header, another scheme, or a malformed value.\n */\nexport function parseBearerToken(authorization: string | null | undefined): string | undefined {\n if (!authorization) return undefined;\n // The scheme is compared after lowercasing instead of with the `i` flag, which together with `u` would let the token\n // class match non-ASCII case variants such as U+212A KELVIN SIGN for `k`.\n const match = /^(\\S+) +([\\w+./~-]+=*) *$/u.exec(authorization);\n return match?.[1]?.toLowerCase() === 'bearer' ? match[2] : undefined;\n}\n\n/** Returns a text field of `FormData`, or undefined when the field is missing or holds a file. */\nexport function getFormString(formData: FormData, name: string): string | undefined {\n const value = formData.get(name);\n return typeof value === 'string' ? value : undefined;\n}\n"],"mappings":"AAIA,SAAgB,EAAiB,EAA8D,CAC7F,GAAI,CAAC,EAAe,OAGpB,IAAM,EAAQ,6BAA6B,KAAK,CAAa,EAC7D,OAAO,IAAQ,EAAE,EAAE,YAAY,IAAM,SAAW,EAAM,GAAK,IAAA,EAC7D,CAGA,SAAgB,EAAc,EAAoB,EAAkC,CAClF,IAAM,EAAQ,EAAS,IAAI,CAAI,EAC/B,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,EAC7C"}
|
package/dist/humanize.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";function e(e,{base:t=1e3,units:n=[`K`,`M`,`B`,`T`,`P`]}={}){if(e<t)return e.toString();let r=-1;for(;e>=t&&r<n.length-1;)e/=t,r++;return e.toFixed(2)+(n[r]??``)}function t(e){let t=Math.round(e/100)/10;if(t<60)return`${t.toFixed(1)}秒`;let n=Math.round(e/1e3);return`${Math.floor(n/60)}分${n%60}秒`}exports.formatElapsedTimeInJapanese=t,exports.humanizeNumber=e;
|
|
1
|
+
"use strict";function e(e,{base:t=1e3,units:n=[`K`,`M`,`B`,`T`,`P`]}={}){if(e<t)return e.toString();let r=-1;for(;e>=t&&r<n.length-1;)e/=t,r++;return e.toFixed(2)+(n[r]??``)}function t(e){let t=Math.round(e/100)/10;if(t<60)return`${t.toFixed(1)}秒`;let n=Math.round(e/1e3);return`${Math.floor(n/60)}分${n%60}秒`}function n(e){let t=Math.round(e);if(t<1e3)return`${t}ms`;let n=Math.round(e/100)/10;if(n<60)return`${n.toFixed(1)}s`;let r=Math.round(e/1e3),i=Math.floor(r/3600),a=`${Math.floor(r/60)%60}m ${r%60}s`;return i>0?`${i}h ${a}`:a}exports.formatDuration=n,exports.formatElapsedTimeInJapanese=t,exports.humanizeNumber=e;
|
|
2
2
|
//# sourceMappingURL=humanize.cjs.map
|
package/dist/humanize.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"humanize.cjs","names":[],"sources":["../src/humanize.ts"],"sourcesContent":["export function humanizeNumber(value: number, { base = 1000, units = ['K', 'M', 'B', 'T', 'P'] } = {}): string {\n if (value < base) {\n return value.toString();\n }\n\n let unitIndex = -1;\n while (value >= base && unitIndex < units.length - 1) {\n value /= base;\n unitIndex++;\n }\n\n return value.toFixed(2) + (units[unitIndex] ?? '');\n}\n\n/**\n * Formats a duration in Japanese: to a tenth of a second under a minute (`59.9秒`), otherwise in whole minutes and\n * seconds (`1分0秒`).\n */\nexport function formatElapsedTimeInJapanese(milliseconds: number): string {\n // Round to the displayed precision before choosing the format, or 59.98s would be shown as `60.0秒`.\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}秒`;\n\n // Round before splitting into minutes and seconds, or 119.8s would be shown as `1分60秒`.\n const roundedSeconds = Math.round(milliseconds / 1000);\n return `${Math.floor(roundedSeconds / 60)}分${roundedSeconds % 60}秒`;\n}\n"],"mappings":"aAAA,SAAgB,EAAe,EAAe,CAAE,OAAO,IAAM,QAAQ,CAAC,IAAK,IAAK,IAAK,IAAK,GAAG,GAAM,CAAC,EAAW,CAC7G,GAAI,EAAQ,EACV,OAAO,EAAM,SAAS,EAGxB,IAAI,EAAY,GAChB,KAAO,GAAS,GAAQ,EAAY,EAAM,OAAS,GACjD,GAAS,EACT,IAGF,OAAO,EAAM,QAAQ,CAAC,GAAK,EAAM,IAAc,GACjD,CAMA,SAAgB,EAA4B,EAA8B,CAExE,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAG3D,IAAM,EAAiB,KAAK,MAAM,EAAe,GAAI,EACrD,MAAO,GAAG,KAAK,MAAM,EAAiB,EAAE,EAAE,GAAG,EAAiB,GAAG,EACnE"}
|
|
1
|
+
{"version":3,"file":"humanize.cjs","names":[],"sources":["../src/humanize.ts"],"sourcesContent":["export function humanizeNumber(value: number, { base = 1000, units = ['K', 'M', 'B', 'T', 'P'] } = {}): string {\n if (value < base) {\n return value.toString();\n }\n\n let unitIndex = -1;\n while (value >= base && unitIndex < units.length - 1) {\n value /= base;\n unitIndex++;\n }\n\n return value.toFixed(2) + (units[unitIndex] ?? '');\n}\n\n/**\n * Formats a duration in Japanese: to a tenth of a second under a minute (`59.9秒`), otherwise in whole minutes and\n * seconds (`1分0秒`).\n */\nexport function formatElapsedTimeInJapanese(milliseconds: number): string {\n // Round to the displayed precision before choosing the format, or 59.98s would be shown as `60.0秒`.\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}秒`;\n\n // Round before splitting into minutes and seconds, or 119.8s would be shown as `1分60秒`.\n const roundedSeconds = Math.round(milliseconds / 1000);\n return `${Math.floor(roundedSeconds / 60)}分${roundedSeconds % 60}秒`;\n}\n\n/**\n * Formats a duration compactly in English: whole milliseconds under a second (`850ms`), a tenth of a second under a\n * minute (`12.3s`), and whole seconds above (`1m 5s`, `2h 0m 7s`).\n */\nexport function formatDuration(milliseconds: number): string {\n // Each branch rounds to its displayed precision before choosing the format, e.g. 59.96s is shown as `1m 0s`.\n const roundedMilliseconds = Math.round(milliseconds);\n if (roundedMilliseconds < 1000) return `${roundedMilliseconds}ms`;\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}s`;\n const totalSeconds = Math.round(milliseconds / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutesAndSeconds = `${Math.floor(totalSeconds / 60) % 60}m ${totalSeconds % 60}s`;\n return hours > 0 ? `${hours}h ${minutesAndSeconds}` : minutesAndSeconds;\n}\n"],"mappings":"aAAA,SAAgB,EAAe,EAAe,CAAE,OAAO,IAAM,QAAQ,CAAC,IAAK,IAAK,IAAK,IAAK,GAAG,GAAM,CAAC,EAAW,CAC7G,GAAI,EAAQ,EACV,OAAO,EAAM,SAAS,EAGxB,IAAI,EAAY,GAChB,KAAO,GAAS,GAAQ,EAAY,EAAM,OAAS,GACjD,GAAS,EACT,IAGF,OAAO,EAAM,QAAQ,CAAC,GAAK,EAAM,IAAc,GACjD,CAMA,SAAgB,EAA4B,EAA8B,CAExE,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAG3D,IAAM,EAAiB,KAAK,MAAM,EAAe,GAAI,EACrD,MAAO,GAAG,KAAK,MAAM,EAAiB,EAAE,EAAE,GAAG,EAAiB,GAAG,EACnE,CAMA,SAAgB,EAAe,EAA8B,CAE3D,IAAM,EAAsB,KAAK,MAAM,CAAY,EACnD,GAAI,EAAsB,IAAM,MAAO,GAAG,EAAoB,IAC9D,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAC3D,IAAM,EAAe,KAAK,MAAM,EAAe,GAAI,EAC7C,EAAQ,KAAK,MAAM,EAAe,IAAI,EACtC,EAAoB,GAAG,KAAK,MAAM,EAAe,EAAE,EAAI,GAAG,IAAI,EAAe,GAAG,GACtF,OAAO,EAAQ,EAAI,GAAG,EAAM,IAAI,IAAsB,CACxD"}
|
package/dist/humanize.d.ts
CHANGED
|
@@ -7,3 +7,8 @@ export declare function humanizeNumber(value: number, { base, units }?: {
|
|
|
7
7
|
* seconds (`1分0秒`).
|
|
8
8
|
*/
|
|
9
9
|
export declare function formatElapsedTimeInJapanese(milliseconds: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Formats a duration compactly in English: whole milliseconds under a second (`850ms`), a tenth of a second under a
|
|
12
|
+
* minute (`12.3s`), and whole seconds above (`1m 5s`, `2h 0m 7s`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatDuration(milliseconds: number): string;
|
package/dist/humanize.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e,{base:t=1e3,units:n=[`K`,`M`,`B`,`T`,`P`]}={}){if(e<t)return e.toString();let r=-1;for(;e>=t&&r<n.length-1;)e/=t,r++;return e.toFixed(2)+(n[r]??``)}function t(e){let t=Math.round(e/100)/10;if(t<60)return`${t.toFixed(1)}秒`;let n=Math.round(e/1e3);return`${Math.floor(n/60)}分${n%60}秒`}export{t as formatElapsedTimeInJapanese,e as humanizeNumber};
|
|
1
|
+
function e(e,{base:t=1e3,units:n=[`K`,`M`,`B`,`T`,`P`]}={}){if(e<t)return e.toString();let r=-1;for(;e>=t&&r<n.length-1;)e/=t,r++;return e.toFixed(2)+(n[r]??``)}function t(e){let t=Math.round(e/100)/10;if(t<60)return`${t.toFixed(1)}秒`;let n=Math.round(e/1e3);return`${Math.floor(n/60)}分${n%60}秒`}function n(e){let t=Math.round(e);if(t<1e3)return`${t}ms`;let n=Math.round(e/100)/10;if(n<60)return`${n.toFixed(1)}s`;let r=Math.round(e/1e3),i=Math.floor(r/3600),a=`${Math.floor(r/60)%60}m ${r%60}s`;return i>0?`${i}h ${a}`:a}export{n as formatDuration,t as formatElapsedTimeInJapanese,e as humanizeNumber};
|
|
2
2
|
//# sourceMappingURL=humanize.js.map
|
package/dist/humanize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"humanize.js","names":[],"sources":["../src/humanize.ts"],"sourcesContent":["export function humanizeNumber(value: number, { base = 1000, units = ['K', 'M', 'B', 'T', 'P'] } = {}): string {\n if (value < base) {\n return value.toString();\n }\n\n let unitIndex = -1;\n while (value >= base && unitIndex < units.length - 1) {\n value /= base;\n unitIndex++;\n }\n\n return value.toFixed(2) + (units[unitIndex] ?? '');\n}\n\n/**\n * Formats a duration in Japanese: to a tenth of a second under a minute (`59.9秒`), otherwise in whole minutes and\n * seconds (`1分0秒`).\n */\nexport function formatElapsedTimeInJapanese(milliseconds: number): string {\n // Round to the displayed precision before choosing the format, or 59.98s would be shown as `60.0秒`.\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}秒`;\n\n // Round before splitting into minutes and seconds, or 119.8s would be shown as `1分60秒`.\n const roundedSeconds = Math.round(milliseconds / 1000);\n return `${Math.floor(roundedSeconds / 60)}分${roundedSeconds % 60}秒`;\n}\n"],"mappings":"AAAA,SAAgB,EAAe,EAAe,CAAE,OAAO,IAAM,QAAQ,CAAC,IAAK,IAAK,IAAK,IAAK,GAAG,GAAM,CAAC,EAAW,CAC7G,GAAI,EAAQ,EACV,OAAO,EAAM,SAAS,EAGxB,IAAI,EAAY,GAChB,KAAO,GAAS,GAAQ,EAAY,EAAM,OAAS,GACjD,GAAS,EACT,IAGF,OAAO,EAAM,QAAQ,CAAC,GAAK,EAAM,IAAc,GACjD,CAMA,SAAgB,EAA4B,EAA8B,CAExE,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAG3D,IAAM,EAAiB,KAAK,MAAM,EAAe,GAAI,EACrD,MAAO,GAAG,KAAK,MAAM,EAAiB,EAAE,EAAE,GAAG,EAAiB,GAAG,EACnE"}
|
|
1
|
+
{"version":3,"file":"humanize.js","names":[],"sources":["../src/humanize.ts"],"sourcesContent":["export function humanizeNumber(value: number, { base = 1000, units = ['K', 'M', 'B', 'T', 'P'] } = {}): string {\n if (value < base) {\n return value.toString();\n }\n\n let unitIndex = -1;\n while (value >= base && unitIndex < units.length - 1) {\n value /= base;\n unitIndex++;\n }\n\n return value.toFixed(2) + (units[unitIndex] ?? '');\n}\n\n/**\n * Formats a duration in Japanese: to a tenth of a second under a minute (`59.9秒`), otherwise in whole minutes and\n * seconds (`1分0秒`).\n */\nexport function formatElapsedTimeInJapanese(milliseconds: number): string {\n // Round to the displayed precision before choosing the format, or 59.98s would be shown as `60.0秒`.\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}秒`;\n\n // Round before splitting into minutes and seconds, or 119.8s would be shown as `1分60秒`.\n const roundedSeconds = Math.round(milliseconds / 1000);\n return `${Math.floor(roundedSeconds / 60)}分${roundedSeconds % 60}秒`;\n}\n\n/**\n * Formats a duration compactly in English: whole milliseconds under a second (`850ms`), a tenth of a second under a\n * minute (`12.3s`), and whole seconds above (`1m 5s`, `2h 0m 7s`).\n */\nexport function formatDuration(milliseconds: number): string {\n // Each branch rounds to its displayed precision before choosing the format, e.g. 59.96s is shown as `1m 0s`.\n const roundedMilliseconds = Math.round(milliseconds);\n if (roundedMilliseconds < 1000) return `${roundedMilliseconds}ms`;\n const roundedTenths = Math.round(milliseconds / 100) / 10;\n if (roundedTenths < 60) return `${roundedTenths.toFixed(1)}s`;\n const totalSeconds = Math.round(milliseconds / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutesAndSeconds = `${Math.floor(totalSeconds / 60) % 60}m ${totalSeconds % 60}s`;\n return hours > 0 ? `${hours}h ${minutesAndSeconds}` : minutesAndSeconds;\n}\n"],"mappings":"AAAA,SAAgB,EAAe,EAAe,CAAE,OAAO,IAAM,QAAQ,CAAC,IAAK,IAAK,IAAK,IAAK,GAAG,GAAM,CAAC,EAAW,CAC7G,GAAI,EAAQ,EACV,OAAO,EAAM,SAAS,EAGxB,IAAI,EAAY,GAChB,KAAO,GAAS,GAAQ,EAAY,EAAM,OAAS,GACjD,GAAS,EACT,IAGF,OAAO,EAAM,QAAQ,CAAC,GAAK,EAAM,IAAc,GACjD,CAMA,SAAgB,EAA4B,EAA8B,CAExE,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAG3D,IAAM,EAAiB,KAAK,MAAM,EAAe,GAAI,EACrD,MAAO,GAAG,KAAK,MAAM,EAAiB,EAAE,EAAE,GAAG,EAAiB,GAAG,EACnE,CAMA,SAAgB,EAAe,EAA8B,CAE3D,IAAM,EAAsB,KAAK,MAAM,CAAY,EACnD,GAAI,EAAsB,IAAM,MAAO,GAAG,EAAoB,IAC9D,IAAM,EAAgB,KAAK,MAAM,EAAe,GAAG,EAAI,GACvD,GAAI,EAAgB,GAAI,MAAO,GAAG,EAAc,QAAQ,CAAC,EAAE,GAC3D,IAAM,EAAe,KAAK,MAAM,EAAe,GAAI,EAC7C,EAAQ,KAAK,MAAM,EAAe,IAAI,EACtC,EAAoB,GAAG,KAAK,MAAM,EAAe,EAAE,EAAI,GAAG,IAAI,EAAe,GAAG,GACtF,OAAO,EAAQ,EAAI,GAAG,EAAM,IAAI,IAAsB,CACxD"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./appEnv.cjs"),t=require("./
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./appEnv.cjs"),t=require("./array.cjs"),n=require("./assert.cjs"),r=require("./concurrency.cjs"),i=require("./crypto.cjs"),a=require("./githubTemplates.cjs"),o=require("./sleep.cjs"),s=require("./error.cjs"),c=require("./filePath.cjs"),l=require("./formatIsoDate.cjs"),u=require("./github.cjs"),d=require("./http.cjs"),f=require("./foreignCjk.cjs"),p=require("./humanize.cjs"),m=require("./mail.cjs"),h=require("./object.cjs"),g=require("./markdown.cjs"),_=require("./parseIsoDate.cjs"),v=require("./parseCommandLineArgs.cjs"),y=require("./number.cjs"),b=require("./text.cjs"),x=require("./prompt.cjs"),S=require("./promptFormatters.cjs"),C=require("./shuffle.cjs"),w=require("./recoverJson.cjs"),T=require("./sqlite.cjs"),E=require("./testingRules.cjs"),D=require("./throttledFetch.cjs"),O=require("./timeout.cjs"),k=require("./url.cjs"),A=require("./yaml.cjs"),j=require("./zenkaku.cjs");exports.BUG_ISSUE_SECTIONS=a.BUG_ISSUE_SECTIONS,exports.CHANGE_ISSUE_SECTIONS=a.CHANGE_ISSUE_SECTIONS,exports.ISSUE_TEMPLATE_RULES=a.ISSUE_TEMPLATE_RULES,exports.PULL_REQUEST_BODY_RULES=a.PULL_REQUEST_BODY_RULES,exports.PULL_REQUEST_REQUIREMENTS_RULES=a.PULL_REQUEST_REQUIREMENTS_RULES,exports.PULL_REQUEST_SECTIONS=a.PULL_REQUEST_SECTIONS,exports.TEST_WRITING_RULES=E.TEST_WRITING_RULES,exports.chunk=t.chunk,exports.clamp=y.clamp,exports.createThrottledFetch=D.createThrottledFetch,exports.detectForeignCjkInJapanese=f.detectForeignCjkInJapanese,exports.ensureTruthy=n.ensureTruthy,exports.errorify=s.errorify,exports.escapeHtml=b.escapeHtml,exports.escapeLikePattern=T.escapeLikePattern,exports.escapePromptTag=x.escapePromptTag,exports.escapeRegExp=b.escapeRegExp,exports.extractCodeBlocks=g.extractCodeBlocks,exports.extractIfSingleOutermostCodeBlock=g.extractIfSingleOutermostCodeBlock,exports.extractSections=g.extractSections,exports.extractTaggedCodeBlock=g.extractTaggedCodeBlock,exports.findForeignCjkCharactersInJapanese=f.findForeignCjkCharactersInJapanese,exports.forEachConcurrently=r.forEachConcurrently,exports.formatDuration=p.formatDuration,exports.formatElapsedTimeInJapanese=p.formatElapsedTimeInJapanese,exports.formatFilesForPrompt=S.formatFilesForPrompt,exports.formatIsoDateInTimeZone=l.formatIsoDateInTimeZone,exports.formatMessagesForPrompt=S.formatMessagesForPrompt,exports.formatPrompt=x.formatPrompt,exports.getAppEnv=e.getAppEnv,exports.getConnectionLevelSqlitePragmas=T.getConnectionLevelSqlitePragmas,exports.getErrorMessage=s.getErrorMessage,exports.getFileExtension=c.getFileExtension,exports.getFormString=d.getFormString,exports.getPersistentSqlitePragmas=T.getPersistentSqlitePragmas,exports.getSafeRedirectPath=k.getSafeRedirectPath,exports.hasErrorCode=s.hasErrorCode,exports.humanizeNumber=p.humanizeNumber,exports.ignoreEnoent=s.ignoreEnoent,exports.ignoreEnoentAsync=s.ignoreEnoentAsync,exports.ignoreError=s.ignoreError,exports.ignoreErrorAsync=s.ignoreErrorAsync,exports.isRecord=h.isRecord,exports.mailTemplates=m.mailTemplates,exports.mapConcurrently=r.mapConcurrently,exports.omitUndefined=h.omitUndefined,exports.parseBearerToken=d.parseBearerToken,exports.parseCommandLineArgs=v.parseCommandLineArgs,exports.parseGitHubRepositoryFullName=u.parseGitHubRepositoryFullName,exports.parseIsoDate=_.parseIsoDate,exports.parseMarkdownSections=g.parseMarkdownSections,exports.parsePositiveInteger=y.parsePositiveInteger,exports.quoteForShell=b.quoteForShell,exports.raceWithTimeout=O.raceWithTimeout,exports.recoverJson=w.recoverJson,exports.renderSectionChecklist=a.renderSectionChecklist,exports.renderSectionTemplate=a.renderSectionTemplate,exports.serializeForPrompt=x.serializeForPrompt,exports.serializeForPromptInTag=x.serializeForPromptInTag,exports.sha256HexAsync=i.sha256HexAsync,exports.shuffle=C.shuffle,exports.shuffleWithSeed=C.shuffleWithSeed,exports.sleep=o.sleep,exports.timingSafeEqualStringAsync=i.timingSafeEqualStringAsync,exports.toCodeBlock=b.toCodeBlock,exports.toTildeCodeBlock=b.toTildeCodeBlock,exports.truncate=b.truncate,exports.truncateForPrompt=x.truncateForPrompt,exports.withRetry=s.withRetry,exports.yamlStringifyOptions=A.yamlStringifyOptions,exports.zenkakuAlphanumericalsToHankaku=j.zenkakuAlphanumericalsToHankaku;
|