maplibre-font-maker-node 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 +42 -2
- package/dist/cli/parse-args.d.ts +17 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +49 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/print-summary.d.ts +7 -0
- package/dist/cli/print-summary.d.ts.map +1 -0
- package/dist/cli/print-summary.js +8 -0
- package/dist/cli/print-summary.js.map +1 -0
- package/dist/cli/resolve-ranges.d.ts +4 -0
- package/dist/cli/resolve-ranges.d.ts.map +1 -0
- package/dist/cli/resolve-ranges.js +15 -0
- package/dist/cli/resolve-ranges.js.map +1 -0
- package/dist/cli/write-generated-files.d.ts +6 -0
- package/dist/cli/write-generated-files.d.ts.map +1 -0
- package/dist/cli/write-generated-files.js +32 -0
- package/dist/cli/write-generated-files.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +84 -0
- package/dist/cli.js.map +1 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# font-maker-node
|
|
1
|
+
# maplibre-font-maker-node
|
|
2
2
|
|
|
3
3
|
A TypeScript library for generating MapLibre-compatible glyph PBF files in memory from TTF, OTF, WOFF, or WOFF2 font bytes.
|
|
4
4
|
Variable fonts are supported, but a specific instantiation must be chosen, so you should supply a value for each axis.
|
|
@@ -6,7 +6,7 @@ Variable fonts are supported, but a specific instantiation must be chosen, so yo
|
|
|
6
6
|
## Usage
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
|
-
import { generateGlyphPbfFiles, latinRanges } from 'font-maker-node';
|
|
9
|
+
import { generateGlyphPbfFiles, latinRanges } from 'maplibre-font-maker-node';
|
|
10
10
|
|
|
11
11
|
const files = await generateGlyphPbfFiles({
|
|
12
12
|
fontstack: 'Barlow Regular',
|
|
@@ -33,6 +33,46 @@ The result is an array of in-memory files:
|
|
|
33
33
|
|
|
34
34
|
The caller is responsible for writing files to disk if desired. The public API does not read font files or write output files. The only filesystem access performed by the library is loading the vendored `maplibre-font-maker/sdfglyph.js` and `maplibre-font-maker/sdfglyph.wasm` runtime files during initialization.
|
|
35
35
|
|
|
36
|
+
## CLI
|
|
37
|
+
|
|
38
|
+
The same package ships a thin command-line wrapper around `generateGlyphPbfFiles`. It reads a font file, generates the glyphs, and writes them to disk.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx maplibre-font-maker-node \
|
|
42
|
+
--font ./fonts/Barlow-Regular.ttf \
|
|
43
|
+
--fontstack "Barlow Regular" \
|
|
44
|
+
--output ./dist/fonts \
|
|
45
|
+
--ranges latin
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This writes the MapLibre-ready layout `<output>/<fontstack>/<start>-<end>.pbf`, e.g. `./dist/fonts/Barlow Regular/0-255.pbf` — exactly the `{fontstack}/{range}.pbf` structure MapLibre's `glyphs` URL expects. Output directories are created automatically.
|
|
49
|
+
|
|
50
|
+
| Option | Description |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `--font <path>` | Input font file (TTF, OTF, WOFF, or WOFF2). Required. |
|
|
53
|
+
| `--fontstack <name>` | MapLibre font stack name. Required. |
|
|
54
|
+
| `--output <dir>` | Output directory. Required. |
|
|
55
|
+
| `--ranges <preset>` | Glyph range preset: `basic-latin`, `latin`, or `all-bmp`. Default: `latin`. |
|
|
56
|
+
| `--force` | Overwrite existing output files. Without it, the command fails if any target file already exists. |
|
|
57
|
+
| `--help` | Show usage. |
|
|
58
|
+
| `--version` | Show the package version. |
|
|
59
|
+
|
|
60
|
+
The CLI exits with code `1` on any failure (missing argument, font not found, invalid preset, generation error), so it fails the surrounding script in CI.
|
|
61
|
+
|
|
62
|
+
### Use it as a build step
|
|
63
|
+
|
|
64
|
+
Because npm exposes the binary on `node_modules/.bin`, you can call it by name from a downstream project's lifecycle scripts to generate glyphs into your build output:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"scripts": {
|
|
69
|
+
"prebuild": "maplibre-font-maker-node --font ./fonts/Barlow-Regular.ttf --fontstack \"Barlow Regular\" --output ./dist/fonts --ranges latin --force"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`prebuild` runs automatically before `build`. Use `--force` so repeated builds don't fail on already-generated files. Each invocation handles one font; chain multiple commands with `&&` for several font stacks.
|
|
75
|
+
|
|
36
76
|
## API
|
|
37
77
|
|
|
38
78
|
```ts
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
font: string;
|
|
3
|
+
fontstack: string;
|
|
4
|
+
output: string;
|
|
5
|
+
ranges: string;
|
|
6
|
+
force: boolean;
|
|
7
|
+
}
|
|
8
|
+
export type ParsedArgs = {
|
|
9
|
+
kind: 'help';
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'version';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'run';
|
|
14
|
+
options: CliOptions;
|
|
15
|
+
};
|
|
16
|
+
export declare function parseCliArgs(argv: string[]): ParsedArgs;
|
|
17
|
+
//# sourceMappingURL=parse-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-args.d.ts","sourceRoot":"","sources":["../../src/cli/parse-args.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAIzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6CvD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { RANGE_PRESETS } from './resolve-ranges.js';
|
|
3
|
+
const DEFAULT_RANGES = 'latin';
|
|
4
|
+
export function parseCliArgs(argv) {
|
|
5
|
+
let values;
|
|
6
|
+
try {
|
|
7
|
+
({ values } = parseArgs({
|
|
8
|
+
args: argv,
|
|
9
|
+
allowPositionals: false,
|
|
10
|
+
strict: true,
|
|
11
|
+
options: {
|
|
12
|
+
font: { type: 'string' },
|
|
13
|
+
fontstack: { type: 'string' },
|
|
14
|
+
output: { type: 'string' },
|
|
15
|
+
ranges: { type: 'string', default: DEFAULT_RANGES },
|
|
16
|
+
force: { type: 'boolean', default: false },
|
|
17
|
+
help: { type: 'boolean', default: false },
|
|
18
|
+
version: { type: 'boolean', default: false },
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new Error(error instanceof Error ? error.message : String(error));
|
|
24
|
+
}
|
|
25
|
+
if (values.help) {
|
|
26
|
+
return { kind: 'help' };
|
|
27
|
+
}
|
|
28
|
+
if (values.version) {
|
|
29
|
+
return { kind: 'version' };
|
|
30
|
+
}
|
|
31
|
+
const font = requireOption(values.font, 'font');
|
|
32
|
+
const fontstack = requireOption(values.fontstack, 'fontstack');
|
|
33
|
+
const output = requireOption(values.output, 'output');
|
|
34
|
+
const ranges = values.ranges ?? DEFAULT_RANGES;
|
|
35
|
+
if (!RANGE_PRESETS.includes(ranges)) {
|
|
36
|
+
throw new Error(`Invalid --ranges preset "${ranges}". Valid presets are: ${RANGE_PRESETS.join(', ')}.`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
kind: 'run',
|
|
40
|
+
options: { font, fontstack, output, ranges, force: values.force ?? false },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function requireOption(value, name) {
|
|
44
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
45
|
+
throw new Error(`Missing required option --${name}.`);
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=parse-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-args.js","sourceRoot":"","sources":["../../src/cli/parse-args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAepD,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,IAAI,MAAM,CAAC;IAEX,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,gBAAgB,EAAE,KAAK;YACvB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE;gBACnD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACzC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;aAC7C;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC;IAE/C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,yBAAyB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK,EAAE;KAC3E,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB,EAAE,IAAY;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"print-summary.d.ts","sourceRoot":"","sources":["../../src/cli/print-summary.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,GAAG,IAAI,CAM5E"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function printSummary({ fontstack, fileCount, output }) {
|
|
2
|
+
console.log('Generated:');
|
|
3
|
+
console.log(` Font stack: ${fontstack}`);
|
|
4
|
+
console.log(` Files: ${fileCount}`);
|
|
5
|
+
console.log(` Output: ${output}`);
|
|
6
|
+
console.log('Done.');
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=print-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"print-summary.js","sourceRoot":"","sources":["../../src/cli/print-summary.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAW;IACpE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-ranges.d.ts","sourceRoot":"","sources":["../../src/cli/resolve-ranges.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,eAAO,MAAM,aAAa,UAAuB,CAAC;AAElD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAU1D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { allBmpRanges, basicLatinRanges, latinRanges } from '../index.js';
|
|
2
|
+
const PRESETS = {
|
|
3
|
+
'basic-latin': basicLatinRanges,
|
|
4
|
+
latin: latinRanges,
|
|
5
|
+
'all-bmp': allBmpRanges,
|
|
6
|
+
};
|
|
7
|
+
export const RANGE_PRESETS = Object.keys(PRESETS);
|
|
8
|
+
export function resolveRanges(preset) {
|
|
9
|
+
const build = PRESETS[preset];
|
|
10
|
+
if (!build) {
|
|
11
|
+
throw new Error(`Invalid --ranges preset "${preset}". Valid presets are: ${RANGE_PRESETS.join(', ')}.`);
|
|
12
|
+
}
|
|
13
|
+
return build();
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=resolve-ranges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-ranges.js","sourceRoot":"","sources":["../../src/cli/resolve-ranges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1E,MAAM,OAAO,GAAuC;IAClD,aAAa,EAAE,gBAAgB;IAC/B,KAAK,EAAE,WAAW;IAClB,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAElD,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,yBAAyB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACvF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,EAAE,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { GeneratedGlyphPbfFile } from '../index.js';
|
|
2
|
+
export interface WriteOptions {
|
|
3
|
+
force: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function writeGeneratedFiles(files: GeneratedGlyphPbfFile[], outputDirectory: string, { force }: WriteOptions): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=write-generated-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-generated-files.d.ts","sourceRoot":"","sources":["../../src/cli/write-generated-files.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,qBAAqB,EAAE,EAC9B,eAAe,EAAE,MAAM,EACvB,EAAE,KAAK,EAAE,EAAE,YAAY,GACtB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
export async function writeGeneratedFiles(files, outputDirectory, { force }) {
|
|
4
|
+
const destinations = files.map((file) => ({
|
|
5
|
+
bytes: file.bytes,
|
|
6
|
+
path: join(outputDirectory, file.filename),
|
|
7
|
+
}));
|
|
8
|
+
if (!force) {
|
|
9
|
+
const existing = await findExisting(destinations.map((destination) => destination.path));
|
|
10
|
+
if (existing.length > 0) {
|
|
11
|
+
throw new Error(`Refusing to overwrite ${existing.length} existing file(s). Pass --force to overwrite:\n` +
|
|
12
|
+
existing.map((path) => ` ${path}`).join('\n'));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
for (const destination of destinations) {
|
|
16
|
+
await mkdir(dirname(destination.path), { recursive: true });
|
|
17
|
+
await writeFile(destination.path, destination.bytes);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function findExisting(paths) {
|
|
21
|
+
const checks = await Promise.all(paths.map(async (path) => {
|
|
22
|
+
try {
|
|
23
|
+
await access(path);
|
|
24
|
+
return path;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
30
|
+
return checks.filter((path) => path !== undefined);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=write-generated-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-generated-files.js","sourceRoot":"","sources":["../../src/cli/write-generated-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQ1C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAA8B,EAC9B,eAAuB,EACvB,EAAE,KAAK,EAAgB;IAEvB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC;KAC3C,CAAC,CAAC,CAAC;IAEJ,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAEzF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,yBAAyB,QAAQ,CAAC,MAAM,iDAAiD;gBACvF,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACjD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,KAAe;IACzC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACrE,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAgCA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvD"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { generateGlyphPbfFiles } from './index.js';
|
|
5
|
+
import { parseCliArgs } from './cli/parse-args.js';
|
|
6
|
+
import { printSummary } from './cli/print-summary.js';
|
|
7
|
+
import { resolveRanges } from './cli/resolve-ranges.js';
|
|
8
|
+
import { writeGeneratedFiles } from './cli/write-generated-files.js';
|
|
9
|
+
const HELP_TEXT = `maplibre-font-maker-node
|
|
10
|
+
|
|
11
|
+
Generate MapLibre glyph PBF files from TTF, OTF, WOFF, or WOFF2 fonts.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
maplibre-font-maker-node \\
|
|
15
|
+
--font <file.ttf> \\
|
|
16
|
+
--fontstack "Barlow Regular" \\
|
|
17
|
+
--output ./fonts
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
--font Input font file (required)
|
|
21
|
+
--fontstack MapLibre font stack name (required)
|
|
22
|
+
--output Output directory (required)
|
|
23
|
+
--ranges Glyph range preset: basic-latin | latin | all-bmp (default: latin)
|
|
24
|
+
--force Overwrite existing files
|
|
25
|
+
--help Show this help
|
|
26
|
+
--version Show version
|
|
27
|
+
`;
|
|
28
|
+
export async function run(argv) {
|
|
29
|
+
const parsed = parseCliArgs(argv);
|
|
30
|
+
if (parsed.kind === 'help') {
|
|
31
|
+
console.log(HELP_TEXT);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (parsed.kind === 'version') {
|
|
35
|
+
console.log(await readVersion());
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await generate(parsed.options);
|
|
39
|
+
}
|
|
40
|
+
async function generate(options) {
|
|
41
|
+
const fontBytes = await readFontFile(options.font);
|
|
42
|
+
const ranges = resolveRanges(options.ranges);
|
|
43
|
+
const files = await generateGlyphPbfFiles({
|
|
44
|
+
fontstack: options.fontstack,
|
|
45
|
+
fonts: [{ name: options.fontstack, bytes: fontBytes }],
|
|
46
|
+
ranges,
|
|
47
|
+
});
|
|
48
|
+
await writeGeneratedFiles(files, options.output, { force: options.force });
|
|
49
|
+
printSummary({
|
|
50
|
+
fontstack: options.fontstack,
|
|
51
|
+
fileCount: files.length,
|
|
52
|
+
output: options.output,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function readFontFile(path) {
|
|
56
|
+
try {
|
|
57
|
+
return new Uint8Array(await readFile(path));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (isErrnoException(error) && error.code === 'ENOENT') {
|
|
61
|
+
throw new Error(`Font file not found: ${path}`);
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Failed to read font file "${path}": ${formatError(error)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function readVersion() {
|
|
67
|
+
const packageUrl = new URL('../package.json', import.meta.url);
|
|
68
|
+
const manifest = JSON.parse(await readFile(packageUrl, 'utf8'));
|
|
69
|
+
return manifest.version ?? 'unknown';
|
|
70
|
+
}
|
|
71
|
+
function isErrnoException(error) {
|
|
72
|
+
return error instanceof Error && 'code' in error;
|
|
73
|
+
}
|
|
74
|
+
function formatError(error) {
|
|
75
|
+
return error instanceof Error ? error.message : String(error);
|
|
76
|
+
}
|
|
77
|
+
const invokedPath = process.argv[1];
|
|
78
|
+
if (invokedPath && pathToFileURL(invokedPath).href === import.meta.url) {
|
|
79
|
+
run(process.argv.slice(2)).catch((error) => {
|
|
80
|
+
console.error(formatError(error));
|
|
81
|
+
process.exitCode = 1;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maplibre-font-maker-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Generate MapLibre-compatible glyph PBF files in memory from TTF, OTF, WOFF, or WOFF2 font bytes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"maplibre-font-maker-node": "./dist/cli.js"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
15
18
|
"dist",
|
|
16
19
|
"maplibre-font-maker",
|