diff --git a/src/index.ts b/src/index.ts index a9c82f5..e923f98 100644 --- a/src/index.ts +++ b/src/index.ts @@ -99,24 +99,70 @@ const SHOW_ELEMENT = 1; const SHOW_COMMENT = 128; const COMMENT_NODE = 8; export function defaultNormalizer(container: ContainerNode) { + const idMap: Map = new Map(); const clone = container.cloneNode(true) as ContainerNode; const document = container.ownerDocument!; - const treeWalker = document.createTreeWalker( + const commentAndElementWalker = document.createTreeWalker( clone, SHOW_ELEMENT | SHOW_COMMENT ); let node: Comment | Element; - let nextNode = treeWalker.nextNode(); + let nextNode = commentAndElementWalker.nextNode(); while ((node = nextNode as Comment | Element)) { - nextNode = treeWalker.nextNode(); - if (node.nodeType === COMMENT_NODE) { - (node as Comment).remove(); + nextNode = commentAndElementWalker.nextNode(); + if (isComment(node)) { + node.remove(); } else { - Array.from((node as Element).attributes) - .map(attr => attr.name) - .filter(attrName => /^data-(w-|widget$|marko(-|$))/.test(attrName)) - .forEach(attrName => (node as Element).removeAttribute(attrName)); + const { id, attributes } = node; + if (/\d/.test(id)) { + let idIndex = idMap.get(id); + + if (idIndex === undefined) { + idIndex = idMap.size; + idMap.set(id, idIndex); + } + + node.id = `GENERATED-${idIndex}`; + } + + for (let i = attributes.length; i--; ) { + const attr = attributes[i]; + + if (/^data-(w-|widget$|marko(-|$))/.test(attr.name)) { + node.removeAttributeNode(attr); + } + } + } + } + + if (idMap.size) { + const elementWalker = document.createTreeWalker(clone, SHOW_ELEMENT); + + nextNode = elementWalker.nextNode(); + while ((node = nextNode as Element)) { + nextNode = elementWalker.nextNode(); + const { attributes } = node; + + for (let i = attributes.length; i--; ) { + const attr = attributes[i]; + const { value } = attr; + const updated = value + .split(" ") + .map(part => { + const idIndex = idMap.get(part); + if (idIndex === undefined) { + return part; + } + + return `GENERATED-${idIndex}`; + }) + .join(" "); + + if (value !== updated) { + attr.value = updated; + } + } } } @@ -132,3 +178,7 @@ function inferName(p: string) { const indexOrTemplate = match[2] === "index" || match[2] === "template"; return indexOrTemplate ? match[1] : match[2]; } + +function isComment(node: Node): node is Comment { + return node.nodeType === COMMENT_NODE; +} diff --git a/test/components/fancy-form/fixtures/data.html b/test/components/fancy-form/fixtures/data.html new file mode 100644 index 0000000..3c7043c --- /dev/null +++ b/test/components/fancy-form/fixtures/data.html @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/test/components/fancy-form/fixtures/data.json b/test/components/fancy-form/fixtures/data.json new file mode 100644 index 0000000..9d061d3 --- /dev/null +++ b/test/components/fancy-form/fixtures/data.json @@ -0,0 +1,4 @@ +{ + "firstName": "Michael", + "lastName": "Rawlings" +} diff --git a/test/components/fancy-form/index.marko b/test/components/fancy-form/index.marko new file mode 100644 index 0000000..dc4217a --- /dev/null +++ b/test/components/fancy-form/index.marko @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/index.test.ts b/test/index.test.ts index 441b018..0fbed20 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -87,6 +87,25 @@ describe("findProjectFixtures", () => { "name": "container", "path": "(cwd)/test/components/container/index.marko", }, + Object { + "component": [Component "(cwd)/test/components/fancy-form/index.marko"], + "fixtures": Object { + "data": Object { + "ext": ".json", + "fixture": Object { + "firstName": "Michael", + "lastName": "Rawlings", + }, + "name": "data", + "path": "(cwd)/test/components/fancy-form/fixtures/data.json", + "render": [Function], + "toString": [Function], + }, + }, + "fixturesPath": "(cwd)/test/components/fancy-form/fixtures", + "name": "fancy-form", + "path": "(cwd)/test/components/fancy-form/index.marko", + }, Object { "component": [Component "(cwd)/test/components/hello/index.marko"], "fixtures": Object {