diff --git a/.github/workflows/documentationjs.yml b/.github/workflows/documentationjs.yml deleted file mode 100644 index e93dc38..0000000 --- a/.github/workflows/documentationjs.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Deploy documentation.js on GitHub pages - -on: - workflow_dispatch: - release: - types: [published] - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Build documentation - uses: zakodium/documentationjs-action@v1 - - name: Deploy to GitHub pages - uses: JamesIves/github-pages-deploy-action@releases/v4 - with: - token: ${{ secrets.BOT_TOKEN }} - branch: gh-pages - folder: docs - clean: true diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml new file mode 100644 index 0000000..6de8daf --- /dev/null +++ b/.github/workflows/typedoc.yml @@ -0,0 +1,14 @@ +name: TypeDoc + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + typedoc: + uses: zakodium/workflows/.github/workflows/typedoc.yml@typedoc-v1 + with: + entry: 'src/index.ts' + secrets: + github-token: ${{ secrets.BOT_TOKEN }} diff --git a/.gitignore b/.gitignore index 81c3507..9ed4bea 100644 --- a/.gitignore +++ b/.gitignore @@ -115,6 +115,7 @@ dist .yarn/install-state.gz .pnp.* +.claude .DS_Store lib diff --git a/package.json b/package.json index 0189583..e9eb2ec 100644 --- a/package.json +++ b/package.json @@ -35,25 +35,25 @@ "url": "https://github.com/cheminfo/arraybuffer-xml-parser/issues" }, "homepage": "https://github.com/cheminfo/arraybuffer-xml-parser#readme", + "dependencies": { + "dynamic-typing": "^2.0.0" + }, "devDependencies": { "@types/he": "^1.2.3", - "@vitest/coverage-v8": "4.0.12", - "@zakodium/tsconfig": "^1.0.2", - "cheminfo-build": "^1.3.1", + "@types/node": "^25.5.0", + "@vitest/coverage-v8": "4.1.2", + "@zakodium/tsconfig": "^1.0.3", + "cheminfo-build": "^1.3.2", "eslint": "^9.39.1", - "eslint-config-cheminfo-typescript": "^21.0.1", - "globals": "^16.5.0", + "eslint-config-cheminfo-typescript": "^21.1.0", + "globals": "^17.4.0", "he": "^1.2.0", - "ml-spectra-processing": "^14.18.1", + "ml-spectra-processing": "^14.22.0", "pako": "^2.1.0", - "prettier": "^3.6.2", - "rimraf": "^6.1.2", + "prettier": "^3.8.1", + "rimraf": "^6.1.3", "typescript": "^5.9.3", "uint8-base64": "^1.0.0", - "vitest": "^4.0.12" - }, - "dependencies": { - "@types/node": "^24.10.1", - "dynamic-typing": "^1.0.1" + "vitest": "^4.1.2" } } diff --git a/src/.npmignore b/src/.npmignore index e75adf4..27e25b8 100644 --- a/src/.npmignore +++ b/src/.npmignore @@ -1,2 +1,3 @@ __tests__ +.DS_Store .npmignore \ No newline at end of file diff --git a/src/XMLNode.ts b/src/XMLNode.ts index 6fadce3..380ebe7 100644 --- a/src/XMLNode.ts +++ b/src/XMLNode.ts @@ -1,4 +1,4 @@ -import type { TagValueProcessor } from './traversable/defaultOptions.js'; +import type { TagValueProcessor } from './traversable/defaultOptions.ts'; export type XMLNodeValue = string | Uint8Array | number | boolean; export type XMLAttributeValue = string | number | boolean; @@ -44,9 +44,9 @@ export class XMLNode { return this.cachedValue; } public addChild(child: XMLNode) { - if (Array.isArray(this.children[child.tagName])) { - //already presents - this.children[child.tagName].push(child); + const existing = this.children[child.tagName]; + if (Array.isArray(existing)) { + existing.push(child); } else { this.children[child.tagName] = [child]; } diff --git a/src/__tests__/arrayModeSpec.test.ts b/src/__tests__/arrayModeSpec.test.ts index 01ff628..405d553 100644 --- a/src/__tests__/arrayModeSpec.test.ts +++ b/src/__tests__/arrayModeSpec.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); diff --git a/src/__tests__/arrayWithExtendedPrototypePropsSpec.test.js b/src/__tests__/arrayWithExtendedPrototypePropsSpec.test.ts similarity index 84% rename from src/__tests__/arrayWithExtendedPrototypePropsSpec.test.js rename to src/__tests__/arrayWithExtendedPrototypePropsSpec.test.ts index dfe96ba..5208c43 100644 --- a/src/__tests__/arrayWithExtendedPrototypePropsSpec.test.js +++ b/src/__tests__/arrayWithExtendedPrototypePropsSpec.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); @@ -15,8 +15,7 @@ describe('XMLParser array with extended prototype props', () => { a: { b: [0, 1] }, }; - // eslint-disable-next-line no-extend-native - Array.prototype.someExtentionOfArrayPrototype = + (Array.prototype as any).someExtentionOfArrayPrototype = 'someExtentionOfArrayPrototype'; const result = parse(xmlData, { diff --git a/src/__tests__/attributesSpec.test.ts b/src/__tests__/attributesSpec.test.ts index b706ade..af7364c 100644 --- a/src/__tests__/attributesSpec.test.ts +++ b/src/__tests__/attributesSpec.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; // import he from 'he'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); diff --git a/src/__tests__/base64.test.js b/src/__tests__/base64.test.ts similarity index 91% rename from src/__tests__/base64.test.js rename to src/__tests__/base64.test.ts index 5d14e20..676caa1 100644 --- a/src/__tests__/base64.test.js +++ b/src/__tests__/base64.test.ts @@ -1,7 +1,7 @@ import { decode as base64decode } from 'uint8-base64'; import { expect, test } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; // library to convert base64 <--> arrayBuffer: https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts const encoder = new TextEncoder(); @@ -15,7 +15,7 @@ test('base64 parsing', () => { AAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhA `); - let result = parse(xmlData, { + const result = parse(xmlData, { attributeNameProcessor: (name) => name, tagValueProcessor: (value, node) => { if (node.tagName !== 'binary') return decoder.decode(value); @@ -23,7 +23,7 @@ test('base64 parsing', () => { // isLittleEndian and the data were encoded in littleEndian return new Float64Array(decoded.buffer); }, - }); + }) as Record; expect(result.binaryDataArray.binary).toStrictEqual( Float64Array.from([1, 2, 3]), diff --git a/src/__tests__/cdataSpec.test.ts b/src/__tests__/cdataSpec.test.ts index 4650ad2..2502f3d 100644 --- a/src/__tests__/cdataSpec.test.ts +++ b/src/__tests__/cdataSpec.test.ts @@ -3,7 +3,7 @@ import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); diff --git a/src/__tests__/cheminfo.test.ts b/src/__tests__/cheminfo.test.ts index cb647a5..4bec61a 100644 --- a/src/__tests__/cheminfo.test.ts +++ b/src/__tests__/cheminfo.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; describe('XMLParser', () => { it('Try to parse a very simple example', () => { diff --git a/src/__tests__/cyrillic.test.ts b/src/__tests__/cyrillic.test.ts index 87d1848..6a8ab28 100644 --- a/src/__tests__/cyrillic.test.ts +++ b/src/__tests__/cyrillic.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; describe('XMLParser', () => { it('should parse XML with cyrillic characters to JSON string', () => { diff --git a/src/__tests__/data.test.ts b/src/__tests__/data.test.ts index 59c6225..937be2a 100644 --- a/src/__tests__/data.test.ts +++ b/src/__tests__/data.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); diff --git a/src/__tests__/parseStream.test.ts b/src/__tests__/parseStream.test.ts index 4555b8c..c0d2f17 100644 --- a/src/__tests__/parseStream.test.ts +++ b/src/__tests__/parseStream.test.ts @@ -3,7 +3,7 @@ import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; -import { parseStream } from '../parseStream.js'; +import { parseStream } from '../parseStream.ts'; describe('parseStream', () => { it('simple case', async () => { diff --git a/src/__tests__/stopNodes.test.ts b/src/__tests__/stopNodes.test.ts index 9b908d3..148b4c3 100644 --- a/src/__tests__/stopNodes.test.ts +++ b/src/__tests__/stopNodes.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); diff --git a/src/__tests__/tagProcessors.test.ts b/src/__tests__/tagProcessors.test.ts index 4a8571b..d24b752 100644 --- a/src/__tests__/tagProcessors.test.ts +++ b/src/__tests__/tagProcessors.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; describe('XMLParser', () => { it('tag name processor', () => { diff --git a/src/__tests__/valueProcessors.test.ts b/src/__tests__/valueProcessors.test.ts index 17c4948..4c86063 100644 --- a/src/__tests__/valueProcessors.test.ts +++ b/src/__tests__/valueProcessors.test.ts @@ -3,7 +3,7 @@ import he from 'he'; // HTML entity encoder/decoder import { describe, expect, it } from 'vitest'; /* eslint-disable camelcase */ -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); const decoder = new TextDecoder(); @@ -89,8 +89,9 @@ describe('XMLParser', () => { const resultMap: Record = {}; parse(xmlData, { tagValueProcessor: (value, node) => { - if (resultMap[node.tagName]) { - resultMap[node.tagName].push(value); + const existing = resultMap[node.tagName]; + if (existing) { + existing.push(value); } else { resultMap[node.tagName] = [value]; } diff --git a/src/__tests__/xmlParser.mz.test.ts b/src/__tests__/xmlParser.mz.test.ts index 56e3110..045d9bc 100644 --- a/src/__tests__/xmlParser.mz.test.ts +++ b/src/__tests__/xmlParser.mz.test.ts @@ -6,7 +6,7 @@ import { recursiveResolve } from 'ml-spectra-processing'; import { decode } from 'uint8-base64'; import { expect, test } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const decoder = new TextDecoder(); @@ -76,7 +76,9 @@ export async function decodeBase64( switch (compression.toLowerCase()) { case 'zlib': { const ds = new DecompressionStream('deflate'); - const decompressedStream = new Blob([uint8Array]) + const decompressedStream = new Blob([ + uint8Array as Uint8Array, + ]) .stream() .pipeThrough(ds); const decompressedArrayBuffer = await new Response( @@ -116,8 +118,8 @@ export async function decodeBase64( i += step ) { for (let j = 0; j < step / 2; j++) { - const temp = uint8Array[i + j]; - uint8Array[i + j] = uint8Array[i + step - 1 - j]; + const temp = uint8Array[i + j] as number; + uint8Array[i + j] = uint8Array[i + step - 1 - j] as number; uint8Array[i + step - 1 - j] = temp; } } diff --git a/src/__tests__/xmlParser.test.ts b/src/__tests__/xmlParser.test.ts index b9645a4..ccec821 100644 --- a/src/__tests__/xmlParser.test.ts +++ b/src/__tests__/xmlParser.test.ts @@ -5,7 +5,7 @@ import { parseString } from 'dynamic-typing'; import { recursiveResolve } from 'ml-spectra-processing'; import { describe, expect, it } from 'vitest'; -import { parse } from '../parse.js'; +import { parse } from '../parse.ts'; const encoder = new TextEncoder(); const decoder = new TextDecoder(); diff --git a/src/bufferUtils/__tests__/arrayIndexOf.test.ts b/src/bufferUtils/__tests__/arrayIndexOf.test.ts index 6775be7..6baebd1 100644 --- a/src/bufferUtils/__tests__/arrayIndexOf.test.ts +++ b/src/bufferUtils/__tests__/arrayIndexOf.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { arrayIndexOf } from '../arrayIndexOf.js'; +import { arrayIndexOf } from '../arrayIndexOf.ts'; describe('arrayIndexOf', () => { it('should find the index pointing to the begining of the found string in array', () => { diff --git a/src/bufferUtils/__tests__/arrayTrim.test.ts b/src/bufferUtils/__tests__/arrayTrim.test.ts index fd92a78..9b748d2 100644 --- a/src/bufferUtils/__tests__/arrayTrim.test.ts +++ b/src/bufferUtils/__tests__/arrayTrim.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; -import { arrayTrim } from '../arrayTrim.js'; +import { arrayTrim } from '../arrayTrim.ts'; test('arrayTrim', () => { const beginning = new Uint8Array([32, 32, 32, 32, 32, 32, 32, 33, 33, 97]); diff --git a/src/bufferUtils/arrayTrim.ts b/src/bufferUtils/arrayTrim.ts index c6daf67..1bce12c 100644 --- a/src/bufferUtils/arrayTrim.ts +++ b/src/bufferUtils/arrayTrim.ts @@ -2,8 +2,8 @@ export function arrayTrim(array: Uint8Array, arg?: unknown) { let i = 0; let j = array.length - 1; - for (; i < array.length && array[i] <= 0x20; i++); - for (; j >= i && array[j] <= 0x20; j--); + for (; i < array.length && (array[i] as number) <= 0x20; i++); + for (; j >= i && (array[j] as number) <= 0x20; j--); if (i === 0 && j === array.length - 1) return array; return array.subarray(i, j + 1); } diff --git a/src/index.ts b/src/index.ts index 3b4c428..8f2a781 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ -export * from './parse.js'; -export * from './parseStream.js'; +export * from './parse.ts'; +export * from './parseStream.ts'; diff --git a/src/parse.ts b/src/parse.ts index c3cc6d5..4b32f31 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,10 +1,10 @@ import type { ParseOptions, RealParseOptions, -} from './traversable/defaultOptions.js'; -import { defaultOptions } from './traversable/defaultOptions.js'; -import { getTraversable } from './traversable/getTraversable.js'; -import { traversableToJSON } from './traversableToJSON.js'; +} from './traversable/defaultOptions.ts'; +import { defaultOptions } from './traversable/defaultOptions.ts'; +import { getTraversable } from './traversable/getTraversable.ts'; +import { traversableToJSON } from './traversableToJSON.ts'; /** * Parse an ArrayBuffer or Uint8Array representing an XML and return an object diff --git a/src/parseStream.ts b/src/parseStream.ts index 6d1f364..26bfdfd 100644 --- a/src/parseStream.ts +++ b/src/parseStream.ts @@ -1,7 +1,7 @@ -import type { StreamParseOptions } from './traversable/defaultOptions.js'; -import { defaultStreamOptions } from './traversable/defaultOptions.js'; -import { getTraversableGenerator } from './traversable/getTraversableGenerator.js'; -import { traversableToJSON } from './traversableToJSON.js'; +import type { StreamParseOptions } from './traversable/defaultOptions.ts'; +import { defaultStreamOptions } from './traversable/defaultOptions.ts'; +import { getTraversableGenerator } from './traversable/getTraversableGenerator.ts'; +import { traversableToJSON } from './traversableToJSON.ts'; /** * Parse a web stream representing an XML and emit objects diff --git a/src/traversable/__tests__/closingIndexForOpeningTag.test.ts b/src/traversable/__tests__/closingIndexForOpeningTag.test.ts index 6e42769..a63df35 100644 --- a/src/traversable/__tests__/closingIndexForOpeningTag.test.ts +++ b/src/traversable/__tests__/closingIndexForOpeningTag.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; -import { closingIndexForOpeningTag } from '../closingIndexForOpeningTag.js'; +import { closingIndexForOpeningTag } from '../closingIndexForOpeningTag.ts'; test('sclosingIndexForOpeningTag', () => { expect( diff --git a/src/traversable/closingIndexForOpeningTag.ts b/src/traversable/closingIndexForOpeningTag.ts index d346ce7..eeb2e7d 100644 --- a/src/traversable/closingIndexForOpeningTag.ts +++ b/src/traversable/closingIndexForOpeningTag.ts @@ -1,4 +1,4 @@ -import { decoder } from './utils/utf8Decoder.js'; +import { decoder } from './utils/utf8Decoder.ts'; /** * Search for the corresponding closing tag '>' diff --git a/src/traversable/defaultOptions.ts b/src/traversable/defaultOptions.ts index cd3abfc..f1c802f 100644 --- a/src/traversable/defaultOptions.ts +++ b/src/traversable/defaultOptions.ts @@ -1,6 +1,6 @@ import { parseString } from 'dynamic-typing'; -import type { XMLAttributeValue, XMLNode } from '../XMLNode.js'; +import type { XMLAttributeValue, XMLNode } from '../XMLNode.ts'; const utf8Decoder = new TextDecoder(); diff --git a/src/traversable/findClosingIndex.ts b/src/traversable/findClosingIndex.ts index 23c0220..4f22e00 100644 --- a/src/traversable/findClosingIndex.ts +++ b/src/traversable/findClosingIndex.ts @@ -1,4 +1,4 @@ -import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.js'; +import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.ts'; export function findClosingIndex( xmlData: Uint8Array, diff --git a/src/traversable/getTraversable.ts b/src/traversable/getTraversable.ts index 78efc19..558f776 100644 --- a/src/traversable/getTraversable.ts +++ b/src/traversable/getTraversable.ts @@ -1,13 +1,13 @@ -import { XMLNode } from '../XMLNode.js'; -import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.js'; -import { arrayTrim } from '../bufferUtils/arrayTrim.js'; +import { XMLNode } from '../XMLNode.ts'; +import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.ts'; +import { arrayTrim } from '../bufferUtils/arrayTrim.ts'; -import { closingIndexForOpeningTag } from './closingIndexForOpeningTag.js'; -import type { RealParseOptions } from './defaultOptions.js'; -import { findClosingIndex } from './findClosingIndex.js'; -import { parseAttributesString } from './parseAttributesString.js'; -import { removeNameSpaceIfNeeded } from './utils/removeNameSpaceIfNeeded.js'; -import { decoder } from './utils/utf8Decoder.js'; +import { closingIndexForOpeningTag } from './closingIndexForOpeningTag.ts'; +import type { RealParseOptions } from './defaultOptions.ts'; +import { findClosingIndex } from './findClosingIndex.ts'; +import { parseAttributesString } from './parseAttributesString.ts'; +import { removeNameSpaceIfNeeded } from './utils/removeNameSpaceIfNeeded.ts'; +import { decoder } from './utils/utf8Decoder.ts'; export function getTraversable(xmlData: Uint8Array, options: RealParseOptions) { const { tagValueProcessor } = options; diff --git a/src/traversable/getTraversableGenerator.ts b/src/traversable/getTraversableGenerator.ts index 53d59f3..99b1f4d 100644 --- a/src/traversable/getTraversableGenerator.ts +++ b/src/traversable/getTraversableGenerator.ts @@ -1,13 +1,13 @@ -import { XMLNode } from '../XMLNode.js'; -import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.js'; -import { arrayTrim } from '../bufferUtils/arrayTrim.js'; +import { XMLNode } from '../XMLNode.ts'; +import { arrayIndexOf } from '../bufferUtils/arrayIndexOf.ts'; +import { arrayTrim } from '../bufferUtils/arrayTrim.ts'; -import { closingIndexForOpeningTag } from './closingIndexForOpeningTag.js'; -import type { RealStreamParseOptions } from './defaultOptions.js'; -import { findClosingIndex } from './findClosingIndex.js'; -import { parseAttributesString } from './parseAttributesString.js'; -import { removeNameSpaceIfNeeded } from './utils/removeNameSpaceIfNeeded.js'; -import { decoder } from './utils/utf8Decoder.js'; +import { closingIndexForOpeningTag } from './closingIndexForOpeningTag.ts'; +import type { RealStreamParseOptions } from './defaultOptions.ts'; +import { findClosingIndex } from './findClosingIndex.ts'; +import { parseAttributesString } from './parseAttributesString.ts'; +import { removeNameSpaceIfNeeded } from './utils/removeNameSpaceIfNeeded.ts'; +import { decoder } from './utils/utf8Decoder.ts'; export async function* getTraversableGenerator( readableStream: ReadableStream, @@ -27,7 +27,7 @@ export async function* getTraversableGenerator( let endStream = chunk.done; let xmlData = new Uint8Array(chunk.value); - const { maxEntrySize = 1e7, maxBufferSize = 2e8 } = options; + const { maxEntrySize, maxBufferSize } = options; for (let i = 0; i < xmlData.length; i++) { if (xmlData.length - i < maxEntrySize && !endStream) { diff --git a/src/traversable/parseAttributesString.ts b/src/traversable/parseAttributesString.ts index 9f3d938..7e8e806 100644 --- a/src/traversable/parseAttributesString.ts +++ b/src/traversable/parseAttributesString.ts @@ -1,6 +1,6 @@ -import { getAllMatches, isEmptySimpleObject } from '../util.js'; +import { getAllMatches, isEmptySimpleObject } from '../util.ts'; -import type { RealParseOptions } from './defaultOptions.js'; +import type { RealParseOptions } from './defaultOptions.ts'; const newLocal = String.raw`([^\s=]+)\s*(=\s*(['"])(.*?)\3)?`; const attrsRegx = new RegExp(newLocal, 'g'); @@ -20,7 +20,7 @@ export function parseAttributesString( // argument 1 is the key, argument 4 is the value const attributes: Record = {}; for (const match of matches) { - const attributeName = resolveNameSpace(match[1], options); + const attributeName = resolveNameSpace(match[1] as string, options); if (attributeName.length > 0) { if (match[4] !== undefined) { if (options.trimValues) { @@ -48,7 +48,7 @@ function resolveNameSpace(tagName: string, options: RealParseOptions) { if (tags[0] === 'xmlns') { return ''; } - if (tags.length === 2) { + if (tags.length === 2 && tags[1] !== undefined) { tagName = prefix + tags[1]; } } diff --git a/src/traversable/utils/removeNameSpaceIfNeeded.ts b/src/traversable/utils/removeNameSpaceIfNeeded.ts index 3b0ef65..fc6351e 100644 --- a/src/traversable/utils/removeNameSpaceIfNeeded.ts +++ b/src/traversable/utils/removeNameSpaceIfNeeded.ts @@ -1,4 +1,4 @@ -import type { ParseOptions } from '../defaultOptions.js'; +import type { ParseOptions } from '../defaultOptions.ts'; export function removeNameSpaceIfNeeded( tagName: string, diff --git a/src/traversableToJSON.ts b/src/traversableToJSON.ts index c975506..67f15ff 100644 --- a/src/traversableToJSON.ts +++ b/src/traversableToJSON.ts @@ -1,11 +1,11 @@ -import type { XMLAttributeValue, XMLNode, XMLNodeValue } from './XMLNode.js'; -import type { RealParseOptions } from './traversable/defaultOptions.js'; +import type { XMLAttributeValue, XMLNode, XMLNodeValue } from './XMLNode.ts'; +import type { RealParseOptions } from './traversable/defaultOptions.ts'; import { isEmptyObject, isEmptySimpleObject, isTagNameInArrayMode, merge, -} from './util.js'; +} from './util.ts'; /** * @@ -49,7 +49,10 @@ export function traversableToJSON( const renamedAttributes: Record = {}; for (const attributeName in node.attributes) { const newAttributeName = attributeNameProcessor(attributeName); - renamedAttributes[newAttributeName] = node.attributes[attributeName]; + const value = node.attributes[attributeName]; + if (value !== undefined) { + renamedAttributes[newAttributeName] = value; + } } attributes = renamedAttributes; } @@ -64,16 +67,19 @@ export function traversableToJSON( for (const tagName in node.children) { const nodes = node.children[tagName]; + if (!nodes) continue; const newTagName = tagNameProcessor ? tagNameProcessor(tagName, nodes) : tagName; - if (nodes?.length > 1) { + if (nodes.length > 1) { result[tagName] = []; for (const child of nodes) { result[newTagName].push(traversableToJSON(child, options, tagName)); } } else { - const subResult = traversableToJSON(nodes[0], options, tagName); + const firstNode = nodes[0]; + if (!firstNode) continue; + const subResult = traversableToJSON(firstNode, options, tagName); const asArray = (arrayMode === true && typeof subResult === 'object') || isTagNameInArrayMode( diff --git a/src/util.ts b/src/util.ts index 6e6afce..7bb55ae 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,4 @@ -import type { XMLAttributeValue, XMLNode } from './XMLNode.js'; +import type { XMLAttributeValue, XMLNode } from './XMLNode.ts'; const nameStartChar = String.raw`:A-Za-z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD`; const nameChar = String.raw`${nameStartChar}\-.\d\u00B7\u0300-\u036F\u203F-\u2040`; @@ -54,10 +54,12 @@ export function merge( ) { if (!source) return; for (const key in source) { + const value = source[key]; + if (value === undefined) continue; if (arrayMode === 'strict') { - target[key] = [source[key]]; + target[key] = [value]; } else { - target[key] = source[key]; + target[key] = value; } } } diff --git a/tsconfig.json b/tsconfig.json index a68fc7e..f7ba89c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "@zakodium/tsconfig", "compilerOptions": { - "noUncheckedIndexedAccess": false, "outDir": "lib", "types": ["node"] }, diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..d9727d8 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + snapshotFormat: { + maxOutputLength: 1e8, + }, + }, +});