@alfacapital-tech/c4builder 0.3.0-rc.2 → 0.3.0-rc.3
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 +5 -0
- package/dist/cli/dispatch.js +5 -1
- package/dist/config/defaults.js +2 -1
- package/dist/config/schema.js +1 -0
- package/dist/core/render/diagrams.js +29 -20
- package/dist/core/render/fonts.js +1 -1
- package/dist/core/render/pngraster.js +6 -9
- package/package.json +1 -1
- package/vendor/fonts/NimbusSans-Bold.otf +0 -0
- package/vendor/fonts/NimbusSans-BoldItalic.otf +0 -0
- package/vendor/fonts/NimbusSans-Italic.otf +0 -0
- package/vendor/fonts/NimbusSans-Regular.otf +0 -0
- package/vendor/fonts/README.md +13 -10
- package/vendor/fonts/LiberationSans-Bold.ttf +0 -0
- package/vendor/fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/vendor/fonts/LiberationSans-Italic.ttf +0 -0
- package/vendor/fonts/LiberationSans-Regular.ttf +0 -0
package/README.MD
CHANGED
|
@@ -42,6 +42,11 @@ With `diagramFormat: png`, diagrams are produced by rasterizing their SVG with
|
|
|
42
42
|
native binary, no browser). This gives a single deterministic PNG for both PlantUML and
|
|
43
43
|
D2, using the bundled font. ditaa diagrams stay native PlantUML PNG.
|
|
44
44
|
|
|
45
|
+
**Fonts.** Diagrams use the bundled Nimbus Sans (Helvetica metrics, Cyrillic and Greek —
|
|
46
|
+
see `vendor/fonts/README.md`), so diagram geometry is identical on any machine.
|
|
47
|
+
`useSystemFonts: true` in `.c4builder` (or `--system-fonts` for one run) renders with the
|
|
48
|
+
machine's fonts instead — machine-dependent by design.
|
|
49
|
+
|
|
45
50
|
The easiest way to get started is with the _new project_ template.
|
|
46
51
|
|
|
47
52
|

|
package/dist/cli/dispatch.js
CHANGED
|
@@ -92,7 +92,8 @@ function getOptions(c) {
|
|
|
92
92
|
WEB_FILE_NAME: c.webFileName,
|
|
93
93
|
SUPPORT_SEARCH: c.supportSearch,
|
|
94
94
|
EXECUTE_SCRIPT: c.executeScript,
|
|
95
|
-
EXCLUDE_OTHER_FILES: c.excludeOtherFiles
|
|
95
|
+
EXCLUDE_OTHER_FILES: c.excludeOtherFiles,
|
|
96
|
+
USE_SYSTEM_FONTS: c.useSystemFonts
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
export default async () => {
|
|
@@ -110,6 +111,7 @@ export default async () => {
|
|
|
110
111
|
.option('-w, --watch', 'watch for changes and rebuild')
|
|
111
112
|
.option('-o, --open', 'open the generated site in the browser (with --site)')
|
|
112
113
|
.option('--docs', 'a brief explanation for the available configuration options')
|
|
114
|
+
.option('--system-fonts', 'render with system fonts instead of the bundled one (not deterministic)')
|
|
113
115
|
.option('-p, --port <n>', 'port used for serving the generated site', (v) => {
|
|
114
116
|
// parseInt молча резал бы опечатку ('30OO' → 30) — валидируем строго.
|
|
115
117
|
if (!isValidPort(v))
|
|
@@ -202,6 +204,8 @@ export default async () => {
|
|
|
202
204
|
// уводил бы последующие запуски на строгий путь (exit 1 до визарда).
|
|
203
205
|
conf.set('hasRun', true);
|
|
204
206
|
const options = getOptions(built.value);
|
|
207
|
+
if (opts.systemFonts)
|
|
208
|
+
options.USE_SYSTEM_FONTS = true; // флаг сильнее ключа конфига
|
|
205
209
|
const reloadEmitter = new EventEmitter();
|
|
206
210
|
reloadEmitter.setMaxListeners(0);
|
|
207
211
|
if (opts.watch) {
|
package/dist/config/defaults.js
CHANGED
package/dist/config/schema.js
CHANGED
|
@@ -53,6 +53,7 @@ export const configSchema = z.object({
|
|
|
53
53
|
diagramFormat: str(defaultConfig.diagramFormat),
|
|
54
54
|
d2Layout: str(defaultConfig.d2Layout),
|
|
55
55
|
charset: str(defaultConfig.charset),
|
|
56
|
+
useSystemFonts: bool(defaultConfig.useSystemFonts),
|
|
56
57
|
// Задаются явно (флаг/промпт) либо тонкой правкой файла — в defaultConfig не входят.
|
|
57
58
|
projectName: optStr(),
|
|
58
59
|
webFileName: optStr(),
|
|
@@ -78,6 +78,9 @@ const d2EngineVersion = () => {
|
|
|
78
78
|
}
|
|
79
79
|
return d2VersionCache;
|
|
80
80
|
};
|
|
81
|
+
// В ключ кеша: смена режима не должна отдавать картинку, отрисованную другим шрифтом
|
|
82
|
+
// (D2 тоже — его PNG растрирует общий resvg).
|
|
83
|
+
export const fontCacheTag = (options) => options.USE_SYSTEM_FONTS ? 'system' : DEFAULT_FONT_NAME;
|
|
81
84
|
export const getMime = (format) => {
|
|
82
85
|
if (format === 'svg')
|
|
83
86
|
return `image/svg+xml`;
|
|
@@ -102,22 +105,24 @@ export const httpGet = async (url) => (await httpGetBuffer(url)).toString('base6
|
|
|
102
105
|
// расходятся между ОС. С пином шрифт берётся из vendor/fonts (JRE своих не несёт,
|
|
103
106
|
// freetype у Temurin бандлед), и SVG получается одинаковым везде.
|
|
104
107
|
// ditaa этим не лечится: его движок берёт AWT-шрифт мимо обеих опций.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
108
|
+
// useSystemFonts убирает все три шрифтовых аргумента — рендер как до пина (машинозависим).
|
|
109
|
+
export const renderArgv = ({ jarPath, includePath, format, charset, isDitaa, useSystemFonts }) => [
|
|
110
|
+
'-Djava.awt.headless=true',
|
|
111
|
+
`-Dplantuml.include.path=${includePath}`,
|
|
112
|
+
...(useSystemFonts ? [] : [`-Dsun.java2d.fontpath=prepend:${FONTS_DIR}`]),
|
|
113
|
+
'-jar',
|
|
114
|
+
jarPath,
|
|
115
|
+
...(isDitaa ? [] : ['-Playout=smetana']),
|
|
116
|
+
...(useSystemFonts
|
|
117
|
+
? []
|
|
118
|
+
: [`-SdefaultFontName=${DEFAULT_FONT_NAME}`, `-SCircledCharacterFontName=${DEFAULT_FONT_NAME}`]),
|
|
119
|
+
'-charset',
|
|
120
|
+
charset,
|
|
121
|
+
`-t${format}`,
|
|
122
|
+
'-pipe'
|
|
123
|
+
];
|
|
124
|
+
export const renderDiagram = (content, options) => new Promise((resolve, reject) => {
|
|
125
|
+
const child = spawn(options.javaBin, renderArgv(options));
|
|
121
126
|
const stdout = [];
|
|
122
127
|
const stderr = [];
|
|
123
128
|
// stdio по умолчанию 'pipe' → потоки заведомо не null; берём их деструктуризацией
|
|
@@ -253,9 +258,10 @@ export const generateImages = async (tree, options, onImageGenerated, cacheConf,
|
|
|
253
258
|
// чексумму → из бэкапа копировалась старая картинка (новые параметры молча
|
|
254
259
|
// игнорировались, кэш чистился только через --reset). Формат/движок/версия
|
|
255
260
|
// движка тоже в ключе: их смена обязана приводить к перерендеру.
|
|
256
|
-
const renderKey = entryPath !== null
|
|
261
|
+
const renderKey = (entryPath !== null
|
|
257
262
|
? `d2\0${d2EngineVersion()}\0layout=${options.D2_LAYOUT}\0fmt=${outFormat}`
|
|
258
|
-
: `puml\0${VENDORED_JAR.version}\0charset=${options.CHARSET}\0fmt=${outFormat}\0ditaa=${diagram.isDitaa}
|
|
263
|
+
: `puml\0${VENDORED_JAR.version}\0charset=${options.CHARSET}\0fmt=${outFormat}\0ditaa=${diagram.isDitaa}`) +
|
|
264
|
+
`\0font=${fontCacheTag(options)}`;
|
|
259
265
|
const cksum = crypto
|
|
260
266
|
.createHash('sha256')
|
|
261
267
|
.update(body + includes + renderKey, 'utf-8')
|
|
@@ -305,10 +311,13 @@ export const generateImages = async (tree, options, onImageGenerated, cacheConf,
|
|
|
305
311
|
includePath,
|
|
306
312
|
format: needsRaster ? 'svg' : outFormat,
|
|
307
313
|
charset: options.CHARSET,
|
|
308
|
-
isDitaa
|
|
314
|
+
isDitaa,
|
|
315
|
+
useSystemFonts: options.USE_SYSTEM_FONTS
|
|
309
316
|
});
|
|
310
317
|
}
|
|
311
|
-
const image = needsRaster
|
|
318
|
+
const image = needsRaster
|
|
319
|
+
? await rasterizeSvgToPng(rendered, options.USE_SYSTEM_FONTS)
|
|
320
|
+
: rendered;
|
|
312
321
|
await writeFile(filePath, image);
|
|
313
322
|
cksumEntry.ok = true;
|
|
314
323
|
}
|
|
@@ -5,4 +5,4 @@ import { VENDOR_DIR } from "../../util/paths.js";
|
|
|
5
5
|
// (`fontDirs`, `defaultFontFamily`). Значения обязаны совпадать — иначе метрики
|
|
6
6
|
// текста разъедутся и PNG-golden покраснеют. НЕ менять без пересбора эталонов.
|
|
7
7
|
export const FONTS_DIR = path.join(VENDOR_DIR, 'fonts');
|
|
8
|
-
export const DEFAULT_FONT_NAME = '
|
|
8
|
+
export const DEFAULT_FONT_NAME = 'Nimbus Sans';
|
|
@@ -20,21 +20,18 @@ const getResvg = () => {
|
|
|
20
20
|
}
|
|
21
21
|
return resvgMod;
|
|
22
22
|
};
|
|
23
|
+
export const resvgFontOptions = (useSystemFonts) => useSystemFonts
|
|
24
|
+
? { loadSystemFonts: true }
|
|
25
|
+
: { fontDirs: [FONTS_DIR], defaultFontFamily: DEFAULT_FONT_NAME, loadSystemFonts: false };
|
|
23
26
|
// SVG (Buffer или строка) → PNG (Buffer), масштаб 1:1 к размеру SVG. Вход — валидный
|
|
24
27
|
// SVG движка: PlantUML ссылается на шрифт по имени (грузим из vendor/fonts), D2 несёт
|
|
25
|
-
// шрифт во вшитом @font-face, но
|
|
28
|
+
// шрифт во вшитом @font-face, но пин по умолчанию фиксируем в обоих случаях.
|
|
26
29
|
// renderAsync считает в napi-пуле тредов: JS-поток не блокируется, PlantUML-пул и
|
|
27
30
|
// D2-очередь продолжают крутиться параллельно растеризации (прежний sync render()
|
|
28
31
|
// останавливал весь event loop на каждую картинку).
|
|
29
|
-
const rasterizeSvgToPng = async (svg) => {
|
|
32
|
+
const rasterizeSvgToPng = async (svg, useSystemFonts = false) => {
|
|
30
33
|
const { renderAsync } = getResvg();
|
|
31
|
-
const rendered = await renderAsync(svg, {
|
|
32
|
-
font: {
|
|
33
|
-
fontDirs: [FONTS_DIR],
|
|
34
|
-
defaultFontFamily: DEFAULT_FONT_NAME,
|
|
35
|
-
loadSystemFonts: false
|
|
36
|
-
}
|
|
37
|
-
});
|
|
34
|
+
const rendered = await renderAsync(svg, { font: resvgFontOptions(useSystemFonts) });
|
|
38
35
|
return rendered.asPng();
|
|
39
36
|
};
|
|
40
37
|
export { rasterizeSvgToPng };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfacapital-tech/c4builder",
|
|
3
|
-
"version": "0.3.0-rc.
|
|
3
|
+
"version": "0.3.0-rc.3",
|
|
4
4
|
"description": "A CLI tool designed to compile a folder structure of markdowns and plant uml files into a site, single file markdown or a collection of markdowns with links",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/fonts/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# Вендорные шрифты
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Nimbus Sans
|
|
4
4
|
|
|
5
|
-
`
|
|
5
|
+
`NimbusSans-{Regular,Bold,Italic,BoldItalic}.otf`
|
|
6
6
|
|
|
7
7
|
- **Назначение:** детерминизм метрик текста в SVG. Ширина текста (`textLength`)
|
|
8
8
|
считается PlantUML из AWT-метрик шрифта; системный `sans-serif` резолвится
|
|
9
9
|
по-разному на разных машинах. Шрифт отдаётся JVM через
|
|
10
|
-
`-Dsun.java2d.fontpath=prepend:` + `-SdefaultFontName=
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<https://github.com/
|
|
10
|
+
`-Dsun.java2d.fontpath=prepend:` + `-SdefaultFontName=Nimbus Sans` и resvg через
|
|
11
|
+
`fontDirs` (см. `src/core/render/fonts.ts`). Пин снимается ключом `useSystemFonts`
|
|
12
|
+
в `.c4builder` / флагом `--system-fonts` — тогда рендер идёт системным шрифтом и
|
|
13
|
+
перестаёт быть машинонезависимым.
|
|
14
|
+
- **Происхождение:** URW base35 (Artifex), релиз 20200910 — файлы побайтно совпадают
|
|
15
|
+
с пакетом `gsfonts` этой версии. Метрически совместим с Helvetica, содержит
|
|
16
|
+
кириллицу и греческий. Апстрим:
|
|
17
|
+
<https://github.com/ArtifexSoftware/urw-base35-fonts>.
|
|
18
|
+
- **Лицензия:** AGPL-3.0-only с шрифтовым исключением
|
|
19
|
+
(`PS-or-PDF-font-exception-20170817`): встраивание шрифта в документы не делает их
|
|
20
|
+
производными работами. Полный текст — в апстрим-репозитории (`LICENSE`).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|