@oxyhq/core 12.5.1 → 12.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/i18n/locales/ar-SA.json +3 -1
- package/dist/cjs/i18n/locales/ca-ES.json +3 -1
- package/dist/cjs/i18n/locales/de-DE.json +3 -1
- package/dist/cjs/i18n/locales/en-US.json +14 -1
- package/dist/cjs/i18n/locales/es-ES.json +14 -1
- package/dist/cjs/i18n/locales/fr-FR.json +3 -1
- package/dist/cjs/i18n/locales/it-IT.json +3 -1
- package/dist/cjs/i18n/locales/ja-JP.json +3 -1
- package/dist/cjs/i18n/locales/ko-KR.json +3 -1
- package/dist/cjs/i18n/locales/locales/ar-SA.json +3 -1
- package/dist/cjs/i18n/locales/locales/ca-ES.json +3 -1
- package/dist/cjs/i18n/locales/locales/de-DE.json +3 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +14 -1
- package/dist/cjs/i18n/locales/locales/es-ES.json +14 -1
- package/dist/cjs/i18n/locales/locales/fr-FR.json +3 -1
- package/dist/cjs/i18n/locales/locales/it-IT.json +3 -1
- package/dist/cjs/i18n/locales/locales/ja-JP.json +3 -1
- package/dist/cjs/i18n/locales/locales/ko-KR.json +3 -1
- package/dist/cjs/i18n/locales/locales/pt-PT.json +3 -1
- package/dist/cjs/i18n/locales/locales/zh-CN.json +3 -1
- package/dist/cjs/i18n/locales/pt-PT.json +3 -1
- package/dist/cjs/i18n/locales/zh-CN.json +3 -1
- package/dist/cjs/mixins/OxyServices.user.js +24 -2
- package/dist/cjs/utils/displayNamePolicyRanges.generated.js +35 -0
- package/dist/cjs/utils/textNormalization.js +9 -4
- package/dist/cjs/utils/validationUtils.js +49 -41
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/i18n/locales/ar-SA.json +3 -1
- package/dist/esm/i18n/locales/ca-ES.json +3 -1
- package/dist/esm/i18n/locales/de-DE.json +3 -1
- package/dist/esm/i18n/locales/en-US.json +14 -1
- package/dist/esm/i18n/locales/es-ES.json +14 -1
- package/dist/esm/i18n/locales/fr-FR.json +3 -1
- package/dist/esm/i18n/locales/it-IT.json +3 -1
- package/dist/esm/i18n/locales/ja-JP.json +3 -1
- package/dist/esm/i18n/locales/ko-KR.json +3 -1
- package/dist/esm/i18n/locales/locales/ar-SA.json +3 -1
- package/dist/esm/i18n/locales/locales/ca-ES.json +3 -1
- package/dist/esm/i18n/locales/locales/de-DE.json +3 -1
- package/dist/esm/i18n/locales/locales/en-US.json +14 -1
- package/dist/esm/i18n/locales/locales/es-ES.json +14 -1
- package/dist/esm/i18n/locales/locales/fr-FR.json +3 -1
- package/dist/esm/i18n/locales/locales/it-IT.json +3 -1
- package/dist/esm/i18n/locales/locales/ja-JP.json +3 -1
- package/dist/esm/i18n/locales/locales/ko-KR.json +3 -1
- package/dist/esm/i18n/locales/locales/pt-PT.json +3 -1
- package/dist/esm/i18n/locales/locales/zh-CN.json +3 -1
- package/dist/esm/i18n/locales/pt-PT.json +3 -1
- package/dist/esm/i18n/locales/zh-CN.json +3 -1
- package/dist/esm/mixins/OxyServices.user.js +24 -2
- package/dist/esm/utils/displayNamePolicyRanges.generated.js +32 -0
- package/dist/esm/utils/textNormalization.js +9 -4
- package/dist/esm/utils/validationUtils.js +50 -42
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/utils/displayNamePolicyRanges.generated.d.ts +32 -0
- package/dist/types/utils/validationUtils.d.ts +48 -34
- package/package.json +9 -4
- package/src/i18n/locales/ar-SA.json +3 -1
- package/src/i18n/locales/ca-ES.json +3 -1
- package/src/i18n/locales/de-DE.json +3 -1
- package/src/i18n/locales/en-US.json +14 -1
- package/src/i18n/locales/es-ES.json +14 -1
- package/src/i18n/locales/fr-FR.json +3 -1
- package/src/i18n/locales/it-IT.json +3 -1
- package/src/i18n/locales/ja-JP.json +3 -1
- package/src/i18n/locales/ko-KR.json +3 -1
- package/src/i18n/locales/pt-PT.json +3 -1
- package/src/i18n/locales/zh-CN.json +3 -1
- package/src/mixins/OxyServices.user.ts +24 -2
- package/src/mixins/__tests__/followCacheInvalidation.test.ts +5 -0
- package/src/mixins/__tests__/userReadCacheBypass.test.ts +8 -0
- package/src/utils/__tests__/validationUtils.test.ts +106 -3
- package/src/utils/displayNamePolicyRanges.generated.ts +40 -0
- package/src/utils/textNormalization.ts +9 -4
- package/src/utils/validationUtils.ts +55 -42
|
@@ -161,7 +161,7 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
161
161
|
*/
|
|
162
162
|
async getProfileByUsername(username: string, options?: { cache?: boolean }): Promise<User> {
|
|
163
163
|
try {
|
|
164
|
-
const user = await this.makeRequest<User>('GET', `/profiles/username/${username}`, undefined, {
|
|
164
|
+
const user = await this.makeRequest<User>('GET', `/profiles/username/${encodeURIComponent(username)}`, undefined, {
|
|
165
165
|
cache: options?.cache ?? true,
|
|
166
166
|
cacheTTL: 5 * 60 * 1000, // 5 minutes cache for profiles
|
|
167
167
|
});
|
|
@@ -244,7 +244,15 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
244
244
|
handle,
|
|
245
245
|
}, {
|
|
246
246
|
cache: true,
|
|
247
|
-
|
|
247
|
+
// 5 min — matches the sibling profile fetches (getUserById /
|
|
248
|
+
// getProfileByUsername). /profiles/resolve now carries the viewer-relative
|
|
249
|
+
// `relationship` (isFollowing / followsYou); `followsYou` is target→viewer,
|
|
250
|
+
// so the viewer can't self-refresh it via a follow action. The GET cache is
|
|
251
|
+
// identity-scoped (keyed by the caller's access-token identity tag → no
|
|
252
|
+
// cross-viewer poison), so a short TTL keeps "Follows you" reasonably fresh
|
|
253
|
+
// without a per-call bypass. The identity fields alone tolerate a longer
|
|
254
|
+
// window, but a 24h stale relationship is not acceptable.
|
|
255
|
+
cacheTTL: 5 * 60 * 1000,
|
|
248
256
|
});
|
|
249
257
|
return normalizeUserIdentityOrNull(result);
|
|
250
258
|
} catch (error: unknown) {
|
|
@@ -725,6 +733,11 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
725
733
|
try {
|
|
726
734
|
const result = await this.makeRequest<FollowMutationResult>('POST', `/users/${userId}/follow`, undefined, { cache: false });
|
|
727
735
|
this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
|
|
736
|
+
// Profile fetches embed viewer-relative `relationship` — bust so a
|
|
737
|
+
// remount doesn't serve a stale isFollowing for up to 5 minutes.
|
|
738
|
+
this.clearCacheEntry(`GET:/users/${userId}`);
|
|
739
|
+
this.clearCacheByPrefix('GET:/profiles/username/');
|
|
740
|
+
this.clearCacheByPrefix('GET:/profiles/resolve');
|
|
728
741
|
// The follow changed the viewer's graph — bust the cached consolidated
|
|
729
742
|
// `GET /users/me/graph` so the next read reflects the new following/
|
|
730
743
|
// mutual set instead of the stale pre-write snapshot.
|
|
@@ -752,7 +765,10 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
752
765
|
// Bust each affected user's cached follow-status (see `followUser`).
|
|
753
766
|
for (const id of userIds) {
|
|
754
767
|
this.clearCacheEntry(`GET:/users/${id}/follow-status`);
|
|
768
|
+
this.clearCacheEntry(`GET:/users/${id}`);
|
|
755
769
|
}
|
|
770
|
+
this.clearCacheByPrefix('GET:/profiles/username/');
|
|
771
|
+
this.clearCacheByPrefix('GET:/profiles/resolve');
|
|
756
772
|
// The batch changed the viewer's graph — bust the consolidated cache.
|
|
757
773
|
this.clearCacheEntry('GET:/users/me/graph');
|
|
758
774
|
return result;
|
|
@@ -778,7 +794,10 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
778
794
|
// Bust each affected user's cached follow-status (see `followUser`).
|
|
779
795
|
for (const id of userIds) {
|
|
780
796
|
this.clearCacheEntry(`GET:/users/${id}/follow-status`);
|
|
797
|
+
this.clearCacheEntry(`GET:/users/${id}`);
|
|
781
798
|
}
|
|
799
|
+
this.clearCacheByPrefix('GET:/profiles/username/');
|
|
800
|
+
this.clearCacheByPrefix('GET:/profiles/resolve');
|
|
782
801
|
// The batch changed the viewer's graph — bust the consolidated cache.
|
|
783
802
|
this.clearCacheEntry('GET:/users/me/graph');
|
|
784
803
|
return result;
|
|
@@ -795,6 +814,9 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
795
814
|
const result = await this.makeRequest<FollowMutationResult>('DELETE', `/users/${userId}/follow`, undefined, { cache: false });
|
|
796
815
|
// Bust the cached follow-status so a remount reads fresh truth (see `followUser`).
|
|
797
816
|
this.clearCacheEntry(`GET:/users/${userId}/follow-status`);
|
|
817
|
+
this.clearCacheEntry(`GET:/users/${userId}`);
|
|
818
|
+
this.clearCacheByPrefix('GET:/profiles/username/');
|
|
819
|
+
this.clearCacheByPrefix('GET:/profiles/resolve');
|
|
798
820
|
// The unfollow changed the viewer's graph — bust the consolidated cache.
|
|
799
821
|
this.clearCacheEntry('GET:/users/me/graph');
|
|
800
822
|
return result;
|
|
@@ -147,12 +147,17 @@ describe('follow-status cache invalidation', () => {
|
|
|
147
147
|
|
|
148
148
|
it('invalidates the exact logical follow-status key on a single follow', async () => {
|
|
149
149
|
const clearSpy = jest.spyOn(oxy, 'clearCacheEntry');
|
|
150
|
+
const clearPrefixSpy = jest.spyOn(oxy, 'clearCacheByPrefix');
|
|
150
151
|
fetchMock.mockResolvedValueOnce(jsonResponse({ success: true, message: 'ok' }));
|
|
151
152
|
|
|
152
153
|
await oxy.followUser('target-3');
|
|
153
154
|
|
|
154
155
|
expect(clearSpy).toHaveBeenCalledWith('GET:/users/target-3/follow-status');
|
|
156
|
+
expect(clearSpy).toHaveBeenCalledWith('GET:/users/target-3');
|
|
157
|
+
expect(clearPrefixSpy).toHaveBeenCalledWith('GET:/profiles/username/');
|
|
158
|
+
expect(clearPrefixSpy).toHaveBeenCalledWith('GET:/profiles/resolve');
|
|
155
159
|
clearSpy.mockRestore();
|
|
160
|
+
clearPrefixSpy.mockRestore();
|
|
156
161
|
});
|
|
157
162
|
|
|
158
163
|
it('does not invalidate or call the network when bulk follow gets an empty list', async () => {
|
|
@@ -117,5 +117,13 @@ describe('getUserById / getProfileByUsername cache bypass', () => {
|
|
|
117
117
|
expect((fresh as unknown as { bio: string }).bio).toBe('new');
|
|
118
118
|
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
119
119
|
});
|
|
120
|
+
|
|
121
|
+
it('URL-encodes the username in the request path', async () => {
|
|
122
|
+
fetchMock.mockResolvedValueOnce(jsonResponse({ id: 'fed-1', username: 'alice@mastodon.social' }));
|
|
123
|
+
await oxy.getProfileByUsername('alice@mastodon.social');
|
|
124
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
125
|
+
const [url] = fetchMock.mock.calls[0] as [string];
|
|
126
|
+
expect(url).toContain('/profiles/username/alice%40mastodon.social');
|
|
127
|
+
});
|
|
120
128
|
});
|
|
121
129
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
1
3
|
import {
|
|
2
4
|
isRequiredString,
|
|
3
5
|
isRequiredNumber,
|
|
@@ -8,6 +10,9 @@ import {
|
|
|
8
10
|
isValidUsername,
|
|
9
11
|
isValidPassword,
|
|
10
12
|
isValidDisplayName,
|
|
13
|
+
DISPLAY_NAME_ALLOWED_SCRIPTS,
|
|
14
|
+
DISPLAY_NAME_DISALLOWED_SOURCE,
|
|
15
|
+
DISPLAY_NAME_ORPHANED_MARK_SOURCE,
|
|
11
16
|
isValidUUID,
|
|
12
17
|
isValidDate,
|
|
13
18
|
isValidFileSize,
|
|
@@ -176,15 +181,15 @@ describe('Validation Utils', () => {
|
|
|
176
181
|
['ᚠ', 'Runic'],
|
|
177
182
|
['Miguel de Icaza ᯅ', 'a Latin name with a trailing Batak letter'],
|
|
178
183
|
])('should return false for non-allowlisted-script letter %p (%s)', (name) => {
|
|
179
|
-
// These characters are General_Category Lo (
|
|
184
|
+
// These characters are General_Category Lo (letters), so the old
|
|
180
185
|
// all-scripts policy accepted them; the curated script allowlist rejects
|
|
181
186
|
// decorative / limited-use scripts a real name never uses.
|
|
182
187
|
expect(isValidDisplayName(name)).toBe(false);
|
|
183
188
|
});
|
|
184
189
|
|
|
185
190
|
it('should return false for control whitespace (tab/newline/CR)', () => {
|
|
186
|
-
//
|
|
187
|
-
// spoofing whitespace that \s would have admitted.
|
|
191
|
+
// Space separators only (General_Category Zs) rejects layout-breaking /
|
|
192
|
+
// multi-line spoofing whitespace that \s would have admitted.
|
|
188
193
|
expect(isValidDisplayName('Ada\tLovelace')).toBe(false);
|
|
189
194
|
expect(isValidDisplayName('Ada\nLovelace')).toBe(false);
|
|
190
195
|
expect(isValidDisplayName('Ada\rLovelace')).toBe(false);
|
|
@@ -196,6 +201,104 @@ describe('Validation Utils', () => {
|
|
|
196
201
|
});
|
|
197
202
|
});
|
|
198
203
|
|
|
204
|
+
// Hermes (React Native) has Unicode property escapes compiled OUT: any such
|
|
205
|
+
// escape (Script_Extensions "scx=…" or General_Category classes) in a `u`-flag
|
|
206
|
+
// regex throws "Invalid RegExp: Invalid property name" at module load and
|
|
207
|
+
// crashes every Oxy RN/Expo app at boot. The display-name policy therefore
|
|
208
|
+
// ships explicit code-point RANGES instead. This block guards that invariant
|
|
209
|
+
// AND proves the range regexes behave identically.
|
|
210
|
+
describe('display-name policy is property-escape-free (Hermes safety)', () => {
|
|
211
|
+
const PROPERTY_ESCAPE = /\\[pP]\{/;
|
|
212
|
+
|
|
213
|
+
it('exposes runtime regex sources that contain NO Unicode property escape', () => {
|
|
214
|
+
expect(PROPERTY_ESCAPE.test(DISPLAY_NAME_ALLOWED_SCRIPTS)).toBe(false);
|
|
215
|
+
expect(PROPERTY_ESCAPE.test(DISPLAY_NAME_DISALLOWED_SOURCE)).toBe(false);
|
|
216
|
+
expect(PROPERTY_ESCAPE.test(DISPLAY_NAME_ORPHANED_MARK_SOURCE)).toBe(false);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('only uses code-point escapes (\\x / \\u) in the class bodies', () => {
|
|
220
|
+
// regexpu-core lowers the property escapes to `\x…` / `\u…` / `\u{…}`
|
|
221
|
+
// code-point escapes. Every backslash-escape in the runtime sources must
|
|
222
|
+
// be one of those forms — never a property escape.
|
|
223
|
+
const escapeLeads = new Set<string>();
|
|
224
|
+
for (const src of [DISPLAY_NAME_DISALLOWED_SOURCE, DISPLAY_NAME_ORPHANED_MARK_SOURCE]) {
|
|
225
|
+
for (const [, lead] of src.matchAll(/\\(.)/g)) {
|
|
226
|
+
escapeLeads.add(lead);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
expect([...escapeLeads].sort()).toEqual(['u', 'x']);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('the shipped (non-test) policy source files contain NO property escape', () => {
|
|
233
|
+
const utilsDir = join(__dirname, '..');
|
|
234
|
+
for (const file of [
|
|
235
|
+
'validationUtils.ts',
|
|
236
|
+
'displayNamePolicyRanges.generated.ts',
|
|
237
|
+
'textNormalization.ts',
|
|
238
|
+
]) {
|
|
239
|
+
const contents = readFileSync(join(utilsDir, file), 'utf8');
|
|
240
|
+
expect(PROPERTY_ESCAPE.test(contents)).toBe(false);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Build the actual regexes exactly as production does (range-only sources +
|
|
245
|
+
// `u` flag + lookbehind — the shape Hermes must accept) and assert the full
|
|
246
|
+
// policy behaves as before across scripts, marks, and rejections.
|
|
247
|
+
const disallowed = new RegExp(DISPLAY_NAME_DISALLOWED_SOURCE, 'u');
|
|
248
|
+
const orphaned = new RegExp(DISPLAY_NAME_ORPHANED_MARK_SOURCE, 'u');
|
|
249
|
+
const passesPolicy = (raw: string) =>
|
|
250
|
+
!disallowed.test(raw) && !orphaned.test(raw.normalize('NFC'));
|
|
251
|
+
|
|
252
|
+
it('constructs the `u`-flag regexes without throwing', () => {
|
|
253
|
+
expect(() => new RegExp(DISPLAY_NAME_DISALLOWED_SOURCE, 'u')).not.toThrow();
|
|
254
|
+
expect(() => new RegExp(DISPLAY_NAME_ORPHANED_MARK_SOURCE, 'u')).not.toThrow();
|
|
255
|
+
// Global variants are what @oxyhq/api compiles for the strip path.
|
|
256
|
+
expect(() => new RegExp(DISPLAY_NAME_DISALLOWED_SOURCE, 'gu')).not.toThrow();
|
|
257
|
+
expect(() => new RegExp(DISPLAY_NAME_ORPHANED_MARK_SOURCE, 'gu')).not.toThrow();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it.each([
|
|
261
|
+
["Renée O'Brien", 'Latin with decomposed accent + apostrophe'],
|
|
262
|
+
['Ada Lovelace', 'ASCII Latin'],
|
|
263
|
+
['山田太郎', 'Han'],
|
|
264
|
+
['田中\u{20000}', 'Han incl. astral CJK Extension B'],
|
|
265
|
+
['Владимир', 'Cyrillic'],
|
|
266
|
+
['مُحَمَد', 'Arabic with harakat (combining marks on base letters)'],
|
|
267
|
+
['נתן', 'Hebrew'],
|
|
268
|
+
['नमस्ते', 'Devanagari'],
|
|
269
|
+
['김철수', 'Hangul'],
|
|
270
|
+
['Αριστοτέλης', 'Greek'],
|
|
271
|
+
['ᏔᎳ', 'Cherokee'],
|
|
272
|
+
['ᠮᠣᠩᠭᠣᠯ', 'Mongolian'],
|
|
273
|
+
])('range regexes ACCEPT allowlisted %p (%s)', (name) => {
|
|
274
|
+
expect(passesPolicy(name)).toBe(true);
|
|
275
|
+
// Parity with the public predicate.
|
|
276
|
+
expect(isValidDisplayName(name)).toBe(true);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it.each([
|
|
280
|
+
['nixCraft \u{1f427}', 'emoji (astral)'],
|
|
281
|
+
['Agent007', 'digit'],
|
|
282
|
+
['Jean-Luc', 'hyphen'],
|
|
283
|
+
['J.R.', 'dot'],
|
|
284
|
+
['ᯅ', 'Batak (non-allowlisted script)'],
|
|
285
|
+
['ᚠ', 'Runic (non-allowlisted script)'],
|
|
286
|
+
['Ada\tLovelace', 'tab (control whitespace)'],
|
|
287
|
+
['Ada\nLovelace', 'newline (control whitespace)'],
|
|
288
|
+
['Ada\rLovelace', 'carriage return (control whitespace)'],
|
|
289
|
+
])('range regexes REJECT %p (%s)', (name) => {
|
|
290
|
+
expect(passesPolicy(name)).toBe(false);
|
|
291
|
+
expect(isValidDisplayName(name)).toBe(false);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('rejects an orphaned combining mark not riding a base letter', () => {
|
|
295
|
+
expect(passesPolicy('༘⋆')).toBe(false); // lone Tibetan mark + star
|
|
296
|
+
expect(orphaned.test('༘')).toBe(true); // bare mark at string start
|
|
297
|
+
// A decomposed accent recomposes under NFC and rides its base letter.
|
|
298
|
+
expect(orphaned.test('é'.normalize('NFC'))).toBe(false);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
199
302
|
describe('isValidUUID', () => {
|
|
200
303
|
it('should return true for valid UUIDs', () => {
|
|
201
304
|
expect(isValidUUID('123e4567-e89b-12d3-a456-426614174000')).toBe(true);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — DO NOT EDIT BY HAND.
|
|
3
|
+
*
|
|
4
|
+
* Explicit Unicode code-point ranges for the display-name character policy,
|
|
5
|
+
* transpiled from the readable Script_Extensions / General_Category allowlist in
|
|
6
|
+
* `scripts/generateDisplayNamePolicyRanges.mjs` with regexpu-core (the same
|
|
7
|
+
* transform Babel uses to lower Unicode property escapes for Hermes targets).
|
|
8
|
+
*
|
|
9
|
+
* Each export is a character-class BODY (no surrounding `[]`) using only
|
|
10
|
+
* `\x…`/`\u…`/`\u{…}` code-point escapes — and ZERO Unicode property
|
|
11
|
+
* escapes — so the regexes built from them in `validationUtils.ts` run
|
|
12
|
+
* identically on V8 (web) and Hermes (React Native), whose engine has Unicode
|
|
13
|
+
* property escapes compiled OUT. A bare property escape at module load throws
|
|
14
|
+
* "Invalid RegExp: Invalid property name" and crashes every Oxy RN/Expo app at
|
|
15
|
+
* boot. The transpiled ranges are the exact same match set as the property
|
|
16
|
+
* escapes, verified across the full code-point space.
|
|
17
|
+
*
|
|
18
|
+
* Classes captured (regexpu-core, u-mode):
|
|
19
|
+
* - DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES: the 30-script Script_Extensions
|
|
20
|
+
* allowlist (scx=Latin, scx=Greek, … scx=Han).
|
|
21
|
+
* - DISPLAY_NAME_COMBINING_MARKS_RANGES: General_Category M (combining marks).
|
|
22
|
+
* - DISPLAY_NAME_SPACE_SEPARATORS_RANGES: General_Category Zs (space
|
|
23
|
+
* separators).
|
|
24
|
+
* - DISPLAY_NAME_LETTERS_RANGES: General_Category L (letters of any script;
|
|
25
|
+
* used only in the orphaned-combining-mark lookbehind).
|
|
26
|
+
*
|
|
27
|
+
* REGENERATE: cd packages/core && bun run generate:display-name-policy
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export const DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES =
|
|
31
|
+
'A-Za-z\\xAA\\xB7\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02B8\\u02BC\\u02C7\\u02C9-\\u02CB\\u02CD\\u02D7\\u02D9\\u02E0-\\u02E4\\u02EA\\u02EB\\u0300-\\u030E\\u0310\\u0311\\u0313\\u0323-\\u0325\\u032D\\u032E\\u0330\\u0331\\u0342\\u0345\\u0358\\u035E\\u0363-\\u0377\\u037A-\\u037D\\u037F\\u0384\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03E1\\u03F0-\\u052F\\u0531-\\u0556\\u0559-\\u058A\\u058D-\\u058F\\u0591-\\u05C7\\u05D0-\\u05EA\\u05EF-\\u05F4\\u0600-\\u0604\\u0606-\\u06DC\\u06DE-\\u06FF\\u0750-\\u07B1\\u0870-\\u0891\\u0897-\\u08E1\\u08E3-\\u0952\\u0955-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u09D7\\u09DC\\u09DD\\u09DF-\\u09E3\\u09E6-\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A59-\\u0A5C\\u0A5E\\u0A66-\\u0A76\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AF1\\u0AF9-\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5C\\u0B5D\\u0B5F-\\u0B63\\u0B66-\\u0B77\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BFA\\u0C00-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3C-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C58-\\u0C5A\\u0C5C\\u0C5D\\u0C60-\\u0C63\\u0C66-\\u0C6F\\u0C77-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDC-\\u0CDE\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1-\\u0CF3\\u0D00-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4F\\u0D54-\\u0D63\\u0D66-\\u0D7F\\u0D81-\\u0D83\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DE6-\\u0DEF\\u0DF2-\\u0DF4\\u0E01-\\u0E3A\\u0E40-\\u0E5B\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECE\\u0ED0-\\u0ED9\\u0EDC-\\u0EDF\\u0F00-\\u0F47\\u0F49-\\u0F6C\\u0F71-\\u0F97\\u0F99-\\u0FBC\\u0FBE-\\u0FCC\\u0FCE-\\u0FD4\\u0FD9\\u0FDA\\u1000-\\u10C5\\u10C7\\u10CD\\u10D0-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u137C\\u1380-\\u1399\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1780-\\u17DD\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1800-\\u1819\\u1820-\\u1878\\u1880-\\u18AA\\u19E0-\\u19FF\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CD0-\\u1CF9\\u1D00-\\u1DC1\\u1DF8\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FC4\\u1FC6-\\u1FD3\\u1FD6-\\u1FDB\\u1FDD-\\u1FEF\\u1FF2-\\u1FF4\\u1FF6-\\u1FFE\\u202F\\u204F\\u205A\\u205D\\u2071\\u207F\\u2090-\\u209C\\u20F0\\u2126\\u212A\\u212B\\u2132\\u214E\\u2160-\\u2188\\u2C60-\\u2C7F\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2DE0-\\u2DFF\\u2E17\\u2E31\\u2E41\\u2E43\\u2E80-\\u2E99\\u2E9B-\\u2EF3\\u2F00-\\u2FD5\\u2FF0-\\u2FFF\\u3001-\\u3003\\u3005-\\u3011\\u3013-\\u301F\\u302A-\\u3035\\u3021-\\u302D\\u3037-\\u303F\\u3041-\\u3096\\u3099-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u3190-\\u31E5\\u31EF-\\u321E\\u3220-\\u3247\\u3260-\\u327E\\u3280-\\u32B0\\u32C0-\\u32CB\\u32D0-\\u3370\\u337B-\\u337F\\u33E0-\\u33FE\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uA640-\\uA69F\\uA700-\\uA707\\uA722-\\uA787\\uA78B-\\uA7DC\\uA7F1-\\uA7FF\\uA830-\\uA839\\uA8E0-\\uA8FF\\uA92E\\uA960-\\uA97C\\uA9E0-\\uA9FE\\uAA60-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABBF\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFDCF\\uFDF0-\\uFDFF\\uFE2E\\uFE2F\\uFE45\\uFE46\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF61-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10140}-\\u{1018E}\\u{101A0}\\u{102E0}-\\u{102FB}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10E60}-\\u{10E7E}\\u{10EC2}-\\u{10EC7}\\u{10ED0}-\\u{10ED8}\\u{10EFA}-\\u{10EFF}\\u{111E1}-\\u{111F4}\\u{11301}\\u{11303}\\u{1133B}\\u{1133C}\\u{11660}-\\u{1166C}\\u{116D0}-\\u{116E3}\\u{11B00}-\\u{11B09}\\u{11FC0}-\\u{11FF1}\\u{11FFF}\\u{16FE2}\\u{16FE3}\\u{16FF0}-\\u{16FF6}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1D200}-\\u{1D245}\\u{1D360}-\\u{1D371}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E08F}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{1EEF0}\\u{1EEF1}\\u{1F200}\\u{1F250}\\u{1F251}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}';
|
|
32
|
+
|
|
33
|
+
export const DISPLAY_NAME_COMBINING_MARKS_RANGES =
|
|
34
|
+
'\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u07FD\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u0897-\\u089F\\u08CA-\\u08E1\\u08E3-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u09FE\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C00-\\u0C04\\u0C3C\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C81-\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0CF3\\u0D00-\\u0D03\\u0D3B\\u0D3C\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D81-\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EBC\\u0EC8-\\u0ECE\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1715\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u180F\\u1885\\u1886\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1AB0-\\u1ADD\\u1AE0-\\u1AEB\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF4\\u1CF7-\\u1CF9\\u1DC0-\\u1DFF\\u20D0-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F-\\uA672\\uA674-\\uA67D\\uA69E\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA82C\\uA880\\uA881\\uA8B4-\\uA8C5\\uA8E0-\\uA8F1\\uA8FF\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uA9E5\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B-\\uAA7D\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE2F\\u{101FD}\\u{102E0}\\u{10376}-\\u{1037A}\\u{10A01}-\\u{10A03}\\u{10A05}\\u{10A06}\\u{10A0C}-\\u{10A0F}\\u{10A38}-\\u{10A3A}\\u{10A3F}\\u{10AE5}\\u{10AE6}\\u{10D24}-\\u{10D27}\\u{10D69}-\\u{10D6D}\\u{10EAB}\\u{10EAC}\\u{10EFA}-\\u{10EFF}\\u{10F46}-\\u{10F50}\\u{10F82}-\\u{10F85}\\u{11000}-\\u{11002}\\u{11038}-\\u{11046}\\u{11070}\\u{11073}\\u{11074}\\u{1107F}-\\u{11082}\\u{110B0}-\\u{110BA}\\u{110C2}\\u{11100}-\\u{11102}\\u{11127}-\\u{11134}\\u{11145}\\u{11146}\\u{11173}\\u{11180}-\\u{11182}\\u{111B3}-\\u{111C0}\\u{111C9}-\\u{111CC}\\u{111CE}\\u{111CF}\\u{1122C}-\\u{11237}\\u{1123E}\\u{11241}\\u{112DF}-\\u{112EA}\\u{11300}-\\u{11303}\\u{1133B}\\u{1133C}\\u{1133E}-\\u{11344}\\u{11347}\\u{11348}\\u{1134B}-\\u{1134D}\\u{11357}\\u{11362}\\u{11363}\\u{11366}-\\u{1136C}\\u{11370}-\\u{11374}\\u{113B8}-\\u{113C0}\\u{113C2}\\u{113C5}\\u{113C7}-\\u{113CA}\\u{113CC}-\\u{113D0}\\u{113D2}\\u{113E1}\\u{113E2}\\u{11435}-\\u{11446}\\u{1145E}\\u{114B0}-\\u{114C3}\\u{115AF}-\\u{115B5}\\u{115B8}-\\u{115C0}\\u{115DC}\\u{115DD}\\u{11630}-\\u{11640}\\u{116AB}-\\u{116B7}\\u{1171D}-\\u{1172B}\\u{1182C}-\\u{1183A}\\u{11930}-\\u{11935}\\u{11937}\\u{11938}\\u{1193B}-\\u{1193E}\\u{11940}\\u{11942}\\u{11943}\\u{119D1}-\\u{119D7}\\u{119DA}-\\u{119E0}\\u{119E4}\\u{11A01}-\\u{11A0A}\\u{11A33}-\\u{11A39}\\u{11A3B}-\\u{11A3E}\\u{11A47}\\u{11A51}-\\u{11A5B}\\u{11A8A}-\\u{11A99}\\u{11B60}-\\u{11B67}\\u{11C2F}-\\u{11C36}\\u{11C38}-\\u{11C3F}\\u{11C92}-\\u{11CA7}\\u{11CA9}-\\u{11CB6}\\u{11D31}-\\u{11D36}\\u{11D3A}\\u{11D3C}\\u{11D3D}\\u{11D3F}-\\u{11D45}\\u{11D47}\\u{11D8A}-\\u{11D8E}\\u{11D90}\\u{11D91}\\u{11D93}-\\u{11D97}\\u{11EF3}-\\u{11EF6}\\u{11F00}\\u{11F01}\\u{11F03}\\u{11F34}-\\u{11F3A}\\u{11F3E}-\\u{11F42}\\u{11F5A}\\u{13440}\\u{13447}-\\u{13455}\\u{1611E}-\\u{1612F}\\u{16AF0}-\\u{16AF4}\\u{16B30}-\\u{16B36}\\u{16F4F}\\u{16F51}-\\u{16F87}\\u{16F8F}-\\u{16F92}\\u{16FE4}\\u{16FF0}\\u{16FF1}\\u{1BC9D}\\u{1BC9E}\\u{1CF00}-\\u{1CF2D}\\u{1CF30}-\\u{1CF46}\\u{1D165}-\\u{1D169}\\u{1D16D}-\\u{1D172}\\u{1D17B}-\\u{1D182}\\u{1D185}-\\u{1D18B}\\u{1D1AA}-\\u{1D1AD}\\u{1D242}-\\u{1D244}\\u{1DA00}-\\u{1DA36}\\u{1DA3B}-\\u{1DA6C}\\u{1DA75}\\u{1DA84}\\u{1DA9B}-\\u{1DA9F}\\u{1DAA1}-\\u{1DAAF}\\u{1E000}-\\u{1E006}\\u{1E008}-\\u{1E018}\\u{1E01B}-\\u{1E021}\\u{1E023}\\u{1E024}\\u{1E026}-\\u{1E02A}\\u{1E08F}\\u{1E130}-\\u{1E136}\\u{1E2AE}\\u{1E2EC}-\\u{1E2EF}\\u{1E4EC}-\\u{1E4EF}\\u{1E5EE}\\u{1E5EF}\\u{1E6E3}\\u{1E6E6}\\u{1E6EE}\\u{1E6EF}\\u{1E6F5}\\u{1E8D0}-\\u{1E8D6}\\u{1E944}-\\u{1E94A}\\u{E0100}-\\u{E01EF}';
|
|
35
|
+
|
|
36
|
+
export const DISPLAY_NAME_SPACE_SEPARATORS_RANGES =
|
|
37
|
+
' \\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000';
|
|
38
|
+
|
|
39
|
+
export const DISPLAY_NAME_LETTERS_RANGES =
|
|
40
|
+
'A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C\\u0C5D\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7DC\\uA7F1-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10000}-\\u{1000B}\\u{1000D}-\\u{10026}\\u{10028}-\\u{1003A}\\u{1003C}\\u{1003D}\\u{1003F}-\\u{1004D}\\u{10050}-\\u{1005D}\\u{10080}-\\u{100FA}\\u{10280}-\\u{1029C}\\u{102A0}-\\u{102D0}\\u{10300}-\\u{1031F}\\u{1032D}-\\u{10340}\\u{10342}-\\u{10349}\\u{10350}-\\u{10375}\\u{10380}-\\u{1039D}\\u{103A0}-\\u{103C3}\\u{103C8}-\\u{103CF}\\u{10400}-\\u{1049D}\\u{104B0}-\\u{104D3}\\u{104D8}-\\u{104FB}\\u{10500}-\\u{10527}\\u{10530}-\\u{10563}\\u{10570}-\\u{1057A}\\u{1057C}-\\u{1058A}\\u{1058C}-\\u{10592}\\u{10594}\\u{10595}\\u{10597}-\\u{105A1}\\u{105A3}-\\u{105B1}\\u{105B3}-\\u{105B9}\\u{105BB}\\u{105BC}\\u{105C0}-\\u{105F3}\\u{10600}-\\u{10736}\\u{10740}-\\u{10755}\\u{10760}-\\u{10767}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10800}-\\u{10805}\\u{10808}\\u{1080A}-\\u{10835}\\u{10837}\\u{10838}\\u{1083C}\\u{1083F}-\\u{10855}\\u{10860}-\\u{10876}\\u{10880}-\\u{1089E}\\u{108E0}-\\u{108F2}\\u{108F4}\\u{108F5}\\u{10900}-\\u{10915}\\u{10920}-\\u{10939}\\u{10940}-\\u{10959}\\u{10980}-\\u{109B7}\\u{109BE}\\u{109BF}\\u{10A00}\\u{10A10}-\\u{10A13}\\u{10A15}-\\u{10A17}\\u{10A19}-\\u{10A35}\\u{10A60}-\\u{10A7C}\\u{10A80}-\\u{10A9C}\\u{10AC0}-\\u{10AC7}\\u{10AC9}-\\u{10AE4}\\u{10B00}-\\u{10B35}\\u{10B40}-\\u{10B55}\\u{10B60}-\\u{10B72}\\u{10B80}-\\u{10B91}\\u{10C00}-\\u{10C48}\\u{10C80}-\\u{10CB2}\\u{10CC0}-\\u{10CF2}\\u{10D00}-\\u{10D23}\\u{10D4A}-\\u{10D65}\\u{10D6F}-\\u{10D85}\\u{10E80}-\\u{10EA9}\\u{10EB0}\\u{10EB1}\\u{10EC2}-\\u{10EC7}\\u{10F00}-\\u{10F1C}\\u{10F27}\\u{10F30}-\\u{10F45}\\u{10F70}-\\u{10F81}\\u{10FB0}-\\u{10FC4}\\u{10FE0}-\\u{10FF6}\\u{11003}-\\u{11037}\\u{11071}\\u{11072}\\u{11075}\\u{11083}-\\u{110AF}\\u{110D0}-\\u{110E8}\\u{11103}-\\u{11126}\\u{11144}\\u{11147}\\u{11150}-\\u{11172}\\u{11176}\\u{11183}-\\u{111B2}\\u{111C1}-\\u{111C4}\\u{111DA}\\u{111DC}\\u{11200}-\\u{11211}\\u{11213}-\\u{1122B}\\u{1123F}\\u{11240}\\u{11280}-\\u{11286}\\u{11288}\\u{1128A}-\\u{1128D}\\u{1128F}-\\u{1129D}\\u{1129F}-\\u{112A8}\\u{112B0}-\\u{112DE}\\u{11305}-\\u{1130C}\\u{1130F}\\u{11310}\\u{11313}-\\u{11328}\\u{1132A}-\\u{11330}\\u{11332}\\u{11333}\\u{11335}-\\u{11339}\\u{1133D}\\u{11350}\\u{1135D}-\\u{11361}\\u{11380}-\\u{11389}\\u{1138B}\\u{1138E}\\u{11390}-\\u{113B5}\\u{113B7}\\u{113D1}\\u{113D3}\\u{11400}-\\u{11434}\\u{11447}-\\u{1144A}\\u{1145F}-\\u{11461}\\u{11480}-\\u{114AF}\\u{114C4}\\u{114C5}\\u{114C7}\\u{11580}-\\u{115AE}\\u{115D8}-\\u{115DB}\\u{11600}-\\u{1162F}\\u{11644}\\u{11680}-\\u{116AA}\\u{116B8}\\u{11700}-\\u{1171A}\\u{11740}-\\u{11746}\\u{11800}-\\u{1182B}\\u{118A0}-\\u{118DF}\\u{118FF}-\\u{11906}\\u{11909}\\u{1190C}-\\u{11913}\\u{11915}\\u{11916}\\u{11918}-\\u{1192F}\\u{1193F}\\u{11941}\\u{119A0}-\\u{119A7}\\u{119AA}-\\u{119D0}\\u{119E1}\\u{119E3}\\u{11A00}\\u{11A0B}-\\u{11A32}\\u{11A3A}\\u{11A50}\\u{11A5C}-\\u{11A89}\\u{11A9D}\\u{11AB0}-\\u{11AF8}\\u{11BC0}-\\u{11BE0}\\u{11C00}-\\u{11C08}\\u{11C0A}-\\u{11C2E}\\u{11C40}\\u{11C72}-\\u{11C8F}\\u{11D00}-\\u{11D06}\\u{11D08}\\u{11D09}\\u{11D0B}-\\u{11D30}\\u{11D46}\\u{11D60}-\\u{11D65}\\u{11D67}\\u{11D68}\\u{11D6A}-\\u{11D89}\\u{11D98}\\u{11DB0}-\\u{11DDB}\\u{11EE0}-\\u{11EF2}\\u{11F02}\\u{11F04}-\\u{11F10}\\u{11F12}-\\u{11F33}\\u{11FB0}\\u{12000}-\\u{12399}\\u{12480}-\\u{12543}\\u{12F90}-\\u{12FF0}\\u{13000}-\\u{1342F}\\u{13441}-\\u{13446}\\u{13460}-\\u{143FA}\\u{14400}-\\u{14646}\\u{16100}-\\u{1611D}\\u{16800}-\\u{16A38}\\u{16A40}-\\u{16A5E}\\u{16A70}-\\u{16ABE}\\u{16AD0}-\\u{16AED}\\u{16B00}-\\u{16B2F}\\u{16B40}-\\u{16B43}\\u{16B63}-\\u{16B77}\\u{16B7D}-\\u{16B8F}\\u{16D40}-\\u{16D6C}\\u{16E40}-\\u{16E7F}\\u{16EA0}-\\u{16EB8}\\u{16EBB}-\\u{16ED3}\\u{16F00}-\\u{16F4A}\\u{16F50}\\u{16F93}-\\u{16F9F}\\u{16FE0}\\u{16FE1}\\u{16FE3}\\u{16FF2}\\u{16FF3}\\u{17000}-\\u{18CD5}\\u{18CFF}-\\u{18D1E}\\u{18D80}-\\u{18DF2}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1B170}-\\u{1B2FB}\\u{1BC00}-\\u{1BC6A}\\u{1BC70}-\\u{1BC7C}\\u{1BC80}-\\u{1BC88}\\u{1BC90}-\\u{1BC99}\\u{1D400}-\\u{1D454}\\u{1D456}-\\u{1D49C}\\u{1D49E}\\u{1D49F}\\u{1D4A2}\\u{1D4A5}\\u{1D4A6}\\u{1D4A9}-\\u{1D4AC}\\u{1D4AE}-\\u{1D4B9}\\u{1D4BB}\\u{1D4BD}-\\u{1D4C3}\\u{1D4C5}-\\u{1D505}\\u{1D507}-\\u{1D50A}\\u{1D50D}-\\u{1D514}\\u{1D516}-\\u{1D51C}\\u{1D51E}-\\u{1D539}\\u{1D53B}-\\u{1D53E}\\u{1D540}-\\u{1D544}\\u{1D546}\\u{1D54A}-\\u{1D550}\\u{1D552}-\\u{1D6A5}\\u{1D6A8}-\\u{1D6C0}\\u{1D6C2}-\\u{1D6DA}\\u{1D6DC}-\\u{1D6FA}\\u{1D6FC}-\\u{1D714}\\u{1D716}-\\u{1D734}\\u{1D736}-\\u{1D74E}\\u{1D750}-\\u{1D76E}\\u{1D770}-\\u{1D788}\\u{1D78A}-\\u{1D7A8}\\u{1D7AA}-\\u{1D7C2}\\u{1D7C4}-\\u{1D7CB}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E100}-\\u{1E12C}\\u{1E137}-\\u{1E13D}\\u{1E14E}\\u{1E290}-\\u{1E2AD}\\u{1E2C0}-\\u{1E2EB}\\u{1E4D0}-\\u{1E4EB}\\u{1E5D0}-\\u{1E5ED}\\u{1E5F0}\\u{1E6C0}-\\u{1E6DE}\\u{1E6E0}-\\u{1E6E2}\\u{1E6E4}\\u{1E6E5}\\u{1E6E7}-\\u{1E6ED}\\u{1E6F0}-\\u{1E6F4}\\u{1E6FE}\\u{1E6FF}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1E800}-\\u{1E8C4}\\u{1E900}-\\u{1E943}\\u{1E94B}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}';
|
|
@@ -52,11 +52,16 @@ const ANY_WHITESPACE_RUN = /\s+/g;
|
|
|
52
52
|
* SEPARATOR (U+2028) / PARAGRAPH SEPARATOR (U+2029), which are mandatory breaks
|
|
53
53
|
* in Unicode and a well-known hazard in JSON/JS payloads. CRLF must be matched
|
|
54
54
|
* before the lone `\r` alternative or it would yield two breaks. The separators
|
|
55
|
-
* are matched by
|
|
56
|
-
*
|
|
57
|
-
*
|
|
55
|
+
* are matched by their code-point ESCAPES (`\u2028` = LINE SEPARATOR, `\u2029` =
|
|
56
|
+
* PARAGRAPH SEPARATOR) rather than by their Unicode Line_Separator /
|
|
57
|
+
* Paragraph_Separator property escapes: React Native's Hermes engine ships with
|
|
58
|
+
* Unicode property escapes compiled OUT and rejects those subcategory property
|
|
59
|
+
* names with "Invalid RegExp: Invalid property name", whereas the `\uXXXX`
|
|
60
|
+
* escapes are exactly equivalent (each property covers exactly its one code
|
|
61
|
+
* point), engine-portable, and drop the now-unneeded `u` flag. (A literal
|
|
62
|
+
* U+2028/U+2029 is itself a LineTerminator and cannot appear in a regex literal.)
|
|
58
63
|
*/
|
|
59
|
-
const LINE_BREAK_FORMS = /\r\n|\r|\
|
|
64
|
+
const LINE_BREAK_FORMS = /\r\n|\r|\u2028|\u2029/g;
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
67
|
* A run of HORIZONTAL whitespace: any whitespace that is not a line break.
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* Validation utilities for common data validation patterns
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import {
|
|
6
|
+
DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES,
|
|
7
|
+
DISPLAY_NAME_COMBINING_MARKS_RANGES,
|
|
8
|
+
DISPLAY_NAME_SPACE_SEPARATORS_RANGES,
|
|
9
|
+
DISPLAY_NAME_LETTERS_RANGES,
|
|
10
|
+
} from './displayNamePolicyRanges.generated';
|
|
11
|
+
|
|
5
12
|
/**
|
|
6
13
|
* Email validation regex
|
|
7
14
|
*/
|
|
@@ -44,15 +51,16 @@ export function isValidPassword(password: string): boolean {
|
|
|
44
51
|
*
|
|
45
52
|
* A clean display name is composed ONLY of:
|
|
46
53
|
* - letters from a curated ALLOWLIST of scripts that real names use
|
|
47
|
-
* ({@link DISPLAY_NAME_ALLOWED_SCRIPTS}) — NOT
|
|
48
|
-
* script), which admits decorative / historic / limited-use scripts
|
|
49
|
-
* characters are
|
|
50
|
-
* Batak, Runic, Deseret, dingbat letters),
|
|
51
|
-
* - combining marks / accents (
|
|
52
|
-
* "é"),
|
|
53
|
-
* - Unicode space separators (
|
|
54
|
-
* space, …) — but NOT control whitespace such as tab, newline,
|
|
55
|
-
* return, which would break layout or enable multi-line
|
|
54
|
+
* ({@link DISPLAY_NAME_ALLOWED_SCRIPTS}) — NOT every letter (General_Category
|
|
55
|
+
* L of ANY script), which admits decorative / historic / limited-use scripts
|
|
56
|
+
* whose characters are letters yet never appear in a real name (e.g. `ᯅ`
|
|
57
|
+
* U+1BC5 Batak, Runic, Deseret, dingbat letters),
|
|
58
|
+
* - combining marks / accents (General_Category M, e.g. the acute accent in a
|
|
59
|
+
* decomposed "é"),
|
|
60
|
+
* - Unicode space separators (General_Category Zs: the ASCII space, NBSP,
|
|
61
|
+
* ideographic space, …) — but NOT control whitespace such as tab, newline,
|
|
62
|
+
* or carriage return, which would break layout or enable multi-line
|
|
63
|
+
* spoofing,
|
|
56
64
|
* - the straight apostrophe (`'`, e.g. "O'Brien").
|
|
57
65
|
*
|
|
58
66
|
* Everything else is rejected: emoji (🐧), symbols (⁂ ⏚), `:emoji:` shortcodes,
|
|
@@ -61,15 +69,26 @@ export function isValidPassword(password: string): boolean {
|
|
|
61
69
|
* includes `<`, `>`, `&`, or `"`, so a value that passes this predicate can
|
|
62
70
|
* never contain an HTML/XSS vector.
|
|
63
71
|
*
|
|
64
|
-
* The allowlist is expressed with Unicode Script_Extensions (
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
72
|
+
* The allowlist is expressed with Unicode Script_Extensions (scx=…) so a letter
|
|
73
|
+
* shared by several scripts (e.g. a Han ideograph used in both Chinese and
|
|
74
|
+
* Japanese) still matches. It is the set of scripts Unicode UTS #39 marks
|
|
75
|
+
* "Recommended" for general interchange / identifiers, plus Cherokee and
|
|
76
|
+
* Mongolian (both in real modern name use). "Common" script is deliberately
|
|
77
|
+
* EXCLUDED — that is where ASCII digits and general punctuation live, and this
|
|
78
|
+
* policy excludes those; the space separators, combining marks, and apostrophe a
|
|
79
|
+
* name needs are added back explicitly. Limited-use / excluded / historic
|
|
80
|
+
* scripts (Batak, Runic, Deseret, Adlam, …) are simply absent.
|
|
81
|
+
*
|
|
82
|
+
* HERMES / RANGES: the class bodies below are built from explicit Unicode
|
|
83
|
+
* code-point RANGES ({@link DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES} et al. from
|
|
84
|
+
* `./displayNamePolicyRanges.generated`), NOT from `scx`/General_Category
|
|
85
|
+
* property escapes. React Native's Hermes engine ships with Unicode property
|
|
86
|
+
* escapes compiled OUT and throws "Invalid RegExp: Invalid property name" for
|
|
87
|
+
* any such escape at module load, crashing every Oxy RN/Expo app at boot. The
|
|
88
|
+
* ranges are the compressed union of exactly those properties (generated on
|
|
89
|
+
* Node/V8, which supports them — see `scripts/generateDisplayNamePolicyRanges.mjs`),
|
|
90
|
+
* so behavior is IDENTICAL on V8 (web) and Hermes (native) with the same `u`
|
|
91
|
+
* flag and lookbehind, but with zero property escapes in the shipped regex.
|
|
73
92
|
*
|
|
74
93
|
* This is the SINGLE definition of the policy: the character-class sources below
|
|
75
94
|
* are the ONE source of truth, shared between the API strip/gate
|
|
@@ -81,40 +100,34 @@ export function isValidPassword(password: string): boolean {
|
|
|
81
100
|
|
|
82
101
|
/**
|
|
83
102
|
* The curated allowlist of Unicode scripts permitted in a display name, as a
|
|
84
|
-
* character-class body of
|
|
85
|
-
*
|
|
103
|
+
* character-class body of explicit code-point ranges (the compressed union of
|
|
104
|
+
* the 30 allowlisted Script_Extensions, generated on V8). Interpolated into the
|
|
105
|
+
* negated class below.
|
|
86
106
|
*/
|
|
87
|
-
export const DISPLAY_NAME_ALLOWED_SCRIPTS =
|
|
88
|
-
'\\p{scx=Latin}\\p{scx=Greek}\\p{scx=Cyrillic}\\p{scx=Armenian}' +
|
|
89
|
-
'\\p{scx=Hebrew}\\p{scx=Arabic}\\p{scx=Thaana}\\p{scx=Devanagari}' +
|
|
90
|
-
'\\p{scx=Bengali}\\p{scx=Gurmukhi}\\p{scx=Gujarati}\\p{scx=Oriya}' +
|
|
91
|
-
'\\p{scx=Tamil}\\p{scx=Telugu}\\p{scx=Kannada}\\p{scx=Malayalam}' +
|
|
92
|
-
'\\p{scx=Sinhala}\\p{scx=Thai}\\p{scx=Lao}\\p{scx=Tibetan}' +
|
|
93
|
-
'\\p{scx=Myanmar}\\p{scx=Georgian}\\p{scx=Hangul}\\p{scx=Ethiopic}' +
|
|
94
|
-
'\\p{scx=Cherokee}\\p{scx=Khmer}\\p{scx=Mongolian}\\p{scx=Hiragana}' +
|
|
95
|
-
'\\p{scx=Katakana}\\p{scx=Bopomofo}\\p{scx=Han}';
|
|
107
|
+
export const DISPLAY_NAME_ALLOWED_SCRIPTS = DISPLAY_NAME_ALLOWED_SCRIPTS_RANGES;
|
|
96
108
|
|
|
97
109
|
/**
|
|
98
110
|
* Source of the disallowed-character pattern: the negation of the full allowed
|
|
99
|
-
* set (allowlisted scripts + combining marks
|
|
100
|
-
*
|
|
101
|
-
*
|
|
111
|
+
* set (allowlisted scripts + combining marks + space separators + the straight
|
|
112
|
+
* apostrophe). Consumers compile this with the `u` flag (and `g` for a global
|
|
113
|
+
* strip). The whitespace class is space separators only (General_Category Zs),
|
|
102
114
|
* NOT `\s` — the latter would admit tab/newline/carriage return, which break
|
|
103
115
|
* layout and enable multi-line spoofing.
|
|
104
116
|
*/
|
|
105
|
-
export const DISPLAY_NAME_DISALLOWED_SOURCE = `[^${DISPLAY_NAME_ALLOWED_SCRIPTS}
|
|
117
|
+
export const DISPLAY_NAME_DISALLOWED_SOURCE = `[^${DISPLAY_NAME_ALLOWED_SCRIPTS}${DISPLAY_NAME_COMBINING_MARKS_RANGES}${DISPLAY_NAME_SPACE_SEPARATORS_RANGES}']`;
|
|
106
118
|
|
|
107
119
|
/**
|
|
108
|
-
* Source of the orphaned combining-mark pattern: a run of
|
|
109
|
-
* to a base letter (preceded by string start, whitespace, the
|
|
110
|
-
* position vacated by a stripped character). A mark preceded by
|
|
111
|
-
* letter
|
|
112
|
-
* multi-mark cluster) is NOT matched because the negative lookbehind
|
|
113
|
-
* position. Used both as a non-global probe (`.test`) and, with the
|
|
114
|
-
* strip whole orphaned runs. The lookbehind intentionally
|
|
115
|
-
*
|
|
120
|
+
* Source of the orphaned combining-mark pattern: a run of combining marks NOT
|
|
121
|
+
* attached to a base letter (preceded by string start, whitespace, the
|
|
122
|
+
* apostrophe, or a position vacated by a stripped character). A mark preceded by
|
|
123
|
+
* a base letter (e.g. the decomposed accent in "Renée") or by another combining
|
|
124
|
+
* mark (a multi-mark cluster) is NOT matched because the negative lookbehind
|
|
125
|
+
* fails at its position. Used both as a non-global probe (`.test`) and, with the
|
|
126
|
+
* `g` flag, to strip whole orphaned runs. The lookbehind intentionally uses the
|
|
127
|
+
* BROAD letters set (General_Category L of any script) so that a mark riding on
|
|
128
|
+
* an allowlisted base letter is preserved.
|
|
116
129
|
*/
|
|
117
|
-
export const DISPLAY_NAME_ORPHANED_MARK_SOURCE =
|
|
130
|
+
export const DISPLAY_NAME_ORPHANED_MARK_SOURCE = `(?<![${DISPLAY_NAME_LETTERS_RANGES}${DISPLAY_NAME_COMBINING_MARKS_RANGES}])[${DISPLAY_NAME_COMBINING_MARKS_RANGES}]+`;
|
|
118
131
|
|
|
119
132
|
/** Non-global probe for the presence of a disallowed character. */
|
|
120
133
|
const DISALLOWED_PROBE = new RegExp(DISPLAY_NAME_DISALLOWED_SOURCE, 'u');
|