Skip to content

Commit

Permalink
BREAKING CHANGE: require loader function
Browse files Browse the repository at this point in the history
Problem:
`import fs from "node:fs"` is not always feasible.

Solution:
Leave the mechanism to load wasm files to the user of the script.
It is required now to configure a `loader` function.

Notes:
- hyphenopoly.deno.js is not longer needed
- Tests and docs are updated accordingly
Fixes #195, Fixes #196
  • Loading branch information
mnater committed Oct 20, 2022
1 parent 24e64cd commit ec563f0
Show file tree
Hide file tree
Showing 24 changed files with 738 additions and 1,120 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Version History

## Version 5.0.0-beta-6 (2022-10-20)
### Breaking changes
* require loader function

## Version 5.0.0-beta-5 (2022-09-29)
### Fixed
* created and updated patterns for german
Expand Down
2 changes: 1 addition & 1 deletion Hyphenopoly.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @license Hyphenopoly 5.0.0-beta.5 - client side hyphenation for webbrowsers
* @license Hyphenopoly 5.0.0-beta.6 - client side hyphenation for webbrowsers
* ©2022 Mathias Nater, Güttingen (mathiasnater at gmail dot com)
* https://github.com/mnater/Hyphenopoly
*
Expand Down
2 changes: 1 addition & 1 deletion Hyphenopoly_Loader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @license Hyphenopoly_Loader 5.0.0-beta.5 - client side hyphenation
* @license Hyphenopoly_Loader 5.0.0-beta.6 - client side hyphenation
* ©2022 Mathias Nater, Güttingen (mathiasnater at gmail dot com)
* https://github.com/mnater/Hyphenopoly
*
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ import hyphenopoly from "hyphenopoly";
const hyphenator = hyphenopoly.config({
"require": ["de", "en-us"],
"hyphen": "",
"loader": async (file) => {
const {readFile} = await import("node:fs/promises");
const {dirname} = await import("node:path");
const {fileURLToPath} = await import("node:url");
const cwd = dirname(fileURLToPath(import.meta.url));
return readFile(`${cwd}/../patterns/${file}`);
},
"exceptions": {
"en-us": "en-han-ces"
}
Expand Down
274 changes: 274 additions & 0 deletions docs/Module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
# hyphenopoly module

The Hyphenopoly-package contains a file called `hyphenopoly.module.js`.
This module provides hyphenation of plain text for applications beyond the browser.

_Note 1: The node module of Hyphenopoly does not support hyphenation of strings containing HTML - just plain text. If you need to hyphenate HTML-Strings [parse them first](./Special-use-cases.md#hyphenate-html-strings-using-hyphenopolymodulejs)._

_Note 2: Even if it is possible, it is not recommended to use `hyphenopoly.module.js` in browser environments. Use `Hyphenopoly_Loader.js` and `Hyphenopoly.js` instead._

## Install

````
npm install hyphenopoly
````

## Usage

Hyphenopoly needs two things to run correctly:
- a [`loader`](#loader) or [`loaderSync`](#loadersync) function that tells how to load the language-specific Webassembly modules.
- an array of needed languages.

These things are configured in the `hyphenopoly.config()` function.

### Usage with one language:

````javascript
import {dirname} from "node:path";
import {fileURLToPath} from "node:url";
import hyphenopoly from "hyphenopoly";
import {readFile} from "node:fs/promises";

function loader(file) {
const cwd = dirname(fileURLToPath(import.meta.url));
return readFile(`${cwd}/../patterns/${file}`);
}

const textHyphenators = hyphenopoly.config({
"hyphen": "",
loader,
"require": ["en-us"]
});

textHyphenators.then(
(hyphenateText) => {
console.log(hyphenateText("Hyphenation enhances justification."));
}
).catch(
(e) => {
console.log(e);
}
);
````

### More then one language:

````javascript
import {dirname} from "node:path";
import {fileURLToPath} from "node:url";
import hyphenopoly from "hyphenopoly";
import {readFile} from "node:fs/promises";

function loader(file) {
const cwd = dirname(fileURLToPath(import.meta.url));
return readFile(`${cwd}/../patterns/${file}`);
}

const textHyphenators = hyphenopoly.config({
"hyphen": "",
loader,
"require": ["de", "en-us"]
});

textHyphenators.get("de").then(
(hyphenateText) => {
console.log(hyphenateText("Silbentrennung verbessert den Blocksatz."));
}
);

textHyphenators.get("en-us").then(
(hyphenateText) => {
console.log(hyphenateText("Hyphenation enhances justification."));
}
);

````

## Synchronous mode

By default, `hyphenopoly.config` returns a promise (or a `Map` of promises). Some code bases are not yet capable of handling async code.
By setting `"sync" : true` the hyphenopoly module switches to a sync mode. Consequently, a synchronous loader `loaderSync` must also be used.

````javascript
import hyphenopoly from "../hyphenopoly.module.js";
import {dirname} from "path";
import {fileURLToPath} from "url";
import {readFileSync} from "node:fs";

function loaderSync(file) {
const cwd = dirname(fileURLToPath(import.meta.url));
return readFileSync(`${cwd}/../patterns/${file}`);
}

const hyphenator = hyphenopoly.config({
"exceptions": {
"en-us": "en-han-ces"
},
"hyphen": "",
loaderSync,
"require": ["de", "en-us"],
"sync": true
});

const hy1 = hyphenator.get("en-us")("hyphenation enhances justification.");
const hy2 = hyphenator.get("de")("Silbentrennung verbessert den Blocksatz.");


console.log(hy1);
console.log(hy2);

````

## Configuration

The `.config`-method takes an object as argument:

Defaults:
````javascript
{
"compound": "hyphen",
"exceptions": {},
"hyphen": String.fromCharCode(173),
"leftmin": 0,
"loader": undefined, //required
"loaderSync": undefined,
"minWordLength": 6,
"mixedCase": true,
"normalize": false,
"orphanControl": 1,
"require": [], //required
"rightmin": 0,
"sync": false
}
````

### loader
The `loader` function takes one string argument (the name of the .wasm file to load, e.g. `"en-us.wasm"`) and must return a `promise` that resolves with a buffer of the language file.

Here are some examples:

````javascript
/* A typical node loader using fs/promises */
import {dirname} from "node:path";
import {fileURLToPath} from "node:url";
import hyphenopoly from "hyphenopoly";
import {readFile} from "node:fs/promises";

function loader(file) {
const cwd = dirname(fileURLToPath(import.meta.url));
return readFile(`${cwd}/../patterns/${file}`);
}
const hyphenator = hyphenopoly.config({
loader,
"require": […]
});
````

````javascript
/* A typical deno loader using Deno.readFile (--allow-read) */
import hyphenopoly from "hyphenopoly";

function loader(file) {
return Deno.readFile(`./patterns/${file}`);
}
const hyphenator = hyphenopoly.config({
loader,
"require": […]
});
````

````javascript
/* A node loader using https */
import hyphenopoly from "hyphenopoly";

async function https(file) {
const https = await import("node:https");
return new Promise((resolve, reject) => {
https.get(`https://cdn.jsdelivr.net/npm/hyphenopoly@5.0.0-beta.5/patterns/${file}`, (res) => {
const rawData = [];
res.on("data", (chunk) => {
rawData.push(chunk);
});
res.on("end", () => {
resolve(Buffer.concat(rawData));
});
res.on("error", (e) => {
reject(e);
});
});
});
}
const hyphenator = hyphenopoly.config({
"loader": https,
"require": […]
});
````

````javascript
/* A node loader using fetch */
import hyphenopoly from "hyphenopoly";

function fetcher(file) {
return fetch(`https://cdn.jsdelivr.net/npm/hyphenopoly@5.0.0-beta.5/patterns/${file}`).then((response) => {
return response.arrayBuffer();
});
}
const hyphenator = hyphenopoly.config({
"loader": fetcher,
"require": […]
});
````

### loaderSync
If hyphenopoly is run in sync-mode a `loaderSync` must be defined instead of `loader`.
The `loaderSync` function takes one string argument (the name of the .wasm file to load, e.g. `"en-us.wasm"`) and must return a buffer of the file data.
Of course, this does not work with fetch and https, which are inherently async.

````javascript
/* A snchrounous node loader using fs */
import hyphenopoly from "../hyphenopoly.module.js";
import {dirname} from "path";
import {fileURLToPath} from "url";
import {readFileSync} from "node:fs";

function loaderSync(file) {
const cwd = dirname(fileURLToPath(import.meta.url));
return readFileSync(`${cwd}/../patterns/${file}`);
}

const hyphenator = hyphenopoly.config({
loaderSync,
"require": […]
});
````

### Other options
For documentation about the other options see the `Hyphenopoly.js`-documentation:

- [compound](./Setup.md#compound)
- [exceptions](./Setup.md#exceptions)
- [hyphen](./Setup.md#hyphen)
- [leftmin](./Setup.md#leftmin-and-rightmin)
- [minWordLength](./Setup.md#minwordlength)
- [mixedCase](./Setup.md#mixedcase)
- [normalize](./Setup.md#normalize)
- [orphanControl](./Setup.md#orphancontrol)
- [rightmin](./Setup.md#leftmin-and-rightmin)

## Supported languages
A list of supported languages can be programmatically obtained by looking at `Hyphenopoly.supportedLanguages`:
````javascript
import hyphenopoly from "hyphenopoly";
hyphenopoly.supportedLanguages.includes("en-us"); //true
hyphenopoly.supportedLanguages.includes("en"); //false
````

## Performance

On my machine with node.js 13.7.0:

| module | setup | hyphenate 270 en words |
| ------------- | -------------:| ----------------------:|
| _hyphenopoly_ | _10ms_ | _0.5ms_ |
| [hyphen](https://www.npmjs.com/package/hyphen) | 18ms | 72ms |
| [hypher](https://www.npmjs.com/package/hypher) | 35ms | 1.2ms |

0 comments on commit ec563f0

Please sign in to comment.