lingotweaker-wasm 0.0.1 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +81 -4
  2. package/pack.js +78 -0
  3. package/package.json +49 -3
package/README.md CHANGED
@@ -1,5 +1,82 @@
1
- # lingotweaker-wasm
1
+ # LingoTweaker (WebAssembly)
2
2
 
3
- Placeholder release. The real package ships the WebAssembly bindings of the
4
- LingoTweaker proofreading engine for browsers and Node.js. See
5
- https://github.com/fiduswriter/LingoTweaker
3
+ WebAssembly bindings for the LingoTweaker proofreading engine (wasm-bindgen),
4
+ for browsers and Node.js. The engine runs entirely from an in-memory data pack,
5
+ so no file system or native addon is required.
6
+
7
+ ```sh
8
+ npm install lingotweaker-wasm@next
9
+ ```
10
+
11
+ ## Browser
12
+
13
+ ```js
14
+ import init, { LtEngine } from "lingotweaker-wasm";
15
+ import { fetchPack } from "lingotweaker-wasm/pack";
16
+
17
+ await init();
18
+
19
+ const pack = await fetchPack("en"); // release asset for this package version
20
+ const engine = new LtEngine(
21
+ "en-US",
22
+ pack,
23
+ JSON.stringify({ today: new Date().toISOString() }),
24
+ );
25
+ const result = JSON.parse(engine.check_json("I can heard you."));
26
+ for (const match of result.matches) {
27
+ console.log(match.rule_id, match.suggestions);
28
+ }
29
+ ```
30
+
31
+ ## Node.js
32
+
33
+ The Node build is CommonJS (`lingotweaker-wasm/node`); the data helper is ESM,
34
+ so import it dynamically from CJS:
35
+
36
+ ```js
37
+ const { LtEngine } = require("lingotweaker-wasm/node");
38
+
39
+ (async () => {
40
+ const { fetchPack } = await import("lingotweaker-wasm/pack");
41
+ const pack = await fetchPack("en");
42
+ const engine = new LtEngine(
43
+ "en-US",
44
+ pack,
45
+ JSON.stringify({ today: new Date().toISOString() }),
46
+ );
47
+ console.log(engine.check_json("I can heard you."));
48
+ })();
49
+ ```
50
+
51
+ Or, from an ES module: `import { LtEngine } from "lingotweaker-wasm/node"`.
52
+
53
+ `today` is required in practice: WebAssembly has no clock, so the date is
54
+ passed in and pinned for the engine's date filters.
55
+
56
+ ## Data
57
+
58
+ The package ships **code only** and depends on the code-only
59
+ `lingotweaker-data` loader; the packs ship in one small package per language
60
+ (`lingotweaker-data-<lang>`). In Node.js the data helper resolves installed
61
+ `lingotweaker-data-<lang>` packages locally; in the browser (or without them)
62
+ it falls back to the per-release GitHub Release assets:
63
+
64
+ ```js
65
+ import { fetchPack, packUrl, manifestUrl } from "lingotweaker-wasm/pack";
66
+
67
+ await fetchPack("en"); // installed lingotweaker-data-en in Node, else release assets
68
+ await fetchPack("gn", { baseUrl: "https://fiduswriter.github.io/LingoTweaker" });
69
+ packUrl("de"); // build a URL yourself
70
+ ```
71
+
72
+ `baseUrl` points at a directory that contains `packs/<lang>.pack.gz` and
73
+ `manifest.json`. All languages are attached to every release; `manifest.json`
74
+ lists file sizes and sha256 hashes. Each pack is also served from any npm CDN
75
+ (`https://cdn.jsdelivr.net/npm/lingotweaker-data-<lang>/packs/<lang>.pack.gz`),
76
+ and you can host the packs yourself.
77
+
78
+ LingoTweaker is an independent project and includes a port of the legacy
79
+ LanguageTool proofreading engine and its rule data. Upstream references and
80
+ licenses are kept; see `THIRD_PARTY_NOTICES.md` in the repository.
81
+
82
+ License: LGPL-2.1-or-later.
package/pack.js ADDED
@@ -0,0 +1,78 @@
1
+ // Data helpers for the `lingotweaker-wasm` package.
2
+ //
3
+ // The engine itself is loaded from an in-memory data pack
4
+ // (`LtEngine(lang, pack, optionsJson)`); this module fetches those packs from
5
+ // the per-release GitHub Release assets and inflates the gzip wrapper.
6
+ //
7
+ // import { fetchPack } from "lingotweaker-wasm/pack";
8
+ // const pack = await fetchPack("en");
9
+ // const engine = new LtEngine("en-US", pack, JSON.stringify({ today: new Date().toISOString() }));
10
+
11
+ // Updated by scripts/release/set-version.sh together with the package version.
12
+ export const DEFAULT_DATA_BASE_URL =
13
+ "https://github.com/fiduswriter/LingoTweaker/releases/download/v0.2.0";
14
+
15
+ /** The URL of the release data manifest (`{ <lang>: { file, bytes, sha256 } }`). */
16
+ export function manifestUrl(baseUrl = DEFAULT_DATA_BASE_URL) {
17
+ return `${baseUrl}/manifest.json`;
18
+ }
19
+
20
+ /** The URL of the gzipped pack for `lang`. */
21
+ export function packUrl(lang, baseUrl = DEFAULT_DATA_BASE_URL) {
22
+ return `${baseUrl}/packs/${lang}.pack.gz`;
23
+ }
24
+
25
+ /** Inflate a gzipped pack (browser `DecompressionStream`, else Node `zlib`). */
26
+ export async function decompressPack(bytes) {
27
+ const u8 = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
28
+ if (typeof DecompressionStream === "function" && typeof Blob === "function") {
29
+ const stream = new Blob([u8]).stream().pipeThrough(new DecompressionStream("gzip"));
30
+ return new Uint8Array(await new Response(stream).arrayBuffer());
31
+ }
32
+ const { gunzipSync } = await import("node:zlib");
33
+ return new Uint8Array(gunzipSync(u8));
34
+ }
35
+
36
+ /**
37
+ * Fetch and inflate the pack for `lang` (`en`, `de`, `gn`, …).
38
+ *
39
+ * Node.js prefers the locally installed `lingotweaker-data-<lang>` data
40
+ * packages; browsers (and any environment without them) fall back to the
41
+ * release assets for this package version. Pass `baseUrl` to use different
42
+ * data — the Pages demo
43
+ * (`https://fiduswriter.github.io/LingoTweaker`) or a local directory.
44
+ */
45
+ export async function fetchPack(lang, options = {}) {
46
+ const { fetch: fetchImpl = fetch } = options;
47
+ let { baseUrl } = options;
48
+ if (!baseUrl) {
49
+ const local = await localPack(lang);
50
+ if (local) return local;
51
+ baseUrl = DEFAULT_DATA_BASE_URL;
52
+ }
53
+ const url = packUrl(lang, baseUrl);
54
+ const response = await fetchImpl(url);
55
+ if (!response.ok) {
56
+ throw new Error(`cannot load ${url}: HTTP ${response.status}`);
57
+ }
58
+ return decompressPack(await response.arrayBuffer());
59
+ }
60
+
61
+ /**
62
+ * Read and inflate a pack from the locally installed data packages (the
63
+ * code-only `lingotweaker-data` loader resolving `lingotweaker-data-<lang>`).
64
+ * Returns `null` outside Node.js, or when the package/language is missing.
65
+ */
66
+ export async function localPack(lang) {
67
+ if (typeof process === "undefined" || !process.versions?.node) return null;
68
+ try {
69
+ const { createRequire } = await import("node:module");
70
+ const require = createRequire(import.meta.url);
71
+ const data = require("lingotweaker-data");
72
+ const { readFile } = await import("node:fs/promises");
73
+ const bytes = await readFile(data.packPath(lang));
74
+ return decompressPack(bytes);
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
package/package.json CHANGED
@@ -1,11 +1,57 @@
1
1
  {
2
2
  "name": "lingotweaker-wasm",
3
- "version": "0.0.1",
4
- "description": "LingoTweaker proofreading engine compiled to WebAssembly",
3
+ "version": "0.2.0",
4
+ "description": "LingoTweaker proofreading engine compiled to WebAssembly (browser and Node)",
5
5
  "license": "LGPL-2.1-or-later",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/fiduswriter/LingoTweaker.git"
9
9
  },
10
- "homepage": "https://fiduswriter.github.io/LingoTweaker/"
10
+ "homepage": "https://fiduswriter.github.io/LingoTweaker/",
11
+ "keywords": [
12
+ "proofreading",
13
+ "grammar",
14
+ "spellcheck",
15
+ "nlp",
16
+ "language",
17
+ "wasm",
18
+ "webassembly"
19
+ ],
20
+ "type": "module",
21
+ "main": "./node/lt_wasm.js",
22
+ "module": "./web/lt_wasm.js",
23
+ "types": "./web/lt_wasm.d.ts",
24
+ "dependencies": {
25
+ "lingotweaker-data": "0.2.0"
26
+ },
27
+ "exports": {
28
+ ".": {
29
+ "types": "./web/lt_wasm.d.ts",
30
+ "browser": "./web/lt_wasm.js",
31
+ "import": "./web/lt_wasm.js",
32
+ "require": "./node/lt_wasm.js",
33
+ "default": "./web/lt_wasm.js"
34
+ },
35
+ "./web": {
36
+ "types": "./web/lt_wasm.d.ts",
37
+ "default": "./web/lt_wasm.js"
38
+ },
39
+ "./node": {
40
+ "types": "./node/lt_wasm.d.ts",
41
+ "default": "./node/lt_wasm.js"
42
+ },
43
+ "./pack": {
44
+ "default": "./pack.js"
45
+ },
46
+ "./package.json": "./package.json"
47
+ },
48
+ "files": [
49
+ "web",
50
+ "node",
51
+ "pack.js",
52
+ "README.md"
53
+ ],
54
+ "engines": {
55
+ "node": ">= 18"
56
+ }
11
57
  }