diff --git a/HISTORY.md b/HISTORY.md index 38b6626dd..1e1054867 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,11 +5,14 @@ All notable changes to this project will be documented in this file. ## unreleased +* Dependencies + * Support `libxml2-wasm@^0.5.0` as an alternative for `libxmljs2` (via [#1184]) * Build * Use _TypeScript_ `v5.7.3` now, was `v5.7.2` (via [#1204]) [#1204]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/1204 +[#1184]: https://github.com/CycloneDX/cyclonedx-javascript-library/pull/1184 ## 7.1.0 -- 2025-01-09 diff --git a/README.md b/README.md index 9fe0c2364..a2c351a78 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,9 @@ See the shipped `package.json` for version constraints. * [`ajv`](https://www.npmjs.com/package/ajv) * [`ajv-formats`](https://www.npmjs.com/package/ajv-formats) * [`ajv-formats-draft2019`](https://www.npmjs.com/package/ajv-formats-draft2019) -* Validation of XML on _Node.js_ requires all of: +* Validation of XML on _Node.js_ requires any of: * [`libxmljs2`](https://www.npmjs.com/package/libxmljs2) + * [`libxml2-wasm@`](https://www.npmjs.com/package/libxml2-wasm@) * the system might need to meet the requirements for [`node-gyp`](https://github.com/TooTallNate/node-gyp#installation), in certain cases. ## Usage diff --git a/docs/dev/decisions/XmlValidator.md b/docs/dev/decisions/XmlValidator.md index 7be0de95b..8a60cdc8f 100644 --- a/docs/dev/decisions/XmlValidator.md +++ b/docs/dev/decisions/XmlValidator.md @@ -22,6 +22,8 @@ There are several implementations for this: * [`libxmljs3`](https://www.npmjs.com/package/libxmljs3) * unmaintained copy of `libxmljs2` * ! DO NOT USE ! +* [`libxml2-wasm`](https://www.npmjs.com/package/libxml2-wasm) + * maintained WASM implementation of a libxml2 wrapper * Any alternative? Please open a pull-request to add them. At the moment of writing (2023-04-21), diff --git a/package.json b/package.json index f5c23633c..a3d197cc0 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "ajv-formats": "^3.0.1", "ajv-formats-draft2019": "^1.6.1", "libxmljs2": "^0.31 || ^0.32 || ^0.33 || ^0.35", + "libxml2-wasm": "^0.5.0", "xmlbuilder2": "^3.0.2" }, "devDependencies": { diff --git a/src/_optPlug.node/__xmlValidators/libxml2-wasm.ts b/src/_optPlug.node/__xmlValidators/libxml2-wasm.ts new file mode 100644 index 000000000..5be0279ce --- /dev/null +++ b/src/_optPlug.node/__xmlValidators/libxml2-wasm.ts @@ -0,0 +1,52 @@ +/*! +This file is part of CycloneDX JavaScript Library. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +Copyright (c) OWASP Foundation. All Rights Reserved. +*/ + +import { readFile } from 'fs/promises'; +import { ParseOption, XmlDocument, XsdValidator } from 'libxml2-wasm'; +import { pathToFileURL } from 'url'; + +import type { ValidationError } from '../../validation/types'; +import type { Functionality, Validator } from '../xmlValidator'; + +/** @internal */ +export default (async function (schemaPath: string): Promise { + const options = ParseOption.XML_PARSE_NONET | ParseOption.XML_PARSE_COMPACT; + const schema = XmlDocument.fromString( + await readFile(schemaPath, 'utf-8'), + { + option: options, + url: pathToFileURL(schemaPath).toString() + }); + const validator = XsdValidator.fromDoc(schema); + + return function (data: string): null | ValidationError { + const doc = XmlDocument.fromString(data, { option: options }); + let errors = null; + try { + validator.validate(doc); + } + catch (validationErrors) { + errors = validationErrors; + } + + doc.dispose(); + + return errors; + } +}) satisfies Functionality diff --git a/src/_optPlug.node/xmlValidator.ts b/src/_optPlug.node/xmlValidator.ts index 67b92a2be..6c2b9700f 100644 --- a/src/_optPlug.node/xmlValidator.ts +++ b/src/_optPlug.node/xmlValidator.ts @@ -27,7 +27,8 @@ export default opWrapper('XmlValidator', [ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-require-imports -- needed */ - ['libxmljs2', () => require('./__xmlValidators/libxmljs2').default] + ['libxmljs2', () => require('./__xmlValidators/libxmljs2').default], + ['libxml2-wasm', () => require('./__xmlValidators/libxml2-wasm').default] // ... add others here, pull-requests welcome! /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-require-imports */ diff --git a/tests/functional/internals/OpPlug.node.xmlValidator.implementation.spec.js b/tests/functional/internals/OpPlug.node.xmlValidator.implementation.spec.js index ba6a08206..9137252a3 100644 --- a/tests/functional/internals/OpPlug.node.xmlValidator.implementation.spec.js +++ b/tests/functional/internals/OpPlug.node.xmlValidator.implementation.spec.js @@ -29,7 +29,7 @@ const { realpathSync } = require('fs') const { join } = require('path') suite('functional: internals: OpPlug.node.xmlValidator implementation', () => { - for (const impl of ['libxmljs2']) { + for (const impl of ['libxmljs2','libxml2-wasm']) { suite(impl, () => { let makeValidator try {