@scalar/helpers 0.2.6 → 0.2.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @scalar/helpers
2
2
 
3
+ ## 0.2.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#7751](https://github.com/scalar/scalar/pull/7751): fix: auth persistence
8
+
9
+ ## 0.2.7
10
+
11
+ ### Patch Changes
12
+
13
+ - [#7720](https://github.com/scalar/scalar/pull/7720): feat: escape XML in json2xml
14
+
3
15
  ## 0.2.6
4
16
 
5
17
  ### Patch Changes
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * This function converts an object to XML.
3
+ * Values are automatically escaped to prevent XML injection attacks.
3
4
  */
4
5
  export declare function json2xml(data: Record<string, any>, options?: {
5
6
  indent?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"json2xml.d.ts","sourceRoot":"","sources":["../../src/file/json2xml.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,OAAO,CAAA;CACpB,UAyEP"}
1
+ {"version":3,"file":"json2xml.d.ts","sourceRoot":"","sources":["../../src/file/json2xml.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,OAAO,CAAA;CACpB,UA2EP"}
@@ -1,3 +1,13 @@
1
+ const XML_ESCAPE_MAP = {
2
+ "&": "&amp;",
3
+ "<": "&lt;",
4
+ ">": "&gt;",
5
+ '"': "&quot;",
6
+ "'": "&apos;"
7
+ };
8
+ function escapeXml(str) {
9
+ return str.replace(/[&<>"']/g, (char) => XML_ESCAPE_MAP[char] ?? char);
10
+ }
1
11
  function json2xml(data, options = {}) {
2
12
  const { indent = " ", format = true, xmlDeclaration = true } = options;
3
13
  const toXml = (value, key, currentIndent) => {
@@ -12,20 +22,21 @@ function json2xml(data, options = {}) {
12
22
  let children = "";
13
23
  for (const attr in value) {
14
24
  if (attr.charAt(0) === "@") {
15
- attributes += " " + attr.substr(1) + '="' + value[attr].toString() + '"';
25
+ attributes += " " + attr.substr(1) + '="' + escapeXml(value[attr].toString()) + '"';
16
26
  }
17
27
  }
18
28
  for (const child in value) {
19
29
  if (child === "#text") {
20
- children += value[child];
30
+ children += escapeXml(value[child]?.toString() ?? "");
21
31
  } else if (child === "#cdata") {
22
- children += "<![CDATA[" + value[child] + "]]>";
32
+ const cdataContent = value[child]?.toString() ?? "";
33
+ children += "<![CDATA[" + cdataContent.replace(/]]>/g, "]]]]><![CDATA[>") + "]]>";
23
34
  } else if (child.charAt(0) !== "@") {
24
35
  hasChild = true;
25
36
  children += toXml(value[child], child, currentIndent + indent);
26
37
  }
27
38
  }
28
- if (hasChild) {
39
+ if (hasChild || children) {
29
40
  xml2 += currentIndent + "<" + key + attributes + ">\n";
30
41
  xml2 += children;
31
42
  xml2 += currentIndent + "</" + key + ">\n";
@@ -33,7 +44,7 @@ function json2xml(data, options = {}) {
33
44
  xml2 += currentIndent + "<" + key + attributes + "/>\n";
34
45
  }
35
46
  } else {
36
- xml2 += currentIndent + "<" + key + ">" + (value?.toString() || "") + "</" + key + ">\n";
47
+ xml2 += currentIndent + "<" + key + ">" + escapeXml(value?.toString() || "") + "</" + key + ">\n";
37
48
  }
38
49
  return xml2;
39
50
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/file/json2xml.ts"],
4
- "sourcesContent": ["/**\n * This function converts an object to XML.\n */\nexport function json2xml(\n data: Record<string, any>,\n options: {\n indent?: string\n format?: boolean\n xmlDeclaration?: boolean\n } = {},\n) {\n const { indent = ' ', format = true, xmlDeclaration = true } = options\n\n const toXml = (value: any, key: string, currentIndent: string): string => {\n let xml = ''\n\n if (Array.isArray(value)) {\n for (let i = 0, n = value.length; i < n; i++) {\n xml += toXml(value[i], key, currentIndent)\n }\n } else if (typeof value === 'object' && value !== null) {\n let hasChild = false\n let attributes = ''\n let children = ''\n\n // Handle attributes (keys starting with @)\n for (const attr in value) {\n if (attr.charAt(0) === '@') {\n attributes += ' ' + attr.substr(1) + '=\"' + value[attr].toString() + '\"'\n }\n }\n\n // Handle children and special content\n for (const child in value) {\n if (child === '#text') {\n children += value[child]\n } else if (child === '#cdata') {\n children += '<![CDATA[' + value[child] + ']]>'\n } else if (child.charAt(0) !== '@') {\n hasChild = true\n children += toXml(value[child], child, currentIndent + indent)\n }\n }\n\n if (hasChild) {\n xml += currentIndent + '<' + key + attributes + '>\\n'\n xml += children\n xml += currentIndent + '</' + key + '>\\n'\n } else {\n xml += currentIndent + '<' + key + attributes + '/>\\n'\n }\n } else {\n xml += currentIndent + '<' + key + '>' + (value?.toString() || '') + '</' + key + '>\\n'\n }\n\n return xml\n }\n\n let xml = ''\n\n // Add XML declaration if requested\n if (xmlDeclaration) {\n xml += '<?xml version=\"1.0\" encoding=\"UTF-8\"?>'\n if (format) {\n xml += '\\n'\n }\n }\n\n // Convert data to XML\n for (const key in data) {\n if (Object.hasOwn(data, key)) {\n xml += toXml(data[key], key, '')\n }\n }\n\n // Format or compact the output\n if (format) {\n return xml.trim()\n }\n\n // Remove all newlines and extra spaces, but keep the XML declaration clean\n return xml.replace(/\\n/g, '').replace(/>\\s+</g, '><').trim()\n}\n"],
5
- "mappings": "AAGO,SAAS,SACd,MACA,UAII,CAAC,GACL;AACA,QAAM,EAAE,SAAS,MAAM,SAAS,MAAM,iBAAiB,KAAK,IAAI;AAEhE,QAAM,QAAQ,CAAC,OAAY,KAAa,kBAAkC;AACxE,QAAIA,OAAM;AAEV,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAI,GAAG,KAAK;AAC5C,QAAAA,QAAO,MAAM,MAAM,CAAC,GAAG,KAAK,aAAa;AAAA,MAC3C;AAAA,IACF,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,UAAI,WAAW;AACf,UAAI,aAAa;AACjB,UAAI,WAAW;AAGf,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,OAAO,CAAC,MAAM,KAAK;AAC1B,wBAAc,MAAM,KAAK,OAAO,CAAC,IAAI,OAAO,MAAM,IAAI,EAAE,SAAS,IAAI;AAAA,QACvE;AAAA,MACF;AAGA,iBAAW,SAAS,OAAO;AACzB,YAAI,UAAU,SAAS;AACrB,sBAAY,MAAM,KAAK;AAAA,QACzB,WAAW,UAAU,UAAU;AAC7B,sBAAY,cAAc,MAAM,KAAK,IAAI;AAAA,QAC3C,WAAW,MAAM,OAAO,CAAC,MAAM,KAAK;AAClC,qBAAW;AACX,sBAAY,MAAM,MAAM,KAAK,GAAG,OAAO,gBAAgB,MAAM;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,UAAU;AACZ,QAAAA,QAAO,gBAAgB,MAAM,MAAM,aAAa;AAChD,QAAAA,QAAO;AACP,QAAAA,QAAO,gBAAgB,OAAO,MAAM;AAAA,MACtC,OAAO;AACL,QAAAA,QAAO,gBAAgB,MAAM,MAAM,aAAa;AAAA,MAClD;AAAA,IACF,OAAO;AACL,MAAAA,QAAO,gBAAgB,MAAM,MAAM,OAAO,OAAO,SAAS,KAAK,MAAM,OAAO,MAAM;AAAA,IACpF;AAEA,WAAOA;AAAA,EACT;AAEA,MAAI,MAAM;AAGV,MAAI,gBAAgB;AAClB,WAAO;AACP,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAAA,EACF;AAGA,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,OAAO,MAAM,GAAG,GAAG;AAC5B,aAAO,MAAM,KAAK,GAAG,GAAG,KAAK,EAAE;AAAA,IACjC;AAAA,EACF;AAGA,MAAI,QAAQ;AACV,WAAO,IAAI,KAAK;AAAA,EAClB;AAGA,SAAO,IAAI,QAAQ,OAAO,EAAE,EAAE,QAAQ,UAAU,IAAI,EAAE,KAAK;AAC7D;",
4
+ "sourcesContent": ["/**\n * Character map for XML escaping to prevent XML injection attacks.\n */\nconst XML_ESCAPE_MAP: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&apos;',\n}\n\n/**\n * Escapes special XML characters to prevent injection attacks.\n */\nfunction escapeXml(str: string): string {\n return str.replace(/[&<>\"']/g, (char) => XML_ESCAPE_MAP[char] ?? char)\n}\n\n/**\n * This function converts an object to XML.\n * Values are automatically escaped to prevent XML injection attacks.\n */\nexport function json2xml(\n data: Record<string, any>,\n options: {\n indent?: string\n format?: boolean\n xmlDeclaration?: boolean\n } = {},\n) {\n const { indent = ' ', format = true, xmlDeclaration = true } = options\n\n const toXml = (value: any, key: string, currentIndent: string): string => {\n let xml = ''\n\n if (Array.isArray(value)) {\n for (let i = 0, n = value.length; i < n; i++) {\n xml += toXml(value[i], key, currentIndent)\n }\n } else if (typeof value === 'object' && value !== null) {\n let hasChild = false\n let attributes = ''\n let children = ''\n\n // Handle attributes (keys starting with @)\n for (const attr in value) {\n if (attr.charAt(0) === '@') {\n attributes += ' ' + attr.substr(1) + '=\"' + escapeXml(value[attr].toString()) + '\"'\n }\n }\n\n // Handle children and special content\n for (const child in value) {\n if (child === '#text') {\n children += escapeXml(value[child]?.toString() ?? '')\n } else if (child === '#cdata') {\n // Escape ]]> sequences to prevent CDATA injection\n const cdataContent = value[child]?.toString() ?? ''\n children += '<![CDATA[' + cdataContent.replace(/]]>/g, ']]]]><![CDATA[>') + ']]>'\n } else if (child.charAt(0) !== '@') {\n hasChild = true\n children += toXml(value[child], child, currentIndent + indent)\n }\n }\n\n if (hasChild || children) {\n xml += currentIndent + '<' + key + attributes + '>\\n'\n xml += children\n xml += currentIndent + '</' + key + '>\\n'\n } else {\n xml += currentIndent + '<' + key + attributes + '/>\\n'\n }\n } else {\n xml += currentIndent + '<' + key + '>' + escapeXml(value?.toString() || '') + '</' + key + '>\\n'\n }\n\n return xml\n }\n\n let xml = ''\n\n // Add XML declaration if requested\n if (xmlDeclaration) {\n xml += '<?xml version=\"1.0\" encoding=\"UTF-8\"?>'\n if (format) {\n xml += '\\n'\n }\n }\n\n // Convert data to XML\n for (const key in data) {\n if (Object.hasOwn(data, key)) {\n xml += toXml(data[key], key, '')\n }\n }\n\n // Format or compact the output\n if (format) {\n return xml.trim()\n }\n\n // Remove all newlines and extra spaces, but keep the XML declaration clean\n return xml.replace(/\\n/g, '').replace(/>\\s+</g, '><').trim()\n}\n"],
5
+ "mappings": "AAGA,MAAM,iBAAyC;AAAA,EAC7C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAKA,SAAS,UAAU,KAAqB;AACtC,SAAO,IAAI,QAAQ,YAAY,CAAC,SAAS,eAAe,IAAI,KAAK,IAAI;AACvE;AAMO,SAAS,SACd,MACA,UAII,CAAC,GACL;AACA,QAAM,EAAE,SAAS,MAAM,SAAS,MAAM,iBAAiB,KAAK,IAAI;AAEhE,QAAM,QAAQ,CAAC,OAAY,KAAa,kBAAkC;AACxE,QAAIA,OAAM;AAEV,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAI,GAAG,KAAK;AAC5C,QAAAA,QAAO,MAAM,MAAM,CAAC,GAAG,KAAK,aAAa;AAAA,MAC3C;AAAA,IACF,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,UAAI,WAAW;AACf,UAAI,aAAa;AACjB,UAAI,WAAW;AAGf,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,OAAO,CAAC,MAAM,KAAK;AAC1B,wBAAc,MAAM,KAAK,OAAO,CAAC,IAAI,OAAO,UAAU,MAAM,IAAI,EAAE,SAAS,CAAC,IAAI;AAAA,QAClF;AAAA,MACF;AAGA,iBAAW,SAAS,OAAO;AACzB,YAAI,UAAU,SAAS;AACrB,sBAAY,UAAU,MAAM,KAAK,GAAG,SAAS,KAAK,EAAE;AAAA,QACtD,WAAW,UAAU,UAAU;AAE7B,gBAAM,eAAe,MAAM,KAAK,GAAG,SAAS,KAAK;AACjD,sBAAY,cAAc,aAAa,QAAQ,QAAQ,iBAAiB,IAAI;AAAA,QAC9E,WAAW,MAAM,OAAO,CAAC,MAAM,KAAK;AAClC,qBAAW;AACX,sBAAY,MAAM,MAAM,KAAK,GAAG,OAAO,gBAAgB,MAAM;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,YAAY,UAAU;AACxB,QAAAA,QAAO,gBAAgB,MAAM,MAAM,aAAa;AAChD,QAAAA,QAAO;AACP,QAAAA,QAAO,gBAAgB,OAAO,MAAM;AAAA,MACtC,OAAO;AACL,QAAAA,QAAO,gBAAgB,MAAM,MAAM,aAAa;AAAA,MAClD;AAAA,IACF,OAAO;AACL,MAAAA,QAAO,gBAAgB,MAAM,MAAM,MAAM,UAAU,OAAO,SAAS,KAAK,EAAE,IAAI,OAAO,MAAM;AAAA,IAC7F;AAEA,WAAOA;AAAA,EACT;AAEA,MAAI,MAAM;AAGV,MAAI,gBAAgB;AAClB,WAAO;AACP,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAAA,EACF;AAGA,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,OAAO,MAAM,GAAG,GAAG;AAC5B,aAAO,MAAM,KAAK,GAAG,GAAG,KAAK,EAAE;AAAA,IACjC;AAAA,EACF;AAGA,MAAI,QAAQ;AACV,WAAO,IAAI,KAAK;AAAA,EAClB;AAGA,SAAO,IAAI,QAAQ,OAAO,EAAE,EAAE,QAAQ,UAAU,IAAI,EAAE,KAAK;AAC7D;",
6
6
  "names": ["xml"]
7
7
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Returns true if the provided value is a plain object
3
+ * (i.e. not null, not an array, and typeof value is "object").
4
+ *
5
+ * This is a type guard useful for narrowing types in TypeScript.
6
+ *
7
+ * Examples:
8
+ * isObject({}) // true
9
+ * isObject({ a: 1 }) // true
10
+ * isObject([]) // false (Array)
11
+ * isObject(null) // false
12
+ * isObject(123) // false
13
+ * isObject('string') // false
14
+ * isObject(new Date()) // true (note: Date is technically an object)
15
+ * isObject(Object.create(null)) // true
16
+ */
17
+ export declare const isObject: (value: unknown) => value is Record<string, unknown>;
18
+ //# sourceMappingURL=is-object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-object.d.ts","sourceRoot":"","sources":["../../src/object/is-object.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAExE,CAAA"}
@@ -0,0 +1,7 @@
1
+ const isObject = (value) => {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ };
4
+ export {
5
+ isObject
6
+ };
7
+ //# sourceMappingURL=is-object.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/object/is-object.ts"],
4
+ "sourcesContent": ["/**\n * Returns true if the provided value is a plain object\n * (i.e. not null, not an array, and typeof value is \"object\").\n *\n * This is a type guard useful for narrowing types in TypeScript.\n *\n * Examples:\n * isObject({}) // true\n * isObject({ a: 1 }) // true\n * isObject([]) // false (Array)\n * isObject(null) // false\n * isObject(123) // false\n * isObject('string') // false\n * isObject(new Date()) // true (note: Date is technically an object)\n * isObject(Object.create(null)) // true\n */\nexport const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"],
5
+ "mappings": "AAgBO,MAAM,WAAW,CAAC,UAAqD;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;",
6
+ "names": []
7
+ }
@@ -1,11 +1,11 @@
1
1
  /** Spy on console.warn */
2
- export declare const consoleWarnSpy: import("vitest").MockInstance<{
2
+ export declare const consoleWarnSpy: import("vitest").Mock<{
3
3
  (...data: any[]): void;
4
4
  (message?: any, ...optionalParams: any[]): void;
5
5
  }>;
6
6
  export declare let isConsoleWarnEnabled: boolean;
7
7
  /** Spy on console.error */
8
- export declare const consoleErrorSpy: import("vitest").MockInstance<{
8
+ export declare const consoleErrorSpy: import("vitest").Mock<{
9
9
  (...data: any[]): void;
10
10
  (message?: any, ...optionalParams: any[]): void;
11
11
  }>;
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "helpers",
15
15
  "js"
16
16
  ],
17
- "version": "0.2.6",
17
+ "version": "0.2.8",
18
18
  "engines": {
19
19
  "node": ">=20"
20
20
  },
@@ -89,8 +89,8 @@
89
89
  ],
90
90
  "devDependencies": {
91
91
  "jsdom": "26.1.0",
92
- "vite": "7.1.11",
93
- "vitest": "3.2.4",
92
+ "vite": "^7.3.1",
93
+ "vitest": "4.0.16",
94
94
  "@scalar/build-tooling": "0.4.1"
95
95
  },
96
96
  "scripts": {