Skip to content

API Reference

This page documents the JavaScript / WASM binding of Suzume, published to npm as @libraz/suzume. Python, Go, C/C++, and the two command-line interfaces have separate guides.

Suzume Class

The main class for Japanese tokenization.

Suzume.create(options?)

Creates a new Suzume instance.

typescript
static async create(options?: SuzumeOptions & { wasmPath?: string }): Promise<Suzume>

SuzumeOptions:

OptionTypeDefaultDescription
wasmPathstringundefinedCustom path to WASM file
freshWasmModulebooleanfalseInstantiate an isolated WASM runtime instead of using the shared cached runtime
preserveVubooleantruePreserve ヴ (don't normalize to ビ etc.)
preserveCasebooleantruePreserve case (don't lowercase ASCII)
preserveSymbolsbooleanfalsePreserve punctuation-like SYMBOL tokens; emoji and content-bearing symbols remain OTHER regardless of this option
mode'normal' | 'search' | 'split''normal'Analysis mode. Use search or split for search-oriented segmentation
lemmatizebooleantrueKeep corrected dictionary forms; POS and conjugation annotations are computed either way
mergeCompoundsbooleanfalseMerge consecutive noun compounds where possible
skipUserDictionarybooleanfalseSkip automatic loading of the bundled user dictionary
skipCoreDictionarybooleanfalseSkip automatic loading of the bundled L2 core dictionary
skipEnvConfigbooleanfalseIgnore native scorer configuration environment variables
reportScorerConfigbooleanfalseAdd scorer configuration diagnostics to dictionaryWarnings
scorerOptionsstring | Record<string, unknown>undefinedFinal-priority scorer overrides, supplied as JSON text or an object serialized to JSON

Currency and unit signs, arrows, mathematical or technical marks, and emoji carry text content, so the default analysis keeps them as OTHER. Set preserveSymbols: true only when punctuation-like tokens such as must also appear in the result.

Returns: Promise<Suzume>

Example:

typescript
// Default usage
const defaultSuzume = await Suzume.create()
defaultSuzume.destroy()

// Custom WASM path
const customWasmSuzume = await Suzume.create({ wasmPath: '/path/to/suzume.wasm' })
customWasmSuzume.destroy()

// With options
const searchSuzume = await Suzume.create({
  preserveSymbols: true,
  preserveVu: false,
  mode: 'search',
  mergeCompounds: true,
  scorerOptions: {
    unary: { noun_prior: 0.25 },
  },
})
searchSuzume.destroy()

Analysis modes:

The mode option controls how text is segmented:

  • normal — balanced segmentation for general use (default).
  • search — search-oriented output that merges consecutive noun compounds into larger searchable units.
  • split — the most aggressive segmentation, breaking compounds into their smallest meaningful units.

In normal mode, mergeCompounds controls noun-compound merging. search enables merging, while split disables it.

scorerOptions is validated during construction, and malformed JSON makes Suzume.create() reject. reportScorerConfig: true records the active configuration in dictionaryWarnings. The WASM build does not read the native scorer environment layer, so skipEnvConfig has no additional effect in this binding.

Shared WASM runtime

By default, calls with the same wasmPath share one cached WASM runtime. Each Suzume object has its own analyzer handle and options, but the handles use the same WebAssembly linear memory. destroy() releases one handle; it does not unload the cached runtime or affect other handles.

Set freshWasmModule: true when an instance must have an isolated runtime. The standalone version() function uses the same cache unless it also receives freshWasmModule: true.


mode

Reads or changes the analysis mode without reloading dictionaries.

typescript
get mode(): 'normal' | 'search' | 'split'
set mode(value: 'normal' | 'search' | 'split')
typescript
console.log(suzume.mode) // "normal"
suzume.mode = 'split'

analyze(text)

Analyzes Japanese text and returns an array of tokens.

typescript
analyze(text: string): Morpheme[]
ParameterTypeDescription
textstringJapanese text to analyze

Returns: Morpheme[]

Example:

typescript
const result = suzume.analyze('東京に行きました')

// Result:
// [
//   { surface: '東京', pos: 'NOUN', posJa: '名詞', ... },
//   { surface: 'に', pos: 'PARTICLE', posJa: '助詞', ... },
//   { surface: '行き', pos: 'VERB', posJa: '動詞', ... },
//   { surface: 'まし', pos: 'AUX', posJa: '助動詞', ... },
//   { surface: 'た', pos: 'AUX', posJa: '助動詞', ... }
// ]

analyzeWithNormalizedText(text)

Analyzes text and returns both the morphemes and the exact normalized string their offsets refer to.

typescript
interface AnalysisResult {
  normalizedText: string
  morphemes: Morpheme[]
}

analyzeWithNormalizedText(text: string): AnalysisResult

Use the UTF-16 offsets when slicing a JavaScript string:

typescript
const { normalizedText, morphemes } =
  suzume.analyzeWithNormalizedText('🎉𠮷字を読む')

for (const morpheme of morphemes) {
  const surface = normalizedText.slice(
    morpheme.startUtf16,
    morpheme.endUtf16,
  )
  console.log(surface)
}

start and end are Unicode code-point offsets into normalizedText. startUtf16 and endUtf16 are JavaScript UTF-16 code-unit offsets and can be passed directly to String.prototype.slice(). The two sets differ before or across characters outside the Basic Multilingual Plane, including many emoji and rare kanji. Offsets refer to normalized text, which may differ from the input. Content-bearing symbols and emoji stay in the default output as OTHER, so their ranges remain represented even when preserveSymbols is false.


generateTags(text, options?)

Generates tags for search indexing, classification, and content analysis. By default it returns content words (nouns, verbs, adjectives, and adverbs) while filtering out particles, auxiliaries, formal nouns, and low-information words.

typescript
generateTags(text: string, options?: TagOptions): Tag[]

Tag:

PropertyTypeDescription
tagstringTag text (surface or lemma depending on useLemma)
posstringPart of speech (NOUN, VERB, ADJ, ADV, etc.)
ParameterTypeDescription
textstringJapanese text to extract tags from
optionsTagOptionsOptional tag generation settings

TagOptions:

OptionTypeDefaultDescription
posFilterreadonly TagPosFilterName[]undefined (all)POS categories to include; an empty array also includes every filterable category
posreadonly TagPosFilterName[]undefinedDeprecated alias for posFilter; posFilter wins when both are present
excludeBasicbooleanfalseExclude basic verbs/words with hiragana-only lemma
useLemmabooleantrueUse lemma (dictionary form) instead of surface form
minLengthnumber2Minimum tag length in characters
maxTagsnumber0Maximum number of tags (0 = unlimited)
excludeParticlesbooleantrueExclude particles
excludeAuxiliariesbooleantrueExclude auxiliaries
excludeFormalNounsbooleantrueExclude formal nouns such as こと and もの
excludeLowInfobooleantrueExclude low-information words
removeDuplicatesbooleantrueRemove duplicate tags

TagPosFilterName is 'noun' | 'verb' | 'adjective' | 'adverb' | 'particle' | 'auxiliary'. Unknown names throw an Error. Particles and auxiliaries also require their exclusion option to be disabled.

Returns: Tag[]

Examples:

typescript
// Basic usage
const tags = suzume.generateTags('東京スカイツリーに行きました')
// [{ tag: '東京', pos: 'NOUN' },
//  { tag: 'スカイツリー', pos: 'NOUN' },
//  { tag: '行く', pos: 'VERB' }]

// Nouns only
const nouns = suzume.generateTags('美しい花が静かに咲いている', {
  posFilter: ['noun'],
  minLength: 1,
})
// [{ tag: '花', pos: 'NOUN' }]

// Particles and auxiliaries
const functionWords = suzume.generateTags('花が咲きます', {
  posFilter: ['particle', 'auxiliary'],
  excludeParticles: false,
  excludeAuxiliaries: false,
  minLength: 1,
})
// [{ tag: 'が', pos: 'PARTICLE' },
//  { tag: 'ます', pos: 'AUX' }]

// Exclude basic verbs (hiragana-only lemma like する, いる, ある, なる...)
const tags2 = suzume.generateTags('新しいプロジェクトを開始して管理する', {
  excludeBasic: false
})
// [{ tag: '新しい', pos: 'ADJ' },
//  { tag: 'プロジェクト', pos: 'NOUN' },
//  { tag: '開始', pos: 'NOUN' },
//  { tag: 'する', pos: 'VERB' },
//  { tag: '管理', pos: 'NOUN' }]

const tags3 = suzume.generateTags('新しいプロジェクトを開始して管理する', {
  excludeBasic: true
})
// [{ tag: '新しい', pos: 'ADJ' },
//  { tag: 'プロジェクト', pos: 'NOUN' },
//  { tag: '開始', pos: 'NOUN' },
//  { tag: '管理', pos: 'NOUN' }]
// 'する' is excluded (lemma is hiragana-only)

// Limit results
const top3 = suzume.generateTags('東京タワーと東京スカイツリーを見学しました', {
  maxTags: 3
})
// [{ tag: '東京', pos: 'NOUN' },
//  { tag: 'タワー', pos: 'NOUN' },
//  { tag: 'スカイツリー', pos: 'NOUN' }]

excludeBasic

excludeBasic: true filters out words whose lemma (dictionary form) is written entirely in hiragana. It removes entries such as する, いる, ある, なる, いく, and くる while keeping kanji-containing entries such as 開始, 管理, and 確認.

Filter pipeline

The tag generator applies these filters in order:

  1. Particles — excluded when excludeParticles is true (default)
  2. Auxiliaries — excluded when excludeAuxiliaries is true (default)
  3. Formal nouns — excluded when excludeFormalNouns is true (default)
  4. Low-info words — excluded when excludeLowInfo is true (default)
  5. Conjunctions — always excluded
  6. Symbols — always excluded
  7. POS filter — if posFilter is non-empty, only matching categories pass
  8. Basic words — if excludeBasic: true, words with hiragana-only lemma are excluded
  9. Tag text — the lemma or surface is selected according to useLemma
  10. Min length — tags shorter than minLength Unicode characters are excluded
  11. Deduplication — duplicate tags are removed when removeDuplicates is true
  12. Result limit — generation stops at maxTags; 0 is unlimited

loadUserDictionary(data)

Adds source dictionary entries to the analyzer. Loads are cumulative until clearUserDictionaries() is called.

typescript
loadUserDictionary(data: string): boolean
ParameterTypeDescription
datastringDictionary entries in the current TSV format; legacy CSV is also accepted

Returns: booleantrue when at least one expanded entry was installed.

Current format: surface<TAB>POS[<TAB>conj_type][<TAB>lemma]. The conjugation type is optional; specify it when inflected forms should be expanded. A third field that is not a recognized conjugation type is treated as the lemma. See User Dictionaries for the complete format.

Example:

typescript
// Single entry
suzume.loadUserDictionary('ChatGPT\tNOUN\n')

// Multiple entries
suzume.loadUserDictionary(`
ChatGPT	NOUN
スカイツリー	NOUN
DeepL	NOUN
`)

// Conjugating entry
suzume.loadUserDictionary('検査する\tVERB\tSURU\n')

loadUserDictionaryCount(data)

Loads a source dictionary and returns the number of expanded entries installed.

typescript
loadUserDictionaryCount(data: string): number

One source row can install multiple entries when Suzume expands conjugated forms, so the result can exceed the number of rows. A return value of 0 means the load failed; inspect lastError and lastErrorCode, or use loadUserDictionaryOrThrow(). Nonfatal skipped-row and expansion diagnostics are appended to dictionaryWarnings.


loadUserDictionaryOrThrow(data)

Loads a source user dictionary and throws a SuzumeError with C API details when no entry can be installed.

typescript
loadUserDictionaryOrThrow(data: string): void

Use this form during setup or tests when a malformed dictionary should fail fast.


loadBinaryDictionary(data)

Adds a compiled binary dictionary (.dic) at runtime. Binary and source dictionary loads are cumulative.

typescript
loadBinaryDictionary(data: Uint8Array): boolean
ParameterTypeDescription
dataUint8ArrayBinary dictionary data (.dic format)

Returns: boolean - true on success

Example:

typescript
// Load from file (Node.js)
import { readFile } from 'fs/promises'
const dictData = new Uint8Array(await readFile('custom.dic'))
suzume.loadBinaryDictionary(dictData)

// Load from URL (Browser)
const response = await fetch('/dictionaries/custom.dic')
const browserDictData = new Uint8Array(await response.arrayBuffer())
suzume.loadBinaryDictionary(browserDictData)

Binary vs source dictionaries

Binary dictionaries (.dic) load faster than source TSV. Use suzume-cli dict compile to compile a TSV dictionary.


loadBinaryDictionaryOrThrow(data)

Loads a compiled binary dictionary and throws an error with C API details when loading fails.

typescript
loadBinaryDictionaryOrThrow(data: Uint8Array): void

clearUserDictionaries()

Removes dictionaries loaded by the caller and clears their runtime warnings. The automatically loaded bundled user dictionary, if present, remains installed.

typescript
clearUserDictionaries(): void

hasCoreDictionary

Reports whether the bundled L2 core dictionary is loaded.

typescript
get hasCoreDictionary(): boolean

This is false when the analyzer was created with skipCoreDictionary: true or when automatic core-dictionary loading failed.


version

Gets the Suzume version string.

typescript
get version(): string

Example:

typescript
console.log(suzume.version) // "0.9.9"

This getter does not require a live analyzer handle and remains available after destroy().


version(options?)

Returns the version without creating an analyzer handle.

typescript
import { version } from '@libraz/suzume'

const current = await version()
console.log(current) // "0.9.9"
typescript
function version(options?: {
  wasmPath?: string
  freshWasmModule?: boolean
}): Promise<string>

The function is asynchronous because it must instantiate or retrieve the WASM runtime.


lastError

Returns the last C API error for the current thread, or an empty string if the last C API call succeeded.

typescript
get lastError(): string

Read it immediately after a method returns false or 0; a later C API call can replace it.


lastErrorCode

Returns the stable native error category for the last failed C ABI call.

typescript
get lastErrorCode(): ErrorCode

dictionaryWarnings

Returns nonfatal diagnostics recorded for this analyzer.

typescript
get dictionaryWarnings(): string[]

The array contains constructor-time dictionary-loading diagnostics, optional scorer-configuration diagnostics, and warnings from successful source dictionary loads, such as skipped records or duplicate expanded entries. clearUserDictionaries() removes warnings from caller-loaded source dictionaries while retaining construction diagnostics. A fatal load failure is reported through the method's return value or exception and through lastError / lastErrorCode.


wasmMemoryBytes()

Returns the current size of this runtime's WebAssembly linear memory in bytes.

typescript
wasmMemoryBytes(): number

Instances on the shared runtime report the same underlying memory size.


destroy()

Releases this analyzer handle and its allocations. The shared WASM runtime remains cached for other and future instances.

typescript
destroy(): void

Automatic cleanup via FinalizationRegistry

Suzume registers a FinalizationRegistry callback, so resources will be freed automatically when the instance is garbage collected. However, calling destroy() explicitly is recommended for immediate cleanup — especially in Node.js where GC timing is unpredictable and WASM memory is not visible to the GC's heap pressure heuristics.

Example:

typescript
const suzume = await Suzume.create()
// ... use suzume ...
suzume.destroy() // Free resources immediately

Morpheme Interface

Represents a single linguistic token.

typescript
interface Morpheme {
  surface: string      // Surface form (as appears in text)
  pos: string          // Part of speech (English)
  baseForm: string     // Base/dictionary form
  posJa: string        // Part of speech (Japanese)
  conjType: string | null  // Conjugation type
  conjForm: string | null  // Conjugation form
  extendedPos: string  // Stable extended POS code (e.g. "VERB_連用")
  start: number        // Start Unicode code-point offset in normalized text
  end: number          // End Unicode code-point offset in normalized text
  startUtf16: number   // Start JavaScript UTF-16 offset
  endUtf16: number     // End JavaScript UTF-16 offset
  isUserDict: boolean
  isFormalNoun: boolean
  isLowInfo: boolean
  isUnknown: boolean
  isFromDictionary: boolean
  score: number
}

Properties

PropertyTypeDescriptionExample
surfacestringSurface form as it appears in text"食べ"
posstringPart of speech in English"VERB"
baseFormstringDictionary/base form"食べる"
posJastringPart of speech in Japanese"動詞"
conjTypestring | nullConjugation type (for verbs/adjectives)"一段"
conjFormstring | nullConjugation form"連用形"
extendedPosstringStable extended POS code"VERB_連用"
startnumberStart Unicode code-point offset in normalized text0
endnumberEnd Unicode code-point offset in normalized text2
startUtf16numberStart JavaScript UTF-16 offset in normalized text0
endUtf16numberEnd JavaScript UTF-16 offset in normalized text2
isUserDictbooleanTrue when matched from a user dictionaryfalse
isFormalNounbooleanTrue for formal nouns such as こと and ものfalse
isLowInfobooleanTrue when marked as low information for tag generationfalse
isUnknownbooleanTrue when generated as an unknown-word candidatefalse
isFromDictionarybooleanTrue when matched from any dictionarytrue
scorenumberCandidate score/cost used by the analyzer12.5

Part of Speech Values

posposJaDescription
NOUN名詞Nouns
VERB動詞Verbs
ADJ形容詞Adjectives
ADV副詞Adverbs
PARTICLE助詞Particles
AUX助動詞Auxiliary verbs
PRON代名詞Pronouns
DET連体詞Adnominal adjectives
CONJ接続詞Conjunctions
INTJ感動詞Interjections
PREFIX接頭辞Prefixes
SUFFIX接尾辞Suffixes
SYMBOL記号Symbols
OTHERその他Other/Unknown

Extended POS Values

The extendedPos property provides fine-grained subcategories beyond the basic pos tag. This is useful when you need to distinguish conjugation forms, particle roles, auxiliary functions, or noun subtypes.

Verb forms:

ValueDescriptionExample
VERB_終止終止形: dictionary form食べる, 書く
VERB_連用連用形: continuative form食べ, 書き
VERB_未然未然形: irrealis form食べ-, 書か-
VERB_音便音便形: euphonic change書い-, 泳い-
VERB_て形て形食べて, 書いて
VERB_仮定仮定形: conditional食べれば, 書けば
VERB_仮定縮約Colloquial conditional with fused ば行きゃ, 食べりゃ, すりゃ
VERB_命令命令形: imperative食べろ, 書け
VERB_連体連体形: attributive(same as shuushi in modern Japanese)
VERB_た形た形: past食べた, 書いた
VERB_たら形たら形: conditional past食べたら, 書いたら

Adjective forms:

ValueDescriptionExample
ADJ_終止終止形: basic form美しい, 高い
ADJ_連用連用形(く): adverbial美しく, 高く
ADJ_語幹語幹: stem (ガル接続)美し-, 高-
ADJ_かっかっ形: past stem美しかっ-, 高かっ-
ADJ_け形け形: conditional stem美しけれ-
ADJ_未然未然形美しくな-
ADJ_NAナ形容詞: na-adjective stem静か, 綺麗

Auxiliaries:

ValueDescriptionExample
AUX_過去過去: past tenseた, だ
AUX_丁寧丁寧: politeます, まし, ませ
AUX_否定否定ない, なかっ
AUX_否定古否定(古語)ぬ, ん
AUX_打消推量打消推量まい
AUX_文語断定文語の断定なり
AUX_文語過去文語の過去けり
AUX_文語断定連体文語の断定・連体たる
AUX_文語完了文語の完了つ, ぬ
AUX_文語過去キClassical past auxiliary き and its inflectionsき, し, しか
AUX_文語当為文語の当為べし
AUX_不可能不可能かねる
AUX_授受授受あげる, くれる, もらう
AUX_願望願望たい, たかっ
AUX_意志意志/推量う, よう
AUX_受身受身れる, られる
AUX_使役使役せる, させる
AUX_可能可能れる, られる
AUX_継続継続いる, い, おる
AUX_完了完了しまう, ちゃう
AUX_準備準備おく, とく
AUX_試行試行みる
AUX_進行進行方向いく
AUX_接近接近くる
AUX_開始開始はじめる
AUX_様態様態そう
AUX_推定推定らしい
AUX_みたい推定みたい
AUX_断定断定だ, で, な, なら
AUX_丁寧断定丁寧断定です, でし
AUX_尊敬尊敬れる, られる
AUX_丁重丁重ござる
AUX_過度過度すぎる
AUX_ガルガル接続がる
AUX_よう様態・比況よう
AUX_KURUWA_POLITE丁寧な補助表現くるわ

Particles:

ValueDescriptionExample
PART_格格助詞が, を, に, で, へ, と, から, まで, より
PART_係係助詞は, も
PART_終終助詞ね, よ, わ, な, か
PART_接続接続助詞て, で, ば, ながら, たり, けど
PART_引用引用助詞と(引用)
PART_副副助詞ばかり, だけ, ほど, しか, など
PART_準体準体助詞
PART_係結係結びこそ, さえ, すら

Nouns:

ValueDescriptionExample
NOUN普通名詞東京, 天気
NOUN_形式形式名詞こと, もの, ところ, わけ
NOUN_転成連用形転成名詞読み, 書き
NOUN_固有固有名詞
NOUN_姓固有名詞(姓)田中, 鈴木
NOUN_名固有名詞(名)太郎
NOUN_数数詞一, 100

Other:

ValueDescription
PRON代名詞
PRON_疑問疑問詞 (何, 誰, どこ)
ADV副詞
ADV_引用引用副詞 (そう, こう)
CONJ接続詞
DET連体詞
PREFIX接頭辞
SUFFIX接尾辞
SUFFIX_直後直後を表す接尾辞
SUFFIX_傾向傾向を表す接尾辞
DET_引用引用を伴う連体詞
SYMBOL記号
INTJ感動詞
OTHERその他
UNKNOWN不明

Error Handling

Native failures are represented by SuzumeError, which extends Error and carries a stable ErrorCode.

typescript
enum ErrorCode {
  Success = 0,
  InvalidUtf8 = 1,
  DictionaryLoadFailed = 2,
  FileNotFound = 3,
  Parse = 4,
  OutOfMemory = 5,
  InvalidInput = 6,
  Internal = 7,
}

class SuzumeError extends Error {
  readonly code: ErrorCode
  constructor(message: string, code?: ErrorCode)
}
typescript
import { ErrorCode, Suzume, SuzumeError } from '@libraz/suzume'

let suzume: Suzume | undefined
try {
  suzume = await Suzume.create()
  suzume.analyze('\uD800') // unpaired UTF-16 surrogate
} catch (error) {
  if (error instanceof SuzumeError) {
    console.error(ErrorCode[error.code], error.message)
  }
} finally {
  suzume?.destroy()
}

Suzume.create(), analyze(), analyzeWithNormalizedText(), generateTags(), the OrThrow dictionary methods, mode changes, and clearUserDictionaries() throw on native failure. The non-throwing dictionary methods return false or 0; use lastError and lastErrorCode for details.

WebAssembly out-of-memory behavior

An allocation failure aborts the WASM runtime instead of returning a normal OutOfMemory result. It does not follow the catchable SuzumeError path, and the affected runtime cannot be reused. Because instances share a runtime by default, an abort also invalidates the other handles on that runtime. Process long documents in chunks, and use freshWasmModule: true when failure isolation is required.


Memory Management

Suzume uses WebAssembly which allocates memory outside the JavaScript heap. A FinalizationRegistry ensures cleanup on GC, but explicit destroy() is strongly recommended — especially in Node.js where GC timing is unpredictable and WASM memory is invisible to the GC's heap pressure heuristics.

typescript
// Good: Clean up when done
const suzume = await Suzume.create()
try {
  const result = suzume.analyze(text)
  // process result...
} finally {
  suzume.destroy()
}

// For long-running apps: reuse the instance
class MyApp {
  private suzume: Suzume | null = null

  async init() {
    this.suzume = await Suzume.create()
  }

  analyze(text: string) {
    return this.suzume?.analyze(text) ?? []
  }

  dispose() {
    this.suzume?.destroy()
    this.suzume = null
  }
}

Node.js

In Node.js, WASM memory is not tracked by V8's heap size. If you create many handles without calling destroy(), memory usage can grow even though the GC sees no pressure. Call destroy() explicitly in server-side code.