Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(html/unstable): add isValidCustomElementName() #5456

Merged
merged 15 commits into from
Aug 1, 2024
1 change: 1 addition & 0 deletions html/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"exports": {
".": "./mod.ts",
"./entities": "./entities.ts",
"./is-valid-custom-element-name": "./is_valid_custom_element_name.ts",
"./named-entity-list.json": "./named_entity_list.json"
}
}
57 changes: 57 additions & 0 deletions html/is_valid_custom_element_name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

const FORBIDDEN_CUSTOM_ELEMENT_NAMES: string[] = [
"annotation-xml",
"color-profile",
"font-face",
"font-face-src",
"font-face-uri",
"font-face-format",
"font-face-name",
"missing-glyph",
] as const;

const CUSTOM_ELEMENT_NAME_CHARS =
/^[a-z](?:[-.0-9_a-z\xB7\xC0-\xD6\xD8-\xF6\xF8-\u037D\u037F-\u1FFF\u200C\u200D\u203F\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])*-(?:[-.0-9_a-z\xB7\xC0-\xD6\xD8-\xF6\xF8-\u037D\u037F-\u1FFF\u200C\u200D\u203F\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])*$/;

/**
* Returns whether the given string is a valid custom element name, as per the
* requirements defined in
* {@link https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name}.
*
* > [!WARNING]
* > **UNSTABLE**: New API, yet to be vetted.
*
* @experimental
*
* The element name must not be any of the following:
* - `annotation-xml`
* - `color-profile`
* - `font-face`
* - `font-face-src`
* - `font-face-uri`
* - `font-face-format`
* - `font-face-name`
* - `missing-glyph`
*
* @example Usage
*
* Using a valid custom element name
*
* ```ts
* import { isValidCustomElementName } from "@std/html/is-valid-custom-element-name";
* import { assertEquals } from "@std/assert";
*
* assertEquals(isValidCustomElementName("custom-element"), true);
* assertEquals(isValidCustomElementName("font-face"), false);
* assertEquals(isValidCustomElementName("custom-element@"), false);
* ```
*
* @param elementName The element name to be validate
* @returns `true` if the element name is valid, `false` otherwise.
*/
export function isValidCustomElementName(elementName: string): boolean {
return !FORBIDDEN_CUSTOM_ELEMENT_NAMES.includes(elementName) &&
CUSTOM_ELEMENT_NAME_CHARS.test(elementName);
}
51 changes: 51 additions & 0 deletions html/is_valid_custom_element_name_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "@std/assert/equals";
import { isValidCustomElementName } from "./is_valid_custom_element_name.ts";

const forbiddenCustomElementNames: string[] = [
"annotation-xml",
"color-profile",
"font-face",
"font-face-src",
"font-face-uri",
"font-face-format",
"font-face-name",
"missing-glyph",
] as const;

Deno.test("isValidCustomElementName()", async (t) => {
await t.step("handles forbidden custom names", () => {
forbiddenCustomElementNames.map((forbiddenName) => {
assertEquals(isValidCustomElementName(forbiddenName), false);
});
});

await t.step("handles custom names with upper cases", () => {
assertEquals(isValidCustomElementName("Custom-element"), false);
});

await t.step("handles custom names with special chars", () => {
assertEquals(isValidCustomElementName("custom-element@"), false);
});

await t.step("handles custom names with numbers", () => {
assertEquals(isValidCustomElementName("custom-1-element"), true);
});

await t.step("handles custom names with underscores", () => {
assertEquals(isValidCustomElementName("custom_element"), false);
});

await t.step("handles custom names with points", () => {
assertEquals(isValidCustomElementName("custom.element"), false);
});

await t.step("handles valid custom names", () => {
assertEquals(isValidCustomElementName("custom-element"), true);
});

await t.step("handles large variety of names", () => {
assertEquals(isValidCustomElementName("math-α"), true);
assertEquals(isValidCustomElementName("emotion-😍"), true);
});
});
1 change: 1 addition & 0 deletions html/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
*/

export * from "./entities.ts";
export * from "./is_valid_custom_element_name.ts";