Skip to content

Commit eba7fa9

Browse files
committed
Improve _htmlNameRegExp() to follow the CommonMark spec
1 parent e774c71 commit eba7fa9

File tree

3 files changed

+163
-15
lines changed

3 files changed

+163
-15
lines changed

tsdoc/src/parser/StringChecks.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ export class StringChecks {
77
private static readonly _urlSchemeRegExp: RegExp = /^[a-z][a-z0-9]*\:\/\//i;
88
private static readonly _urlSchemeAfterRegExp: RegExp = /^[a-z][a-z0-9]*\:\/\/./i;
99

10+
// HTML element definitions:
11+
// https://spec.commonmark.org/0.29/#tag-name
1012
// https://www.w3.org/TR/html5/syntax.html#tag-name
1113
// https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
12-
private static readonly _htmlNameRegExp: RegExp = /^[a-z][\-.0-9_a-z]*$/i;
14+
//
15+
// We use the CommonMark spec:
16+
// "A tag name consists of an ASCII letter followed by zero or more ASCII letters, digits, or hyphens (-)."
17+
private static readonly _htmlNameRegExp: RegExp = /^[a-z]+[a-z0-9\-]*$/i;
1318

1419
// Note: In addition to letters, numbers, underscores, and dollar signs, modern ECMAScript
1520
// also allows Unicode categories such as letters, combining marks, digits, and connector punctuation.
@@ -86,7 +91,7 @@ export class StringChecks {
8691
*/
8792
public static explainIfInvalidHtmlName(htmlName: string): string | undefined {
8893
if (!StringChecks._htmlNameRegExp.test(htmlName)) {
89-
return 'An HTML name must be a sequence of letters separated by hyphens';
94+
return 'An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens';
9095
}
9196

9297
return undefined;

tsdoc/src/parser/__tests__/NodeParserHtml.test.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,22 @@ test('07 Closing tags, negative', () => {
108108
].join('\n'));
109109
});
110110

111-
test('08 Unusual element names', () => {
111+
test('08 Unusual HTML names, positive', () => {
112112
TestHelpers.parseAndMatchNodeParserSnapshot([
113113
'/**',
114114
' * <a1/>',
115115
' * <a-a>',
116-
' * <a--a>',
117-
' * <a.2>',
116+
' * <a--9->',
117+
' */'
118+
].join('\n'));
119+
});
120+
121+
test('09 Unusual HTML names, negative', () => {
122+
TestHelpers.parseAndMatchNodeParserSnapshot([
123+
'/**',
124+
' * <1a/>',
125+
' * <a.a>',
126+
' * <_a>',
118127
' */'
119128
].join('\n'));
120129
});

tsdoc/src/parser/__tests__/__snapshots__/NodeParserHtml.test.ts.snap

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,15 +1702,14 @@ Object {
17021702
}
17031703
`;
17041704

1705-
exports[`08 Unusual element names 1`] = `
1705+
exports[`08 Unusual HTML names, positive 1`] = `
17061706
Object {
1707-
"buffer": "/**[n] * [<]a1/[>][n] * [<]a-a[>][n] * [<]a--a[>][n] * [<]a.2[>][n] */",
1707+
"buffer": "/**[n] * [<]a1/[>][n] * [<]a-a[>][n] * [<]a--9-[>][n] */",
17081708
"gaps": Array [],
17091709
"lines": Array [
17101710
"[<]a1/[>]",
17111711
"[<]a-a[>]",
1712-
"[<]a--a[>]",
1713-
"[<]a.2[>]",
1712+
"[<]a--9-[>]",
17141713
],
17151714
"logMessages": Array [],
17161715
"nodes": Object {
@@ -1783,7 +1782,7 @@ Object {
17831782
},
17841783
Object {
17851784
"kind": "Excerpt: HtmlStartTag_Name",
1786-
"nodeExcerpt": "a--a",
1785+
"nodeExcerpt": "a--9-",
17871786
},
17881787
Object {
17891788
"kind": "Excerpt: HtmlStartTag_ClosingDelimiter",
@@ -1800,19 +1799,154 @@ Object {
18001799
},
18011800
],
18021801
},
1802+
],
1803+
},
1804+
],
1805+
},
1806+
],
1807+
},
1808+
}
1809+
`;
1810+
1811+
exports[`09 Unusual HTML names, negative 1`] = `
1812+
Object {
1813+
"buffer": "/**[n] * [<]1a/[>][n] * [<]a.a[>][n] * [<]_a[>][n] */",
1814+
"gaps": Array [],
1815+
"lines": Array [
1816+
"[<]1a/[>]",
1817+
"[<]a.a[>]",
1818+
"[<]_a[>]",
1819+
],
1820+
"logMessages": Array [
1821+
"(2,4): Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1822+
"(2,8): The \\">\\" character should be escaped using a backslash to avoid confusion with an HTML tag",
1823+
"(3,4): Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1824+
"(3,8): The \\">\\" character should be escaped using a backslash to avoid confusion with an HTML tag",
1825+
"(4,4): Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1826+
"(4,7): The \\">\\" character should be escaped using a backslash to avoid confusion with an HTML tag",
1827+
],
1828+
"nodes": Object {
1829+
"kind": "Comment",
1830+
"nodes": Array [
1831+
Object {
1832+
"kind": "Section",
1833+
"nodes": Array [
1834+
Object {
1835+
"kind": "Paragraph",
1836+
"nodes": Array [
18031837
Object {
1804-
"kind": "HtmlStartTag",
1838+
"errorLocation": "1a",
1839+
"errorLocationPrecedingToken": "<",
1840+
"errorMessage": "Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1841+
"kind": "ErrorText",
18051842
"nodes": Array [
18061843
Object {
1807-
"kind": "Excerpt: HtmlStartTag_OpeningDelimiter",
1844+
"kind": "Excerpt: ErrorText",
18081845
"nodeExcerpt": "[<]",
18091846
},
1847+
],
1848+
},
1849+
Object {
1850+
"kind": "PlainText",
1851+
"nodes": Array [
1852+
Object {
1853+
"kind": "Excerpt: PlainText",
1854+
"nodeExcerpt": "1a/",
1855+
},
1856+
],
1857+
},
1858+
Object {
1859+
"errorLocation": "[>]",
1860+
"errorLocationPrecedingToken": "/",
1861+
"errorMessage": "The [q][>][q] character should be escaped using a backslash to avoid confusion with an HTML tag",
1862+
"kind": "ErrorText",
1863+
"nodes": Array [
18101864
Object {
1811-
"kind": "Excerpt: HtmlStartTag_Name",
1812-
"nodeExcerpt": "a.2",
1865+
"kind": "Excerpt: ErrorText",
1866+
"nodeExcerpt": "[>]",
18131867
},
1868+
],
1869+
},
1870+
Object {
1871+
"kind": "SoftBreak",
1872+
"nodes": Array [
18141873
Object {
1815-
"kind": "Excerpt: HtmlStartTag_ClosingDelimiter",
1874+
"kind": "Excerpt: SoftBreak",
1875+
"nodeExcerpt": "[n]",
1876+
},
1877+
],
1878+
},
1879+
Object {
1880+
"errorLocation": "a.a",
1881+
"errorLocationPrecedingToken": "<",
1882+
"errorMessage": "Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1883+
"kind": "ErrorText",
1884+
"nodes": Array [
1885+
Object {
1886+
"kind": "Excerpt: ErrorText",
1887+
"nodeExcerpt": "[<]",
1888+
},
1889+
],
1890+
},
1891+
Object {
1892+
"kind": "PlainText",
1893+
"nodes": Array [
1894+
Object {
1895+
"kind": "Excerpt: PlainText",
1896+
"nodeExcerpt": "a.a",
1897+
},
1898+
],
1899+
},
1900+
Object {
1901+
"errorLocation": "[>]",
1902+
"errorLocationPrecedingToken": "a",
1903+
"errorMessage": "The [q][>][q] character should be escaped using a backslash to avoid confusion with an HTML tag",
1904+
"kind": "ErrorText",
1905+
"nodes": Array [
1906+
Object {
1907+
"kind": "Excerpt: ErrorText",
1908+
"nodeExcerpt": "[>]",
1909+
},
1910+
],
1911+
},
1912+
Object {
1913+
"kind": "SoftBreak",
1914+
"nodes": Array [
1915+
Object {
1916+
"kind": "Excerpt: SoftBreak",
1917+
"nodeExcerpt": "[n]",
1918+
},
1919+
],
1920+
},
1921+
Object {
1922+
"errorLocation": "_a",
1923+
"errorLocationPrecedingToken": "<",
1924+
"errorMessage": "Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens",
1925+
"kind": "ErrorText",
1926+
"nodes": Array [
1927+
Object {
1928+
"kind": "Excerpt: ErrorText",
1929+
"nodeExcerpt": "[<]",
1930+
},
1931+
],
1932+
},
1933+
Object {
1934+
"kind": "PlainText",
1935+
"nodes": Array [
1936+
Object {
1937+
"kind": "Excerpt: PlainText",
1938+
"nodeExcerpt": "_a",
1939+
},
1940+
],
1941+
},
1942+
Object {
1943+
"errorLocation": "[>]",
1944+
"errorLocationPrecedingToken": "_a",
1945+
"errorMessage": "The [q][>][q] character should be escaped using a backslash to avoid confusion with an HTML tag",
1946+
"kind": "ErrorText",
1947+
"nodes": Array [
1948+
Object {
1949+
"kind": "Excerpt: ErrorText",
18161950
"nodeExcerpt": "[>]",
18171951
},
18181952
],

0 commit comments

Comments
 (0)