@laisuk/opencc-fmmseg-wasm 0.2.0 → 0.2.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/bin/opencc.js ADDED
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import process from "process";
6
+
7
+ import init, {
8
+ OpenccWasm,
9
+ convert_office_bytes
10
+ } from "../opencc_fmmseg_wasm.js";
11
+
12
+ const OFFICE_FORMATS = new Set([
13
+ "docx",
14
+ "xlsx",
15
+ "pptx",
16
+ "odt",
17
+ "ods",
18
+ "odp",
19
+ "epub"
20
+ ]);
21
+
22
+ let wasmInitialized = false;
23
+
24
+ async function ensureWasmInitialized() {
25
+ if (wasmInitialized) {
26
+ return;
27
+ }
28
+
29
+ const wasmPath = new URL("../opencc_fmmseg_wasm_bg.wasm", import.meta.url);
30
+ const wasmBytes = fs.readFileSync(wasmPath);
31
+
32
+ await init({
33
+ module_or_path: wasmBytes
34
+ });
35
+
36
+ wasmInitialized = true;
37
+ }
38
+
39
+ function printHelp() {
40
+ console.log(`
41
+ opencc-fmmseg WASM CLI
42
+
43
+ Usage:
44
+ opencc.js convert [options]
45
+ opencc.js office [options]
46
+
47
+ Commands:
48
+ convert Convert plain text
49
+ office Convert Office / EPUB documents
50
+
51
+ Convert options:
52
+ -i, --input <file> Input text file; stdin if omitted
53
+ -o, --output <file> Output text file; stdout if omitted
54
+ -c, --config <conversion> Conversion config (default: s2t)
55
+ -p, --punct Enable punctuation conversion
56
+ --in-enc <encoding> Input encoding (default: utf8)
57
+ --out-enc <encoding> Output encoding (default: utf8)
58
+
59
+ Office options:
60
+ -i, --input <file> Input Office / EPUB file
61
+ -o, --output <file> Output file
62
+ -c, --config <conversion> Conversion config (default: s2t)
63
+ -p, --punct Enable punctuation conversion
64
+ --format <format> docx | xlsx | pptx | odt | ods | odp | epub
65
+ --auto-ext Append extension to output if missing
66
+ --keep-font Preserve font-family information (default)
67
+ --no-keep-font Do not preserve font-family information
68
+
69
+ General options:
70
+ -h, --help Show help
71
+
72
+ Examples:
73
+ node ./bin/opencc.js convert -i a.txt -o b.txt -c s2t
74
+ node ./bin/opencc.js convert -i a.txt -o b.txt -c s2tw -p
75
+ cat a.txt | node ./bin/opencc.js convert -c t2s
76
+
77
+ node ./bin/opencc.js office -i a.docx -o b.docx -c s2t -p
78
+ node ./bin/opencc.js office -i a.epub -c s2tw --auto-ext
79
+ `);
80
+ }
81
+
82
+ function getArg(args, shortName, longName, defaultValue = null) {
83
+ const candidates = [];
84
+
85
+ if (shortName) {
86
+ candidates.push(shortName);
87
+ }
88
+ if (longName) {
89
+ candidates.push(longName);
90
+ }
91
+
92
+ for (const name of candidates) {
93
+ const index = args.indexOf(name);
94
+
95
+ if (index !== -1 && index + 1 < args.length) {
96
+ return args[index + 1];
97
+ }
98
+ }
99
+
100
+ return defaultValue;
101
+ }
102
+
103
+ function hasFlag(args, shortName, longName) {
104
+ return (
105
+ (shortName && args.includes(shortName)) ||
106
+ (longName && args.includes(longName))
107
+ );
108
+ }
109
+
110
+ function readInputText(filePath, encoding) {
111
+ if (!filePath) {
112
+ return fs.readFileSync(0, encoding);
113
+ }
114
+
115
+ if (!fs.existsSync(filePath)) {
116
+ console.error(`Error: Input file not found: ${filePath}`);
117
+ process.exit(1);
118
+ }
119
+
120
+ return fs.readFileSync(filePath, encoding);
121
+ }
122
+
123
+ function writeOutputText(filePath, text, encoding) {
124
+ if (!filePath) {
125
+ process.stdout.write(text);
126
+ return;
127
+ }
128
+
129
+ fs.writeFileSync(filePath, text, encoding);
130
+ }
131
+
132
+ function inferOfficeFormat(inputFile, explicitFormat) {
133
+ if (explicitFormat) {
134
+ const normalized = explicitFormat.trim().toLowerCase();
135
+
136
+ if (!OFFICE_FORMATS.has(normalized)) {
137
+ throw new Error(
138
+ `Invalid office format: ${explicitFormat}. ` +
139
+ `Valid formats: ${Array.from(OFFICE_FORMATS).join(", ")}`
140
+ );
141
+ }
142
+
143
+ return normalized;
144
+ }
145
+
146
+ const ext = path.extname(inputFile).slice(1).toLowerCase();
147
+
148
+ if (!OFFICE_FORMATS.has(ext)) {
149
+ throw new Error(
150
+ `Invalid Office file extension: .${ext || "(none)"}. ` +
151
+ "Valid extensions: .docx | .xlsx | .pptx | .odt | .ods | .odp | .epub"
152
+ );
153
+ }
154
+
155
+ return ext;
156
+ }
157
+
158
+ function makeDefaultOfficeOutput(inputFile, officeFormat, autoExt) {
159
+ const parsed = path.parse(inputFile);
160
+ const ext = autoExt && OFFICE_FORMATS.has(officeFormat)
161
+ ? `.${officeFormat}`
162
+ : parsed.ext;
163
+
164
+ return path.join(
165
+ parsed.dir || process.cwd(),
166
+ `${parsed.name}_converted${ext}`
167
+ );
168
+ }
169
+
170
+ function applyAutoExt(outputFile, officeFormat, autoExt) {
171
+ if (!autoExt || path.extname(outputFile)) {
172
+ return outputFile;
173
+ }
174
+
175
+ if (!OFFICE_FORMATS.has(officeFormat)) {
176
+ return outputFile;
177
+ }
178
+
179
+ return `${outputFile}.${officeFormat}`;
180
+ }
181
+
182
+ async function runConvert(args) {
183
+ const input = getArg(args, "-i", "--input");
184
+ const output = getArg(args, "-o", "--output");
185
+ const config = getArg(args, "-c", "--config", "s2t");
186
+ const inEnc = getArg(args, null, "--in-enc", "utf8");
187
+ const outEnc = getArg(args, null, "--out-enc", "utf8");
188
+ const punct = hasFlag(args, "-p", "--punct");
189
+
190
+ await ensureWasmInitialized();
191
+
192
+ const cc = new OpenccWasm(config);
193
+
194
+ const inputText = readInputText(input, inEnc);
195
+ const outputText = cc.convert(inputText, punct);
196
+
197
+ writeOutputText(output, outputText, outEnc);
198
+
199
+ const inFrom = input || "<stdin>";
200
+ const outTo = output || "stdout";
201
+
202
+ if (process.stderr.isTTY) {
203
+ if (!output && outputText && !outputText.endsWith("\n")) {
204
+ console.error();
205
+ }
206
+
207
+ console.error(`Conversion completed (${config}): ${inFrom} -> ${outTo}`);
208
+ }
209
+ }
210
+
211
+ async function runOffice(args) {
212
+ const input = getArg(args, "-i", "--input");
213
+ let output = getArg(args, "-o", "--output");
214
+ const config = getArg(args, "-c", "--config", "s2t");
215
+ const explicitFormat = getArg(args, null, "--format");
216
+ const punct = hasFlag(args, "-p", "--punct");
217
+ const autoExt = hasFlag(args, null, "--auto-ext");
218
+ const keepFont = !hasFlag(args, null, "--no-keep-font");
219
+
220
+ if (!input) {
221
+ throw new Error("Input file is missing.");
222
+ }
223
+
224
+ if (!fs.existsSync(input) || !fs.statSync(input).isFile()) {
225
+ throw new Error(`Input file not found: ${input}`);
226
+ }
227
+
228
+ const officeFormat = inferOfficeFormat(input, explicitFormat);
229
+
230
+ if (!output) {
231
+ output = makeDefaultOfficeOutput(input, officeFormat, autoExt);
232
+ console.error(`Output file not specified. Using: ${output}`);
233
+ } else {
234
+ output = applyAutoExt(output, officeFormat, autoExt);
235
+ }
236
+
237
+ await ensureWasmInitialized();
238
+
239
+ const inputBytes = fs.readFileSync(input);
240
+
241
+ const outputBytes = convert_office_bytes(
242
+ inputBytes,
243
+ officeFormat,
244
+ config,
245
+ punct,
246
+ keepFont
247
+ );
248
+
249
+ fs.writeFileSync(output, outputBytes);
250
+
251
+ console.error(`Conversion completed (${config}, ${officeFormat}): ${input} -> ${output}`);
252
+ }
253
+
254
+ async function main() {
255
+ const args = process.argv.slice(2);
256
+
257
+ if (args.length === 0 || hasFlag(args, "-h", "--help")) {
258
+ printHelp();
259
+ return;
260
+ }
261
+
262
+ const command = args[0];
263
+
264
+ switch (command) {
265
+ case "convert":
266
+ if (hasFlag(args.slice(1), "-h", "--help")) {
267
+ printHelp();
268
+ return;
269
+ }
270
+ await runConvert(args.slice(1));
271
+ break;
272
+
273
+ case "office":
274
+ if (hasFlag(args.slice(1), "-h", "--help")) {
275
+ printHelp();
276
+ return;
277
+ }
278
+ await runOffice(args.slice(1));
279
+ break;
280
+
281
+ default:
282
+ console.error(`Unknown command: ${command}`);
283
+ printHelp();
284
+ process.exit(1);
285
+ }
286
+ }
287
+
288
+ main().catch(err => {
289
+ console.error(err && err.message ? err.message : err);
290
+ process.exit(1);
291
+ });
Binary file
package/package.json CHANGED
@@ -2,13 +2,30 @@
2
2
  "name": "@laisuk/opencc-fmmseg-wasm",
3
3
  "type": "module",
4
4
  "description": "WebAssembly bindings for opencc-fmmseg, a high-performance OpenCC-compatible Simplified/Traditional Chinese converter.",
5
- "version": "0.2.0",
5
+ "version": "0.2.2",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/laisuk/opencc-fmmseg-wasm.git"
10
10
  },
11
+ "keywords": [
12
+ "opencc",
13
+ "chinese",
14
+ "simplified-chinese",
15
+ "traditional-chinese",
16
+ "wasm",
17
+ "webassembly",
18
+ "opencc-fmmseg",
19
+ "text-conversion",
20
+ "cjk",
21
+ "zh-hans",
22
+ "zh-hant"
23
+ ],
24
+ "bin": {
25
+ "opencc-fmmseg": "bin/opencc.js"
26
+ },
11
27
  "files": [
28
+ "bin/",
12
29
  "opencc_fmmseg_wasm_bg.wasm",
13
30
  "opencc_fmmseg_wasm.js",
14
31
  "opencc_fmmseg_wasm.d.ts"