Skip to content

Commit

Permalink
Sane buildflow (#703)
Browse files Browse the repository at this point in the history
* Migrate to Mocha 10

- Rename src/*.js to src/*.mjs and test/*.js to test/*.spec.mjs
- Move misplaced "eslint-plugin-local-rules" to devDependencies
- Remove unused reify now that we are fully .mjs
- Deprecate load*/download functions and remove associated tests
- Remove dead code (private load*() function, isNode/isBrowser...)
- Support multiple test runner:

```sh
npx mocha
npx bun test
npx jasmine "**/*.spec.mjs" # may fail on strict compare
```

* Rework eslint rules

There are currently 3 local rules:
- ban forEach => migrate to a "selector" rule
- prevent import loop => did nothing
- force import extension => esbuild enforce it already

This halves (226 => 139) our NPM dependencies

* Use eslint@9

Use new configuration format since package.json based configuration have been droped

* Apply remarks
  • Loading branch information
yne authored May 24, 2024
1 parent c6a3cb8 commit 68c43ac
Show file tree
Hide file tree
Showing 122 changed files with 1,116 additions and 3,724 deletions.
57 changes: 26 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Select one of the following sources in the next example:

<!-- using module declaration (need full path) -->
<script type=module>
import { parse } from "https://unpkg.com/opentype.js/dist/opentype.module.js";
import { parse } from "https://unpkg.com/opentype.js/dist/opentype.mjs";
parse(...);
</script>
```
Expand Down Expand Up @@ -80,14 +80,18 @@ If you plan on improving or debugging opentype.js, you can:

### Loading a WOFF/OTF/TTF font

This is done in two steps: first, we load the font file into an `ArrayBuffer` ...
```js
// case 1: from an URL
// either from an URL
const buffer = fetch('/fonts/my.woff').then(res => res.arrayBuffer());
// case 2: from filesystem (node)
// ... or from filesystem (node)
const buffer = require('fs').promises.readFile('./my.woff');
// case 3: from an <input type=file id=myfile>
// ... or from an <input type=file id=myfile> (browser)
const buffer = document.getElementById('myfile').files[0].arrayBuffer();
```

... then we `.parse()` it into a `Font` instance
```js
// if running in async context:
const font = opentype.parse(await buffer);
console.log(font);
Expand All @@ -99,7 +103,8 @@ buffer.then(data => {
})
```

### Loading a WOFF2 font
<details>
<summary>Loading a WOFF2 font</summary>

WOFF2 Brotli compression perform [29% better](https://www.w3.org/TR/WOFF20ER/#appendixB) than it WOFF predecessor.
But this compression is also more complex, and would result in a much heavier (&gt;10×!) opentype.js library (≈120KB => ≈1400KB).
Expand All @@ -123,30 +128,14 @@ if (!window.Module) {
// decompress before parsing
const font = opentype.parse(Module.decompress(await buffer));
```
</details>

### Loading a font (1.x style)

This example relies on the deprecated `.load()` method
### Craft a font

```js
// case 1: from an URL
const font = opentype.load('./fonts/my.woff', {}, {isUrl: true});
// case 2: from filesystem
const font = opentype.load('./fonts/my.woff', {}, {isUrl: false});

// ... play with `font` ...
console.log(font.supported);
```
It is also possible to craft a Font from scratch by defining each glyph bézier paths.

### Writing a font
Once you have a `Font` object (either by using `opentype.load()` or by creating a new one from scratch) you can write it
back out as a binary file.

In the browser, you can use `Font.download()` to instruct the browser to download a binary .OTF file. The name is based
on the font name.
```javascript
// Create the bézier paths for each of the glyphs.
// Note that the .notdef glyph is required.
// this .notdef glyph is required.
const notdefGlyph = new opentype.Glyph({
name: '.notdef',
advanceWidth: 650,
Expand All @@ -164,21 +153,27 @@ const aGlyph = new opentype.Glyph({
path: aPath
});

const glyphs = [notdefGlyph, aGlyph];
const font = new opentype.Font({
familyName: 'OpenTypeSans',
styleName: 'Medium',
unitsPerEm: 1000,
ascender: 800,
descender: -200,
glyphs: glyphs});
font.download();
glyphs: [notdefGlyph, aGlyph]});
```

If you want to inspect the font, use `font.toTables()`
to generate an object showing the data structures that map directly to binary values.
If you want to get an `ArrayBuffer`, use `font.toArrayBuffer()`.
### Saving a Font

Once you have a `Font` object (from crafting or from `.parse()`) you can save it back out as file.

```js
// using node:fs
fs.writeFileSync("out.otf", Buffer.from(font.toArrayBuffer()));

// using the browser to createElement a <a> that will be clicked
const href = window.URL.createObjectURL(new Blob([font.toArrayBuffer()]), {type: "font/opentype"});
Object.assign(document.createElement('a'), {download: "out.otf", href}).click();
```

### The Font object
A Font represents a loaded OpenType font file. It contains a set of glyphs and methods to draw text on a drawing context, or to get a path representing the text.
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/creating-fonts.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ <h1><output name="fontFamilyName"></output></h1>
</form>

<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";
function hexDump(bytes) {
var hexString = bytes.map(function(v) {
var h = v.toString(16);
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/font-editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ <h1>Experimental font editor</h1>

<textarea id="code"></textarea>
<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

function linePoint(t, x1, y1, x2, y2) {
return [x1 + t * (x2 - x1),
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/reading-writing.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ <h1><output name="fontFamilyName"></output></h1>
</form>

<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

// Create a canvas and adds it to the document.
// Returns the 2d drawing context.
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/typescript/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

import opentype from '../../dist/opentype.module'
import opentype from '../../dist/opentype.mjs'
console.log(opentype)
// or
import { load } from '../../dist/opentype.module'
import { load } from '../../dist/opentype.mjs'
console.log(load)
// or
import * as mySpecialOpentype from '../../dist/opentype.module'
import * as mySpecialOpentype from '../../dist/opentype.mjs'
console.log(mySpecialOpentype)
2 changes: 1 addition & 1 deletion docs/font-inspector.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

var font = null;
const fontSize = 32;
Expand Down
2 changes: 1 addition & 1 deletion docs/glyph-inspector.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

window.opentype = opentype;

Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

const form = document.forms.demo;
form.oninput = renderText;
Expand Down
2 changes: 1 addition & 1 deletion docs/module.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script type="module">
import * as ot from '/dist/opentype.module.js';
import * as ot from '/dist/opentype.mjs';
console.log(ot)
</script>
43 changes: 0 additions & 43 deletions eslint-local-rules.js

This file was deleted.

50 changes: 50 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import js from "@eslint/js";

export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2018,
sourceType: "module",
globals: {
console: "readonly",
// ugly platform-dependant classes and objects
DecompressionStream: "readonly",
Response: "readonly",
TextDecoder: "readonly",
SVGPathElement: "readonly",
DOMParser: "readonly",
Image: "readonly",
document: "readonly",
}
},
rules: {
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-restricted-syntax": [
"error",
{
"message": "For consistency, Use `for()` loops instead of `.forEach()`",
"selector": "MemberExpression > Identifier[name=\"forEach\"]"
}
]
}
}
]
Loading

0 comments on commit 68c43ac

Please sign in to comment.