@ym-print/core 0.1.0-rc.1 → 0.1.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/dist/plugins.d.ts CHANGED
@@ -16,11 +16,19 @@ export interface PluginFragment {
16
16
  spacing?: boolean;
17
17
  }
18
18
  export interface ElementPlugin {
19
+ /** Rewrite only declared static image references when a copied resource id collides. */
20
+ remapResources?: (payload: Record<string, unknown>, ids: Readonly<Record<string, string>>) => Record<string, unknown>;
21
+ /** True when resource ids can depend on runtime data rather than resources(payload). */
22
+ dynamicResources?: (payload: Record<string, unknown>) => boolean;
19
23
  paginate?: (payload: Record<string, unknown>, context: PluginLayoutContext) => PluginFragment[];
24
+ /** Page coordinates of the first placement, with per-page origins for repeated bands and fragments. */
20
25
  finalize?: (payload: Record<string, unknown>, context: PluginLayoutContext & {
21
- pages: readonly Pick<LayoutPage, 'id' | 'widthUm' | 'heightUm'>[];
22
26
  xUm: number;
23
27
  yUm: number;
28
+ pages: ReadonlyArray<Pick<LayoutPage, 'id' | 'widthUm' | 'heightUm'> & {
29
+ xUm?: number;
30
+ yUm?: number;
31
+ }>;
24
32
  }) => {
25
33
  pageId: string;
26
34
  commands: DrawCommand[];
@@ -53,7 +61,7 @@ export declare class PrintRegistry {
53
61
  payload(id: string, value: Record<string, unknown>): Record<string, unknown>;
54
62
  capabilities(): string[];
55
63
  }
56
- export declare const builtinElements: readonly [ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin];
64
+ export declare const builtinElements: readonly [ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin, ElementPlugin];
57
65
  export declare const defaultRegistry: PrintRegistry;
58
66
  export declare const createPrintRegistry: (elements?: readonly ElementPlugin[], functions?: readonly PrintFunction[]) => PrintRegistry;
59
67
  export declare function pluginContext(nodeId: string, data: EvalContext, font: TextFont, widthUm: number, heightUm: number): PluginLayoutContext;
@@ -0,0 +1,21 @@
1
+ import type { TextStyle } from './protocol.js';
2
+ import type { TextFont } from './font.js';
3
+ import type { ElementPlugin } from './plugins.js';
4
+ export interface PrintTimePayload {
5
+ prefix: string;
6
+ format: string;
7
+ style: TextStyle;
8
+ }
9
+ export declare const DEFAULT_PRINT_TIME_FORMAT = "yyyy-MM-dd HH-mm-ss";
10
+ export declare const PRINT_TIME_FORMATS: readonly ["yyyy-MM-dd HH-mm-ss", "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy年MM月dd日 HH时mm分ss秒", "yyyyMMdd_HHmmss", "yyyy-MM-dd", "HH:mm:ss"];
11
+ export declare const defaultPrintTime: PrintTimePayload;
12
+ /** System-local wall time. Quoted literals allow formats such as yyyy-MM-dd'T'HH:mm:ss. */
13
+ export declare function formatPrintTime(timestamp: number, format?: string): string;
14
+ export declare function printTimeText(payload: PrintTimePayload, timestamp: number): string;
15
+ export declare function measurePrintTime(payload: PrintTimePayload, baseFont: TextFont, widthUm: number, timestamp?: number): {
16
+ value: string;
17
+ style: TextStyle;
18
+ top: number;
19
+ height: number;
20
+ };
21
+ export declare const printTimePlugin: ElementPlugin;
@@ -410,6 +410,10 @@ export interface EvalContext {
410
410
  functionBudget?: {
411
411
  remaining: number;
412
412
  };
413
+ textBudget?: {
414
+ remaining: number;
415
+ };
416
+ printTime?: number;
413
417
  }
414
418
  export interface Transform {
415
419
  rotationMdeg: number;
@@ -0,0 +1,8 @@
1
+ export declare const TEXT_LIMITS: {
2
+ readonly valueChars: 100000;
3
+ readonly layoutChars: 2000000;
4
+ readonly measureChars: 5000000;
5
+ readonly lines: 10000;
6
+ };
7
+ /** Check before Unicode segmentation, normalization or font measurement allocates work. */
8
+ export declare function boundedText(value: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ym-print/core",
3
- "version": "0.1.0-rc.1",
3
+ "version": "0.1.0-rc.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,7 +25,8 @@
25
25
  "ajv": "8.20.0",
26
26
  "bwip-js": "4.11.4",
27
27
  "decimal.js": "10.6.0",
28
- "parse5": "8.0.1"
28
+ "parse5": "8.0.1",
29
+ "re2js": "2.9.1"
29
30
  },
30
31
  "license": "UNLICENSED",
31
32
  "description": "Web print template protocol, data binding and deterministic layout engine",
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Oleksii Vasyliev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,136 +0,0 @@
1
- // src/protocol.ts
2
- var e = class extends Error {
3
- code;
4
- nodeId;
5
- path;
6
- details;
7
- dataPath;
8
- scope;
9
- issues;
10
- constructor(e, t, n, r, i) {
11
- super(t), this.code = e, this.nodeId = n, this.path = r, this.details = i, this.name = "PrintError", this.dataPath = i?.dataPath, this.scope = i?.scope, this.issues = i?.issues;
12
- }
13
- };
14
- function t(t, n) {
15
- if (!Number.isSafeInteger(t)) throw new e("INVALID_GEOMETRY", `${n} 必须为安全整数`);
16
- }
17
- function n(n, r) {
18
- if (r <= 0n) throw new e("INVALID_GEOMETRY", "分母必须大于零");
19
- let i = n < 0n ? -1n : 1n, a = n * i, o = Number(i * ((a + r / 2n) / r));
20
- return t(o, "换算结果"), o;
21
- }
22
- var r = (e) => n(BigInt(e) * 25400n, 72000n), i = (e) => e * 72 / 25400, a = (e) => e / 1e3;
23
- // src/font.ts
24
- function o(t, n) {
25
- if (!t || typeof t != "object" || Object.keys(t).some((e) => ![
26
- "minSizeMpt",
27
- "stepMpt",
28
- "mode"
29
- ].includes(e)) || !Number.isSafeInteger(t.minSizeMpt) || t.minSizeMpt < 1e3 || t.minSizeMpt > 72e3 || t.stepMpt !== void 0 && (!Number.isSafeInteger(t.stepMpt) || t.stepMpt < 100 || t.stepMpt > 1e4) || t.mode !== void 0 && !["wrap", "single-line"].includes(t.mode) || n && t.minSizeMpt > n.sizeMpt) throw new e("TEXT_FIT_INVALID", "自适应最小字号需为 1–72 pt 且不大于初始字号,步长为 0.1–10 pt");
30
- }
31
- function s(t, n, r, i, a, s) {
32
- if (!s) {
33
- let e = x(t, n, i.sizeMpt, l(a, i), i.letterSpacingUm);
34
- return {
35
- lines: e,
36
- style: _(i, a, e)
37
- };
38
- }
39
- if (!Number.isSafeInteger(n) || !Number.isSafeInteger(r) || n < 1 || r < 1) throw new e("TEXT_FIT_INVALID", "文字自适应区域需为正整数");
40
- o(s, i);
41
- let c = s.stepMpt ?? 500, u = Math.floor((i.sizeMpt - s.minSizeMpt) / c), d = i.sizeMpt, f = (o) => {
42
- let c = {
43
- ...i,
44
- sizeMpt: o,
45
- lineHeightMpt: Math.max(1e3, Math.round(i.lineHeightMpt * o / d))
46
- }, u = l(a, c);
47
- try {
48
- let e = s.mode === "single-line" ? t.includes("\n") ? void 0 : [t] : x(t, n, o, u, c.letterSpacingUm);
49
- return !e || e.some((e) => u.measure(e, o, c.letterSpacingUm) > n) || e.length * h(c, a, e.join("")).heightUm > r ? void 0 : {
50
- lines: e,
51
- style: _(c, a, e)
52
- };
53
- } catch (t) {
54
- if (t instanceof e && t.code === "LAYOUT_OVERFLOW") return;
55
- throw t;
56
- }
57
- }, p = f(d);
58
- if (p) return p;
59
- let m = 0, g = u, v;
60
- for (; m <= g;) {
61
- let e = Math.floor((m + g) / 2), t = f(s.minSizeMpt + e * c);
62
- t ? (v = t, m = e + 1) : g = e - 1;
63
- }
64
- if (!v) throw new e("TEXT_FIT_FAILED", "缩到最小字号仍无法放入文字框,请增大尺寸或调整最小字号");
65
- return v;
66
- }
67
- var c = "\"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", Arial, sans-serif", l = (e, t) => e.forStyle?.(t) ?? e;
68
- function u(t) {
69
- if (!Number.isSafeInteger(t) || t < -5e3 || t > 2e4) throw new e("TEXT_SPACING_INVALID", "字距需为 -5–20 mm 的整数微米值");
70
- }
71
- var d = new Intl.Segmenter("und", { granularity: "grapheme" }), f = new Intl.Segmenter("und", { granularity: "word" }), p = (e) => Array.from(d.segment(e), (e) => e.segment), m = (e) => Array.from(f.segment(e), (e) => e.segment);
72
- function h(e, t, n = "") {
73
- let r = l(t, e), i = n ? r.metrics?.(n, e.sizeMpt) : void 0, a = r.toUm(r.ascent - r.descent, e.sizeMpt), o = r.toUm(r.ascent, e.sizeMpt), s = a - o, c = i && i.ascentUm > o + 2 ? i.ascentUm : o, u = i && i.descentUm > s + 2 ? i.descentUm : s, d = Math.round(e.lineHeightMpt * 25400 / 72e3), f = r.system ? Math.max(d, c + u) : d;
74
- return {
75
- heightUm: f,
76
- baselineUm: Math.round((f - c - u) / 2) + c
77
- };
78
- }
79
- function g(e, t) {
80
- return h(e, t).heightUm;
81
- }
82
- function _(e, t, n) {
83
- let r = h(e, t, n.join("")).heightUm;
84
- return r > g(e, t) ? {
85
- ...e,
86
- lineHeightMpt: Math.ceil(r * 72e3 / 25400)
87
- } : e;
88
- }
89
- function v(t) {
90
- if (typeof t != "string" || !t.trim() || t.length > 256 || /[;{}<>\\()@:\u0000-\u001f]/u.test(t) || [
91
- "inherit",
92
- "initial",
93
- "unset",
94
- "revert",
95
- "revert-layer"
96
- ].includes(t.trim().toLowerCase())) throw new e("FONT_FAMILY_INVALID", "字体名称需要 1–256 字,不能包含样式代码或控制字符;继承字体请留空");
97
- }
98
- var y = /^[,。!?:;、)》】」』,.!?;:)]$/u, b = /[(《【「『(\[]$/u;
99
- function x(t, n, r, i, a = 0) {
100
- if (u(a), n <= 0) throw new e("LAYOUT_OVERFLOW", "文字可用宽度必须大于零");
101
- let o = [];
102
- for (let s of t.normalize("NFC").replace(/\r\n?/g, "\n").split("\n")) {
103
- if (s === "") {
104
- o.push("");
105
- continue;
106
- }
107
- let t = "", c = m(s);
108
- for (let s of c) if (!t && i.measure(s, r, a) <= n) t = s;
109
- else if (t && i.measure(t + s, r, a) <= n) t += s;
110
- else {
111
- if (t && i.measure(s, r, a) <= n && !y.test(s)) {
112
- let e = "";
113
- if (b.test(t)) {
114
- let n = p(t);
115
- e = n.pop(), t = n.join("");
116
- }
117
- t && o.push(t.replace(/[ \t]+$/u, "")), t = e;
118
- }
119
- for (let c of p(s)) {
120
- if (i.measure(c, r, a) > n) throw new e("LAYOUT_OVERFLOW", `单字宽度超过文字框:${c}`);
121
- if (t && i.measure(t + c, r, a) > n) {
122
- let s = "";
123
- if (y.test(c) || b.test(t)) {
124
- let e = p(t);
125
- s = e.pop(), t = e.join("");
126
- }
127
- if (t && o.push(t.replace(/[ \t]+$/u, "")), t = s, i.measure(t + c, r, a) > n) throw new e("LAYOUT_OVERFLOW", "标点禁则需要更宽的文字框");
128
- }
129
- t += c;
130
- }
131
- }
132
- t && o.push(t.replace(/[ \t]+$/u, ""));
133
- }
134
- return o;
135
- }
136
- export { a as _, p as a, m as c, u as d, x as f, n as g, r as h, _ as i, o as l, t as m, s as n, h as o, e as p, l as r, g as s, c as t, v as u, i as v };