Skip to content

Commit b200b8f

Browse files
committed
fix #78
1 parent b0d58b8 commit b200b8f

File tree

6 files changed

+118
-25
lines changed

6 files changed

+118
-25
lines changed

packages/hast-util-from-webparser/index.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
Comment,
66
Text,
77
Node,
8-
Doctype
8+
Doctype,
9+
Attribute
910
} from '@starptech/webparser'
1011

1112
const htmlSchema = require('property-information/html')
@@ -161,15 +162,16 @@ function comment(ast: Comment): HastNode {
161162
return { type: 'comment', value: ast.value }
162163
}
163164

164-
function getAttributeNameAndNS(name: string) {
165-
// support vue :foo attributes but respect
166-
// namespace syntax from webparser like :ns:attribute
167-
if (name.split(':').length === 2) {
168-
return { ns: null, name: name }
165+
function getAttributeName(attribute: Attribute) {
166+
const colons = attribute.name.split(':')
167+
168+
// attrName from webparser: ":xmlns:xlink"
169+
// remove first colon because it was added by webparser
170+
if (attribute.implicitNs === true && colons.length >= 3) {
171+
return colons.slice(1).join(':')
169172
}
170173

171-
const info = splitNsName(name)
172-
return { ns: info[0], name: info[1] }
174+
return attribute.name
173175
}
174176

175177
function getElementNameAndNS(name: string, implicitNs = false) {
@@ -199,9 +201,7 @@ function element(
199201
let node
200202

201203
for (const attr of ast.attrs) {
202-
const attrInfo = getAttributeNameAndNS(attr.name)
203-
props[attrInfo.ns ? attrInfo.ns + ':' + attrInfo.name : attrInfo.name] =
204-
attr.value
204+
props[getAttributeName(attr)] = attr.value
205205
}
206206

207207
node = fn(nameInfo.name, props, children)

packages/hast-util-from-webparser/test/__snapshots__/index.test.ts.snap

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,66 @@ Object {
223223
}
224224
`;
225225

226+
exports[`Attributes with colon, binding syntax and namespace 1`] = `
227+
Object {
228+
"children": Array [
229+
Object {
230+
"children": Array [
231+
Object {
232+
"children": Array [],
233+
"data": Object {
234+
"selfClosing": true,
235+
},
236+
"position": Object {
237+
"end": Object {
238+
"column": 108,
239+
"line": 1,
240+
"offset": 108,
241+
},
242+
"start": Object {
243+
"column": 14,
244+
"line": 1,
245+
"offset": 14,
246+
},
247+
},
248+
"properties": Object {
249+
":foo": "dddd",
250+
":xlink:href": "'myHref'",
251+
"xmlnsXLink": "http://www.w3.org/1999/xlink",
252+
},
253+
"tagName": "prism-editor",
254+
"type": "element",
255+
},
256+
],
257+
"data": Object {
258+
"selfClosing": false,
259+
},
260+
"position": Object {
261+
"end": Object {
262+
"column": 114,
263+
"line": 1,
264+
"offset": 114,
265+
},
266+
"start": Object {
267+
"column": 0,
268+
"line": 1,
269+
"offset": 0,
270+
},
271+
},
272+
"properties": Object {
273+
"id": "app",
274+
},
275+
"tagName": "div",
276+
"type": "element",
277+
},
278+
],
279+
"data": Object {
280+
"selfClosing": false,
281+
},
282+
"type": "root",
283+
}
284+
`;
285+
226286
exports[`Attributes with namespace 1`] = `
227287
Object {
228288
"children": Array [

packages/hast-util-from-webparser/test/index.test.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import { HtmlParser } from '@starptech/webparser'
22
import fromWebParser from '../index'
33

4+
function getParserOpt() {
5+
return {
6+
ignoreFirstLf: false,
7+
decodeEntities: false,
8+
selfClosingCustomElements: true,
9+
selfClosingElements: true
10+
}
11+
}
12+
413
test('Attributes', () => {
5-
const parser = new HtmlParser()
14+
const parser = new HtmlParser(getParserOpt())
615
const result = parser.parse(
716
`<p id="foo" class="bar baz" data-qux="quux"></p>
817
<p data-123="456"></p>
@@ -20,7 +29,7 @@ test('Attributes', () => {
2029
})
2130

2231
test('Element void', () => {
23-
const parser = new HtmlParser()
32+
const parser = new HtmlParser(getParserOpt())
2433
const result = parser.parse(
2534
`
2635
<img>
@@ -39,7 +48,7 @@ test('Element void', () => {
3948
})
4049

4150
test('Simple', () => {
42-
const parser = new HtmlParser()
51+
const parser = new HtmlParser(getParserOpt())
4352
const result = parser.parse(`<div><p>foo</p></div>`, 'TestComp')
4453

4554
expect(result.errors.length).toBe(0)
@@ -50,7 +59,7 @@ test('Simple', () => {
5059
})
5160

5261
test('SVG', () => {
53-
const parser = new HtmlParser()
62+
const parser = new HtmlParser(getParserOpt())
5463
const result = parser.parse(
5564
`<div>
5665
<svg width="230" height="120" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -69,7 +78,7 @@ test('SVG', () => {
6978
})
7079

7180
test('SVG - should preserve explicit svg namespace', () => {
72-
const parser = new HtmlParser()
81+
const parser = new HtmlParser(getParserOpt())
7382
const result = parser.parse(
7483
`<div>
7584
<svg:svg width="230" height="120" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -88,7 +97,7 @@ test('SVG - should preserve explicit svg namespace', () => {
8897
})
8998

9099
test('Template', () => {
91-
const parser = new HtmlParser()
100+
const parser = new HtmlParser(getParserOpt())
92101
const result = parser.parse(
93102
`<template id="text">!</template>
94103
<TEMPLATE id="html"><strong>importance</strong> and <em>emphasis</em>.</TEMPLATE>`,
@@ -103,7 +112,7 @@ test('Template', () => {
103112
})
104113

105114
test('Comment', () => {
106-
const parser = new HtmlParser()
115+
const parser = new HtmlParser(getParserOpt())
107116
const result = parser.parse(`<!-- foo -->`, 'TestComp')
108117

109118
expect(result.errors.length).toBe(0)
@@ -114,7 +123,7 @@ test('Comment', () => {
114123
})
115124

116125
test('Attributes with colon or @ as prefix', () => {
117-
const parser = new HtmlParser()
126+
const parser = new HtmlParser(getParserOpt())
118127
const result = parser.parse(`<div :type="" @foo="bar"></div>`, 'TestComp')
119128

120129
expect(result.errors.length).toBe(0)
@@ -124,8 +133,22 @@ test('Attributes with colon or @ as prefix', () => {
124133
expect(node).toMatchSnapshot()
125134
})
126135

136+
test('Attributes with colon, binding syntax and namespace', () => {
137+
const parser = new HtmlParser(getParserOpt())
138+
const result = parser.parse(
139+
`<div id="app"><prism-editor :xlink:href="'myHref'" :foo="dddd" xmlns:xlink="http://www.w3.org/1999/xlink" /></div>`,
140+
'TestComp'
141+
)
142+
143+
expect(result.errors.length).toBe(0)
144+
145+
const node = fromWebParser(result.rootNodes, {})
146+
147+
expect(node).toMatchSnapshot()
148+
})
149+
127150
test('Case sensitive attributes', () => {
128-
const parser = new HtmlParser()
151+
const parser = new HtmlParser(getParserOpt())
129152
const result = parser.parse(`<div ASYNC></div>`, 'TestComp')
130153

131154
expect(result.errors.length).toBe(0)
@@ -136,7 +159,7 @@ test('Case sensitive attributes', () => {
136159
})
137160

138161
test('Doctype', () => {
139-
const parser = new HtmlParser()
162+
const parser = new HtmlParser(getParserOpt())
140163
const result = parser.parse(`<!DOCTYPE html>`, 'TestComp')
141164

142165
expect(result.errors.length).toBe(0)
@@ -147,7 +170,7 @@ test('Doctype', () => {
147170
})
148171

149172
test('Doctype nameless', () => {
150-
const parser = new HtmlParser()
173+
const parser = new HtmlParser(getParserOpt())
151174
const result = parser.parse(`<!DOCTYPE>`, 'TestComp')
152175

153176
expect(result.errors.length).toBe(0)
@@ -158,7 +181,7 @@ test('Doctype nameless', () => {
158181
})
159182

160183
test('Doctype with html skeleton', () => {
161-
const parser = new HtmlParser()
184+
const parser = new HtmlParser(getParserOpt())
162185
const result = parser.parse(
163186
`<!DOCTYPE><html><head></head><body>foo</body></html>`,
164187
'TestComp'
@@ -172,7 +195,7 @@ test('Doctype with html skeleton', () => {
172195
})
173196

174197
test('Attributes with namespace', () => {
175-
const parser = new HtmlParser()
198+
const parser = new HtmlParser(getParserOpt())
176199
const result = parser.parse(
177200
`<svg xmlns:xlink="http://www.w3.org/1999/xlink"></svg>`,
178201
'TestComp'
@@ -186,7 +209,7 @@ test('Attributes with namespace', () => {
186209
})
187210

188211
test('Gaps detection - should set gapAfter data on elements followed by empty lines', () => {
189-
const parser = new HtmlParser()
212+
const parser = new HtmlParser(getParserOpt())
190213
const result = parser.parse(
191214
`<div></div>
192215

packages/webparser/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ const result = parser.parse('<div></div>')
2323
There are four different types of nodes
2424

2525
- Doctype
26+
2627
```js
2728
{
2829
value: '<!doctype html>',
2930
sourceSpan: null
3031
}
3132
```
33+
3234
- Element
35+
3336
```js
3437
{
3538
name: 'div',
@@ -45,16 +48,20 @@ There are four different types of nodes
4548
Void or self-closing elements can be checked when the `startSourceSpan` is equals the `endSourceSpan`.
4649

4750
- Attribute
51+
4852
```js
4953
{
5054
name: 'div',
5155
value: 'foo',
5256
children: [],
57+
implicitNs: false,
5358
sourceSpan:null,
5459
valueSpan: null
5560
}
5661
```
62+
5763
- Comment
64+
5865
```js
5966
{
6067
value: 'foo comment',

packages/webparser/src/ast.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class Attribute implements Node {
1717
constructor(
1818
public name: string,
1919
public value: string,
20+
public implicitNs: boolean,
2021
public sourceSpan: ParseSourceSpan,
2122
public valueSpan?: ParseSourceSpan
2223
) {}

packages/webparser/src/parser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ class _TreeBuilder {
384384

385385
private _consumeAttr(attrName: lex.Token): html.Attribute {
386386
const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1])
387+
let implicitNs = attrName.parts[0] != null
387388
let end = attrName.sourceSpan.end
388389
let value = ''
389390
let valueSpan: ParseSourceSpan = undefined!
@@ -396,6 +397,7 @@ class _TreeBuilder {
396397
return new html.Attribute(
397398
fullName,
398399
value,
400+
implicitNs,
399401
new ParseSourceSpan(attrName.sourceSpan.start, end),
400402
valueSpan
401403
)

0 commit comments

Comments
 (0)