Skip to content

Commit 452ac88

Browse files
marcaaronOSBotify
authored andcommitted
Merge pull request #31219 from Expensify/revert-27414-@kosmydel/handle-invisible-characters
[CP-staging] Revert "Handle invisible characters in forms" (cherry picked from commit 5e2c39f)
1 parent 11c8d76 commit 452ac88

File tree

9 files changed

+33
-313
lines changed

9 files changed

+33
-313
lines changed

src/CONST.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,10 +1371,6 @@ const CONST = {
13711371
ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g,
13721372

13731373
ENCODE_PERCENT_CHARACTER: /%(25)+/g,
1374-
1375-
INVISIBLE_CHARACTERS_GROUPS: /[\p{C}\p{Z}]/gu,
1376-
1377-
OTHER_INVISIBLE_CHARACTERS: /[\u3164]/g,
13781374
},
13791375

13801376
PRONOUNS: {

src/components/Form.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {withOnyx} from 'react-native-onyx';
66
import _ from 'underscore';
77
import compose from '@libs/compose';
88
import * as ErrorUtils from '@libs/ErrorUtils';
9-
import * as ValidationUtils from '@libs/ValidationUtils';
109
import Visibility from '@libs/Visibility';
1110
import stylePropTypes from '@styles/stylePropTypes';
1211
import styles from '@styles/styles';
@@ -127,8 +126,14 @@ function Form(props) {
127126
*/
128127
const onValidate = useCallback(
129128
(values, shouldClearServerError = true) => {
130-
// Trim all string values
131-
const trimmedStringValues = ValidationUtils.prepareValues(values);
129+
const trimmedStringValues = {};
130+
_.each(values, (inputValue, inputID) => {
131+
if (_.isString(inputValue)) {
132+
trimmedStringValues[inputID] = inputValue.trim();
133+
} else {
134+
trimmedStringValues[inputID] = inputValue;
135+
}
136+
});
132137

133138
if (shouldClearServerError) {
134139
FormActions.setErrors(props.formID, null);
@@ -186,7 +191,7 @@ function Form(props) {
186191

187192
return touchedInputErrors;
188193
},
189-
[props.formID, validate, errors],
194+
[errors, touchedInputs, props.formID, validate],
190195
);
191196

192197
useEffect(() => {
@@ -223,14 +228,11 @@ function Form(props) {
223228
return;
224229
}
225230

226-
// Trim all string values
227-
const trimmedStringValues = ValidationUtils.prepareValues(inputValues);
228-
229231
// Touches all form inputs so we can validate the entire form
230232
_.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true));
231233

232234
// Validate form and return early if any errors are found
233-
if (!_.isEmpty(onValidate(trimmedStringValues))) {
235+
if (!_.isEmpty(onValidate(inputValues))) {
234236
return;
235237
}
236238

@@ -240,8 +242,8 @@ function Form(props) {
240242
}
241243

242244
// Call submit handler
243-
onSubmit(trimmedStringValues);
244-
}, [props.formState.isLoading, props.network.isOffline, props.enabledWhenOffline, inputValues, onValidate, onSubmit]);
245+
onSubmit(inputValues);
246+
}, [props.formState, onSubmit, inputRefs, inputValues, onValidate, touchedInputs, props.network.isOffline, props.enabledWhenOffline]);
245247

246248
/**
247249
* Loops over Form's children and automatically supplies Form props to them

src/components/Form/FormProvider.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import _ from 'underscore';
66
import networkPropTypes from '@components/networkPropTypes';
77
import {withNetwork} from '@components/OnyxProvider';
88
import compose from '@libs/compose';
9-
import * as ValidationUtils from '@libs/ValidationUtils';
109
import Visibility from '@libs/Visibility';
1110
import stylePropTypes from '@styles/stylePropTypes';
1211
import * as FormActions from '@userActions/FormActions';
@@ -109,7 +108,14 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
109108

110109
const onValidate = useCallback(
111110
(values, shouldClearServerError = true) => {
112-
const trimmedStringValues = ValidationUtils.prepareValues(values);
111+
const trimmedStringValues = {};
112+
_.each(values, (inputValue, inputID) => {
113+
if (_.isString(inputValue)) {
114+
trimmedStringValues[inputID] = inputValue.trim();
115+
} else {
116+
trimmedStringValues[inputID] = inputValue;
117+
}
118+
});
113119

114120
if (shouldClearServerError) {
115121
FormActions.setErrors(formID, null);
@@ -180,14 +186,11 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
180186
return;
181187
}
182188

183-
// Prepare values before submitting
184-
const trimmedStringValues = ValidationUtils.prepareValues(inputValues);
185-
186189
// Touches all form inputs so we can validate the entire form
187190
_.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true));
188191

189192
// Validate form and return early if any errors are found
190-
if (!_.isEmpty(onValidate(trimmedStringValues))) {
193+
if (!_.isEmpty(onValidate(inputValues))) {
191194
return;
192195
}
193196

@@ -196,7 +199,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
196199
return;
197200
}
198201

199-
onSubmit(trimmedStringValues);
202+
onSubmit(inputValues);
200203
}, [enabledWhenOffline, formState.isLoading, inputValues, network.isOffline, onSubmit, onValidate]);
201204

202205
const registerInput = useCallback(

src/libs/StringUtils.ts

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,4 @@ function sanitizeString(str: string): string {
1010
return _.deburr(str).toLowerCase().replaceAll(CONST.REGEX.NON_ALPHABETIC_AND_NON_LATIN_CHARS, '');
1111
}
1212

13-
/**
14-
* Check if the string would be empty if all invisible characters were removed.
15-
*/
16-
function isEmptyString(value: string): boolean {
17-
// \p{C} matches all 'Other' characters
18-
// \p{Z} matches all separators (spaces etc.)
19-
// Source: http://www.unicode.org/reports/tr18/#General_Category_Property
20-
let transformed = value.replace(CONST.REGEX.INVISIBLE_CHARACTERS_GROUPS, '');
21-
22-
// Remove other invisible characters that are not in the above unicode categories
23-
transformed = transformed.replace(CONST.REGEX.OTHER_INVISIBLE_CHARACTERS, '');
24-
25-
// Check if after removing invisible characters the string is empty
26-
return transformed === '';
27-
}
28-
29-
/**
30-
* Remove invisible characters from a string except for spaces and format characters for emoji, and trim it.
31-
*/
32-
function removeInvisibleCharacters(value: string): string {
33-
let result = value;
34-
35-
// Remove spaces:
36-
// - \u200B: zero-width space
37-
// - \u00A0: non-breaking space
38-
// - \u2060: word joiner
39-
result = result.replace(/[\u200B\u00A0\u2060]/g, '');
40-
41-
// Remove all characters from the 'Other' (C) category except for format characters (Cf)
42-
// because some of them are used for emojis
43-
result = result.replace(/[\p{Cc}\p{Cs}\p{Co}\p{Cn}]/gu, '');
44-
45-
// Remove characters from the (Cf) category that are not used for emojis
46-
result = result.replace(/[\u200E-\u200F]/g, '');
47-
48-
// Remove all characters from the 'Separator' (Z) category except for Space Separator (Zs)
49-
result = result.replace(/[\p{Zl}\p{Zp}]/gu, '');
50-
51-
// If the result consist of only invisible characters, return an empty string
52-
if (isEmptyString(result)) {
53-
return '';
54-
}
55-
56-
return result.trim();
57-
}
58-
59-
export default {sanitizeString, isEmptyString, removeInvisibleCharacters};
13+
export default {sanitizeString};

src/libs/ValidationUtils.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {Report} from '@src/types/onyx';
99
import * as OnyxCommon from '@src/types/onyx/OnyxCommon';
1010
import * as CardUtils from './CardUtils';
1111
import * as LoginUtils from './LoginUtils';
12-
import StringUtils from './StringUtils';
1312

1413
/**
1514
* Implements the Luhn Algorithm, a checksum formula used to validate credit card
@@ -74,7 +73,7 @@ function isValidPastDate(date: string | Date): boolean {
7473
*/
7574
function isRequiredFulfilled(value: string | Date | unknown[] | Record<string, unknown>): boolean {
7675
if (typeof value === 'string') {
77-
return !StringUtils.isEmptyString(value);
76+
return value.trim().length > 0;
7877
}
7978

8079
if (isDate(value)) {
@@ -353,25 +352,6 @@ function isValidAccountRoute(accountID: number): boolean {
353352
return CONST.REGEX.NUMBER.test(String(accountID)) && accountID > 0;
354353
}
355354

356-
type ValuesType = Record<string, unknown>;
357-
358-
/**
359-
* This function is used to remove invisible characters from strings before validation and submission.
360-
*/
361-
function prepareValues(values: ValuesType): ValuesType {
362-
const trimmedStringValues: ValuesType = {};
363-
364-
for (const [inputID, inputValue] of Object.entries(values)) {
365-
if (typeof inputValue === 'string') {
366-
trimmedStringValues[inputID] = StringUtils.removeInvisibleCharacters(inputValue);
367-
} else {
368-
trimmedStringValues[inputID] = inputValue;
369-
}
370-
}
371-
372-
return trimmedStringValues;
373-
}
374-
375355
export {
376356
meetsMinimumAgeRequirement,
377357
meetsMaximumAgeRequirement,
@@ -405,5 +385,4 @@ export {
405385
isNumeric,
406386
isValidAccountRoute,
407387
isValidRecoveryCode,
408-
prepareValues,
409388
};

src/pages/workspace/WorkspaceSettingsPage.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import compose from '@libs/compose';
2020
import Navigation from '@libs/Navigation/Navigation';
2121
import * as ReportUtils from '@libs/ReportUtils';
2222
import * as UserUtils from '@libs/UserUtils';
23-
import * as ValidationUtils from '@libs/ValidationUtils';
2423
import styles from '@styles/styles';
2524
import * as Policy from '@userActions/Policy';
2625
import CONST from '@src/CONST';
@@ -78,7 +77,7 @@ function WorkspaceSettingsPage({policy, currencyList, windowWidth, route}) {
7877
const errors = {};
7978
const name = values.name.trim();
8079

81-
if (!ValidationUtils.isRequiredFulfilled(name)) {
80+
if (!name || !name.length) {
8281
errors.name = 'workspace.editor.nameIsRequiredError';
8382
} else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) {
8483
// Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16

src/stories/Form.stories.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import StatePicker from '@components/StatePicker';
1010
import Text from '@components/Text';
1111
import TextInput from '@components/TextInput';
1212
import NetworkConnection from '@libs/NetworkConnection';
13-
import * as ValidationUtils from '@libs/ValidationUtils';
1413
import styles from '@styles/styles';
1514
import * as FormActions from '@userActions/FormActions';
1615
import CONST from '@src/CONST';
@@ -178,28 +177,28 @@ const defaultArgs = {
178177
submitButtonText: 'Submit',
179178
validate: (values) => {
180179
const errors = {};
181-
if (!ValidationUtils.isRequiredFulfilled(values.routingNumber)) {
180+
if (!values.routingNumber) {
182181
errors.routingNumber = 'Please enter a routing number';
183182
}
184-
if (!ValidationUtils.isRequiredFulfilled(values.accountNumber)) {
183+
if (!values.accountNumber) {
185184
errors.accountNumber = 'Please enter an account number';
186185
}
187-
if (!ValidationUtils.isRequiredFulfilled(values.street)) {
186+
if (!values.street) {
188187
errors.street = 'Please enter an address';
189188
}
190-
if (!ValidationUtils.isRequiredFulfilled(values.dob)) {
189+
if (!values.dob) {
191190
errors.dob = 'Please enter your date of birth';
192191
}
193-
if (!ValidationUtils.isRequiredFulfilled(values.pickFruit)) {
192+
if (!values.pickFruit) {
194193
errors.pickFruit = 'Please select a fruit';
195194
}
196-
if (!ValidationUtils.isRequiredFulfilled(values.pickAnotherFruit)) {
195+
if (!values.pickAnotherFruit) {
197196
errors.pickAnotherFruit = 'Please select a fruit';
198197
}
199-
if (!ValidationUtils.isRequiredFulfilled(values.state)) {
198+
if (!values.state) {
200199
errors.state = 'Please select a state';
201200
}
202-
if (!ValidationUtils.isRequiredFulfilled(values.checkbox)) {
201+
if (!values.checkbox) {
203202
errors.checkbox = 'You must accept the Terms of Service to continue';
204203
}
205204
return errors;

tests/unit/isEmptyString.js

Lines changed: 0 additions & 92 deletions
This file was deleted.

0 commit comments

Comments
 (0)