@dev-pi2pie/word-counter 0.1.4 → 0.1.5-canary.2
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/README.md +75 -0
- package/dist/cjs/detector.cjs +427 -0
- package/dist/cjs/detector.cjs.map +1 -0
- package/dist/cjs/index.cjs +10 -1257
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/markdown.cjs +1318 -0
- package/dist/cjs/markdown.cjs.map +1 -0
- package/dist/esm/bin.mjs +966 -298
- package/dist/esm/bin.mjs.map +1 -1
- package/dist/esm/detector.d.mts +37 -0
- package/dist/esm/detector.mjs +412 -0
- package/dist/esm/detector.mjs.map +1 -0
- package/dist/esm/index.d.mts +1 -1
- package/dist/esm/index.mjs +2 -1248
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index2.d.mts +2 -0
- package/dist/esm/markdown.mjs +1229 -0
- package/dist/esm/markdown.mjs.map +1 -0
- package/dist/esm/worker/count-worker.mjs +412 -47
- package/dist/esm/worker/count-worker.mjs.map +1 -1
- package/dist/esm/worker-pool.mjs +6 -3
- package/dist/esm/worker-pool.mjs.map +1 -1
- package/dist/wasm-language-detector/LICENSE +21 -0
- package/dist/wasm-language-detector/language_detector.d.ts +4 -0
- package/dist/wasm-language-detector/language_detector.js +132 -0
- package/dist/wasm-language-detector/language_detector_bg.wasm +0 -0
- package/dist/wasm-language-detector/language_detector_bg.wasm.d.ts +8 -0
- package/dist/wasm-language-detector/package.json +17 -0
- package/package.json +18 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-pool.mjs","names":[],"sources":["../../src/cli/batch/jobs/worker-pool.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport type { SectionMode } from \"../../../markdown\";\nimport type wordCounter from \"../../../wc\";\nimport type { BatchProgressSnapshot } from \"../../progress/reporter\";\nimport type { BatchFileResult, BatchSkip } from \"../../types\";\nimport type {\n WorkerRequestMessage,\n WorkerResponseMessage,\n WorkerTaskMessage,\n} from \"./worker/protocol\";\n\ntype CountBatchInputsWithWorkerPoolOptions = {\n filePaths: string[];\n jobs: number;\n section: SectionMode;\n wcOptions: Parameters<typeof wordCounter>[1];\n preserveCollectorSegments: boolean;\n onFileProcessed?: (snapshot: BatchProgressSnapshot) => void;\n};\n\nexport class WorkerPoolUnavailableError extends Error {}\nexport class WorkerPoolTaskFatalError extends Error {\n path: string;\n code?: string;\n\n constructor(path: string, code: string | undefined, message: string) {\n super(message);\n this.path = path;\n this.code = code;\n }\n}\n\ntype CompletedEntry =\n | {\n kind: \"file\";\n file: BatchFileResult;\n }\n | {\n kind: \"skip\";\n skip: BatchSkip;\n };\n\ntype PendingTask = {\n index: number;\n path: string;\n workerIndex: number;\n};\n\nfunction resolveWorkerEntryUrl(): URL | null {\n const candidates = [\n new URL(\"./worker/count-worker.mjs\", import.meta.url),\n new URL(\"./worker/count-worker.js\", import.meta.url),\n new URL(\"./worker/count-worker.ts\", import.meta.url),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(fileURLToPath(candidate))) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction isWorkerResponseMessage(value: unknown): value is WorkerResponseMessage {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n if (!(\"type\" in value)) {\n return false;\n }\n\n const type = (value as { type?: unknown }).type;\n return type === \"result\" || type === \"fatal\";\n}\n\nexport async function countBatchInputsWithWorkerPool(\n options: CountBatchInputsWithWorkerPoolOptions,\n): Promise<{ files: BatchFileResult[]; skipped: BatchSkip[] }> {\n if (options.filePaths.length === 0) {\n return { files: [], skipped: [] };\n }\n\n const workerEntryUrl = resolveWorkerEntryUrl();\n if (!workerEntryUrl) {\n throw new WorkerPoolUnavailableError(\n \"Worker pool unavailable: count-worker entry file was not found.\",\n );\n }\n\n const safeRequestedJobs = Number.isFinite(options.jobs) ? Math.floor(options.jobs) : 1;\n const workerCount = Math.max(1, Math.min(options.filePaths.length, safeRequestedJobs));\n const workers: Worker[] = [];\n const completedEntries: Array<CompletedEntry | undefined> = new Array(options.filePaths.length);\n const pendingTasks = new Map<number, PendingTask>();\n const requestedShutdownWorkers = new Set<number>();\n let nextIndex = 0;\n let nextTaskId = 1;\n let completed = 0;\n let settled = false;\n\n const teardownWorkers = async (): Promise<void> => {\n await Promise.allSettled(workers.map((worker) => worker.terminate()));\n };\n\n return new Promise((resolve, reject) => {\n const fail = async (error: Error): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n await teardownWorkers();\n reject(error);\n };\n\n const complete = async (): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n await teardownWorkers();\n\n const files: BatchFileResult[] = [];\n const skipped: BatchSkip[] = [];\n for (const entry of completedEntries) {\n if (!entry) {\n reject(new Error(\"Worker pool finalize failed: missing completed entry.\"));\n return;\n }\n if (entry.kind === \"file\") {\n files.push(entry.file);\n continue;\n }\n skipped.push(entry.skip);\n }\n\n resolve({ files, skipped });\n };\n\n const assignNextTask = (worker: Worker, workerIndex: number): void => {\n if (settled) {\n return;\n }\n\n if (nextIndex >= options.filePaths.length) {\n requestedShutdownWorkers.add(workerIndex);\n const shutdown: WorkerRequestMessage = { type: \"shutdown\" };\n worker.postMessage(shutdown);\n return;\n }\n\n const index = nextIndex;\n nextIndex += 1;\n const path = options.filePaths[index];\n if (!path) {\n void fail(new Error(`Worker pool dispatch failed: missing path at index ${index}.`));\n return;\n }\n\n const taskId = nextTaskId;\n nextTaskId += 1;\n pendingTasks.set(taskId, { index, path, workerIndex });\n\n const message: WorkerTaskMessage = {\n type: \"task\",\n taskId,\n index,\n path,\n };\n worker.postMessage(message);\n };\n\n for (let workerIndex = 0; workerIndex < workerCount; workerIndex += 1) {\n let worker: Worker;\n try {\n worker = new Worker(workerEntryUrl, {\n workerData: {\n section: options.section,\n wcOptions: options.wcOptions,\n preserveCollectorSegments: options.preserveCollectorSegments,\n },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n void fail(new WorkerPoolUnavailableError(`Worker pool initialization failed: ${message}`));\n return;\n }\n\n workers.push(worker);\n\n worker.on(\"message\", (value: unknown) => {\n if (!isWorkerResponseMessage(value)) {\n void fail(new Error(\"Worker protocol mismatch: received unknown response payload.\"));\n return;\n }\n\n const pending = pendingTasks.get(value.taskId);\n if (!pending) {\n void fail(new Error(`Worker protocol mismatch: unknown task id ${value.taskId}.`));\n return;\n }\n\n pendingTasks.delete(value.taskId);\n if (value.index !== pending.index) {\n void fail(\n new Error(\n `Worker protocol mismatch: task index mismatch for ${value.taskId} (expected ${pending.index}, got ${value.index}).`,\n ),\n );\n return;\n }\n\n if (value.type === \"fatal\") {\n void fail(\n new WorkerPoolTaskFatalError(\n value.path,\n value.code,\n `Worker task failed for ${value.path} (${value.code ?? \"UNKNOWN\"}): ${value.message}`,\n ),\n );\n return;\n }\n\n if (value.payload.kind === \"file\") {\n completedEntries[pending.index] = {\n kind: \"file\",\n file: value.payload.file,\n };\n } else {\n completedEntries[pending.index] = {\n kind: \"skip\",\n skip: value.payload.skip,\n };\n }\n\n completed += 1;\n options.onFileProcessed?.({\n completed,\n total: options.filePaths.length,\n });\n\n if (completed >= options.filePaths.length) {\n void complete();\n return;\n }\n\n assignNextTask(worker, workerIndex);\n });\n\n worker.on(\"error\", (error) => {\n const message = error instanceof Error ? error.message : String(error);\n void fail(new Error(`Worker runtime failed: ${message}`));\n });\n\n worker.on(\"exit\", (code) => {\n if (settled) {\n return;\n }\n\n const hasPendingTask = [...pendingTasks.values()].some(\n (task) => task.workerIndex === workerIndex,\n );\n const requestedShutdown = requestedShutdownWorkers.has(workerIndex);\n\n if (hasPendingTask) {\n void fail(new Error(`Worker exited before completing assigned tasks (code ${code}).`));\n return;\n }\n\n if (code !== 0) {\n void fail(new Error(`Worker exited unexpectedly with code ${code}.`));\n return;\n }\n\n if (!requestedShutdown && completed < options.filePaths.length) {\n void fail(new Error(\"Worker exited unexpectedly before completion.\"));\n }\n });\n\n assignNextTask(worker, workerIndex);\n }\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"worker-pool.mjs","names":[],"sources":["../../src/cli/batch/jobs/worker-pool.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport type { SectionMode } from \"../../../markdown\";\nimport type { DetectorMode } from \"../../../detector\";\nimport type wordCounter from \"../../../wc\";\nimport type { BatchProgressSnapshot } from \"../../progress/reporter\";\nimport type { BatchFileResult, BatchSkip } from \"../../types\";\nimport type {\n WorkerRequestMessage,\n WorkerResponseMessage,\n WorkerTaskMessage,\n} from \"./worker/protocol\";\n\ntype CountBatchInputsWithWorkerPoolOptions = {\n filePaths: string[];\n jobs: number;\n section: SectionMode;\n detectorMode: DetectorMode;\n wcOptions: Parameters<typeof wordCounter>[1];\n preserveCollectorSegments: boolean;\n onFileProcessed?: (snapshot: BatchProgressSnapshot) => void;\n};\n\nexport class WorkerPoolUnavailableError extends Error {}\nexport class WorkerPoolTaskFatalError extends Error {\n path: string;\n code?: string;\n\n constructor(path: string, code: string | undefined, message: string) {\n super(message);\n this.path = path;\n this.code = code;\n }\n}\n\ntype CompletedEntry =\n | {\n kind: \"file\";\n file: BatchFileResult;\n }\n | {\n kind: \"skip\";\n skip: BatchSkip;\n };\n\ntype PendingTask = {\n index: number;\n path: string;\n workerIndex: number;\n};\n\nexport function resolveWorkerEntryUrl(): URL | null {\n const candidates = [\n new URL(\"./worker/count-worker.mjs\", import.meta.url),\n new URL(\"./worker/count-worker.js\", import.meta.url),\n new URL(\"./worker/count-worker.ts\", import.meta.url),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(fileURLToPath(candidate))) {\n return candidate;\n }\n }\n\n return null;\n}\n\nexport function isWorkerThreadsAvailable(): boolean {\n return typeof Worker === \"function\";\n}\n\nfunction isWorkerResponseMessage(value: unknown): value is WorkerResponseMessage {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n if (!(\"type\" in value)) {\n return false;\n }\n\n const type = (value as { type?: unknown }).type;\n return type === \"result\" || type === \"fatal\";\n}\n\nexport async function countBatchInputsWithWorkerPool(\n options: CountBatchInputsWithWorkerPoolOptions,\n): Promise<{ files: BatchFileResult[]; skipped: BatchSkip[] }> {\n if (options.filePaths.length === 0) {\n return { files: [], skipped: [] };\n }\n\n const workerEntryUrl = resolveWorkerEntryUrl();\n if (!workerEntryUrl) {\n throw new WorkerPoolUnavailableError(\n \"Worker pool unavailable: count-worker entry file was not found.\",\n );\n }\n\n const safeRequestedJobs = Number.isFinite(options.jobs) ? Math.floor(options.jobs) : 1;\n const workerCount = Math.max(1, Math.min(options.filePaths.length, safeRequestedJobs));\n const workers: Worker[] = [];\n const completedEntries: Array<CompletedEntry | undefined> = new Array(options.filePaths.length);\n const pendingTasks = new Map<number, PendingTask>();\n const requestedShutdownWorkers = new Set<number>();\n let nextIndex = 0;\n let nextTaskId = 1;\n let completed = 0;\n let settled = false;\n\n const teardownWorkers = async (): Promise<void> => {\n await Promise.allSettled(workers.map((worker) => worker.terminate()));\n };\n\n return new Promise((resolve, reject) => {\n const fail = async (error: Error): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n await teardownWorkers();\n reject(error);\n };\n\n const complete = async (): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n await teardownWorkers();\n\n const files: BatchFileResult[] = [];\n const skipped: BatchSkip[] = [];\n for (const entry of completedEntries) {\n if (!entry) {\n reject(new Error(\"Worker pool finalize failed: missing completed entry.\"));\n return;\n }\n if (entry.kind === \"file\") {\n files.push(entry.file);\n continue;\n }\n skipped.push(entry.skip);\n }\n\n resolve({ files, skipped });\n };\n\n const assignNextTask = (worker: Worker, workerIndex: number): void => {\n if (settled) {\n return;\n }\n\n if (nextIndex >= options.filePaths.length) {\n requestedShutdownWorkers.add(workerIndex);\n const shutdown: WorkerRequestMessage = { type: \"shutdown\" };\n worker.postMessage(shutdown);\n return;\n }\n\n const index = nextIndex;\n nextIndex += 1;\n const path = options.filePaths[index];\n if (!path) {\n void fail(new Error(`Worker pool dispatch failed: missing path at index ${index}.`));\n return;\n }\n\n const taskId = nextTaskId;\n nextTaskId += 1;\n pendingTasks.set(taskId, { index, path, workerIndex });\n\n const message: WorkerTaskMessage = {\n type: \"task\",\n taskId,\n index,\n path,\n };\n worker.postMessage(message);\n };\n\n for (let workerIndex = 0; workerIndex < workerCount; workerIndex += 1) {\n let worker: Worker;\n try {\n worker = new Worker(workerEntryUrl, {\n workerData: {\n section: options.section,\n detectorMode: options.detectorMode,\n wcOptions: options.wcOptions,\n preserveCollectorSegments: options.preserveCollectorSegments,\n },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n void fail(new WorkerPoolUnavailableError(`Worker pool initialization failed: ${message}`));\n return;\n }\n\n workers.push(worker);\n\n worker.on(\"message\", (value: unknown) => {\n if (!isWorkerResponseMessage(value)) {\n void fail(new Error(\"Worker protocol mismatch: received unknown response payload.\"));\n return;\n }\n\n const pending = pendingTasks.get(value.taskId);\n if (!pending) {\n void fail(new Error(`Worker protocol mismatch: unknown task id ${value.taskId}.`));\n return;\n }\n\n pendingTasks.delete(value.taskId);\n if (value.index !== pending.index) {\n void fail(\n new Error(\n `Worker protocol mismatch: task index mismatch for ${value.taskId} (expected ${pending.index}, got ${value.index}).`,\n ),\n );\n return;\n }\n\n if (value.type === \"fatal\") {\n void fail(\n new WorkerPoolTaskFatalError(\n value.path,\n value.code,\n `Worker task failed for ${value.path} (${value.code ?? \"UNKNOWN\"}): ${value.message}`,\n ),\n );\n return;\n }\n\n if (value.payload.kind === \"file\") {\n completedEntries[pending.index] = {\n kind: \"file\",\n file: value.payload.file,\n };\n } else {\n completedEntries[pending.index] = {\n kind: \"skip\",\n skip: value.payload.skip,\n };\n }\n\n completed += 1;\n options.onFileProcessed?.({\n completed,\n total: options.filePaths.length,\n });\n\n if (completed >= options.filePaths.length) {\n void complete();\n return;\n }\n\n assignNextTask(worker, workerIndex);\n });\n\n worker.on(\"error\", (error) => {\n const message = error instanceof Error ? error.message : String(error);\n void fail(new Error(`Worker runtime failed: ${message}`));\n });\n\n worker.on(\"exit\", (code) => {\n if (settled) {\n return;\n }\n\n const hasPendingTask = [...pendingTasks.values()].some(\n (task) => task.workerIndex === workerIndex,\n );\n const requestedShutdown = requestedShutdownWorkers.has(workerIndex);\n\n if (hasPendingTask) {\n void fail(new Error(`Worker exited before completing assigned tasks (code ${code}).`));\n return;\n }\n\n if (code !== 0) {\n void fail(new Error(`Worker exited unexpectedly with code ${code}.`));\n return;\n }\n\n if (!requestedShutdown && completed < options.filePaths.length) {\n void fail(new Error(\"Worker exited unexpectedly before completion.\"));\n }\n });\n\n assignNextTask(worker, workerIndex);\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dev-pi2pie
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* @ts-self-types="./language_detector.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} text
|
|
5
|
+
* @param {string} _route_tag
|
|
6
|
+
* @returns {any}
|
|
7
|
+
*/
|
|
8
|
+
function detect_language(text, _route_tag) {
|
|
9
|
+
const ptr0 = passStringToWasm0(text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
10
|
+
const len0 = WASM_VECTOR_LEN;
|
|
11
|
+
const ptr1 = passStringToWasm0(_route_tag, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
12
|
+
const len1 = WASM_VECTOR_LEN;
|
|
13
|
+
const ret = wasm.detect_language(ptr0, len0, ptr1, len1);
|
|
14
|
+
return ret;
|
|
15
|
+
}
|
|
16
|
+
exports.detect_language = detect_language;
|
|
17
|
+
|
|
18
|
+
function __wbg_get_imports() {
|
|
19
|
+
const import0 = {
|
|
20
|
+
__proto__: null,
|
|
21
|
+
__wbg___wbindgen_throw_6ddd609b62940d55: function(arg0, arg1) {
|
|
22
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
23
|
+
},
|
|
24
|
+
__wbg_new_ab79df5bd7c26067: function() {
|
|
25
|
+
const ret = new Object();
|
|
26
|
+
return ret;
|
|
27
|
+
},
|
|
28
|
+
__wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
|
|
29
|
+
arg0[arg1] = arg2;
|
|
30
|
+
},
|
|
31
|
+
__wbindgen_cast_0000000000000001: function(arg0) {
|
|
32
|
+
// Cast intrinsic for `F64 -> Externref`.
|
|
33
|
+
const ret = arg0;
|
|
34
|
+
return ret;
|
|
35
|
+
},
|
|
36
|
+
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
37
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
38
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
39
|
+
return ret;
|
|
40
|
+
},
|
|
41
|
+
__wbindgen_init_externref_table: function() {
|
|
42
|
+
const table = wasm.__wbindgen_externrefs;
|
|
43
|
+
const offset = table.grow(4);
|
|
44
|
+
table.set(0, undefined);
|
|
45
|
+
table.set(offset + 0, undefined);
|
|
46
|
+
table.set(offset + 1, null);
|
|
47
|
+
table.set(offset + 2, true);
|
|
48
|
+
table.set(offset + 3, false);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
__proto__: null,
|
|
53
|
+
"./language_detector_bg.js": import0,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getStringFromWasm0(ptr, len) {
|
|
58
|
+
ptr = ptr >>> 0;
|
|
59
|
+
return decodeText(ptr, len);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let cachedUint8ArrayMemory0 = null;
|
|
63
|
+
function getUint8ArrayMemory0() {
|
|
64
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
65
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
66
|
+
}
|
|
67
|
+
return cachedUint8ArrayMemory0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
71
|
+
if (realloc === undefined) {
|
|
72
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
73
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
74
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
75
|
+
WASM_VECTOR_LEN = buf.length;
|
|
76
|
+
return ptr;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let len = arg.length;
|
|
80
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
81
|
+
|
|
82
|
+
const mem = getUint8ArrayMemory0();
|
|
83
|
+
|
|
84
|
+
let offset = 0;
|
|
85
|
+
|
|
86
|
+
for (; offset < len; offset++) {
|
|
87
|
+
const code = arg.charCodeAt(offset);
|
|
88
|
+
if (code > 0x7F) break;
|
|
89
|
+
mem[ptr + offset] = code;
|
|
90
|
+
}
|
|
91
|
+
if (offset !== len) {
|
|
92
|
+
if (offset !== 0) {
|
|
93
|
+
arg = arg.slice(offset);
|
|
94
|
+
}
|
|
95
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
96
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
97
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
98
|
+
|
|
99
|
+
offset += ret.written;
|
|
100
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
WASM_VECTOR_LEN = offset;
|
|
104
|
+
return ptr;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
108
|
+
cachedTextDecoder.decode();
|
|
109
|
+
function decodeText(ptr, len) {
|
|
110
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const cachedTextEncoder = new TextEncoder();
|
|
114
|
+
|
|
115
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
116
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
117
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
118
|
+
view.set(buf);
|
|
119
|
+
return {
|
|
120
|
+
read: arg.length,
|
|
121
|
+
written: buf.length
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let WASM_VECTOR_LEN = 0;
|
|
127
|
+
|
|
128
|
+
const wasmPath = `${__dirname}/language_detector_bg.wasm`;
|
|
129
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
130
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
131
|
+
let wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
|
|
132
|
+
wasm.__wbindgen_start();
|
|
Binary file
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const detect_language: (a: number, b: number, c: number, d: number) => any;
|
|
5
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
6
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
7
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
8
|
+
export const __wbindgen_start: () => void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "language-detector",
|
|
3
|
+
"description": "Internal WASM-backed language detector for word-counter",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/dev-pi2pie/word-counter"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"language_detector_bg.wasm",
|
|
12
|
+
"language_detector.js",
|
|
13
|
+
"language_detector.d.ts"
|
|
14
|
+
],
|
|
15
|
+
"main": "language_detector.js",
|
|
16
|
+
"types": "language_detector.d.ts"
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-pi2pie/word-counter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5-canary.2",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"cli",
|
|
6
6
|
"intl-segmenter",
|
|
@@ -28,32 +28,40 @@
|
|
|
28
28
|
"type": "module",
|
|
29
29
|
"main": "./dist/cjs/index.cjs",
|
|
30
30
|
"module": "./dist/esm/index.mjs",
|
|
31
|
-
"types": "./dist/esm/
|
|
31
|
+
"types": "./dist/esm/index2.d.mts",
|
|
32
32
|
"exports": {
|
|
33
33
|
".": {
|
|
34
|
-
"types": "./dist/esm/
|
|
34
|
+
"types": "./dist/esm/index2.d.mts",
|
|
35
35
|
"import": "./dist/esm/index.mjs",
|
|
36
36
|
"require": "./dist/cjs/index.cjs"
|
|
37
37
|
},
|
|
38
|
+
"./detector": {
|
|
39
|
+
"types": "./dist/esm/detector.d.mts",
|
|
40
|
+
"import": "./dist/esm/detector.mjs",
|
|
41
|
+
"require": "./dist/cjs/detector.cjs"
|
|
42
|
+
},
|
|
38
43
|
"./package.json": "./package.json"
|
|
39
44
|
},
|
|
40
45
|
"scripts": {
|
|
41
|
-
"build": "node scripts/generate-embedded-version.mjs && tsdown",
|
|
42
|
-
"
|
|
46
|
+
"build": "node scripts/generate-embedded-version.mjs && tsdown && node scripts/build-wasm.mjs",
|
|
47
|
+
"build:wasm": "node scripts/build-wasm.mjs",
|
|
48
|
+
"verify:package-contents": "node scripts/verify-package-contents.mjs",
|
|
49
|
+
"type-check": "tsc -p tsconfig.json && tsc -p tsconfig.test.json",
|
|
43
50
|
"test": "bun test",
|
|
44
51
|
"test:ci": "bun run build && bun test",
|
|
45
52
|
"cli": "node dist/esm/bin.mjs"
|
|
46
53
|
},
|
|
47
54
|
"dependencies": {
|
|
48
55
|
"commander": "^14.0.3",
|
|
49
|
-
"yaml": "^2.8.
|
|
56
|
+
"yaml": "^2.8.3"
|
|
50
57
|
},
|
|
51
58
|
"devDependencies": {
|
|
52
|
-
"@types/
|
|
53
|
-
"
|
|
54
|
-
"
|
|
59
|
+
"@types/bun": "^1.3.11",
|
|
60
|
+
"@types/node": "^25.5.0",
|
|
61
|
+
"oxfmt": "^0.41.0",
|
|
62
|
+
"oxlint": "^1.56.0",
|
|
55
63
|
"picocolors": "^1.1.1",
|
|
56
|
-
"tsdown": "^0.
|
|
64
|
+
"tsdown": "^0.21.4",
|
|
57
65
|
"typescript": "^5.9.3"
|
|
58
66
|
},
|
|
59
67
|
"peerDependencies": {
|