From feb19c68529ef36377aca8a7d5d768befdb654bd Mon Sep 17 00:00:00 2001 From: Seth Falco Date: Sat, 13 Jan 2024 15:25:58 +0000 Subject: [PATCH] feat: add explicit option for unquoted attribute values --- lib/sax.js | 10 ++++- test/unquoted-attribute-values.js | 71 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/unquoted-attribute-values.js diff --git a/lib/sax.js b/lib/sax.js index ffd441a..7f4189a 100644 --- a/lib/sax.js +++ b/lib/sax.js @@ -71,6 +71,12 @@ parser.ns = Object.create(rootNS) } + // disallow unquoted attribute values if not otherwise configured + // and strict mode is true + if (parser.opt.unquotedAttributeValues === undefined) { + parser.opt.unquotedAttributeValues = !strict; + } + // mostly just for error reporting parser.trackPosition = parser.opt.position !== false if (parser.trackPosition) { @@ -1365,7 +1371,9 @@ parser.q = c parser.state = S.ATTRIB_VALUE_QUOTED } else { - strictFail(parser, 'Unquoted attribute value') + if (!parser.opt.unquotedAttributeValues) { + error(parser, 'Unquoted attribute value') + } parser.state = S.ATTRIB_VALUE_UNQUOTED parser.attribValue = c } diff --git a/test/unquoted-attribute-values.js b/test/unquoted-attribute-values.js new file mode 100644 index 0000000..42e3f7c --- /dev/null +++ b/test/unquoted-attribute-values.js @@ -0,0 +1,71 @@ +// strict: true +require(__dirname).test({ + xml: '', + expect: [ + ['opentagstart', { name: 'svg', attributes: {} }], + ['error', 'Unquoted attribute value\nLine: 0\nColumn: 12\nChar: 2'], + ['attribute', { name: 'width', value: '20px' }], + ['error', 'Unquoted attribute value\nLine: 0\nColumn: 24\nChar: 2'], + ['attribute', { name: 'height', value: '20px' }], + ['opentag', { name: 'svg', attributes: { + width: '20px', + height: '20px' + }, isSelfClosing: true }], + ['closetag', 'svg'], + ], + strict: true +}) + +// strict: false +require(__dirname).test({ + xml: '', + expect: [ + ['opentagstart', { name: 'SVG', attributes: {} }], + ['attribute', { name: 'WIDTH', value: '20px' }], + ['attribute', { name: 'HEIGHT', value: '20px' }], + ['opentag', { name: 'SVG', attributes: { + WIDTH: '20px', + HEIGHT: '20px' + }, isSelfClosing: true }], + ['closetag', 'SVG'], + ], + strict: false +}) + +// strict: true, opt: { unquotedAttributeValues: true } +require(__dirname).test({ + xml: '', + expect: [ + ['opentagstart', { name: 'svg', attributes: {} }], + ['attribute', { name: 'width', value: '20px' }], + ['attribute', { name: 'height', value: '20px' }], + ['opentag', { name: 'svg', attributes: { + width: '20px', + height: '20px' + }, isSelfClosing: true }], + ['closetag', 'svg'], + ], + strict: true, + opt: { + unquotedAttributeValues: true + } +}) + +// strict: false, opt: { unquotedAttributeValues: true } +require(__dirname).test({ + xml: '', + expect: [ + ['opentagstart', { name: 'SVG', attributes: {} }], + ['attribute', { name: 'WIDTH', value: '20px' }], + ['attribute', { name: 'HEIGHT', value: '20px' }], + ['opentag', { name: 'SVG', attributes: { + WIDTH: '20px', + HEIGHT: '20px' + }, isSelfClosing: true }], + ['closetag', 'SVG'], + ], + strict: false, + opt: { + unquotedAttributeValues: true + } +})