fix: Restore iPadOS 15 compatibility by removing unsupported regex (#2756)
## Summary Removes an unsupported negative regex lookbehind from input-helper entity ID validation. Advanced Camera Card v8 fails to load on Safari/iPadOS 15 because the browser cannot parse `(?<!_)`. This prevents the `advanced-camera-card` custom element from registering. The replacement preserves the existing validation behavior without lookbehind: - Accepts valid `input_*` helper entity IDs. - Rejects object IDs beginning or ending with `_`. - Rejects object IDs containing `__`. - Restores compatibility with Safari versions before 16.4. This closes #2753 ## Testing - Added regression coverage for valid and invalid input-helper entity IDs. - TypeScript typecheck passes. - ESLint passes for the changed files. - Build succeeds. - Confirmed the generated distribution contains no negative lookbehind syntax. - Direct validation of the replacement regex passes. ## Reproduction - Device: iPad mini 4 - OS: iPadOS 15.8.8 - Last working release: v7.27.4 - Affected releases: v8.0.0 and v8.0.1 - Browser error: ```text SyntaxError: Invalid regular expression: invalid group specifier name Safari and Safari on iOS did not support regex lookbehind until version 16.4. --------- Co-authored-by: dermotduffy <dermot.duffy@gmail.com>
This commit is contained in:
co-authored by
dermotduffy
parent
95b85bf608
commit
54e261fd54
@@ -7,10 +7,13 @@ import type { ConditionEvaluator, ConditionOfType, EvaluatorContext } from './ty
|
||||
// Home Assistant resolves an expected value that names an `input_*` helper to
|
||||
// that helper's current state (its Lovelace state-condition behavior), on both
|
||||
// the state and the attribute path; only these helper domains are resolved.
|
||||
// Regexp directly from:
|
||||
// Matches the same entity IDs as the regexp in Home Assistant:
|
||||
// https://github.com/home-assistant/core/blob/dev/homeassistant/helpers/condition.py
|
||||
// That regexp rejects a trailing `_` with a lookbehind, which Safari before
|
||||
// 16.4 fails to parse (taking the whole card down), so the leading and trailing
|
||||
// character are spelled out here instead.
|
||||
const INPUT_ENTITY_ID =
|
||||
/^input_(?:select|text|number|boolean|datetime)\.(?!.+__)(?!_)[\da-z_]+(?<!_)$/;
|
||||
/^input_(?:select|text|number|boolean|datetime)\.(?!.+__)[\da-z](?:[\da-z_]*[\da-z])?$/;
|
||||
|
||||
const isInputHelperName = (value: unknown): value is string =>
|
||||
typeof value === 'string' && INPUT_ENTITY_ID.test(value);
|
||||
|
||||
@@ -734,6 +734,34 @@ describe('state condition', () => {
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['input_text.expected', true],
|
||||
['input_text.a_1', true],
|
||||
['input_text.', false],
|
||||
['input_text._expected', false],
|
||||
['input_text.__expected', false],
|
||||
['input_text.expected_', false],
|
||||
['input_text.expected__name', false],
|
||||
])('should resolve only a valid input helper ID: %s', (entityID, shouldResolve) => {
|
||||
const evaluator = createConditionEvaluator(
|
||||
{
|
||||
condition: 'state' as const,
|
||||
entity_id: 'binary_sensor.foo',
|
||||
state: entityID,
|
||||
},
|
||||
createEvaluatorContext(),
|
||||
);
|
||||
|
||||
expect(
|
||||
evaluator.evaluate({
|
||||
hass: createHASS({
|
||||
'binary_sensor.foo': createStateEntity({ state: 'armed' }),
|
||||
[entityID]: createStateEntity({ state: 'armed' }),
|
||||
}),
|
||||
}).result,
|
||||
).toBe(shouldResolve);
|
||||
});
|
||||
|
||||
it('should not resolve a non-input entity name', () => {
|
||||
// Only `input_*` helpers are resolved; other entity names compare literally.
|
||||
const evaluator = createConditionEvaluator(
|
||||
|
||||
Reference in New Issue
Block a user