From 16eed23084534d4ee0872c56eba4a2413aacc7d1 Mon Sep 17 00:00:00 2001 From: Doctor Wu Date: Sun, 1 Dec 2024 15:30:28 +0800 Subject: [PATCH 1/3] feat(compiler-core/vapor): reuse html nesting from compiler-dom related #293 --- packages/compiler-dom/src/htmlNesting.ts | 12 +- packages/compiler-dom/src/index.ts | 2 + packages/compiler-vapor/src/html-nesting.ts | 196 ------------------ .../src/transforms/transformElement.ts | 2 +- 4 files changed, 14 insertions(+), 198 deletions(-) delete mode 100644 packages/compiler-vapor/src/html-nesting.ts diff --git a/packages/compiler-dom/src/htmlNesting.ts b/packages/compiler-dom/src/htmlNesting.ts index cb0a7626d..8b75d059a 100644 --- a/packages/compiler-dom/src/htmlNesting.ts +++ b/packages/compiler-dom/src/htmlNesting.ts @@ -58,7 +58,18 @@ const onlyValidChildren: Record> = { 'template', ]), optgroup: new Set(['option']), + /** + * Though validate-html-nesting declared hr is not a valid child of select + * Keep hr as valid select children, Referring https://html.spec.whatwg.org/multipage/grouping-content.html#the-hr-element + */ select: new Set(['optgroup', 'option', 'hr']), + /** + * Though validate-html-nesting declared math should only have mrow as it's children + * Referring mathml-core spec, it's not fact + * https://w3c.github.io/mathml-core/#dfn-mrow + */ + // math: new Set(['mrow']), + script: new Set(), // table table: new Set(['caption', 'colgroup', 'tbody', 'tfoot', 'thead']), tr: new Set(['td', 'th']), @@ -67,7 +78,6 @@ const onlyValidChildren: Record> = { thead: new Set(['tr']), tfoot: new Set(['tr']), // these elements can not have any children elements - script: emptySet, iframe: emptySet, option: emptySet, textarea: emptySet, diff --git a/packages/compiler-dom/src/index.ts b/packages/compiler-dom/src/index.ts index 9c5489900..785e44d90 100644 --- a/packages/compiler-dom/src/index.ts +++ b/packages/compiler-dom/src/index.ts @@ -10,6 +10,7 @@ import { noopDirectiveTransform, } from '@vue/compiler-core' import { parserOptions } from './parserOptions' +import { isValidHTMLNesting } from './htmlNesting' import { transformStyle } from './transforms/transformStyle' import { transformVHtml } from './transforms/vHtml' import { transformVText } from './transforms/vText' @@ -23,6 +24,7 @@ import { validateHtmlNesting } from './transforms/validateHtmlNesting' import { extend } from '@vue/shared' export { parserOptions } +export { isValidHTMLNesting } export const DOMNodeTransforms: NodeTransform[] = [ transformStyle, diff --git a/packages/compiler-vapor/src/html-nesting.ts b/packages/compiler-vapor/src/html-nesting.ts deleted file mode 100644 index 932be552e..000000000 --- a/packages/compiler-vapor/src/html-nesting.ts +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Copied from https://github.com/MananTank/validate-html-nesting - * with ISC license - * - * To avoid runtime dependency on validate-html-nesting - * This file should not change very often in the original repo - * but we may need to keep it up-to-date from time to time. - */ - -/** - * returns true if given parent-child nesting is valid HTML - */ -export function isValidHTMLNesting(parent: string, child: string): boolean { - // if we know the list of children that are the only valid children for the given parent - if (parent in onlyValidChildren) { - return onlyValidChildren[parent].has(child) - } - - // if we know the list of parents that are the only valid parents for the given child - if (child in onlyValidParents) { - return onlyValidParents[child].has(parent) - } - - // if we know the list of children that are NOT valid for the given parent - if (parent in knownInvalidChildren) { - // check if the child is in the list of invalid children - // if so, return false - if (knownInvalidChildren[parent].has(child)) return false - } - - // if we know the list of parents that are NOT valid for the given child - if (child in knownInvalidParents) { - // check if the parent is in the list of invalid parents - // if so, return false - if (knownInvalidParents[child].has(parent)) return false - } - - return true -} - -const headings = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']) -const emptySet = new Set([]) - -/** - * maps element to set of elements that can be it's children, no other */ -const onlyValidChildren: Record> = { - head: new Set([ - 'base', - 'basefront', - 'bgsound', - 'link', - 'meta', - 'title', - 'noscript', - 'noframes', - 'style', - 'script', - 'template', - ]), - optgroup: new Set(['option']), - select: new Set(['optgroup', 'option']), - math: new Set(['mrow']), - script: new Set(), - // table - table: new Set(['caption', 'colgroup', 'tbody', 'tfoot', 'thead']), - tr: new Set(['td', 'th']), - colgroup: new Set(['col']), - tbody: new Set(['tr']), - thead: new Set(['tr']), - tfoot: new Set(['tr']), - // these elements can not have any children elements - iframe: emptySet, - option: emptySet, - textarea: emptySet, - style: emptySet, - title: emptySet, -} - -/** maps elements to set of elements which can be it's parent, no other */ -const onlyValidParents: Record> = { - // sections - html: emptySet, - body: new Set(['html']), - head: new Set(['html']), - // table - td: new Set(['tr']), - colgroup: new Set(['table']), - caption: new Set(['table']), - tbody: new Set(['table']), - tfoot: new Set(['table']), - col: new Set(['colgroup']), - th: new Set(['tr']), - thead: new Set(['table']), - tr: new Set(['tbody', 'thead', 'tfoot']), - // data list - dd: new Set(['dl', 'div']), - dt: new Set(['dl', 'div']), - // other - figcaption: new Set(['figure']), - // li: new Set(["ul", "ol"]), - summary: new Set(['details']), - area: new Set(['map']), -} as const - -/** maps element to set of elements that can not be it's children, others can */ -const knownInvalidChildren: Record> = { - p: new Set([ - 'address', - 'article', - 'aside', - 'blockquote', - 'center', - 'details', - 'dialog', - 'dir', - 'div', - 'dl', - 'fieldset', - 'figure', - 'footer', - 'form', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'header', - 'hgroup', - 'hr', - 'li', - 'main', - 'nav', - 'menu', - 'ol', - 'p', - 'pre', - 'section', - 'table', - 'ul', - ]), - svg: new Set([ - 'b', - 'blockquote', - 'br', - 'code', - 'dd', - 'div', - 'dl', - 'dt', - 'em', - 'embed', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'hr', - 'i', - 'img', - 'li', - 'menu', - 'meta', - 'ol', - 'p', - 'pre', - 'ruby', - 's', - 'small', - 'span', - 'strong', - 'sub', - 'sup', - 'table', - 'u', - 'ul', - 'var', - ]), -} as const - -/** maps element to set of elements that can not be it's parent, others can */ -const knownInvalidParents: Record> = { - a: new Set(['a']), - button: new Set(['button']), - dd: new Set(['dd', 'dt']), - dt: new Set(['dd', 'dt']), - form: new Set(['form']), - li: new Set(['li']), - h1: headings, - h2: headings, - h3: headings, - h4: headings, - h5: headings, - h6: headings, -} diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index 51f0e427e..64b460407 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -1,4 +1,3 @@ -import { isValidHTMLNesting } from '../html-nesting' import { type AttributeNode, type ComponentNode, @@ -37,6 +36,7 @@ import { } from '../ir' import { EMPTY_EXPRESSION } from './utils' import { findProp } from '../utils' +import { isValidHTMLNesting } from '@vue/compiler-dom' export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap( // the leading comma is intentional so empty string "" is also included From 0eaa24689cfa65e926ff6ccd52c241900ac9e80c Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Wed, 4 Dec 2024 16:58:34 +0800 Subject: [PATCH 2/3] chore: tidy isValidHTMLNesting export --- packages/compiler-dom/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/compiler-dom/src/index.ts b/packages/compiler-dom/src/index.ts index 785e44d90..950901e7b 100644 --- a/packages/compiler-dom/src/index.ts +++ b/packages/compiler-dom/src/index.ts @@ -10,7 +10,6 @@ import { noopDirectiveTransform, } from '@vue/compiler-core' import { parserOptions } from './parserOptions' -import { isValidHTMLNesting } from './htmlNesting' import { transformStyle } from './transforms/transformStyle' import { transformVHtml } from './transforms/vHtml' import { transformVText } from './transforms/vText' @@ -24,7 +23,6 @@ import { validateHtmlNesting } from './transforms/validateHtmlNesting' import { extend } from '@vue/shared' export { parserOptions } -export { isValidHTMLNesting } export const DOMNodeTransforms: NodeTransform[] = [ transformStyle, @@ -77,4 +75,5 @@ export { DOMErrorMessages, } from './errors' export { resolveModifiers } from './transforms/vOn' +export { isValidHTMLNesting } from './htmlNesting' export * from '@vue/compiler-core' From 9c93c22792b08c099810309f3abb6f5554b381df Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Wed, 4 Dec 2024 17:36:16 +0800 Subject: [PATCH 3/3] chore: update code comments --- packages/compiler-dom/src/htmlNesting.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/compiler-dom/src/htmlNesting.ts b/packages/compiler-dom/src/htmlNesting.ts index 8b75d059a..8fa6afce2 100644 --- a/packages/compiler-dom/src/htmlNesting.ts +++ b/packages/compiler-dom/src/htmlNesting.ts @@ -5,6 +5,8 @@ * To avoid runtime dependency on validate-html-nesting * This file should not change very often in the original repo * but we may need to keep it up-to-date from time to time. + * the validate-html-nexting's new code may not work in vue + * double check before updating this file. */ /** @@ -69,7 +71,7 @@ const onlyValidChildren: Record> = { * https://w3c.github.io/mathml-core/#dfn-mrow */ // math: new Set(['mrow']), - script: new Set(), + // table table: new Set(['caption', 'colgroup', 'tbody', 'tfoot', 'thead']), tr: new Set(['td', 'th']), @@ -77,7 +79,9 @@ const onlyValidChildren: Record> = { tbody: new Set(['tr']), thead: new Set(['tr']), tfoot: new Set(['tr']), + // these elements can not have any children elements + script: emptySet, iframe: emptySet, option: emptySet, textarea: emptySet,