@samitouri / QOS-React / commits / 767f52237c

Use .slice() for all substring-ing (#26677)

- substr is Annex B - substring silently flips its arguments if they're in the "wrong order", which is confusing - slice is better than sliced bread (no pun intended) and also it works the same way on Arrays so there's less to remember --- > I'd be down to just lint and enforce a single form just for the potential compression savings by using a repeated string. _Originally posted by @sebmarkbage in https://github.com/facebook/react/pull/26663#discussion_r1170455401_

Sophie Alpert committed Apr 19, 2023 at 14:26 UTC 767f52237cf7892ad07726f21e3e8bacfc8af839
35 files changed +97 -90
.eslintrc.js
+8 -1
@@ -236,7 +236,14 @@ module.exports = {
236 'no-inner-declarations': [ERROR, 'functions'],
237 'no-multi-spaces': ERROR,
238 'no-restricted-globals': [ERROR].concat(restrictedGlobals),
239 - 'no-restricted-syntax': [ERROR, 'WithStatement'],
239 + 'no-restricted-syntax': [
240 + ERROR,
241 + 'WithStatement',
242 + {
243 + selector: 'MemberExpression[property.name=/^(?:substring|substr)$/]',
244 + message: 'Prefer string.slice() over .substring() and .substr().',
245 + },
246 + ],
247 'no-shadow': ERROR,
248 'no-unused-vars': [ERROR, {args: 'none'}],
249 'no-use-before-define': OFF,
fixtures/concurrent/time-slicing/src/index.js
+1 -1
@@ -22,7 +22,7 @@ class App extends PureComponent {
22 }
23 const multiplier = input.length !== 0 ? input.length : 1;
24 const complexity =
25 - (parseInt(window.location.search.substring(1), 10) / 100) * 25 || 25;
25 + (parseInt(window.location.search.slice(1), 10) / 100) * 25 || 25;
26 const data = _.range(5).map(t =>
27 _.range(complexity * multiplier).map((j, i) => {
28 return {
fixtures/dom/src/react-loader.js
+1 -1
@@ -11,7 +11,7 @@ import semver from 'semver';
11
12 function parseQuery(qstr) {
13 var query = {};
14 - var a = qstr.substr(1).split('&');
14 + var a = qstr.slice(1).split('&');
15
16 for (var i = 0; i < a.length; i++) {
17 var b = a[i].split('=');
packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
+1 -1
@@ -18,7 +18,7 @@ const ReactHooksESLintRule = ReactHooksESLintPlugin.rules['exhaustive-deps'];
18 function normalizeIndent(strings) {
19 const codeLines = strings[0].split('\n');
20 const leftPadding = codeLines[1].match(/\s+/)[0];
21 - return codeLines.map(line => line.substr(leftPadding.length)).join('\n');
21 + return codeLines.map(line => line.slice(leftPadding.length)).join('\n');
22 }
23
24 // ***************************************************
packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
+1 -1
@@ -26,7 +26,7 @@ ESLintTester.setDefaultConfig({
26 function normalizeIndent(strings) {
27 const codeLines = strings[0].split('\n');
28 const leftPadding = codeLines[1].match(/\s+/)[0];
29 - return codeLines.map(line => line.substr(leftPadding.length)).join('\n');
29 + return codeLines.map(line => line.slice(leftPadding.length)).join('\n');
30 }
31
32 // ***************************************************
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+1 -1
@@ -1103,7 +1103,7 @@ export default {
1103 extraWarning =
1104 ` You can also do a functional update '${
1105 setStateRecommendation.setter
1106 - }(${setStateRecommendation.missingDep.substring(
1106 + }(${setStateRecommendation.missingDep.slice(
1107 0,
1108 1,
1109 )} => ...)' if you only need '${
packages/react-client/src/ReactFlightClient.js
+9 -9
@@ -515,11 +515,11 @@ export function parseModelString(
515 switch (value[1]) {
516 case '$': {
517 // This was an escaped string value.
518 - return value.substring(1);
518 + return value.slice(1);
519 }
520 case 'L': {
521 // Lazy node
522 - const id = parseInt(value.substring(2), 16);
522 + const id = parseInt(value.slice(2), 16);
523 const chunk = getChunk(response, id);
524 // We create a React.lazy wrapper around any lazy values.
525 // When passed into React, we'll know how to suspend on this.
@@ -527,21 +527,21 @@ export function parseModelString(
527 }
528 case '@': {
529 // Promise
530 - const id = parseInt(value.substring(2), 16);
530 + const id = parseInt(value.slice(2), 16);
531 const chunk = getChunk(response, id);
532 return chunk;
533 }
534 case 'S': {
535 // Symbol
536 - return Symbol.for(value.substring(2));
536 + return Symbol.for(value.slice(2));
537 }
538 case 'P': {
539 // Server Context Provider
540 - return getOrCreateServerContext(value.substring(2)).Provider;
540 + return getOrCreateServerContext(value.slice(2)).Provider;
541 }
542 case 'F': {
543 // Server Reference
544 - const id = parseInt(value.substring(2), 16);
544 + const id = parseInt(value.slice(2), 16);
545 const chunk = getChunk(response, id);
546 switch (chunk.status) {
547 case RESOLVED_MODEL:
@@ -582,15 +582,15 @@ export function parseModelString(
582 }
583 case 'D': {
584 // Date
585 - return new Date(Date.parse(value.substring(2)));
585 + return new Date(Date.parse(value.slice(2)));
586 }
587 case 'n': {
588 // BigInt
589 - return BigInt(value.substring(2));
589 + return BigInt(value.slice(2));
590 }
591 default: {
592 // We assume that anything else is a reference ID.
593 - const id = parseInt(value.substring(1), 16);
593 + const id = parseInt(value.slice(1), 16);
594 const chunk = getChunk(response, id);
595 switch (chunk.status) {
596 case RESOLVED_MODEL:
packages/react-client/src/ReactFlightClientStream.js
+6 -6
@@ -35,7 +35,7 @@ function processFullRow(response: Response, row: string): void {
35 return;
36 }
37 const colon = row.indexOf(':', 0);
38 - const id = parseInt(row.substring(0, colon), 16);
38 + const id = parseInt(row.slice(0, colon), 16);
39 const tag = row[colon + 1];
40 // When tags that are not text are added, check them here before
41 // parsing the row as text.
@@ -43,11 +43,11 @@ function processFullRow(response: Response, row: string): void {
43 // }
44 switch (tag) {
45 case 'I': {
46 - resolveModule(response, id, row.substring(colon + 2));
46 + resolveModule(response, id, row.slice(colon + 2));
47 return;
48 }
49 case 'E': {
50 - const errorInfo = JSON.parse(row.substring(colon + 2));
50 + const errorInfo = JSON.parse(row.slice(colon + 2));
51 if (__DEV__) {
52 resolveErrorDev(
53 response,
@@ -63,7 +63,7 @@ function processFullRow(response: Response, row: string): void {
63 }
64 default: {
65 // We assume anything else is JSON.
66 - resolveModel(response, id, row.substring(colon + 1));
66 + resolveModel(response, id, row.slice(colon + 1));
67 return;
68 }
69 }
@@ -76,13 +76,13 @@ export function processStringChunk(
76 ): void {
77 let linebreak = chunk.indexOf('\n', offset);
78 while (linebreak > -1) {
79 - const fullrow = response._partialRow + chunk.substring(offset, linebreak);
79 + const fullrow = response._partialRow + chunk.slice(offset, linebreak);
80 processFullRow(response, fullrow);
81 response._partialRow = '';
82 offset = linebreak + 1;
83 linebreak = chunk.indexOf('\n', offset);
84 }
85 - response._partialRow += chunk.substring(offset);
85 + response._partialRow += chunk.slice(offset);
86 }
87
88 export function processBinaryChunk(
packages/react-debug-tools/src/ReactDebugHooks.js
+2 -2
@@ -513,10 +513,10 @@ function parseCustomHookName(functionName: void | string): string {
513 if (startIndex === -1) {
514 startIndex = 0;
515 }
516 - if (functionName.substr(startIndex, 3) === 'use') {
516 + if (functionName.slice(startIndex, startIndex + 3) === 'use') {
517 startIndex += 3;
518 }
519 - return functionName.substr(startIndex);
519 + return functionName.slice(startIndex);
520 }
521
522 function buildTree(
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+1 -1
@@ -869,7 +869,7 @@ describe('ReactHooksInspectionIntegration', () => {
869 const Suspense = React.Suspense;
870
871 function Foo(props) {
872 - const [value] = React.useState(props.defaultValue.substr(0, 3));
872 + const [value] = React.useState(props.defaultValue.slice(0, 3));
873 return <div>{value}</div>;
874 }
875 Foo.defaultProps = {
packages/react-devtools-extensions/deploy.js
+1 -1
@@ -27,7 +27,7 @@ const main = async buildId => {
27 const json = JSON.parse(file);
28 const alias = json.alias[0];
29
30 - const commit = execSync('git rev-parse HEAD').toString().trim().substr(0, 7);
30 + const commit = execSync('git rev-parse HEAD').toString().trim().slice(0, 7);
31
32 let date = new Date();
33 date = `${date.toLocaleDateString()} – ${date.toLocaleTimeString()}`;
packages/react-devtools-shared/src/__tests__/__serializers__/hookSerializer.js
+1 -1
@@ -13,7 +13,7 @@ function serializeHook(hook) {
13 // Remove user-specific portions of this file path.
14 let fileName = hook.hookSource.fileName;
15 const index = fileName.lastIndexOf('/react-devtools-shared/');
16 - fileName = fileName.substring(index + 1);
16 + fileName = fileName.slice(index + 1);
17
18 let subHooks = hook.subHooks;
19 if (subHooks) {
packages/react-devtools-shared/src/backend/renderer.js
+1 -1
@@ -4315,7 +4315,7 @@ export function attach(
4315 if (pseudoKey === undefined) {
4316 throw new Error('Expected root pseudo key to be known.');
4317 }
4318 - const name = pseudoKey.substring(0, pseudoKey.lastIndexOf(':'));
4318 + const name = pseudoKey.slice(0, pseudoKey.lastIndexOf(':'));
4319 const counter = rootDisplayNameCounter.get(name);
4320 if (counter === undefined) {
4321 throw new Error('Expected counter to be known.');
packages/react-devtools-shared/src/devtools/utils.js
+1 -1
@@ -155,7 +155,7 @@ export function sanitizeForParse(value: any): any | string {
155 value.charAt(0) === "'" &&
156 value.charAt(value.length - 1) === "'"
157 ) {
158 - return '"' + value.substr(1, value.length - 2) + '"';
158 + return '"' + value.slice(1, value.length - 1) + '"';
159 }
160 }
161 return value;
packages/react-devtools-shared/src/devtools/views/utils.js
+4 -4
@@ -36,10 +36,10 @@ export function createRegExp(string: string): RegExp {
36 // Allow /regex/ syntax with optional last /
37 if (string[0] === '/') {
38 // Cut off first slash
39 - string = string.substring(1);
39 + string = string.slice(1);
40 // Cut off last slash, but only if it's there
41 if (string[string.length - 1] === '/') {
42 - string = string.substring(0, string.length - 1);
42 + string = string.slice(0, string.length - 1);
43 }
44 try {
45 return new RegExp(string, 'i');
@@ -186,9 +186,9 @@ export function truncateText(text: string, maxLength: number): string {
186 const {length} = text;
187 if (length > maxLength) {
188 return (
189 - text.substr(0, Math.floor(maxLength / 2)) +
189 + text.slice(0, Math.floor(maxLength / 2)) +
190 '…' +
191 - text.substr(length - Math.ceil(maxLength / 2) - 1)
191 + text.slice(length - Math.ceil(maxLength / 2) - 1)
192 );
193 } else {
194 return text;
packages/react-devtools-shared/src/utils.js
+1 -1
@@ -693,7 +693,7 @@ function truncateForDisplay(
693 length: number = MAX_PREVIEW_STRING_LENGTH,
694 ) {
695 if (string.length > length) {
696 - return string.substr(0, length) + '…';
696 + return string.slice(0, length) + '…';
697 } else {
698 return string;
699 }
packages/react-devtools-timeline/src/EventTooltip.js
+1 -1
@@ -249,7 +249,7 @@ const TooltipNetworkMeasure = ({
249 let urlToDisplay = url;
250 if (urlToDisplay.length > MAX_TOOLTIP_TEXT_LENGTH) {
251 const half = Math.floor(MAX_TOOLTIP_TEXT_LENGTH / 2);
252 - urlToDisplay = url.substr(0, half) + '…' + url.substr(url.length - half);
252 + urlToDisplay = url.slice(0, half) + '…' + url.slice(url.length - half);
253 }
254
255 const timestampBegin = sendRequestTimestamp;
packages/react-devtools-timeline/src/content-views/utils/text.js
+1 -1
@@ -45,7 +45,7 @@ export function trimText(
45 while (startIndex <= stopIndex) {
46 const currentIndex = Math.floor((startIndex + stopIndex) / 2);
47 const trimmedText =
48 - currentIndex === maxIndex ? text : text.substr(0, currentIndex) + '…';
48 + currentIndex === maxIndex ? text : text.slice(0, currentIndex) + '…';
49
50 if (getTextWidth(context, trimmedText) <= width) {
51 if (longestValidIndex < currentIndex) {
packages/react-devtools-timeline/src/import-worker/preprocessData.js
+21 -21
@@ -476,10 +476,10 @@ function processTimelineEvent(
476 break;
477 case 'blink.user_timing':
478 if (name.startsWith('--react-version-')) {
479 - const [reactVersion] = name.substr(16).split('-');
479 + const [reactVersion] = name.slice(16).split('-');
480 currentProfilerData.reactVersion = reactVersion;
481 } else if (name.startsWith('--profiler-version-')) {
482 - const [versionString] = name.substr(19).split('-');
482 + const [versionString] = name.slice(19).split('-');
483 profilerVersion = parseInt(versionString, 10);
484 if (profilerVersion !== SCHEDULING_PROFILER_VERSION) {
485 throw new InvalidProfileError(
@@ -487,7 +487,7 @@ function processTimelineEvent(
487 );
488 }
489 } else if (name.startsWith('--react-lane-labels-')) {
490 - const [laneLabelTuplesString] = name.substr(20).split('-');
490 + const [laneLabelTuplesString] = name.slice(20).split('-');
491 updateLaneToLabelMap(currentProfilerData, laneLabelTuplesString);
492 } else if (name.startsWith('--component-')) {
493 processReactComponentMeasure(
@@ -497,7 +497,7 @@ function processTimelineEvent(
497 state,
498 );
499 } else if (name.startsWith('--schedule-render-')) {
500 - const [laneBitmaskString] = name.substr(18).split('-');
500 + const [laneBitmaskString] = name.slice(18).split('-');
501
502 currentProfilerData.schedulingEvents.push({
503 type: 'schedule-render',
@@ -506,7 +506,7 @@ function processTimelineEvent(
506 warning: null,
507 });
508 } else if (name.startsWith('--schedule-forced-update-')) {
509 - const [laneBitmaskString, componentName] = name.substr(25).split('-');
509 + const [laneBitmaskString, componentName] = name.slice(25).split('-');
510
511 const forceUpdateEvent = {
512 type: 'schedule-force-update',
@@ -524,7 +524,7 @@ function processTimelineEvent(
524
525 currentProfilerData.schedulingEvents.push(forceUpdateEvent);
526 } else if (name.startsWith('--schedule-state-update-')) {
527 - const [laneBitmaskString, componentName] = name.substr(24).split('-');
527 + const [laneBitmaskString, componentName] = name.slice(24).split('-');
528
529 const stateUpdateEvent = {
530 type: 'schedule-state-update',
@@ -542,7 +542,7 @@ function processTimelineEvent(
542
543 currentProfilerData.schedulingEvents.push(stateUpdateEvent);
544 } else if (name.startsWith('--error-')) {
545 - const [componentName, phase, message] = name.substr(8).split('-');
545 + const [componentName, phase, message] = name.slice(8).split('-');
546
547 currentProfilerData.thrownErrors.push({
548 componentName,
@@ -553,7 +553,7 @@ function processTimelineEvent(
553 });
554 } else if (name.startsWith('--suspense-suspend-')) {
555 const [id, componentName, phase, laneBitmaskString, promiseName] = name
556 - .substr(19)
556 + .slice(19)
557 .split('-');
558 const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
559
@@ -604,7 +604,7 @@ function processTimelineEvent(
604 currentProfilerData.suspenseEvents.push(suspenseEvent);
605 state.unresolvedSuspenseEvents.set(id, suspenseEvent);
606 } else if (name.startsWith('--suspense-resolved-')) {
607 - const [id] = name.substr(20).split('-');
607 + const [id] = name.slice(20).split('-');
608 const suspenseEvent = state.unresolvedSuspenseEvents.get(id);
609 if (suspenseEvent != null) {
610 state.unresolvedSuspenseEvents.delete(id);
@@ -613,7 +613,7 @@ function processTimelineEvent(
613 suspenseEvent.resolution = 'resolved';
614 }
615 } else if (name.startsWith('--suspense-rejected-')) {
616 - const [id] = name.substr(20).split('-');
616 + const [id] = name.slice(20).split('-');
617 const suspenseEvent = state.unresolvedSuspenseEvents.get(id);
618 if (suspenseEvent != null) {
619 state.unresolvedSuspenseEvents.delete(id);
@@ -637,7 +637,7 @@ function processTimelineEvent(
637 state.potentialLongNestedUpdate = null;
638 }
639
640 - const [laneBitmaskString] = name.substr(15).split('-');
640 + const [laneBitmaskString] = name.slice(15).split('-');
641
642 throwIfIncomplete('render', state.measureStack);
643 if (getLastType(state.measureStack) !== 'render-idle') {
@@ -682,7 +682,7 @@ function processTimelineEvent(
682 );
683 } else if (name.startsWith('--commit-start-')) {
684 state.nextRenderShouldGenerateNewBatchID = true;
685 - const [laneBitmaskString] = name.substr(15).split('-');
685 + const [laneBitmaskString] = name.slice(15).split('-');
686
687 markWorkStarted(
688 'commit',
@@ -705,7 +705,7 @@ function processTimelineEvent(
705 state.measureStack,
706 );
707 } else if (name.startsWith('--layout-effects-start-')) {
708 - const [laneBitmaskString] = name.substr(23).split('-');
708 + const [laneBitmaskString] = name.slice(23).split('-');
709
710 markWorkStarted(
711 'layout-effects',
@@ -722,7 +722,7 @@ function processTimelineEvent(
722 state.measureStack,
723 );
724 } else if (name.startsWith('--passive-effects-start-')) {
725 - const [laneBitmaskString] = name.substr(24).split('-');
725 + const [laneBitmaskString] = name.slice(24).split('-');
726
727 markWorkStarted(
728 'passive-effects',
@@ -739,7 +739,7 @@ function processTimelineEvent(
739 state.measureStack,
740 );
741 } else if (name.startsWith('--react-internal-module-start-')) {
742 - const stackFrameStart = name.substr(30);
742 + const stackFrameStart = name.slice(30);
743
744 if (!state.internalModuleStackStringSet.has(stackFrameStart)) {
745 state.internalModuleStackStringSet.add(stackFrameStart);
@@ -749,7 +749,7 @@ function processTimelineEvent(
749 state.internalModuleCurrentStackFrame = parsedStackFrameStart;
750 }
751 } else if (name.startsWith('--react-internal-module-stop-')) {
752 - const stackFrameStop = name.substr(29);
752 + const stackFrameStop = name.slice(29);
753
754 if (!state.internalModuleStackStringSet.has(stackFrameStop)) {
755 state.internalModuleStackStringSet.add(stackFrameStop);
@@ -833,7 +833,7 @@ function processReactComponentMeasure(
833 state: ProcessorState,
834 ): void {
835 if (name.startsWith('--component-render-start-')) {
836 - const [componentName] = name.substr(25).split('-');
836 + const [componentName] = name.slice(25).split('-');
837
838 assertNoOverlappingComponentMeasure(state);
839
@@ -856,7 +856,7 @@ function processReactComponentMeasure(
856 currentProfilerData.componentMeasures.push(componentMeasure);
857 }
858 } else if (name.startsWith('--component-layout-effect-mount-start-')) {
859 - const [componentName] = name.substr(38).split('-');
859 + const [componentName] = name.slice(38).split('-');
860
861 assertNoOverlappingComponentMeasure(state);
862
@@ -879,7 +879,7 @@ function processReactComponentMeasure(
879 currentProfilerData.componentMeasures.push(componentMeasure);
880 }
881 } else if (name.startsWith('--component-layout-effect-unmount-start-')) {
882 - const [componentName] = name.substr(40).split('-');
882 + const [componentName] = name.slice(40).split('-');
883
884 assertNoOverlappingComponentMeasure(state);
885
@@ -902,7 +902,7 @@ function processReactComponentMeasure(
902 currentProfilerData.componentMeasures.push(componentMeasure);
903 }
904 } else if (name.startsWith('--component-passive-effect-mount-start-')) {
905 - const [componentName] = name.substr(39).split('-');
905 + const [componentName] = name.slice(39).split('-');
906
907 assertNoOverlappingComponentMeasure(state);
908
@@ -925,7 +925,7 @@ function processReactComponentMeasure(
925 currentProfilerData.componentMeasures.push(componentMeasure);
926 }
927 } else if (name.startsWith('--component-passive-effect-unmount-start-')) {
928 - const [componentName] = name.substr(41).split('-');
928 + const [componentName] = name.slice(41).split('-');
929
930 assertNoOverlappingComponentMeasure(state);
931
packages/react-devtools-timeline/src/utils/formatting.js
+1 -1
@@ -26,7 +26,7 @@ export function formatDuration(ms: number): string {
26
27 export function trimString(string: string, length: number): string {
28 if (string.length > length) {
29 - return `${string.substr(0, length - 1)}…`;
29 + return `${string.slice(0, length - 1)}…`;
30 }
31 return string;
32 }
packages/react-dom-bindings/src/client/DOMPropertyOperations.js
+1 -1
@@ -203,7 +203,7 @@ export function setValueForPropertyOnCustomComponent(
203 ) {
204 if (name[0] === 'o' && name[1] === 'n') {
205 const useCapture = name.endsWith('Capture');
206 - const eventName = name.substr(2, useCapture ? name.length - 9 : undefined);
206 + const eventName = name.slice(2, useCapture ? name.length - 7 : undefined);
207
208 const prevProps = getFiberCurrentPropsFromNode(node);
209 const prevValue = prevProps != null ? prevProps[name] : null;
packages/react-dom-bindings/src/server/escapeTextForBrowser.js
+2 -2
@@ -88,14 +88,14 @@ function escapeHtml(string: string) {
88 }
89
90 if (lastIndex !== index) {
91 - html += str.substring(lastIndex, index);
91 + html += str.slice(lastIndex, index);
92 }
93
94 lastIndex = index + 1;
95 html += escape;
96 }
97
98 - return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
98 + return lastIndex !== index ? html + str.slice(lastIndex, index) : html;
99 }
100 // end code copied and modified from escape-html
101
packages/react-reconciler/src/__tests__/ReactNewContext-test.js
+1 -1
@@ -1635,7 +1635,7 @@ describe('ReactNewContext', () => {
1635
1636 const LIMIT = 100;
1637 for (let i = 0; i < LIMIT; i++) {
1638 - const seed = Math.random().toString(36).substr(2, 5);
1638 + const seed = Math.random().toString(36).slice(2, 7);
1639 const actions = randomActions(5);
1640 try {
1641 simulate(seed, actions);
packages/react-server-dom-webpack/src/ReactFlightClientConfigNodeBundler.js
+2 -2
@@ -69,8 +69,8 @@ export function resolveServerReference<T>(
69 id: ServerReferenceId,
70 ): ClientReference<T> {
71 const idx = id.lastIndexOf('#');
72 - const specifier = id.substr(0, idx);
73 - const name = id.substr(idx + 1);
72 + const specifier = id.slice(0, idx);
73 + const name = id.slice(idx + 1);
74 return {specifier, name};
75 }
76
packages/react-server-dom-webpack/src/ReactFlightClientConfigWebpackBundler.js
+2 -2
@@ -85,8 +85,8 @@ export function resolveServerReference<T>(
85 // probably go back to encoding path and name separately on the client reference.
86 const idx = id.lastIndexOf('#');
87 if (idx !== -1) {
88 - name = id.substr(idx + 1);
89 - resolvedModuleData = bundlerConfig[id.substr(0, idx)];
88 + name = id.slice(idx + 1);
89 + resolvedModuleData = bundlerConfig[id.slice(0, idx)];
90 }
91 if (!resolvedModuleData) {
92 throw new Error(
packages/react-server-dom-webpack/src/ReactFlightServerConfigWebpackBundler.js
+2 -2
@@ -71,8 +71,8 @@ export function resolveClientReferenceMetadata<T>(
71 // probably go back to encoding path and name separately on the client reference.
72 const idx = modulePath.lastIndexOf('#');
73 if (idx !== -1) {
74 - name = modulePath.substr(idx + 1);
75 - resolvedModuleData = config[modulePath.substr(0, idx)];
74 + name = modulePath.slice(idx + 1);
75 + resolvedModuleData = config[modulePath.slice(0, idx)];
76 }
77 if (!resolvedModuleData) {
78 throw new Error(
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+2 -2
@@ -87,8 +87,8 @@ describe('ReactFlightDOMBrowser', () => {
87 // probably go back to encoding path and name separately on the client reference.
88 const idx = ref.lastIndexOf('#');
89 if (idx !== -1) {
90 - name = ref.substr(idx + 1);
91 - resolvedModuleData = webpackServerMap[ref.substr(0, idx)];
90 + name = ref.slice(idx + 1);
91 + resolvedModuleData = webpackServerMap[ref.slice(0, idx)];
92 }
93 if (!resolvedModuleData) {
94 throw new Error(
packages/react-server/src/ReactFlightReplyServer.js
+10 -10
@@ -374,21 +374,21 @@ function parseModelString(
374 switch (value[1]) {
375 case '$': {
376 // This was an escaped string value.
377 - return value.substring(1);
377 + return value.slice(1);
378 }
379 case '@': {
380 // Promise
381 - const id = parseInt(value.substring(2), 16);
381 + const id = parseInt(value.slice(2), 16);
382 const chunk = getChunk(response, id);
383 return chunk;
384 }
385 case 'S': {
386 // Symbol
387 - return Symbol.for(value.substring(2));
387 + return Symbol.for(value.slice(2));
388 }
389 case 'F': {
390 // Server Reference
391 - const id = parseInt(value.substring(2), 16);
391 + const id = parseInt(value.slice(2), 16);
392 const chunk = getChunk(response, id);
393 if (chunk.status === RESOLVED_MODEL) {
394 initializeModelChunk(chunk);
@@ -411,7 +411,7 @@ function parseModelString(
411 }
412 case 'K': {
413 // FormData
414 - const stringId = value.substring(2);
414 + const stringId = value.slice(2);
415 const formPrefix = response._prefix + stringId + '_';
416 const data = new FormData();
417 const backingFormData = response._formData;
@@ -421,7 +421,7 @@ function parseModelString(
421 // $FlowFixMe[prop-missing] FormData has forEach on it.
422 backingFormData.forEach((entry: File | string, entryKey: string) => {
423 if (entryKey.startsWith(formPrefix)) {
424 - data.append(entryKey.substr(formPrefix.length), entry);
424 + data.append(entryKey.slice(formPrefix.length), entry);
425 }
426 });
427 return data;
@@ -449,15 +449,15 @@ function parseModelString(
449 }
450 case 'D': {
451 // Date
452 - return new Date(Date.parse(value.substring(2)));
452 + return new Date(Date.parse(value.slice(2)));
453 }
454 case 'n': {
455 // BigInt
456 - return BigInt(value.substring(2));
456 + return BigInt(value.slice(2));
457 }
458 default: {
459 // We assume that anything else is a reference ID.
460 - const id = parseInt(value.substring(1), 16);
460 + const id = parseInt(value.slice(1), 16);
461 const chunk = getChunk(response, id);
462 switch (chunk.status) {
463 case RESOLVED_MODEL:
@@ -517,7 +517,7 @@ export function resolveField(
517 const prefix = response._prefix;
518 if (key.startsWith(prefix)) {
519 const chunks = response._chunks;
520 - const id = +key.substr(prefix.length);
520 + const id = +key.slice(prefix.length);
521 const chunk = chunks.get(id);
522 if (chunk) {
523 // We were waiting on this key so now we can resolve it.
packages/shared/ReactSerializationErrors.js
+1 -1
@@ -90,7 +90,7 @@ export function describeValueForErrorMessage(value: mixed): string {
90 switch (typeof value) {
91 case 'string': {
92 return JSON.stringify(
93 - value.length <= 10 ? value : value.substr(0, 10) + '...',
93 + value.length <= 10 ? value : value.slice(0, 10) + '...',
94 );
95 }
96 case 'object': {
scripts/babel/transform-test-gate-pragma.js
+2 -2
@@ -74,7 +74,7 @@ function transform(babel) {
74 continue;
75 }
76
77 - const next3 = code.substring(i, i + 3);
77 + const next3 = code.slice(i, i + 3);
78 if (next3 === '===') {
79 tokens.push({type: '=='});
80 i += 3;
@@ -86,7 +86,7 @@ function transform(babel) {
86 continue;
87 }
88
89 - const next2 = code.substring(i, i + 2);
89 + const next2 = code.slice(i, i + 2);
90 switch (next2) {
91 case '&&':
92 case '||':
scripts/jest/setupHostConfigs.js
+1 -1
@@ -116,7 +116,7 @@ function mockAllConfigs(rendererInfo) {
116 // We want the reconciler to pick up the host config for this renderer.
117 jest.mock(path, () => {
118 let idx = path.lastIndexOf('/');
119 - let forkPath = path.substr(0, idx) + '/forks' + path.substr(idx);
119 + let forkPath = path.slice(0, idx) + '/forks' + path.slice(idx);
120 return jest.requireActual(`${forkPath}.${rendererInfo.shortName}.js`);
121 });
122 });
scripts/jest/setupTests.js
+2 -2
@@ -76,7 +76,7 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
76 // Don't throw yet though b'c it might be accidentally caught and suppressed.
77 const stack = new Error().stack;
78 unexpectedConsoleCallStacks.push([
79 - stack.substr(stack.indexOf('\n') + 1),
79 + stack.slice(stack.indexOf('\n') + 1),
80 util.format(format, ...args),
81 ]);
82 };
@@ -178,7 +178,7 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
178 const args = matches[2]
179 .split('&')
180 .filter(s => s.startsWith('args[]='))
181 - .map(s => s.substr('args[]='.length))
181 + .map(s => s.slice('args[]='.length))
182 .map(decodeURIComponent);
183 const format = errorMap[code];
184 let argIndex = 0;
scripts/release/utils.js
+1 -1
@@ -118,7 +118,7 @@ const getDateStringForCommit = async commit => {
118
119 // On CI environment, this string is wrapped with quotes '...'s
120 if (dateString.startsWith("'")) {
121 - dateString = dateString.substr(1, 8);
121 + dateString = dateString.slice(1, 9);
122 }
123
124 return dateString;
scripts/rollup/build-all-release-channels.js
+3 -3
@@ -36,7 +36,7 @@ let dateString = String(
36
37 // On CI environment, this string is wrapped with quotes '...'s
38 if (dateString.startsWith("'")) {
39 - dateString = dateString.substr(1, 8);
39 + dateString = dateString.slice(1, 9);
40 }
41
42 // Build the artifacts using a placeholder React version. We'll then do a string
@@ -173,7 +173,7 @@ function processStable(buildDir) {
173 }
174 updatePlaceholderReactVersionInCompiledArtifacts(
175 buildDir + '/facebook-www',
176 - ReactVersion + '-www-classic-' + hash.digest('hex').substr(0, 8)
176 + ReactVersion + '-www-classic-' + hash.digest('hex').slice(0, 8)
177 );
178 }
179
@@ -227,7 +227,7 @@ function processExperimental(buildDir, version) {
227 }
228 updatePlaceholderReactVersionInCompiledArtifacts(
229 buildDir + '/facebook-www',
230 - ReactVersion + '-www-modern-' + hash.digest('hex').substr(0, 8)
230 + ReactVersion + '-www-modern-' + hash.digest('hex').slice(0, 8)
231 );
232 }
233
scripts/rollup/packaging.js
+1 -1
@@ -172,7 +172,7 @@ function getTarOptions(tgzName, packageName) {
172 entries: [CONTENTS_FOLDER],
173 map(header) {
174 if (header.name.indexOf(CONTENTS_FOLDER + '/') === 0) {
175 - header.name = header.name.substring(CONTENTS_FOLDER.length + 1);
175 + header.name = header.name.slice(CONTENTS_FOLDER.length + 1);
176 }
177 },
178 },