Skip to content

Commit

Permalink
unique-id: Adjust uniqueId() implementation to only generate valid …
Browse files Browse the repository at this point in the history
…selectors

Regular UUIDs are allowed to start with numeric digits, but CSS selectors may not start with those. This change adjusts the implementation to only return UUIDs starting with a letter instead of a digit.
  • Loading branch information
Turbo87 committed Jun 21, 2022
1 parent ffe7d76 commit 2ffa93d
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
8 changes: 5 additions & 3 deletions packages/@ember/-internals/glimmer/lib/helpers/unique-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ export default internalHelper((): Reference<string> => {
// This code should be reasonably fast, and provide a unique value every time
// it's called, which is what we need here. It produces a string formatted as a
// standard UUID, which avoids accidentally turning Ember-specific
// implementation details into an intimate API.
// implementation details into an intimate API. It also ensures that the UUID
// always starts with a letter, to avoid creating invalid IDs with a numeric
// digit at the start.
function uniqueId() {
// @ts-expect-error this one-liner abuses weird JavaScript semantics that
// TypeScript (legitimately) doesn't like, but they're nonetheless valid and
// specced.
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (a) =>
(a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
return ([3e7] + -1e3 + -4e3 + -2e3 + -1e11).replace(/[0-3]/g, (a) =>
((a * 4) ^ ((Math.random() * 16) >> (a & 2))).toString(16)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,24 @@ if (EMBER_UNIQUE_ID_HELPER) {
});
}

['@test it only generates valid selectors']() {
let iterations = 1000;
let reNumericStart = /^\d/;

let template = '<p>{{unique-id}}</p>'.repeat(iterations);
super.render(template);

for (let i = 0; i < iterations; i++) {
let textNode = this.nthChild(i).firstChild;
let text = textNode.data;

this.assert.false(
reNumericStart.test(text),
`{{unique-id}} should produce valid selectors` + text
);
}
}

render(template, ...rest) {
// If there are three parameters to `render`, the second parameter is the
// template's arguments.
Expand Down

0 comments on commit 2ffa93d

Please sign in to comment.