@cj-tech-master/excelts 7.3.0 → 7.4.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.
@@ -304,7 +304,7 @@ function toPlainObject(element, options) {
304
304
  break;
305
305
  case "element": {
306
306
  const value = convertElement(child);
307
- addChildValue(obj, child.name, value, opts.alwaysArray);
307
+ addChildValue(obj, child.name, value, opts.alwaysArray, opts.isArray);
308
308
  hasChildren = true;
309
309
  break;
310
310
  }
@@ -10,6 +10,7 @@ export interface ResolvedOptions {
10
10
  readonly attrPrefix: string;
11
11
  readonly textKey: string;
12
12
  readonly alwaysArray: boolean;
13
+ readonly isArray: ((name: string) => boolean) | null;
13
14
  readonly preserveCData: boolean;
14
15
  readonly ignoreWS: boolean;
15
16
  }
@@ -26,4 +27,4 @@ export declare function resolveValue(obj: Record<string, unknown>, text: string,
26
27
  * Add a resolved child value into a parent object, merging repeated names
27
28
  * into arrays.
28
29
  */
29
- export declare function addChildValue(parent: Record<string, unknown>, name: string, value: unknown, alwaysArray: boolean): void;
30
+ export declare function addChildValue(parent: Record<string, unknown>, name: string, value: unknown, alwaysArray: boolean, isArray: ((name: string) => boolean) | null): void;
@@ -9,6 +9,7 @@ export function resolveOptions(options) {
9
9
  attrPrefix: options?.attributePrefix ?? "@_",
10
10
  textKey: options?.textKey ?? "#text",
11
11
  alwaysArray: options?.alwaysArray ?? false,
12
+ isArray: options?.isArray ?? null,
12
13
  preserveCData: options?.preserveCData ?? true,
13
14
  ignoreWS: options?.ignoreWhitespaceText ?? true
14
15
  };
@@ -64,7 +65,7 @@ export function resolveValue(obj, text, hasAttributes, hasChildren, opts) {
64
65
  * Add a resolved child value into a parent object, merging repeated names
65
66
  * into arrays.
66
67
  */
67
- export function addChildValue(parent, name, value, alwaysArray) {
68
+ export function addChildValue(parent, name, value, alwaysArray, isArray) {
68
69
  const existing = parent[name];
69
70
  if (existing !== undefined) {
70
71
  if (Array.isArray(existing)) {
@@ -75,6 +76,7 @@ export function addChildValue(parent, name, value, alwaysArray) {
75
76
  }
76
77
  }
77
78
  else {
78
- parent[name] = alwaysArray ? [value] : value;
79
+ const wrap = alwaysArray || (isArray !== null && isArray(name));
80
+ parent[name] = wrap ? [value] : value;
79
81
  }
80
82
  }
@@ -113,9 +113,7 @@ function parseXmlToObject(xml, options) {
113
113
  */
114
114
  function finishFrame(frame, parent, opts) {
115
115
  const value = resolveValue(frame.obj, frame.text, frame.hasAttributes, frame.hasChildren, opts);
116
- // The document root element (child of synthetic root) should never be
117
- // wrapped in an array by alwaysArray — it's always a direct value.
118
116
  const isDocRoot = parent.name === "";
119
- addChildValue(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray);
117
+ addChildValue(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray, isDocRoot ? null : opts.isArray);
120
118
  }
121
119
  export { parseXmlToObject };
@@ -223,6 +223,13 @@ export interface ToPlainObjectOptions {
223
223
  * @default false
224
224
  */
225
225
  alwaysArray?: boolean;
226
+ /**
227
+ * Callback to determine whether a specific tag name should always be wrapped
228
+ * in an array, even if only a single element exists. Takes precedence over
229
+ * `alwaysArray` for matching names. When both `isArray` and `alwaysArray` are
230
+ * set, a tag is wrapped if either returns/is true.
231
+ */
232
+ isArray?: (name: string) => boolean;
226
233
  /**
227
234
  * When true, include CDATA node values (already merged to text by default
228
235
  * in `parseXml`, only relevant with `cdataAsNodes`).
@@ -313,7 +313,7 @@ function toPlainObject(element, options) {
313
313
  break;
314
314
  case "element": {
315
315
  const value = convertElement(child);
316
- (0, to_object_shared_1.addChildValue)(obj, child.name, value, opts.alwaysArray);
316
+ (0, to_object_shared_1.addChildValue)(obj, child.name, value, opts.alwaysArray, opts.isArray);
317
317
  hasChildren = true;
318
318
  break;
319
319
  }
@@ -14,6 +14,7 @@ function resolveOptions(options) {
14
14
  attrPrefix: options?.attributePrefix ?? "@_",
15
15
  textKey: options?.textKey ?? "#text",
16
16
  alwaysArray: options?.alwaysArray ?? false,
17
+ isArray: options?.isArray ?? null,
17
18
  preserveCData: options?.preserveCData ?? true,
18
19
  ignoreWS: options?.ignoreWhitespaceText ?? true
19
20
  };
@@ -69,7 +70,7 @@ function resolveValue(obj, text, hasAttributes, hasChildren, opts) {
69
70
  * Add a resolved child value into a parent object, merging repeated names
70
71
  * into arrays.
71
72
  */
72
- function addChildValue(parent, name, value, alwaysArray) {
73
+ function addChildValue(parent, name, value, alwaysArray, isArray) {
73
74
  const existing = parent[name];
74
75
  if (existing !== undefined) {
75
76
  if (Array.isArray(existing)) {
@@ -80,6 +81,7 @@ function addChildValue(parent, name, value, alwaysArray) {
80
81
  }
81
82
  }
82
83
  else {
83
- parent[name] = alwaysArray ? [value] : value;
84
+ const wrap = alwaysArray || (isArray !== null && isArray(name));
85
+ parent[name] = wrap ? [value] : value;
84
86
  }
85
87
  }
@@ -116,8 +116,6 @@ function parseXmlToObject(xml, options) {
116
116
  */
117
117
  function finishFrame(frame, parent, opts) {
118
118
  const value = (0, to_object_shared_1.resolveValue)(frame.obj, frame.text, frame.hasAttributes, frame.hasChildren, opts);
119
- // The document root element (child of synthetic root) should never be
120
- // wrapped in an array by alwaysArray — it's always a direct value.
121
119
  const isDocRoot = parent.name === "";
122
- (0, to_object_shared_1.addChildValue)(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray);
120
+ (0, to_object_shared_1.addChildValue)(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray, isDocRoot ? null : opts.isArray);
123
121
  }
@@ -304,7 +304,7 @@ function toPlainObject(element, options) {
304
304
  break;
305
305
  case "element": {
306
306
  const value = convertElement(child);
307
- addChildValue(obj, child.name, value, opts.alwaysArray);
307
+ addChildValue(obj, child.name, value, opts.alwaysArray, opts.isArray);
308
308
  hasChildren = true;
309
309
  break;
310
310
  }
@@ -9,6 +9,7 @@ export function resolveOptions(options) {
9
9
  attrPrefix: options?.attributePrefix ?? "@_",
10
10
  textKey: options?.textKey ?? "#text",
11
11
  alwaysArray: options?.alwaysArray ?? false,
12
+ isArray: options?.isArray ?? null,
12
13
  preserveCData: options?.preserveCData ?? true,
13
14
  ignoreWS: options?.ignoreWhitespaceText ?? true
14
15
  };
@@ -64,7 +65,7 @@ export function resolveValue(obj, text, hasAttributes, hasChildren, opts) {
64
65
  * Add a resolved child value into a parent object, merging repeated names
65
66
  * into arrays.
66
67
  */
67
- export function addChildValue(parent, name, value, alwaysArray) {
68
+ export function addChildValue(parent, name, value, alwaysArray, isArray) {
68
69
  const existing = parent[name];
69
70
  if (existing !== undefined) {
70
71
  if (Array.isArray(existing)) {
@@ -75,6 +76,7 @@ export function addChildValue(parent, name, value, alwaysArray) {
75
76
  }
76
77
  }
77
78
  else {
78
- parent[name] = alwaysArray ? [value] : value;
79
+ const wrap = alwaysArray || (isArray !== null && isArray(name));
80
+ parent[name] = wrap ? [value] : value;
79
81
  }
80
82
  }
@@ -113,9 +113,7 @@ function parseXmlToObject(xml, options) {
113
113
  */
114
114
  function finishFrame(frame, parent, opts) {
115
115
  const value = resolveValue(frame.obj, frame.text, frame.hasAttributes, frame.hasChildren, opts);
116
- // The document root element (child of synthetic root) should never be
117
- // wrapped in an array by alwaysArray — it's always a direct value.
118
116
  const isDocRoot = parent.name === "";
119
- addChildValue(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray);
117
+ addChildValue(parent.obj, frame.name, value, isDocRoot ? false : opts.alwaysArray, isDocRoot ? null : opts.isArray);
120
118
  }
121
119
  export { parseXmlToObject };
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v7.3.0
2
+ * @cj-tech-master/excelts v7.4.0
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v7.3.0
2
+ * @cj-tech-master/excelts v7.4.0
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -10,6 +10,7 @@ export interface ResolvedOptions {
10
10
  readonly attrPrefix: string;
11
11
  readonly textKey: string;
12
12
  readonly alwaysArray: boolean;
13
+ readonly isArray: ((name: string) => boolean) | null;
13
14
  readonly preserveCData: boolean;
14
15
  readonly ignoreWS: boolean;
15
16
  }
@@ -26,4 +27,4 @@ export declare function resolveValue(obj: Record<string, unknown>, text: string,
26
27
  * Add a resolved child value into a parent object, merging repeated names
27
28
  * into arrays.
28
29
  */
29
- export declare function addChildValue(parent: Record<string, unknown>, name: string, value: unknown, alwaysArray: boolean): void;
30
+ export declare function addChildValue(parent: Record<string, unknown>, name: string, value: unknown, alwaysArray: boolean, isArray: ((name: string) => boolean) | null): void;
@@ -223,6 +223,13 @@ export interface ToPlainObjectOptions {
223
223
  * @default false
224
224
  */
225
225
  alwaysArray?: boolean;
226
+ /**
227
+ * Callback to determine whether a specific tag name should always be wrapped
228
+ * in an array, even if only a single element exists. Takes precedence over
229
+ * `alwaysArray` for matching names. When both `isArray` and `alwaysArray` are
230
+ * set, a tag is wrapped if either returns/is true.
231
+ */
232
+ isArray?: (name: string) => boolean;
226
233
  /**
227
234
  * When true, include CDATA node values (already merged to text by default
228
235
  * in `parseXml`, only relevant with `cdataAsNodes`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cj-tech-master/excelts",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "description": "TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",