@onerjs/serializers 8.41.5 → 8.41.7

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.
Files changed (67) hide show
  1. package/3MF/3mfSerializer.configuration.d.ts +9 -0
  2. package/3MF/3mfSerializer.configuration.js +11 -0
  3. package/3MF/3mfSerializer.configuration.js.map +1 -0
  4. package/3MF/3mfSerializer.d.ts +132 -0
  5. package/3MF/3mfSerializer.js +328 -0
  6. package/3MF/3mfSerializer.js.map +1 -0
  7. package/3MF/core/index.d.ts +2 -0
  8. package/3MF/core/index.js +4 -0
  9. package/3MF/core/index.js.map +1 -0
  10. package/3MF/core/model/3mf.builder.d.ts +231 -0
  11. package/3MF/core/model/3mf.builder.js +403 -0
  12. package/3MF/core/model/3mf.builder.js.map +1 -0
  13. package/3MF/core/model/3mf.d.ts +329 -0
  14. package/3MF/core/model/3mf.interfaces.d.ts +321 -0
  15. package/3MF/core/model/3mf.interfaces.js +39 -0
  16. package/3MF/core/model/3mf.interfaces.js.map +1 -0
  17. package/3MF/core/model/3mf.js +377 -0
  18. package/3MF/core/model/3mf.js.map +1 -0
  19. package/3MF/core/model/3mf.opc.d.ts +66 -0
  20. package/3MF/core/model/3mf.opc.interfaces.d.ts +126 -0
  21. package/3MF/core/model/3mf.opc.interfaces.js +75 -0
  22. package/3MF/core/model/3mf.opc.interfaces.js.map +1 -0
  23. package/3MF/core/model/3mf.opc.js +91 -0
  24. package/3MF/core/model/3mf.opc.js.map +1 -0
  25. package/3MF/core/model/3mf.serializer.d.ts +118 -0
  26. package/3MF/core/model/3mf.serializer.js +171 -0
  27. package/3MF/core/model/3mf.serializer.js.map +1 -0
  28. package/3MF/core/model/3mf.types.d.ts +46 -0
  29. package/3MF/core/model/3mf.types.js +2 -0
  30. package/3MF/core/model/3mf.types.js.map +1 -0
  31. package/3MF/core/model/index.d.ts +7 -0
  32. package/3MF/core/model/index.js +8 -0
  33. package/3MF/core/model/index.js.map +1 -0
  34. package/3MF/core/xml/index.d.ts +6 -0
  35. package/3MF/core/xml/index.js +7 -0
  36. package/3MF/core/xml/index.js.map +1 -0
  37. package/3MF/core/xml/xml.builder.bytes.d.ts +33 -0
  38. package/3MF/core/xml/xml.builder.bytes.js +60 -0
  39. package/3MF/core/xml/xml.builder.bytes.js.map +1 -0
  40. package/3MF/core/xml/xml.builder.d.ts +94 -0
  41. package/3MF/core/xml/xml.builder.js +286 -0
  42. package/3MF/core/xml/xml.builder.js.map +1 -0
  43. package/3MF/core/xml/xml.builder.string.d.ts +19 -0
  44. package/3MF/core/xml/xml.builder.string.js +35 -0
  45. package/3MF/core/xml/xml.builder.string.js.map +1 -0
  46. package/3MF/core/xml/xml.interfaces.d.ts +91 -0
  47. package/3MF/core/xml/xml.interfaces.js +110 -0
  48. package/3MF/core/xml/xml.interfaces.js.map +1 -0
  49. package/3MF/core/xml/xml.serializer.d.ts +39 -0
  50. package/3MF/core/xml/xml.serializer.format.d.ts +92 -0
  51. package/3MF/core/xml/xml.serializer.format.js +122 -0
  52. package/3MF/core/xml/xml.serializer.format.js.map +1 -0
  53. package/3MF/core/xml/xml.serializer.js +261 -0
  54. package/3MF/core/xml/xml.serializer.js.map +1 -0
  55. package/3MF/index.d.ts +3 -0
  56. package/3MF/index.js +5 -0
  57. package/3MF/index.js.map +1 -0
  58. package/index.d.ts +1 -0
  59. package/index.js +1 -0
  60. package/index.js.map +1 -1
  61. package/legacy/legacy-3mfSerializer.d.ts +1 -0
  62. package/legacy/legacy-3mfSerializer.js +20 -0
  63. package/legacy/legacy-3mfSerializer.js.map +1 -0
  64. package/legacy/legacy.d.ts +1 -0
  65. package/legacy/legacy.js +1 -0
  66. package/legacy/legacy.js.map +1 -1
  67. package/package.json +3 -3
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @param x
3
+ * @returns
4
+ */
5
+ export function IsQualifiedName(x) {
6
+ return typeof x?.name === "string";
7
+ }
8
+ const XML_CLASS_META = Symbol("__xml:meta$__");
9
+ const XML_CLASS_NAME = Symbol("__xml:name$__");
10
+ function AddXmlMeta(target, meta) {
11
+ const ctor = target.constructor;
12
+ (ctor[XML_CLASS_META] ?? (ctor[XML_CLASS_META] = [])).push(meta);
13
+ }
14
+ /**
15
+ * @param name
16
+ * @returns
17
+ */
18
+ export function XmlName(name) {
19
+ return (ctor) => {
20
+ ctor[XML_CLASS_NAME] = name;
21
+ };
22
+ }
23
+ /**
24
+ * tell the serializer to ignore the property
25
+ * @returns
26
+ */
27
+ export function XmlIgnore() {
28
+ return (target, prop) => AddXmlMeta(target, { kind: "none", prop, ignore: true });
29
+ }
30
+ /**
31
+ * tell the serializer to serialize the property as attribute
32
+ * @returns
33
+ */
34
+ export function XmlAttr(opts) {
35
+ return (target, prop) => AddXmlMeta(target, { kind: "attr", prop, ...opts });
36
+ }
37
+ /**
38
+ * tell the serializer to serialize the property as element - this is the default behavior but shoud be
39
+ * specified when wanted to update the default name of the classe or if the class is not decorated (without \@XmlName)
40
+ * @returns
41
+ */
42
+ export function XmlElem(opts) {
43
+ return (target, prop) => AddXmlMeta(target, { kind: "elem", prop, ...opts });
44
+ }
45
+ /**
46
+ *
47
+ * @param obj
48
+ * @returns
49
+ */
50
+ export function GetXmlFieldMeta(obj) {
51
+ return (obj?.constructor?.[XML_CLASS_META] ?? []);
52
+ }
53
+ /**
54
+ *
55
+ * @param obj
56
+ * @returns
57
+ */
58
+ export function GetXmlName(obj) {
59
+ const n = obj?.constructor?.[XML_CLASS_NAME];
60
+ return n ? n : undefined;
61
+ }
62
+ /**
63
+ *
64
+ * @param s
65
+ * @returns
66
+ */
67
+ function LooksLikeXmlNcName(s) {
68
+ // Approximation ASCII de NCName: pas de ":" et demarre par lettre ou underscore
69
+ // Puis lettres/chiffres/underscore/point/tiret.
70
+ return /^[A-Za-z_][A-Za-z0-9._-]*$/.test(s);
71
+ }
72
+ /**
73
+ *
74
+ * @param qn
75
+ * @returns
76
+ */
77
+ export function XmlNameToParts(qn) {
78
+ if (IsQualifiedName(qn)) {
79
+ return qn;
80
+ }
81
+ const s = (qn ?? "").trim();
82
+ if (!s) {
83
+ return { name: "" };
84
+ }
85
+ const i = s.indexOf(":");
86
+ if (i === -1) {
87
+ return { name: s };
88
+ }
89
+ // Un QName XML ne doit contenir qu un seul ":".
90
+ // Si il y en a plusieurs, on considere que ce n est pas un QName.
91
+ if (s.indexOf(":", i + 1) !== -1) {
92
+ return { name: s };
93
+ }
94
+ const prefix = s.slice(0, i);
95
+ const local = s.slice(i + 1);
96
+ if (LooksLikeXmlNcName(prefix) && LooksLikeXmlNcName(local)) {
97
+ return { ns: prefix, name: local };
98
+ }
99
+ return { name: s };
100
+ }
101
+ /**
102
+ *
103
+ * @param name
104
+ * @param prefix
105
+ * @returns
106
+ */
107
+ export function ToQualifiedString(name, prefix) {
108
+ return prefix ? `${prefix}:${name}` : name;
109
+ }
110
+ //# sourceMappingURL=xml.interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.interfaces.js","sourceRoot":"","sources":["../../../../../../dev/serializers/src/3MF/core/xml/xml.interfaces.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IXmlSerializerFormatOptions } from \"./xml.serializer.format\";\r\n\r\n/** */\r\nexport interface IQualifiedName {\r\n /** */\r\n ns?: string;\r\n /** */\r\n name: string;\r\n}\r\n\r\n/** */\r\nexport interface IXmlBuilder {\r\n dec(version: string, encoding?: string, standalone?: boolean): IXmlBuilder;\r\n att(ns: string | null, n: string, v: string): IXmlBuilder;\r\n ele(ns: string | null, n: string): IXmlBuilder;\r\n text(txt: string): IXmlBuilder;\r\n end(): IXmlBuilder;\r\n}\r\n\r\n/**\r\n * @param x\r\n * @returns\r\n */\r\nexport function IsQualifiedName(x: unknown): x is { name: string } {\r\n return typeof (x as any)?.name === \"string\";\r\n}\r\n\r\nexport type XmlName = string | IQualifiedName;\r\n\r\ntype FieldKind = \"attr\" | \"elem\" | \"none\";\r\n\r\n/**\r\n *\r\n */\r\nexport interface IFormatter<T = any> {\r\n toString(value: T): string;\r\n}\r\n\r\nexport type FormatterCtor<T> = new (args: IXmlSerializerFormatOptions) => IFormatter<T>;\r\n\r\ntype FieldMeta = {\r\n kind: FieldKind;\r\n prop: string;\r\n name?: XmlName;\r\n ignore?: boolean;\r\n formatter?: FormatterCtor<any>;\r\n};\r\n\r\nconst XML_CLASS_META = Symbol(\"__xml:meta$__\");\r\nconst XML_CLASS_NAME = Symbol(\"__xml:name$__\");\r\n\r\nfunction AddXmlMeta(target: any, meta: FieldMeta) {\r\n const ctor = target.constructor;\r\n (ctor[XML_CLASS_META] ??= []).push(meta);\r\n}\r\n\r\n/**\r\n * @param name\r\n * @returns\r\n */\r\nexport function XmlName(name: XmlName) {\r\n return (ctor: Function) => {\r\n (ctor as any)[XML_CLASS_NAME] = name;\r\n };\r\n}\r\n\r\n/**\r\n * tell the serializer to ignore the property\r\n * @returns\r\n */\r\nexport function XmlIgnore() {\r\n return (target: any, prop: string) => AddXmlMeta(target, { kind: \"none\", prop, ignore: true });\r\n}\r\n\r\n/**\r\n * tell the serializer to serialize the property as attribute\r\n * @returns\r\n */\r\nexport function XmlAttr(opts?: { name: XmlName; formatter?: FormatterCtor<any> }) {\r\n return (target: any, prop: string) => AddXmlMeta(target, { kind: \"attr\", prop, ...opts });\r\n}\r\n\r\n/**\r\n * tell the serializer to serialize the property as element - this is the default behavior but shoud be\r\n * specified when wanted to update the default name of the classe or if the class is not decorated (without \\@XmlName)\r\n * @returns\r\n */\r\nexport function XmlElem(opts?: { name: XmlName }) {\r\n return (target: any, prop: string) => AddXmlMeta(target, { kind: \"elem\", prop, ...opts });\r\n}\r\n\r\n/**\r\n *\r\n * @param obj\r\n * @returns\r\n */\r\nexport function GetXmlFieldMeta(obj: any): FieldMeta[] {\r\n return (obj?.constructor?.[XML_CLASS_META] ?? []) as FieldMeta[];\r\n}\r\n\r\n/**\r\n *\r\n * @param obj\r\n * @returns\r\n */\r\nexport function GetXmlName(obj: any): XmlName | undefined {\r\n const n = obj?.constructor?.[XML_CLASS_NAME];\r\n return n ? (n as XmlName) : undefined;\r\n}\r\n\r\n/**\r\n *\r\n * @param s\r\n * @returns\r\n */\r\nfunction LooksLikeXmlNcName(s: string): boolean {\r\n // Approximation ASCII de NCName: pas de \":\" et demarre par lettre ou underscore\r\n // Puis lettres/chiffres/underscore/point/tiret.\r\n return /^[A-Za-z_][A-Za-z0-9._-]*$/.test(s);\r\n}\r\n\r\n/**\r\n *\r\n * @param qn\r\n * @returns\r\n */\r\nexport function XmlNameToParts(qn: XmlName): IQualifiedName {\r\n if (IsQualifiedName(qn)) {\r\n return qn;\r\n }\r\n const s = (qn ?? \"\").trim();\r\n if (!s) {\r\n return { name: \"\" };\r\n }\r\n const i = s.indexOf(\":\");\r\n if (i === -1) {\r\n return { name: s };\r\n }\r\n\r\n // Un QName XML ne doit contenir qu un seul \":\".\r\n // Si il y en a plusieurs, on considere que ce n est pas un QName.\r\n if (s.indexOf(\":\", i + 1) !== -1) {\r\n return { name: s };\r\n }\r\n\r\n const prefix = s.slice(0, i);\r\n const local = s.slice(i + 1);\r\n\r\n if (LooksLikeXmlNcName(prefix) && LooksLikeXmlNcName(local)) {\r\n return { ns: prefix, name: local };\r\n }\r\n return { name: s };\r\n}\r\n\r\n/**\r\n *\r\n * @param name\r\n * @param prefix\r\n * @returns\r\n */\r\nexport function ToQualifiedString(name: string, prefix?: string): string {\r\n return prefix ? `${prefix}:${name}` : name;\r\n}\r\n"]}
@@ -0,0 +1,39 @@
1
+ import { type IXmlBuilder, type XmlName } from "./xml.interfaces.js";
2
+ import { type IXmlSerializerFormatOptions } from "./xml.serializer.format.js";
3
+ /**
4
+ */
5
+ export declare class XmlSerializer {
6
+ /** */
7
+ private _format;
8
+ /** */
9
+ private _builder;
10
+ /** */
11
+ private _ns;
12
+ /** */
13
+ private _prefixCount;
14
+ private _nFmt?;
15
+ /**
16
+ *
17
+ * @param builder
18
+ * @param format
19
+ */
20
+ constructor(builder: IXmlBuilder, format?: IXmlSerializerFormatOptions);
21
+ /**
22
+ *
23
+ * @param ns
24
+ * @returns
25
+ */
26
+ withNamespace(...ns: XmlName[]): XmlSerializer;
27
+ /**
28
+ *
29
+ * @param root
30
+ * @param name
31
+ */
32
+ serialize(root: object, name?: XmlName): void;
33
+ private _writeObject;
34
+ private _getPrefix;
35
+ private _writeObjectContent;
36
+ private _gatherNamespaces;
37
+ private _assignNamespace;
38
+ private _buildNsPrefix;
39
+ }
@@ -0,0 +1,92 @@
1
+ import type { IFormatter } from "./xml.interfaces.js";
2
+ /**
3
+ *
4
+ */
5
+ export interface IXmlSerializerNumberOptions {
6
+ /**
7
+ *
8
+ */
9
+ eps: number;
10
+ /**
11
+ *
12
+ */
13
+ maxDecimalsCap?: number;
14
+ /**
15
+ *
16
+ */
17
+ trimTrailingZeros?: boolean;
18
+ /**
19
+ *
20
+ */
21
+ fixedDecimals?: number;
22
+ /**
23
+ *
24
+ */
25
+ allowScientific?: boolean;
26
+ /**
27
+ *
28
+ */
29
+ snapNearZero?: boolean;
30
+ /**
31
+ *
32
+ */
33
+ zeroThreshold?: number;
34
+ /**
35
+ *
36
+ */
37
+ perAttributeEps?: Record<string, number>;
38
+ }
39
+ /**
40
+ *
41
+ */
42
+ export interface IXmlSerializerFormatOptions {
43
+ /**
44
+ *
45
+ */
46
+ number?: IXmlSerializerNumberOptions;
47
+ }
48
+ export declare const DefaultXmlSerializerNumberOptions: Readonly<IXmlSerializerNumberOptions>;
49
+ export declare const DefaultXmlSerializerFormatOptions: Readonly<IXmlSerializerFormatOptions>;
50
+ /**
51
+ *@param opts
52
+ *@returns
53
+ */
54
+ export declare function ResolveNumberOptions(opts?: IXmlSerializerNumberOptions): Required<Omit<IXmlSerializerNumberOptions, "perAttributeEps" | "fixedDecimals" | "maxDecimalsCap" | "trimTrailingZeros" | "allowScientific" | "snapNearZero" | "zeroThreshold">> & Pick<IXmlSerializerNumberOptions, "perAttributeEps" | "fixedDecimals"> & {
55
+ maxDecimalsCap: number;
56
+ trimTrailingZeros: boolean;
57
+ allowScientific: boolean;
58
+ snapNearZero: boolean;
59
+ zeroThreshold: number;
60
+ };
61
+ /**
62
+ *@param opts
63
+ *@returns
64
+ */
65
+ export declare function ResolveFormatOptions(opts?: IXmlSerializerFormatOptions): {
66
+ number: Required<Omit<IXmlSerializerNumberOptions, "maxDecimalsCap" | "trimTrailingZeros" | "fixedDecimals" | "allowScientific" | "snapNearZero" | "zeroThreshold" | "perAttributeEps">> & Pick<IXmlSerializerNumberOptions, "fixedDecimals" | "perAttributeEps"> & {
67
+ maxDecimalsCap: number;
68
+ trimTrailingZeros: boolean;
69
+ allowScientific: boolean;
70
+ snapNearZero: boolean;
71
+ zeroThreshold: number;
72
+ };
73
+ };
74
+ /**
75
+ *
76
+ */
77
+ export declare class NumberFormatter implements IFormatter<number> {
78
+ o: IXmlSerializerFormatOptions;
79
+ private _o;
80
+ /**
81
+ *
82
+ * @param o
83
+ */
84
+ constructor(o: IXmlSerializerFormatOptions);
85
+ /**
86
+ *
87
+ * @param x
88
+ * @returns
89
+ */
90
+ toString(x: number): string;
91
+ private _clampInt;
92
+ }
@@ -0,0 +1,122 @@
1
+ export const DefaultXmlSerializerNumberOptions = Object.freeze({
2
+ eps: 1e-6,
3
+ maxDecimalsCap: 15,
4
+ trimTrailingZeros: true,
5
+ // fixedDecimals: undefined,
6
+ allowScientific: false,
7
+ snapNearZero: true,
8
+ // zeroThreshold defaults to eps if not provided
9
+ // perAttributeEps: undefined,
10
+ });
11
+ export const DefaultXmlSerializerFormatOptions = Object.freeze({
12
+ number: DefaultXmlSerializerNumberOptions,
13
+ });
14
+ /**
15
+ *@param opts
16
+ *@returns
17
+ */
18
+ export function ResolveNumberOptions(opts) {
19
+ const eps = opts?.eps ?? DefaultXmlSerializerNumberOptions.eps;
20
+ return {
21
+ eps,
22
+ maxDecimalsCap: opts?.maxDecimalsCap ?? DefaultXmlSerializerNumberOptions.maxDecimalsCap,
23
+ trimTrailingZeros: opts?.trimTrailingZeros ?? DefaultXmlSerializerNumberOptions.trimTrailingZeros,
24
+ fixedDecimals: opts?.fixedDecimals,
25
+ allowScientific: opts?.allowScientific ?? DefaultXmlSerializerNumberOptions.allowScientific,
26
+ snapNearZero: opts?.snapNearZero ?? DefaultXmlSerializerNumberOptions.snapNearZero,
27
+ zeroThreshold: opts?.zeroThreshold ?? eps,
28
+ perAttributeEps: opts?.perAttributeEps,
29
+ };
30
+ }
31
+ /**
32
+ *@param opts
33
+ *@returns
34
+ */
35
+ export function ResolveFormatOptions(opts) {
36
+ return {
37
+ number: ResolveNumberOptions(opts?.number),
38
+ };
39
+ }
40
+ /**
41
+ *
42
+ */
43
+ export class NumberFormatter {
44
+ /**
45
+ *
46
+ * @param o
47
+ */
48
+ constructor(o) {
49
+ this.o = o;
50
+ this._o = o.number;
51
+ if (!Number.isFinite(this._o.eps) || this._o.eps <= 0) {
52
+ throw new Error("opts.eps must be a finite, positive number");
53
+ }
54
+ }
55
+ /**
56
+ *
57
+ * @param x
58
+ * @returns
59
+ */
60
+ toString(x) {
61
+ if (!Number.isFinite(x)) {
62
+ throw new Error(`Cannot format non-finite number: ${x}`);
63
+ }
64
+ const opts = this._o;
65
+ const maxDecimalsCap = this._clampInt(opts.maxDecimalsCap ?? 15, 0, 20);
66
+ const trimTrailingZeros = opts.trimTrailingZeros ?? true;
67
+ const snapNearZero = opts.snapNearZero ?? true;
68
+ const zeroThreshold = opts.zeroThreshold ?? opts.eps;
69
+ // Quantize to eps grid
70
+ const inv = 1 / opts.eps;
71
+ let q = Math.round(x * inv) / inv;
72
+ // Normalize -0 to 0
73
+ if (Object.is(q, -0)) {
74
+ q = 0;
75
+ }
76
+ // Snap tiny values to 0 (helps size + stability)
77
+ if (snapNearZero && Math.abs(q) <= zeroThreshold) {
78
+ q = 0;
79
+ }
80
+ // Choose decimals policy
81
+ let decimals;
82
+ if (opts.fixedDecimals !== undefined) {
83
+ decimals = this._clampInt(opts.fixedDecimals, 0, maxDecimalsCap);
84
+ }
85
+ else {
86
+ // decimals needed for eps steps
87
+ decimals = this._clampInt(Math.ceil(-Math.log10(opts.eps)), 0, maxDecimalsCap);
88
+ }
89
+ // Note: this implementation intentionally avoids scientific notation.
90
+ // If allowScientific=true, you may want a different path (toPrecision).
91
+ if (opts.allowScientific) {
92
+ // Still avoid scientific here; keep deterministic fixed output.
93
+ // If you really want scientific, implement a separate branch.
94
+ }
95
+ // Fast path when decimals = 0
96
+ if (decimals === 0) {
97
+ return String(Math.trunc(q));
98
+ }
99
+ // Start fixed, then optionally trim
100
+ let s = q.toFixed(decimals);
101
+ if (trimTrailingZeros && opts.fixedDecimals === undefined) {
102
+ // Trim trailing zeros and optional trailing dot
103
+ s = s
104
+ .replace(/(\.\d*?[1-9])0+$/, "$1")
105
+ .replace(/\.0+$/, "")
106
+ .replace(/\.$/, "");
107
+ }
108
+ // Safety: ensure no scientific notation (should not happen with toFixed)
109
+ if (/[eE]/.test(s)) {
110
+ throw new Error(`Scientific notation not allowed in XML output: ${s}`);
111
+ }
112
+ return s;
113
+ }
114
+ _clampInt(n, min, max) {
115
+ if (!Number.isFinite(n)) {
116
+ return min;
117
+ }
118
+ n = Math.trunc(n);
119
+ return Math.max(min, Math.min(max, n));
120
+ }
121
+ }
122
+ //# sourceMappingURL=xml.serializer.format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.serializer.format.js","sourceRoot":"","sources":["../../../../../../dev/serializers/src/3MF/core/xml/xml.serializer.format.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IFormatter } from \"./xml.interfaces\";\r\n\r\n/**\r\n *\r\n */\r\nexport interface IXmlSerializerNumberOptions {\r\n /**\r\n *\r\n */\r\n eps: number;\r\n /**\r\n *\r\n */\r\n maxDecimalsCap?: number; // default 15\r\n /**\r\n *\r\n */\r\n trimTrailingZeros?: boolean; // default true\r\n /**\r\n *\r\n */\r\n fixedDecimals?: number; // optional, overrides trim\r\n /**\r\n *\r\n */\r\n allowScientific?: boolean; // default false\r\n /**\r\n *\r\n */\r\n snapNearZero?: boolean; // default true\r\n /**\r\n *\r\n */\r\n zeroThreshold?: number; // default eps\r\n /**\r\n *\r\n */\r\n perAttributeEps?: Record<string, number>;\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport interface IXmlSerializerFormatOptions {\r\n /**\r\n *\r\n */\r\n number?: IXmlSerializerNumberOptions;\r\n}\r\n\r\nexport const DefaultXmlSerializerNumberOptions: Readonly<IXmlSerializerNumberOptions> = Object.freeze({\r\n eps: 1e-6,\r\n maxDecimalsCap: 15,\r\n trimTrailingZeros: true,\r\n // fixedDecimals: undefined,\r\n allowScientific: false,\r\n snapNearZero: true,\r\n // zeroThreshold defaults to eps if not provided\r\n // perAttributeEps: undefined,\r\n});\r\n\r\nexport const DefaultXmlSerializerFormatOptions: Readonly<IXmlSerializerFormatOptions> = Object.freeze({\r\n number: DefaultXmlSerializerNumberOptions,\r\n});\r\n\r\n/**\r\n *@param opts\r\n *@returns\r\n */\r\nexport function ResolveNumberOptions(opts?: IXmlSerializerNumberOptions): Required<\r\n Omit<IXmlSerializerNumberOptions, \"perAttributeEps\" | \"fixedDecimals\" | \"maxDecimalsCap\" | \"trimTrailingZeros\" | \"allowScientific\" | \"snapNearZero\" | \"zeroThreshold\">\r\n> &\r\n Pick<IXmlSerializerNumberOptions, \"perAttributeEps\" | \"fixedDecimals\"> & {\r\n maxDecimalsCap: number;\r\n trimTrailingZeros: boolean;\r\n allowScientific: boolean;\r\n snapNearZero: boolean;\r\n zeroThreshold: number;\r\n } {\r\n const eps = opts?.eps ?? DefaultXmlSerializerNumberOptions.eps;\r\n\r\n return {\r\n eps,\r\n maxDecimalsCap: opts?.maxDecimalsCap ?? DefaultXmlSerializerNumberOptions.maxDecimalsCap!,\r\n trimTrailingZeros: opts?.trimTrailingZeros ?? DefaultXmlSerializerNumberOptions.trimTrailingZeros!,\r\n fixedDecimals: opts?.fixedDecimals,\r\n allowScientific: opts?.allowScientific ?? DefaultXmlSerializerNumberOptions.allowScientific!,\r\n snapNearZero: opts?.snapNearZero ?? DefaultXmlSerializerNumberOptions.snapNearZero!,\r\n zeroThreshold: opts?.zeroThreshold ?? eps,\r\n perAttributeEps: opts?.perAttributeEps,\r\n };\r\n}\r\n\r\n/**\r\n *@param opts\r\n *@returns\r\n */\r\nexport function ResolveFormatOptions(opts?: IXmlSerializerFormatOptions) {\r\n return {\r\n number: ResolveNumberOptions(opts?.number),\r\n };\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport class NumberFormatter implements IFormatter<number> {\r\n private _o: IXmlSerializerNumberOptions;\r\n\r\n /**\r\n *\r\n * @param o\r\n */\r\n public constructor(public o: IXmlSerializerFormatOptions) {\r\n this._o = o.number!;\r\n\r\n if (!Number.isFinite(this._o.eps) || this._o.eps <= 0) {\r\n throw new Error(\"opts.eps must be a finite, positive number\");\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * @param x\r\n * @returns\r\n */\r\n\r\n public toString(x: number): string {\r\n if (!Number.isFinite(x)) {\r\n throw new Error(`Cannot format non-finite number: ${x}`);\r\n }\r\n\r\n const opts = this._o;\r\n const maxDecimalsCap = this._clampInt(opts.maxDecimalsCap ?? 15, 0, 20);\r\n const trimTrailingZeros = opts.trimTrailingZeros ?? true;\r\n const snapNearZero = opts.snapNearZero ?? true;\r\n const zeroThreshold = opts.zeroThreshold ?? opts.eps;\r\n\r\n // Quantize to eps grid\r\n const inv = 1 / opts.eps;\r\n let q = Math.round(x * inv) / inv;\r\n\r\n // Normalize -0 to 0\r\n if (Object.is(q, -0)) {\r\n q = 0;\r\n }\r\n\r\n // Snap tiny values to 0 (helps size + stability)\r\n if (snapNearZero && Math.abs(q) <= zeroThreshold) {\r\n q = 0;\r\n }\r\n\r\n // Choose decimals policy\r\n let decimals: number;\r\n if (opts.fixedDecimals !== undefined) {\r\n decimals = this._clampInt(opts.fixedDecimals, 0, maxDecimalsCap);\r\n } else {\r\n // decimals needed for eps steps\r\n decimals = this._clampInt(Math.ceil(-Math.log10(opts.eps)), 0, maxDecimalsCap);\r\n }\r\n\r\n // Note: this implementation intentionally avoids scientific notation.\r\n // If allowScientific=true, you may want a different path (toPrecision).\r\n if (opts.allowScientific) {\r\n // Still avoid scientific here; keep deterministic fixed output.\r\n // If you really want scientific, implement a separate branch.\r\n }\r\n\r\n // Fast path when decimals = 0\r\n if (decimals === 0) {\r\n return String(Math.trunc(q));\r\n }\r\n\r\n // Start fixed, then optionally trim\r\n let s = q.toFixed(decimals);\r\n\r\n if (trimTrailingZeros && opts.fixedDecimals === undefined) {\r\n // Trim trailing zeros and optional trailing dot\r\n s = s\r\n .replace(/(\\.\\d*?[1-9])0+$/, \"$1\")\r\n .replace(/\\.0+$/, \"\")\r\n .replace(/\\.$/, \"\");\r\n }\r\n\r\n // Safety: ensure no scientific notation (should not happen with toFixed)\r\n if (/[eE]/.test(s)) {\r\n throw new Error(`Scientific notation not allowed in XML output: ${s}`);\r\n }\r\n\r\n return s;\r\n }\r\n\r\n private _clampInt(n: number, min: number, max: number): number {\r\n if (!Number.isFinite(n)) {\r\n return min;\r\n }\r\n n = Math.trunc(n);\r\n return Math.max(min, Math.min(max, n));\r\n }\r\n}\r\n"]}
@@ -0,0 +1,261 @@
1
+ import { XmlNameToParts, GetXmlName, ToQualifiedString, GetXmlFieldMeta } from "./xml.interfaces.js";
2
+ import { NumberFormatter, ResolveFormatOptions } from "./xml.serializer.format.js";
3
+ function IsDate(x) {
4
+ return x instanceof Date;
5
+ }
6
+ function IsString(x) {
7
+ return typeof x === "string";
8
+ }
9
+ function IsNumber(x) {
10
+ return typeof x === "number";
11
+ }
12
+ function IsPrimitive(x) {
13
+ return typeof x === "string" || typeof x === "number" || typeof x === "boolean" || typeof x === "bigint" || IsDate(x);
14
+ }
15
+ function IsPrimitiveButString(x) {
16
+ return typeof x === "number" || typeof x === "boolean" || typeof x === "bigint" || IsDate(x);
17
+ }
18
+ /**
19
+ */
20
+ export class XmlSerializer {
21
+ /**
22
+ *
23
+ * @param builder
24
+ * @param format
25
+ */
26
+ constructor(builder, format) {
27
+ /** */
28
+ this._ns = new Map();
29
+ /** */
30
+ this._prefixCount = 0;
31
+ this._builder = builder;
32
+ this._format = ResolveFormatOptions(format);
33
+ this._nFmt = new NumberFormatter(this._format);
34
+ }
35
+ /**
36
+ *
37
+ * @param ns
38
+ * @returns
39
+ */
40
+ withNamespace(...ns) {
41
+ for (const s of ns) {
42
+ this._assignNamespace(s);
43
+ }
44
+ return this;
45
+ }
46
+ /**
47
+ *
48
+ * @param root
49
+ * @param name
50
+ */
51
+ serialize(root, name) {
52
+ name = name ?? GetXmlName(root);
53
+ if (!name) {
54
+ throw new Error("can not find name for given object");
55
+ }
56
+ const currentName = XmlNameToParts(name);
57
+ if (currentName.ns) {
58
+ // ensure we register the root namespace as default if not already set...
59
+ this._assignNamespace(currentName.ns, "xmlns");
60
+ }
61
+ this._gatherNamespaces(root, new WeakSet());
62
+ const doc = this._builder.ele(null, currentName.name);
63
+ for (const [v, n] of Array.from(this._ns.entries())) {
64
+ doc.att("xmlns", n, v);
65
+ }
66
+ this._writeObjectContent(doc, root, new WeakSet().add(root));
67
+ this._builder.end();
68
+ }
69
+ _writeObject(builder, source, visited) {
70
+ if (visited.has(source)) {
71
+ return;
72
+ }
73
+ visited.add(source);
74
+ if (Array.isArray(source)) {
75
+ for (const item of source) {
76
+ if (IsPrimitiveButString(item)) {
77
+ continue;
78
+ }
79
+ if (IsString(item)) {
80
+ this._builder.text(item);
81
+ continue;
82
+ }
83
+ this._writeObject(builder, item, visited);
84
+ }
85
+ return;
86
+ }
87
+ const qname = GetXmlName(source);
88
+ if (!qname) {
89
+ return;
90
+ }
91
+ const currentName = XmlNameToParts(qname);
92
+ const prefix = this._getPrefix(currentName);
93
+ const tmp = ToQualifiedString(currentName.name, prefix);
94
+ builder.ele(null, tmp);
95
+ this._writeObjectContent(builder, source, visited);
96
+ this._builder.end();
97
+ }
98
+ _getPrefix(qn) {
99
+ if (qn.ns) {
100
+ const p = this._ns.get(qn.ns.toLowerCase());
101
+ if (p !== "xmlns") {
102
+ return p;
103
+ }
104
+ }
105
+ return undefined;
106
+ }
107
+ _writeObjectContent(builder, source, visited) {
108
+ // gather meta and build index
109
+ const metas = GetXmlFieldMeta(source) ?? [];
110
+ const metaByProp = new Map();
111
+ for (const m of metas) {
112
+ const arr = metaByProp.get(m.prop) ?? [];
113
+ arr.push(m);
114
+ metaByProp.set(m.prop, arr);
115
+ }
116
+ // ensure the att are processed first, otherwize, the tag might be closed...
117
+ const keys = Object.keys(source).sort((a, b) => {
118
+ const aHasAttr = (metaByProp.get(a) ?? []).some((m) => m.kind === "attr");
119
+ const bHasAttr = (metaByProp.get(b) ?? []).some((m) => m.kind === "attr");
120
+ if (aHasAttr === bHasAttr) {
121
+ return 0;
122
+ }
123
+ return aHasAttr ? -1 : 1; // attr d abord
124
+ });
125
+ // We decide per property, using metadata if present
126
+ for (const prop of keys) {
127
+ const value = source[prop];
128
+ if (value === null || value === undefined) {
129
+ continue;
130
+ }
131
+ const propMetas = metaByProp.get(prop);
132
+ if (propMetas) {
133
+ const ignored = propMetas.some((m) => m.ignore === true || m.kind === "none");
134
+ if (ignored) {
135
+ continue;
136
+ }
137
+ for (const m of propMetas) {
138
+ const name = m.name ?? m.prop.toLowerCase(); // if the name is not defined, we assume it's the lower case version of name of the property.
139
+ if (name) {
140
+ switch (m.kind) {
141
+ case "attr": {
142
+ let vStr = null;
143
+ if (IsNumber(value) && this._nFmt) {
144
+ vStr = this._nFmt.toString(value);
145
+ }
146
+ if (m.formatter) {
147
+ // TODO : cache the created formatter to avoid to many allocation.
148
+ const f = new m.formatter(this._format);
149
+ vStr = f.toString(value);
150
+ }
151
+ vStr = vStr ?? value.toString();
152
+ if (vStr) {
153
+ const currentName = XmlNameToParts(name);
154
+ const prefix = this._getPrefix(currentName);
155
+ const tmp = ToQualifiedString(currentName.name, prefix);
156
+ builder.att(null, tmp, vStr);
157
+ }
158
+ break;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ continue;
164
+ }
165
+ if (IsPrimitiveButString(value)) {
166
+ continue;
167
+ }
168
+ if (IsString(value)) {
169
+ this._builder.text(value);
170
+ continue;
171
+ }
172
+ this._writeObject(builder, value, visited);
173
+ }
174
+ }
175
+ // this is the first browse of the hierarchy to collect the namespaces and assign placeholder.( ns0, ns1,...)
176
+ _gatherNamespaces(tag, visited) {
177
+ if (visited.has(tag)) {
178
+ return;
179
+ }
180
+ visited.add(tag);
181
+ if (Array.isArray(tag)) {
182
+ for (const item of tag) {
183
+ if (IsPrimitive(item)) {
184
+ continue;
185
+ }
186
+ this._gatherNamespaces(item, visited);
187
+ }
188
+ return;
189
+ }
190
+ const qname = GetXmlName(tag);
191
+ if (qname) {
192
+ this._assignNamespace(qname);
193
+ }
194
+ // gather meta and build index
195
+ const metas = GetXmlFieldMeta(tag) ?? [];
196
+ const metaByProp = new Map();
197
+ for (const m of metas) {
198
+ const arr = metaByProp.get(m.prop) ?? [];
199
+ arr.push(m);
200
+ metaByProp.set(m.prop, arr);
201
+ }
202
+ // We decide per property, using metadata if present
203
+ const toVisit = [];
204
+ for (const prop of Object.keys(tag)) {
205
+ const value = tag[prop];
206
+ if (value === null || value === undefined) {
207
+ continue;
208
+ }
209
+ const propMetas = metaByProp.get(prop);
210
+ if (propMetas) {
211
+ const ignored = propMetas.some((m) => m.ignore === true || m.kind === "none");
212
+ if (ignored) {
213
+ continue;
214
+ }
215
+ for (const m of propMetas) {
216
+ if (m.name) {
217
+ this._assignNamespace(m.name);
218
+ }
219
+ }
220
+ }
221
+ toVisit.push(value);
222
+ }
223
+ for (const v of toVisit) {
224
+ if (IsPrimitive(v)) {
225
+ continue;
226
+ }
227
+ this._gatherNamespaces(v, visited);
228
+ }
229
+ }
230
+ _assignNamespace(qn, prefix) {
231
+ const nqn = XmlNameToParts(qn);
232
+ if (nqn?.ns) {
233
+ const ns = nqn.ns.toLowerCase();
234
+ if (!this._ns.get(ns)) {
235
+ this._ns.set(ns, prefix ?? this._buildNsPrefix(ns));
236
+ }
237
+ return;
238
+ }
239
+ if (prefix === "xmlns") {
240
+ const ns = nqn.name.toLowerCase();
241
+ if (!this._ns.get(ns)) {
242
+ this._ns.set(ns, prefix ?? this._buildNsPrefix(ns));
243
+ }
244
+ }
245
+ }
246
+ _buildNsPrefix(_ns) {
247
+ let alreadyReferenced = false;
248
+ let value;
249
+ do {
250
+ value = `ns${this._prefixCount++}`;
251
+ for (const v of Array.from(this._ns.values())) {
252
+ if (v === value) {
253
+ alreadyReferenced = true;
254
+ break;
255
+ }
256
+ }
257
+ } while (alreadyReferenced);
258
+ return value;
259
+ }
260
+ }
261
+ //# sourceMappingURL=xml.serializer.js.map