react-native-jieba 0.1.0 → 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.
- package/README.md +98 -2
- package/lib/module/NativeJieba.web.js +60 -0
- package/lib/module/NativeJieba.web.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/init.js +2 -2
- package/lib/module/init.js.map +1 -1
- package/lib/module/init.web.js +28 -0
- package/lib/module/init.web.js.map +1 -0
- package/lib/module/jieba.js +1 -1
- package/lib/module/jieba.js.map +1 -1
- package/lib/typescript/src/NativeJieba.web.d.ts +15 -0
- package/lib/typescript/src/NativeJieba.web.d.ts.map +1 -0
- package/lib/typescript/src/init.d.ts +9 -1
- package/lib/typescript/src/init.d.ts.map +1 -1
- package/lib/typescript/src/init.web.d.ts +4 -0
- package/lib/typescript/src/init.web.d.ts.map +1 -0
- package/lib/typescript/src/jieba.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/NativeJieba.web.ts +82 -0
- package/src/init.ts +10 -1
- package/src/init.web.ts +32 -0
- package/src/jieba.ts +1 -4
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Native Chinese text segmentation for React Native, powered by [cppjieba](https:/
|
|
|
5
5
|
- Runs on the New Architecture as a C++ Turbo Module — no bridge overhead, no JS port of jieba.
|
|
6
6
|
- Ships the cppjieba dictionaries (`jieba.dict.utf8`, `hmm_model.utf8`, `idf.utf8`, `stop_words.utf8`, `user.dict.utf8`) inside the package, bundled as iOS pod resources and Android assets.
|
|
7
7
|
- Supports the standard jieba modes: precise (`cut`), full (`cutAll`), search engine (`cutForSearch`), HMM (`cutHMM`), small-word (`cutSmall`), POS tagging (`tag`), and TF-IDF keyword extraction (`extract`).
|
|
8
|
+
- Works on **web** (react-native-web) via [`jieba-wasm`](https://github.com/fengkx/jieba-wasm), with the same API.
|
|
8
9
|
|
|
9
10
|
## Requirements
|
|
10
11
|
|
|
@@ -28,6 +29,23 @@ cd ios && pod install
|
|
|
28
29
|
|
|
29
30
|
Android: no extra steps — autolinking picks up the AAR.
|
|
30
31
|
|
|
32
|
+
Web (react-native-web): install the optional `jieba-wasm` peer dependency, which provides the WebAssembly backend.
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install jieba-wasm
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Any bundler that handles `.wasm` assets (Vite, Webpack 5, Metro-web, etc.) will bundle the binary automatically.
|
|
39
|
+
|
|
40
|
+
If you use **Vite**, exclude `jieba-wasm` from dependency pre-bundling so its `.wasm` is served from the package directory (otherwise the binary isn't copied into `.vite/deps` and the fetch 404s):
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// vite.config.js
|
|
44
|
+
export default {
|
|
45
|
+
optimizeDeps: { exclude: ['jieba-wasm'] },
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
31
49
|
## Usage
|
|
32
50
|
|
|
33
51
|
Call `initJieba()` once before the first segmentation call. On iOS the dictionary path is resolved from the app bundle automatically; on Android it extracts the bundled assets to `filesDir/jieba-dict/` on first run.
|
|
@@ -62,11 +80,11 @@ extract('我是拖拉机学院手扶拖拉机专业的。', 5);
|
|
|
62
80
|
|
|
63
81
|
## API
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
On native, all segmentation calls are synchronous JSI calls — no Promises. On web they are synchronous too, but `initJieba()` must finish first (it loads the wasm module).
|
|
66
84
|
|
|
67
85
|
| Function | Signature | Notes |
|
|
68
86
|
| --- | --- | --- |
|
|
69
|
-
| `initJieba()` | `() => Promise<void>` | Must be awaited once before any other call. Idempotent. |
|
|
87
|
+
| `initJieba(options?)` | `(options?: { wasmUrl?: string \| URL \| Request }) => Promise<void>` | Must be awaited once before any other call. Idempotent. `wasmUrl` is web-only and rarely needed (override where the `.wasm` is served). |
|
|
70
88
|
| `cut(sentence, hmm?)` | `(string, boolean) => string[]` | Precise mode. `hmm` defaults to `true`. |
|
|
71
89
|
| `cutAll(sentence)` | `(string) => string[]` | Full mode (every possible word). |
|
|
72
90
|
| `cutForSearch(sentence, hmm?)` | `(string, boolean) => string[]` | Search-engine mode. |
|
|
@@ -77,12 +95,90 @@ All segmentation calls are synchronous JSI calls — no Promises.
|
|
|
77
95
|
| `insertUserWord(word, tag?)` | `(string, string) => boolean` | Adds a user dictionary word at runtime. |
|
|
78
96
|
| `find(word)` | `(string) => boolean` | Tests whether a word is in the dictionary. |
|
|
79
97
|
|
|
98
|
+
### Web support
|
|
99
|
+
|
|
100
|
+
On web the implementation is backed by [`jieba-wasm`](https://github.com/fengkx/jieba-wasm) (jieba-rs compiled to WebAssembly) instead of cppjieba. The core API is identical, with a few caveats because jieba-wasm exposes a smaller surface:
|
|
101
|
+
|
|
102
|
+
| Function | Web behavior |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `cut`, `cutAll`, `cutForSearch`, `tag` | Fully supported. |
|
|
105
|
+
| `insertUserWord` | Supported (maps to jieba-wasm `add_word`); the `tag` argument is honored, frequency is auto-assigned. |
|
|
106
|
+
| `cutHMM` | Falls back to `cut(sentence, true)` (jieba-wasm has no HMM-only mode). |
|
|
107
|
+
| `cutSmall` | Falls back to `cut`; the `maxWordLen` argument is accepted for parity but ignored. |
|
|
108
|
+
| `find` | Approximated: returns `true` when the word survives precise (non-HMM) segmentation as a single token. |
|
|
109
|
+
| `extract` | **Not supported** — throws. jieba-wasm does not ship the IDF dictionary needed for TF-IDF extraction. |
|
|
110
|
+
|
|
111
|
+
#### Example (Vite + react-native-web)
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
// vite.config.js
|
|
115
|
+
import { defineConfig } from 'vite';
|
|
116
|
+
import react from '@vitejs/plugin-react';
|
|
117
|
+
|
|
118
|
+
export default defineConfig({
|
|
119
|
+
plugins: [react()],
|
|
120
|
+
resolve: {
|
|
121
|
+
alias: { 'react-native': 'react-native-web' },
|
|
122
|
+
},
|
|
123
|
+
// jieba-wasm resolves its `.wasm` via `import.meta.url`; pre-bundling into
|
|
124
|
+
// `.vite/deps` would leave the binary behind, so exclude it.
|
|
125
|
+
optimizeDeps: { exclude: ['jieba-wasm'] },
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// App.tsx
|
|
131
|
+
import { useEffect, useState } from 'react';
|
|
132
|
+
import { Platform, Text, View } from 'react-native';
|
|
133
|
+
import { initJieba, cut, cutForSearch, tag, extract } from 'react-native-jieba';
|
|
134
|
+
|
|
135
|
+
export default function App() {
|
|
136
|
+
const [words, setWords] = useState<string[] | null>(null);
|
|
137
|
+
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
// On web this loads + instantiates the wasm module (async).
|
|
140
|
+
// On native it's a near-instant no-op / dict-path setup.
|
|
141
|
+
initJieba()
|
|
142
|
+
.then(() => {
|
|
143
|
+
setWords(cut('我来到北京清华大学'));
|
|
144
|
+
// → ['我', '来到', '北京', '清华大学']
|
|
145
|
+
|
|
146
|
+
cutForSearch('小明硕士毕业于中国科学院计算所');
|
|
147
|
+
// → ['小明', '硕士', '毕业', '于', '中国', '科学', '学院', ...]
|
|
148
|
+
|
|
149
|
+
tag('我爱北京天安门');
|
|
150
|
+
// → [{ word: '我', tag: 'r' }, { word: '爱', tag: 'v' }, ...]
|
|
151
|
+
|
|
152
|
+
// extract() throws on web — guard it for cross-platform code.
|
|
153
|
+
const keywords = Platform.OS === 'web' ? [] : extract('…', 5);
|
|
154
|
+
})
|
|
155
|
+
.catch((e) => console.error(e));
|
|
156
|
+
}, []);
|
|
157
|
+
|
|
158
|
+
if (!words) return <Text>Loading…</Text>;
|
|
159
|
+
return (
|
|
160
|
+
<View>
|
|
161
|
+
{words.map((w, i) => (
|
|
162
|
+
<Text key={i}>{w}</Text>
|
|
163
|
+
))}
|
|
164
|
+
</View>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
To self-host the binary (CDN or custom path), pass `wasmUrl`:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
await initJieba({ wasmUrl: 'https://cdn.example.com/jieba_rs_wasm_bg.wasm' });
|
|
173
|
+
```
|
|
174
|
+
|
|
80
175
|
## How it works
|
|
81
176
|
|
|
82
177
|
- The Turbo Module lives in `cpp/JiebaImpl.{h,cpp}` and wraps `cppjieba::Jieba` as a JSI Cxx module.
|
|
83
178
|
- iOS resolves the dictionary directory from `NSBundle` in `ios/OnLoad.mm` before the module is registered, so `initJieba()` is a no-op on iOS.
|
|
84
179
|
- Android ships the dictionary as AAR assets and extracts them on demand via `JiebaAndroidHelperModule`, which then hands the path to the C++ module via the codegen-exposed `setDictPath` JSI method.
|
|
85
180
|
- cppjieba and its `limonp` dependency are vendored as git submodules under `cpp/cppjieba/`. The published npm tarball contains only the headers and dictionaries that are actually needed at build time.
|
|
181
|
+
- On web, `react-native-web`'s bundler resolution picks up `src/NativeJieba.web.ts` and `src/init.web.ts`. `initJieba()` lazily imports `jieba-wasm`, awaits its async wasm initializer, and routes the JS API to the wasm exports.
|
|
86
182
|
|
|
87
183
|
## Contributing
|
|
88
184
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// `jieba-wasm` exposes the same segmentation primitives as cppjieba, but a
|
|
4
|
+
// smaller surface: cut / cutAll / cutForSearch / tag / add_word. The remaining
|
|
5
|
+
// native methods are polyfilled on top of those where the semantics allow, and
|
|
6
|
+
// throw otherwise. The wasm module is loaded lazily by `initJieba()` (see
|
|
7
|
+
// `init.web.ts`) and handed to this shim via `setJiebaWasm`.
|
|
8
|
+
|
|
9
|
+
let wasm = null;
|
|
10
|
+
export function setJiebaWasm(module) {
|
|
11
|
+
wasm = module;
|
|
12
|
+
}
|
|
13
|
+
function getWasm() {
|
|
14
|
+
if (!wasm) {
|
|
15
|
+
throw new Error('react-native-jieba: jieba-wasm is not initialized. ' + 'Call (and await) initJieba() before any segmentation call.');
|
|
16
|
+
}
|
|
17
|
+
return wasm;
|
|
18
|
+
}
|
|
19
|
+
const Jieba = {
|
|
20
|
+
setDictPath() {
|
|
21
|
+
// No-op on web: jieba-wasm bundles its own dictionary.
|
|
22
|
+
},
|
|
23
|
+
cut(sentence, hmm) {
|
|
24
|
+
return getWasm().cut(sentence, hmm);
|
|
25
|
+
},
|
|
26
|
+
cutAll(sentence) {
|
|
27
|
+
return getWasm().cut_all(sentence);
|
|
28
|
+
},
|
|
29
|
+
cutForSearch(sentence, hmm) {
|
|
30
|
+
return getWasm().cut_for_search(sentence, hmm);
|
|
31
|
+
},
|
|
32
|
+
cutHMM(sentence) {
|
|
33
|
+
// jieba-wasm has no HMM-only mode; precise cut with HMM enabled is the
|
|
34
|
+
// closest equivalent.
|
|
35
|
+
return getWasm().cut(sentence, true);
|
|
36
|
+
},
|
|
37
|
+
cutSmall(sentence, _maxWordLen) {
|
|
38
|
+
// jieba-wasm does not expose a max-word-length cut; fall back to precise
|
|
39
|
+
// cut. The maxWordLen argument is accepted for API parity but ignored.
|
|
40
|
+
return getWasm().cut(sentence, true);
|
|
41
|
+
},
|
|
42
|
+
tag(sentence) {
|
|
43
|
+
return getWasm().tag(sentence);
|
|
44
|
+
},
|
|
45
|
+
extract() {
|
|
46
|
+
throw new Error('react-native-jieba: extract() (TF-IDF keyword extraction) is not ' + 'supported on web — jieba-wasm does not ship the IDF dictionary.');
|
|
47
|
+
},
|
|
48
|
+
insertUserWord(word, tag) {
|
|
49
|
+
// add_word returns the inserted word's frequency (>= 0 on success).
|
|
50
|
+
return getWasm().add_word(word, undefined, tag === '' ? undefined : tag) >= 0;
|
|
51
|
+
},
|
|
52
|
+
find(word) {
|
|
53
|
+
// jieba-wasm has no dictionary lookup; approximate it by checking whether
|
|
54
|
+
// the word survives precise (non-HMM) segmentation as a single token.
|
|
55
|
+
const segments = getWasm().cut(word, false);
|
|
56
|
+
return segments.length === 1 && segments[0] === word;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
export default Jieba;
|
|
60
|
+
//# sourceMappingURL=NativeJieba.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["wasm","setJiebaWasm","module","getWasm","Error","Jieba","setDictPath","cut","sentence","hmm","cutAll","cut_all","cutForSearch","cut_for_search","cutHMM","cutSmall","_maxWordLen","tag","extract","insertUserWord","word","add_word","undefined","find","segments","length"],"sourceRoot":"../../src","sources":["NativeJieba.web.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;;AAaA,IAAIA,IAA4B,GAAG,IAAI;AAEvC,OAAO,SAASC,YAAYA,CAACC,MAAuB,EAAQ;EAC1DF,IAAI,GAAGE,MAAM;AACf;AAEA,SAASC,OAAOA,CAAA,EAAoB;EAClC,IAAI,CAACH,IAAI,EAAE;IACT,MAAM,IAAII,KAAK,CACb,qDAAqD,GACnD,4DACJ,CAAC;EACH;EACA,OAAOJ,IAAI;AACb;AAEA,MAAMK,KAAW,GAAG;EAClBC,WAAWA,CAAA,EAAG;IACZ;EAAA,CACD;EACDC,GAAGA,CAACC,QAAQ,EAAEC,GAAG,EAAE;IACjB,OAAON,OAAO,CAAC,CAAC,CAACI,GAAG,CAACC,QAAQ,EAAEC,GAAG,CAAC;EACrC,CAAC;EACDC,MAAMA,CAACF,QAAQ,EAAE;IACf,OAAOL,OAAO,CAAC,CAAC,CAACQ,OAAO,CAACH,QAAQ,CAAC;EACpC,CAAC;EACDI,YAAYA,CAACJ,QAAQ,EAAEC,GAAG,EAAE;IAC1B,OAAON,OAAO,CAAC,CAAC,CAACU,cAAc,CAACL,QAAQ,EAAEC,GAAG,CAAC;EAChD,CAAC;EACDK,MAAMA,CAACN,QAAQ,EAAE;IACf;IACA;IACA,OAAOL,OAAO,CAAC,CAAC,CAACI,GAAG,CAACC,QAAQ,EAAE,IAAI,CAAC;EACtC,CAAC;EACDO,QAAQA,CAACP,QAAQ,EAAEQ,WAAW,EAAE;IAC9B;IACA;IACA,OAAOb,OAAO,CAAC,CAAC,CAACI,GAAG,CAACC,QAAQ,EAAE,IAAI,CAAC;EACtC,CAAC;EACDS,GAAGA,CAACT,QAAQ,EAAE;IACZ,OAAOL,OAAO,CAAC,CAAC,CAACc,GAAG,CAACT,QAAQ,CAAC;EAChC,CAAC;EACDU,OAAOA,CAAA,EAAG;IACR,MAAM,IAAId,KAAK,CACb,mEAAmE,GACjE,iEACJ,CAAC;EACH,CAAC;EACDe,cAAcA,CAACC,IAAI,EAAEH,GAAG,EAAE;IACxB;IACA,OACEd,OAAO,CAAC,CAAC,CAACkB,QAAQ,CAACD,IAAI,EAAEE,SAAS,EAAEL,GAAG,KAAK,EAAE,GAAGK,SAAS,GAAGL,GAAG,CAAC,IAAI,CAAC;EAE1E,CAAC;EACDM,IAAIA,CAACH,IAAI,EAAE;IACT;IACA;IACA,MAAMI,QAAQ,GAAGrB,OAAO,CAAC,CAAC,CAACI,GAAG,CAACa,IAAI,EAAE,KAAK,CAAC;IAC3C,OAAOI,QAAQ,CAACC,MAAM,KAAK,CAAC,IAAID,QAAQ,CAAC,CAAC,CAAC,KAAKJ,IAAI;EACtD;AACF,CAAC;AAED,eAAef,KAAK","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["cut","cutAll","cutForSearch","cutHMM","cutSmall","tag","extract","insertUserWord","find","initJieba"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,GAAG,EACHC,MAAM,EACNC,YAAY,EACZC,MAAM,EACNC,QAAQ,EACRC,GAAG,EACHC,OAAO,EACPC,cAAc,EACdC,IAAI,QACC,YAAS;AAEhB,SAASC,SAAS,QAAQ,
|
|
1
|
+
{"version":3,"names":["cut","cutAll","cutForSearch","cutHMM","cutSmall","tag","extract","insertUserWord","find","initJieba"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,GAAG,EACHC,MAAM,EACNC,YAAY,EACZC,MAAM,EACNC,QAAQ,EACRC,GAAG,EACHC,OAAO,EACPC,cAAc,EACdC,IAAI,QACC,YAAS;AAEhB,SAASC,SAAS,QAAQ,QAAQ","ignoreList":[]}
|
package/lib/module/init.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { Platform } from 'react-native';
|
|
4
|
-
import Jieba from
|
|
4
|
+
import Jieba from './NativeJieba';
|
|
5
5
|
import JiebaAndroidHelper from "./NativeJiebaAndroidHelper.js";
|
|
6
6
|
let initPromise = null;
|
|
7
|
-
export function initJieba() {
|
|
7
|
+
export function initJieba(_options = {}) {
|
|
8
8
|
if (initPromise) return initPromise;
|
|
9
9
|
initPromise = (async () => {
|
|
10
10
|
if (Platform.OS === 'android') {
|
package/lib/module/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Platform","Jieba","JiebaAndroidHelper","initPromise","initJieba","OS","Error","path","prepareDictDir","setDictPath","catch","err"],"sourceRoot":"../../src","sources":["init.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,KAAK,MAAM,
|
|
1
|
+
{"version":3,"names":["Platform","Jieba","JiebaAndroidHelper","initPromise","initJieba","_options","OS","Error","path","prepareDictDir","setDictPath","catch","err"],"sourceRoot":"../../src","sources":["init.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,KAAK,MAAM,eAAe;AACjC,OAAOC,kBAAkB,MAAM,+BAA4B;AAW3D,IAAIC,WAAiC,GAAG,IAAI;AAE5C,OAAO,SAASC,SAASA,CAACC,QAA0B,GAAG,CAAC,CAAC,EAAiB;EACxE,IAAIF,WAAW,EAAE,OAAOA,WAAW;EACnCA,WAAW,GAAG,CAAC,YAAY;IACzB,IAAIH,QAAQ,CAACM,EAAE,KAAK,SAAS,EAAE;MAC7B,IAAI,CAACJ,kBAAkB,EAAE;QACvB,MAAM,IAAIK,KAAK,CACb,kEACF,CAAC;MACH;MACA,MAAMC,IAAI,GAAG,MAAMN,kBAAkB,CAACO,cAAc,CAAC,CAAC;MACtDR,KAAK,CAACS,WAAW,CAACF,IAAI,CAAC;IACzB;IACA;EACF,CAAC,EAAE,CAAC,CAACG,KAAK,CAAEC,GAAG,IAAK;IAClBT,WAAW,GAAG,IAAI;IAClB,MAAMS,GAAG;EACX,CAAC,CAAC;EACF,OAAOT,WAAW;AACpB","ignoreList":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { setJiebaWasm } from "./NativeJieba.web.js";
|
|
4
|
+
let initPromise = null;
|
|
5
|
+
export function initJieba(options = {}) {
|
|
6
|
+
if (initPromise) return initPromise;
|
|
7
|
+
initPromise = (async () => {
|
|
8
|
+
// `jieba-wasm` resolves to its `web` build under the `browser`/`import`
|
|
9
|
+
// conditions, whose default export is an async initializer that fetches
|
|
10
|
+
// and instantiates the wasm binary.
|
|
11
|
+
const wasm = await import('jieba-wasm');
|
|
12
|
+
|
|
13
|
+
// With no argument, jieba-wasm's `web` initializer resolves the binary via
|
|
14
|
+
// `new URL('jieba_rs_wasm_bg.wasm', import.meta.url)` *relative to its own
|
|
15
|
+
// module*, which bundlers (Vite, Webpack 5, …) rewrite to the correct
|
|
16
|
+
// emitted asset URL in both dev and production. Only pass `wasmUrl` when the
|
|
17
|
+
// consumer explicitly overrides where the binary is served from — passing a
|
|
18
|
+
// wrong/relative path here makes the dev server return index.html and wasm
|
|
19
|
+
// instantiation fails with a bad magic word.
|
|
20
|
+
await wasm.default(options.wasmUrl);
|
|
21
|
+
setJiebaWasm(wasm);
|
|
22
|
+
})().catch(err => {
|
|
23
|
+
initPromise = null;
|
|
24
|
+
throw err;
|
|
25
|
+
});
|
|
26
|
+
return initPromise;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=init.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["setJiebaWasm","initPromise","initJieba","options","wasm","default","wasmUrl","catch","err"],"sourceRoot":"../../src","sources":["init.web.ts"],"mappings":";;AAAA,SAASA,YAAY,QAA8B,sBAAmB;AAKtE,IAAIC,WAAiC,GAAG,IAAI;AAE5C,OAAO,SAASC,SAASA,CAACC,OAAyB,GAAG,CAAC,CAAC,EAAiB;EACvE,IAAIF,WAAW,EAAE,OAAOA,WAAW;EACnCA,WAAW,GAAG,CAAC,YAAY;IACzB;IACA;IACA;IACA,MAAMG,IAAI,GAAI,MAAM,MAAM,CAAC,YAAY,CAEpB;;IAEnB;IACA;IACA;IACA;IACA;IACA;IACA;IACA,MAAMA,IAAI,CAACC,OAAO,CAACF,OAAO,CAACG,OAAO,CAAC;IACnCN,YAAY,CAACI,IAAI,CAAC;EACpB,CAAC,EAAE,CAAC,CAACG,KAAK,CAAEC,GAAG,IAAK;IAClBP,WAAW,GAAG,IAAI;IAClB,MAAMO,GAAG;EACX,CAAC,CAAC;EACF,OAAOP,WAAW;AACpB","ignoreList":[]}
|
package/lib/module/jieba.js
CHANGED
package/lib/module/jieba.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Jieba","cut","sentence","hmm","cutAll","cutForSearch","cutHMM","cutSmall","maxWordLen","tag","extract","topK","insertUserWord","word","find"],"sourceRoot":"../../src","sources":["jieba.ts"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,
|
|
1
|
+
{"version":3,"names":["Jieba","cut","sentence","hmm","cutAll","cutForSearch","cutHMM","cutSmall","maxWordLen","tag","extract","topK","insertUserWord","word","find"],"sourceRoot":"../../src","sources":["jieba.ts"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,eAAe;AAKjC,OAAO,SAASC,GAAGA,CAACC,QAAgB,EAAEC,GAAY,GAAG,IAAI,EAAY;EACnE,OAAOH,KAAK,CAACC,GAAG,CAACC,QAAQ,EAAEC,GAAG,CAAC;AACjC;AAEA,OAAO,SAASC,MAAMA,CAACF,QAAgB,EAAY;EACjD,OAAOF,KAAK,CAACI,MAAM,CAACF,QAAQ,CAAC;AAC/B;AAEA,OAAO,SAASG,YAAYA,CAACH,QAAgB,EAAEC,GAAY,GAAG,IAAI,EAAY;EAC5E,OAAOH,KAAK,CAACK,YAAY,CAACH,QAAQ,EAAEC,GAAG,CAAC;AAC1C;AAEA,OAAO,SAASG,MAAMA,CAACJ,QAAgB,EAAY;EACjD,OAAOF,KAAK,CAACM,MAAM,CAACJ,QAAQ,CAAC;AAC/B;AAEA,OAAO,SAASK,QAAQA,CAACL,QAAgB,EAAEM,UAAkB,EAAY;EACvE,OAAOR,KAAK,CAACO,QAAQ,CAACL,QAAQ,EAAEM,UAAU,CAAC;AAC7C;AAEA,OAAO,SAASC,GAAGA,CAACP,QAAgB,EAAY;EAC9C,OAAOF,KAAK,CAACS,GAAG,CAACP,QAAQ,CAAC;AAC5B;AAEA,OAAO,SAASQ,OAAOA,CAACR,QAAgB,EAAES,IAAY,GAAG,CAAC,EAAa;EACrE,OAAOX,KAAK,CAACU,OAAO,CAACR,QAAQ,EAAES,IAAI,CAAC;AACtC;AAEA,OAAO,SAASC,cAAcA,CAACC,IAAY,EAAEJ,GAAW,GAAG,EAAE,EAAW;EACtE,OAAOT,KAAK,CAACY,cAAc,CAACC,IAAI,EAAEJ,GAAG,CAAC;AACxC;AAEA,OAAO,SAASK,IAAIA,CAACD,IAAY,EAAW;EAC1C,OAAOb,KAAK,CAACc,IAAI,CAACD,IAAI,CAAC;AACzB","ignoreList":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Spec } from './NativeJieba';
|
|
2
|
+
export type JiebaWasmModule = {
|
|
3
|
+
cut(text: string, hmm?: boolean | null): string[];
|
|
4
|
+
cut_all(text: string): string[];
|
|
5
|
+
cut_for_search(text: string, hmm?: boolean | null): string[];
|
|
6
|
+
tag(sentence: string, hmm?: boolean | null): Array<{
|
|
7
|
+
word: string;
|
|
8
|
+
tag: string;
|
|
9
|
+
}>;
|
|
10
|
+
add_word(word: string, freq?: number | null, tag?: string | null): number;
|
|
11
|
+
};
|
|
12
|
+
export declare function setJiebaWasm(module: JiebaWasmModule): void;
|
|
13
|
+
declare const Jieba: Spec;
|
|
14
|
+
export default Jieba;
|
|
15
|
+
//# sourceMappingURL=NativeJieba.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeJieba.web.d.ts","sourceRoot":"","sources":["../../../src/NativeJieba.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAQ1C,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;IAClD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;IAC7D,GAAG,CACD,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,GACnB,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;CAC3E,CAAC;AAIF,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAE1D;AAYD,QAAA,MAAM,KAAK,EAAE,IA4CZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type InitJiebaOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Web only: URL (or fetch input) for the jieba-wasm `.wasm` binary. Most
|
|
4
|
+
* bundlers resolve it automatically, so this is only needed when the asset
|
|
5
|
+
* is served from a custom location. Ignored on iOS and Android.
|
|
6
|
+
*/
|
|
7
|
+
wasmUrl?: string | URL | Request;
|
|
8
|
+
};
|
|
9
|
+
export declare function initJieba(_options?: InitJiebaOptions): Promise<void>;
|
|
2
10
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/init.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;CAClC,CAAC;AAIF,wBAAgB,SAAS,CAAC,QAAQ,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.web.d.ts","sourceRoot":"","sources":["../../../src/init.web.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAI/C,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jieba.d.ts","sourceRoot":"","sources":["../../../src/jieba.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,OAAc,GAAG,MAAM,EAAE,CAEnE;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjD;AAED,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"jieba.d.ts","sourceRoot":"","sources":["../../../src/jieba.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,OAAc,GAAG,MAAM,EAAE,CAEnE;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,OAAc,GAAG,MAAM,EAAE,CAE5E;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEjD;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE;AAED,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9C;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,GAAG,OAAO,EAAE,CAErE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAW,GAAG,OAAO,CAEtE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-jieba",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Native Chinese text segmentation for React Native, powered by cppjieba.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"eslint-plugin-ft-flow": "^3.0.11",
|
|
95
95
|
"eslint-plugin-prettier": "^5.5.5",
|
|
96
96
|
"jest": "^30.3.0",
|
|
97
|
+
"jieba-wasm": "^2.4.0",
|
|
97
98
|
"lefthook": "^2.1.4",
|
|
98
99
|
"prettier": "^3.8.1",
|
|
99
100
|
"react": "19.2.3",
|
|
@@ -105,9 +106,15 @@
|
|
|
105
106
|
"typescript": "^6.0.2"
|
|
106
107
|
},
|
|
107
108
|
"peerDependencies": {
|
|
109
|
+
"jieba-wasm": ">=2.0.0",
|
|
108
110
|
"react": ">=18.0.0",
|
|
109
111
|
"react-native": ">=0.85.0"
|
|
110
112
|
},
|
|
113
|
+
"peerDependenciesMeta": {
|
|
114
|
+
"jieba-wasm": {
|
|
115
|
+
"optional": true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
111
118
|
"workspaces": [
|
|
112
119
|
"example"
|
|
113
120
|
],
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Spec } from './NativeJieba';
|
|
2
|
+
|
|
3
|
+
// `jieba-wasm` exposes the same segmentation primitives as cppjieba, but a
|
|
4
|
+
// smaller surface: cut / cutAll / cutForSearch / tag / add_word. The remaining
|
|
5
|
+
// native methods are polyfilled on top of those where the semantics allow, and
|
|
6
|
+
// throw otherwise. The wasm module is loaded lazily by `initJieba()` (see
|
|
7
|
+
// `init.web.ts`) and handed to this shim via `setJiebaWasm`.
|
|
8
|
+
|
|
9
|
+
export type JiebaWasmModule = {
|
|
10
|
+
cut(text: string, hmm?: boolean | null): string[];
|
|
11
|
+
cut_all(text: string): string[];
|
|
12
|
+
cut_for_search(text: string, hmm?: boolean | null): string[];
|
|
13
|
+
tag(
|
|
14
|
+
sentence: string,
|
|
15
|
+
hmm?: boolean | null
|
|
16
|
+
): Array<{ word: string; tag: string }>;
|
|
17
|
+
add_word(word: string, freq?: number | null, tag?: string | null): number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let wasm: JiebaWasmModule | null = null;
|
|
21
|
+
|
|
22
|
+
export function setJiebaWasm(module: JiebaWasmModule): void {
|
|
23
|
+
wasm = module;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getWasm(): JiebaWasmModule {
|
|
27
|
+
if (!wasm) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'react-native-jieba: jieba-wasm is not initialized. ' +
|
|
30
|
+
'Call (and await) initJieba() before any segmentation call.'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return wasm;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const Jieba: Spec = {
|
|
37
|
+
setDictPath() {
|
|
38
|
+
// No-op on web: jieba-wasm bundles its own dictionary.
|
|
39
|
+
},
|
|
40
|
+
cut(sentence, hmm) {
|
|
41
|
+
return getWasm().cut(sentence, hmm);
|
|
42
|
+
},
|
|
43
|
+
cutAll(sentence) {
|
|
44
|
+
return getWasm().cut_all(sentence);
|
|
45
|
+
},
|
|
46
|
+
cutForSearch(sentence, hmm) {
|
|
47
|
+
return getWasm().cut_for_search(sentence, hmm);
|
|
48
|
+
},
|
|
49
|
+
cutHMM(sentence) {
|
|
50
|
+
// jieba-wasm has no HMM-only mode; precise cut with HMM enabled is the
|
|
51
|
+
// closest equivalent.
|
|
52
|
+
return getWasm().cut(sentence, true);
|
|
53
|
+
},
|
|
54
|
+
cutSmall(sentence, _maxWordLen) {
|
|
55
|
+
// jieba-wasm does not expose a max-word-length cut; fall back to precise
|
|
56
|
+
// cut. The maxWordLen argument is accepted for API parity but ignored.
|
|
57
|
+
return getWasm().cut(sentence, true);
|
|
58
|
+
},
|
|
59
|
+
tag(sentence) {
|
|
60
|
+
return getWasm().tag(sentence);
|
|
61
|
+
},
|
|
62
|
+
extract() {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'react-native-jieba: extract() (TF-IDF keyword extraction) is not ' +
|
|
65
|
+
'supported on web — jieba-wasm does not ship the IDF dictionary.'
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
insertUserWord(word, tag) {
|
|
69
|
+
// add_word returns the inserted word's frequency (>= 0 on success).
|
|
70
|
+
return (
|
|
71
|
+
getWasm().add_word(word, undefined, tag === '' ? undefined : tag) >= 0
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
find(word) {
|
|
75
|
+
// jieba-wasm has no dictionary lookup; approximate it by checking whether
|
|
76
|
+
// the word survives precise (non-HMM) segmentation as a single token.
|
|
77
|
+
const segments = getWasm().cut(word, false);
|
|
78
|
+
return segments.length === 1 && segments[0] === word;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default Jieba;
|
package/src/init.ts
CHANGED
|
@@ -2,9 +2,18 @@ import { Platform } from 'react-native';
|
|
|
2
2
|
import Jieba from './NativeJieba';
|
|
3
3
|
import JiebaAndroidHelper from './NativeJiebaAndroidHelper';
|
|
4
4
|
|
|
5
|
+
export type InitJiebaOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Web only: URL (or fetch input) for the jieba-wasm `.wasm` binary. Most
|
|
8
|
+
* bundlers resolve it automatically, so this is only needed when the asset
|
|
9
|
+
* is served from a custom location. Ignored on iOS and Android.
|
|
10
|
+
*/
|
|
11
|
+
wasmUrl?: string | URL | Request;
|
|
12
|
+
};
|
|
13
|
+
|
|
5
14
|
let initPromise: Promise<void> | null = null;
|
|
6
15
|
|
|
7
|
-
export function initJieba(): Promise<void> {
|
|
16
|
+
export function initJieba(_options: InitJiebaOptions = {}): Promise<void> {
|
|
8
17
|
if (initPromise) return initPromise;
|
|
9
18
|
initPromise = (async () => {
|
|
10
19
|
if (Platform.OS === 'android') {
|
package/src/init.web.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { setJiebaWasm, type JiebaWasmModule } from './NativeJieba.web';
|
|
2
|
+
import type { InitJiebaOptions } from './init';
|
|
3
|
+
|
|
4
|
+
export type { InitJiebaOptions } from './init';
|
|
5
|
+
|
|
6
|
+
let initPromise: Promise<void> | null = null;
|
|
7
|
+
|
|
8
|
+
export function initJieba(options: InitJiebaOptions = {}): Promise<void> {
|
|
9
|
+
if (initPromise) return initPromise;
|
|
10
|
+
initPromise = (async () => {
|
|
11
|
+
// `jieba-wasm` resolves to its `web` build under the `browser`/`import`
|
|
12
|
+
// conditions, whose default export is an async initializer that fetches
|
|
13
|
+
// and instantiates the wasm binary.
|
|
14
|
+
const wasm = (await import('jieba-wasm')) as unknown as {
|
|
15
|
+
default: (input?: string | URL | Request) => Promise<unknown>;
|
|
16
|
+
} & JiebaWasmModule;
|
|
17
|
+
|
|
18
|
+
// With no argument, jieba-wasm's `web` initializer resolves the binary via
|
|
19
|
+
// `new URL('jieba_rs_wasm_bg.wasm', import.meta.url)` *relative to its own
|
|
20
|
+
// module*, which bundlers (Vite, Webpack 5, …) rewrite to the correct
|
|
21
|
+
// emitted asset URL in both dev and production. Only pass `wasmUrl` when the
|
|
22
|
+
// consumer explicitly overrides where the binary is served from — passing a
|
|
23
|
+
// wrong/relative path here makes the dev server return index.html and wasm
|
|
24
|
+
// instantiation fails with a bad magic word.
|
|
25
|
+
await wasm.default(options.wasmUrl);
|
|
26
|
+
setJiebaWasm(wasm);
|
|
27
|
+
})().catch((err) => {
|
|
28
|
+
initPromise = null;
|
|
29
|
+
throw err;
|
|
30
|
+
});
|
|
31
|
+
return initPromise;
|
|
32
|
+
}
|
package/src/jieba.ts
CHANGED
|
@@ -11,10 +11,7 @@ export function cutAll(sentence: string): string[] {
|
|
|
11
11
|
return Jieba.cutAll(sentence);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function cutForSearch(
|
|
15
|
-
sentence: string,
|
|
16
|
-
hmm: boolean = true
|
|
17
|
-
): string[] {
|
|
14
|
+
export function cutForSearch(sentence: string, hmm: boolean = true): string[] {
|
|
18
15
|
return Jieba.cutForSearch(sentence, hmm);
|
|
19
16
|
}
|
|
20
17
|
|