Skip to content

Commit 1307371

Browse files
committed
feat(@angular-devkit/schematics): support unicode character HTML element names
The HTML specification allows for a wide variety of characters to be present within a custom element name. The previous behavior limited the names to mostly alphanumeric characters. This change opens up the names to include the characters specified within the specification for custom element names.
1 parent a1aa8d5 commit 1307371

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

packages/angular_devkit/schematics/src/formats/html-selector.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,47 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import { schema } from '@angular-devkit/core';
109

10+
// As per https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
11+
// * Without mandatory `-` as the application prefix will generally cover its inclusion
12+
// * And an allowance for upper alpha characters
13+
14+
// NOTE: This should eventually be broken out into two formats: full and partial (allows for prefix)
15+
16+
const unicodeRanges = [
17+
[0xC0, 0xD6],
18+
[0xD8, 0xF6],
19+
[0xF8, 0x37D],
20+
[0x37F, 0x1FFF],
21+
[0x200C, 0x200D],
22+
[0x203F, 0x2040],
23+
[0x2070, 0x218F],
24+
[0x2C00, 0x2FEF],
25+
[0x3001, 0xD7FF],
26+
[0xF900, 0xFDCF],
27+
[0xFDF0, 0xFFFD],
28+
[0x10000, 0xEFFFF],
29+
];
30+
31+
function isValidElementName(name: string) {
32+
let regex = '^[a-zA-Z][';
33+
34+
regex += '-.0-9_a-zA-Z\\u{B7}';
35+
36+
for (const range of unicodeRanges) {
37+
regex += `\\u{${range[0].toString(16)}}-\\u{${range[1].toString(16)}}`;
38+
}
39+
40+
regex += ']*$';
1141

12-
// Must start with a letter, and must contain only alphanumeric characters or dashes.
13-
// When adding a dash the segment after the dash must also start with a letter.
14-
export const htmlSelectorRe = /^[a-zA-Z][.0-9a-zA-Z]*(:?-[a-zA-Z][.0-9a-zA-Z]*)*$/;
42+
return new RegExp(regex, 'u').test(name);
43+
}
1544

1645
export const htmlSelectorFormat: schema.SchemaFormat = {
1746
name: 'html-selector',
1847
formatter: {
1948
async: false,
20-
validate: (selector: string) => htmlSelectorRe.test(selector),
49+
validate: name => typeof name === 'string' && isValidElementName(name),
2150
},
2251
};

packages/angular_devkit/schematics/src/formats/html-selector_spec.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import { map } from 'rxjs/operators';
109
import { formatValidator } from './format-validator';
1110
import { htmlSelectorFormat } from './html-selector';
1211

13-
1412
describe('Schematics HTML selector format', () => {
1513
it('accepts correct selectors', done => {
1614
const data = { selector: 'my-selector' };
@@ -45,14 +43,25 @@ describe('Schematics HTML selector format', () => {
4543
.toPromise().then(done, done.fail);
4644
});
4745

48-
it('rejects selectors with non-letter after dash', done => {
46+
it('accepts selectors with non-letter after dash', done => {
4947
const data = { selector: 'my-1selector' };
5048
const dataSchema = {
5149
properties: { selector: { type: 'string', format: 'html-selector' } },
5250
};
5351

5452
formatValidator(data, dataSchema, [htmlSelectorFormat])
55-
.pipe(map(result => expect(result.success).toBe(false)))
53+
.pipe(map(result => expect(result.success).toBe(true)))
54+
.toPromise().then(done, done.fail);
55+
});
56+
57+
it('accepts selectors with unicode', done => {
58+
const data = { selector: 'app-root😀' };
59+
const dataSchema = {
60+
properties: { selector: { type: 'string', format: 'html-selector' } },
61+
};
62+
63+
formatValidator(data, dataSchema, [htmlSelectorFormat])
64+
.pipe(map(result => expect(result.success).toBe(true)))
5665
.toPromise().then(done, done.fail);
5766
});
5867
});

0 commit comments

Comments
 (0)