chore(deps): update dependency prettier to v2.3.0 (#42074)

* chore(deps): update dependency prettier to v2.3.0

* chore: apply formating per prettier

* fix: correctly disable import/no-unresolved

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Mrugesh Mohapatra <hi@mrugesh.dev>
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
renovate[bot]
2021-05-10 08:48:49 -07:00
committed by GitHub
parent 66dd85f64a
commit 21dd80c47a
30 changed files with 212 additions and 254 deletions

View File

@ -676,10 +676,8 @@ export default function initializeUser(User) {
const updateData = { $set: {} }; const updateData = { $set: {} };
return this.getCompletedChallenges$() return this.getCompletedChallenges$()
.flatMap(() => { .flatMap(() => {
const { const { updated, isNewCompletionCount } =
updated, buildCompletedChallengesUpdate(this.completedChallenges, project);
isNewCompletionCount
} = buildCompletedChallengesUpdate(this.completedChallenges, project);
updateData.$set.completedChallenges = updated; updateData.$set.completedChallenges = updated;
if (isNewCompletionCount) { if (isNewCompletionCount) {
let points = []; let points = [];
@ -830,12 +828,8 @@ export default function initializeUser(User) {
if (!user) { if (!user) {
return Observable.of({}); return Observable.of({});
} }
const { const { completedChallenges, progressTimestamps, timezone, profileUI } =
completedChallenges, user;
progressTimestamps,
timezone,
profileUI
} = user;
const allUser = { const allUser = {
..._.pick(user, publicUserProps), ..._.pick(user, publicUserProps),
isGithub: !!user.githubProfile, isGithub: !!user.githubProfile,

View File

@ -97,11 +97,8 @@ export const devLoginRedirect = () => {
}; };
}; };
export const createPassportCallbackAuthenticator = (strategy, config) => ( export const createPassportCallbackAuthenticator =
req, (strategy, config) => (req, res, next) => {
res,
next
) => {
return passport.authenticate( return passport.authenticate(
strategy, strategy,
{ session: false }, { session: false },

View File

@ -53,14 +53,12 @@ export const mockCancellationHook = {
}, },
links: [ links: [
{ {
href: href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1VF24938EU372274X-83540367M0110254R',
'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1VF24938EU372274X-83540367M0110254R',
rel: 'self', rel: 'self',
method: 'GET' method: 'GET'
}, },
{ {
href: href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1VF24938EU372274X-83540367M0110254R/resend',
'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1VF24938EU372274X-83540367M0110254R/resend',
rel: 'resend', rel: 'resend',
method: 'POST' method: 'POST'
} }
@ -156,32 +154,27 @@ export const mockActivationHook = {
}, },
links: [ links: [
{ {
href: href: 'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G',
'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G',
rel: 'self', rel: 'self',
method: 'GET' method: 'GET'
}, },
{ {
href: href: 'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G',
'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G',
rel: 'edit', rel: 'edit',
method: 'PATCH' method: 'PATCH'
}, },
{ {
href: href: 'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/suspend',
'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/suspend',
rel: 'suspend', rel: 'suspend',
method: 'POST' method: 'POST'
}, },
{ {
href: href: 'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/cancel',
'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/cancel',
rel: 'cancel', rel: 'cancel',
method: 'POST' method: 'POST'
}, },
{ {
href: href: 'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/capture',
'https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G/capture',
rel: 'capture', rel: 'capture',
method: 'POST' method: 'POST'
} }
@ -194,15 +187,13 @@ export const mockActivationHook = {
}, },
links: [ links: [
{ {
href: href: 'https://api.paypal.com/v1/notifications/webhooks-events/WH-77687562XN25889J8-8Y6T55435R66168T6',
'https://api.paypal.com/v1/notifications/webhooks-events/WH-77687562XN25889J8-8Y6T55435R66168T6',
rel: 'self', rel: 'self',
method: 'GET', method: 'GET',
encType: 'application/json' encType: 'application/json'
}, },
{ {
href: href: 'https://api.paypal.com/v1/notifications/webhooks-events/WH-77687562XN25889J8-8Y6T55435R66168T6/resend',
'https://api.paypal.com/v1/notifications/webhooks-events/WH-77687562XN25889J8-8Y6T55435R66168T6/resend',
rel: 'resend', rel: 'resend',
method: 'POST', method: 'POST',
encType: 'application/json' encType: 'application/json'

View File

@ -17,7 +17,9 @@ export function wrapHandledError(
} }
// for use with express-validator error formatter // for use with express-validator error formatter
export const createValidatorErrorFormatter = (type, redirectTo) => ({ msg }) => export const createValidatorErrorFormatter =
(type, redirectTo) =>
({ msg }) =>
wrapHandledError(new Error(msg), { wrapHandledError(new Error(msg), {
type, type,
message: msg, message: msg,

View File

@ -24,10 +24,8 @@ jest.mock('axios');
const verificationUrl = `https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature`; const verificationUrl = `https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature`;
const tokenUrl = `https://api.sandbox.paypal.com/v1/oauth2/token`; const tokenUrl = `https://api.sandbox.paypal.com/v1/oauth2/token`;
const { const { body: activationHookBody, headers: activationHookHeaders } =
body: activationHookBody, mockActivationHook;
headers: activationHookHeaders
} = mockActivationHook;
describe('donation', () => { describe('donation', () => {
describe('getAsyncPaypalToken', () => { describe('getAsyncPaypalToken', () => {

View File

@ -78,7 +78,9 @@ export function ifUserRedirectTo(status) {
} }
// for use with express-validator error formatter // for use with express-validator error formatter
export const createValidatorErrorHandler = (...args) => (req, res, next) => { export const createValidatorErrorHandler =
(...args) =>
(req, res, next) => {
const validation = validationResult(req).formatWith( const validation = validationResult(req).formatWith(
createValidatorErrorFormatter(...args) createValidatorErrorFormatter(...args)
); );

View File

@ -25,9 +25,13 @@ const propTypes = {
showLoading: PropTypes.bool showLoading: PropTypes.bool
}; };
const createRequestedUserSelector = () => (state, { maybeUser = '' }) => const createRequestedUserSelector =
() =>
(state, { maybeUser = '' }) =>
userByNameSelector(maybeUser.toLowerCase())(state); userByNameSelector(maybeUser.toLowerCase())(state);
const createIsSessionUserSelector = () => (state, { maybeUser = '' }) => const createIsSessionUserSelector =
() =>
(state, { maybeUser = '' }) =>
maybeUser.toLowerCase() === usernameSelector(state); maybeUser.toLowerCase() === usernameSelector(state);
const makeMapStateToProps = () => (state, props) => { const makeMapStateToProps = () => (state, props) => {

View File

@ -14,15 +14,17 @@ function rendererCreateWithRedux(ui) {
describe('<Intro />', () => { describe('<Intro />', () => {
it('has no blockquotes when loggedOut', () => { it('has no blockquotes when loggedOut', () => {
const container = rendererCreateWithRedux(<Intro {...loggedOutProps} />) const container = rendererCreateWithRedux(
.root; <Intro {...loggedOutProps} />
).root;
expect(container.findAllByType('blockquote').length === 0).toBeTruthy(); expect(container.findAllByType('blockquote').length === 0).toBeTruthy();
expect(container.findAllByType('h1').length === 1).toBeTruthy(); expect(container.findAllByType('h1').length === 1).toBeTruthy();
}); });
it('has a blockquote when loggedIn', () => { it('has a blockquote when loggedIn', () => {
const container = rendererCreateWithRedux(<Intro {...loggedInProps} />) const container = rendererCreateWithRedux(
.root; <Intro {...loggedInProps} />
).root;
expect(container.findAllByType('blockquote').length === 1).toBeTruthy(); expect(container.findAllByType('blockquote').length === 1).toBeTruthy();
expect(container.findAllByType('h1').length === 1).toBeTruthy(); expect(container.findAllByType('h1').length === 1).toBeTruthy();
}); });

View File

@ -21,13 +21,8 @@ const propTypes = {
}; };
const ProjectModal = props => { const ProjectModal = props => {
const { const { isOpen, projectTitle, files, solution, handleSolutionModalHide } =
isOpen, props;
projectTitle,
files,
solution,
handleSolutionModalHide
} = props;
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Modal <Modal

View File

@ -1,6 +1,8 @@
import { navigate } from 'gatsby'; import { navigate } from 'gatsby';
const createRedirect = (to = '/') => () => { const createRedirect =
(to = '/') =>
() => {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
navigate(to); navigate(to);
} }

View File

@ -2,8 +2,10 @@ import React from 'react';
import { Trans } from 'react-i18next'; import { Trans } from 'react-i18next';
// Matches editor links for: Replit, Glitch, CodeSandbox, GitHub // Matches editor links for: Replit, Glitch, CodeSandbox, GitHub
const editorRegex = /repl\.?it(\.com)?\/(@|join\/)|glitch\.com\/edit\/#!|codesandbox\.io\/s\/|github\.com/; const editorRegex =
const fCCRegex = /codepen\.io\/freecodecamp|freecodecamp\.rocks|github\.com\/freecodecamp/i; /repl\.?it(\.com)?\/(@|join\/)|glitch\.com\/edit\/#!|codesandbox\.io\/s\/|github\.com/;
const fCCRegex =
/codepen\.io\/freecodecamp|freecodecamp\.rocks|github\.com\/freecodecamp/i;
const localhostRegex = /localhost:/; const localhostRegex = /localhost:/;
const httpRegex = /http(?!s|([^s]+?localhost))/; const httpRegex = /http(?!s|([^s]+?localhost))/;
@ -21,5 +23,7 @@ export const localhostValidator = value =>
export const httpValidator = value => export const httpValidator = value =>
httpRegex.test(value) ? <Trans>validation.http-url</Trans> : null; httpRegex.test(value) ? <Trans>validation.http-url</Trans> : null;
export const composeValidators = (...validators) => value => export const composeValidators =
(...validators) =>
value =>
validators.reduce((error, validator) => error ?? validator?.(value), null); validators.reduce((error, validator) => error ?? validator?.(value), null);

View File

@ -285,13 +285,8 @@ export class CertificationSettings extends Component {
); );
}; };
renderProjectsFor = (certName, isCert) => { renderProjectsFor = (certName, isCert) => {
const { const { username, isHonest, createFlashMessage, t, verifyCert } =
username, this.props;
isHonest,
createFlashMessage,
t,
verifyCert
} = this.props;
const { certSlug } = first(projectMap[certName]); const { certSlug } = first(projectMap[certName]);
const certLocation = `/certification/${username}/${certSlug}`; const certLocation = `/certification/${username}/${certSlug}`;
const createClickHandler = certSlug => e => { const createClickHandler = certSlug => e => {
@ -332,12 +327,8 @@ export class CertificationSettings extends Component {
// legacy projects rendering // legacy projects rendering
handleSubmitLegacy({ values: formChalObj }) { handleSubmitLegacy({ values: formChalObj }) {
const { const { isHonest, createFlashMessage, verifyCert, updateLegacyCert } =
isHonest, this.props;
createFlashMessage,
verifyCert,
updateLegacyCert
} = this.props;
let legacyTitle; let legacyTitle;
let certSlug; let certSlug;
let certs = Object.keys(legacyProjectMap); let certs = Object.keys(legacyProjectMap);

View File

@ -141,17 +141,11 @@ class EmailSettings extends Component {
emailForm: { newEmail, confirmNewEmail, currentEmail, isPristine } emailForm: { newEmail, confirmNewEmail, currentEmail, isPristine }
} = this.state; } = this.state;
const { const { isEmailVerified, updateQuincyEmail, sendQuincyEmail, t } =
isEmailVerified, this.props;
updateQuincyEmail,
sendQuincyEmail,
t
} = this.props;
const { const { state: newEmailValidation, message: newEmailValidationMessage } =
state: newEmailValidation, this.getValidationForNewEmail();
message: newEmailValidationMessage
} = this.getValidationForNewEmail();
const { const {
state: confirmEmailValidation, state: confirmEmailValidation,

View File

@ -165,20 +165,14 @@ class InternetSettings extends Component {
message: githubProfileValidationMessage message: githubProfileValidationMessage
} = this.getValidationStateFor(githubProfile); } = this.getValidationStateFor(githubProfile);
const { const { state: linkedinValidation, message: linkedinValidationMessage } =
state: linkedinValidation, this.getValidationStateFor(linkedin);
message: linkedinValidationMessage
} = this.getValidationStateFor(linkedin);
const { const { state: twitterValidation, message: twitterValidationMessage } =
state: twitterValidation, this.getValidationStateFor(twitter);
message: twitterValidationMessage
} = this.getValidationStateFor(twitter);
const { const { state: websiteValidation, message: websiteValidationMessage } =
state: websiteValidation, this.getValidationStateFor(website);
message: websiteValidationMessage
} = this.getValidationStateFor(website);
return ( return (
<Fragment> <Fragment>

View File

@ -123,9 +123,8 @@ class PortfolioSettings extends Component {
const { state: titleState } = this.getTitleValidation(title); const { state: titleState } = this.getTitleValidation(title);
const { state: urlState } = this.getUrlValidation(url); const { state: urlState } = this.getUrlValidation(url);
const { state: imageState } = this.getUrlValidation(image, true); const { state: imageState } = this.getUrlValidation(image, true);
const { state: descriptionState } = this.getDescriptionValidation( const { state: descriptionState } =
description this.getDescriptionValidation(description);
);
return [titleState, imageState, urlState, descriptionState] return [titleState, imageState, urlState, descriptionState]
.filter(Boolean) .filter(Boolean)
.every(state => state === 'success'); .every(state => state === 'success');
@ -192,19 +191,15 @@ class PortfolioSettings extends Component {
const { t } = this.props; const { t } = this.props;
const { id, title, description, url, image } = portfolio; const { id, title, description, url, image } = portfolio;
const pristine = this.isFormPristine(id); const pristine = this.isFormPristine(id);
const { const { state: titleState, message: titleMessage } =
state: titleState, this.getTitleValidation(title);
message: titleMessage
} = this.getTitleValidation(title);
const { state: urlState, message: urlMessage } = this.getUrlValidation(url); const { state: urlState, message: urlMessage } = this.getUrlValidation(url);
const { state: imageState, message: imageMessage } = this.getUrlValidation( const { state: imageState, message: imageMessage } = this.getUrlValidation(
image, image,
true true
); );
const { const { state: descriptionState, message: descriptionMessage } =
state: descriptionState, this.getDescriptionValidation(description);
message: descriptionMessage
} = this.getDescriptionValidation(description);
return ( return (
<div key={id}> <div key={id}>

View File

@ -206,13 +206,8 @@ class ShowClassic extends Component {
} }
renderInstructionsPanel({ showToolPanel }) { renderInstructionsPanel({ showToolPanel }) {
const { const { block, description, instructions, superBlock, translationPending } =
block, this.getChallenge();
description,
instructions,
superBlock,
translationPending
} = this.getChallenge();
const { forumTopicId, title } = this.getChallenge(); const { forumTopicId, title } = this.getChallenge();
return ( return (

View File

@ -32,9 +32,8 @@ function createQuestionEpic(action$, state$, { window }) {
tap(() => { tap(() => {
const state = state$.value; const state = state$.value;
const files = challengeFilesSelector(state); const files = challengeFilesSelector(state);
const { title: challengeTitle, helpCategory } = challengeMetaSelector( const { title: challengeTitle, helpCategory } =
state challengeMetaSelector(state);
);
const { const {
navigator: { userAgent }, navigator: { userAgent },
location: { href } location: { href }

View File

@ -74,9 +74,9 @@ export function* executeChallengeSaga({
yield put(initLogs()); yield put(initLogs());
yield put(initConsole(i18next.t('learn.running-tests'))); yield put(initConsole(i18next.t('learn.running-tests')));
// reset tests to initial state // reset tests to initial state
const tests = (yield select( const tests = (yield select(challengeTestsSelector)).map(
challengeTestsSelector ({ text, testString }) => ({ text, testString })
)).map(({ text, testString }) => ({ text, testString })); );
yield put(updateTests(tests)); yield put(updateTests(tests));
yield fork(takeEveryLog, consoleProxy); yield fork(takeEveryLog, consoleProxy);

View File

@ -67,7 +67,9 @@ const createFrame = (document, id) => ctx => {
}; };
const hiddenFrameClassName = 'hide-test-frame'; const hiddenFrameClassName = 'hide-test-frame';
const mountFrame = document => ({ element, ...rest }) => { const mountFrame =
document =>
({ element, ...rest }) => {
const oldFrame = document.getElementById(element.id); const oldFrame = document.getElementById(element.id);
if (oldFrame) { if (oldFrame) {
element.className = oldFrame.className || hiddenFrameClassName; element.className = oldFrame.className || hiddenFrameClassName;

View File

@ -20,9 +20,11 @@ const CertificationCard = ({ certSlug, superBlock, i18nCertText }) => {
setIsExpanded(!isExpanded); setIsExpanded(!isExpanded);
}; };
const { expand: expandText, collapse: collapseText, steps: stepsText } = t( const {
'intro:misc-text' expand: expandText,
); collapse: collapseText,
steps: stepsText
} = t('intro:misc-text');
return ( return (
<ScrollableAnchor id='claim-cert-block'> <ScrollableAnchor id='claim-cert-block'>
<div className={`block ${isExpanded ? 'open' : ''}`}> <div className={`block ${isExpanded ? 'open' : ''}`}>

View File

@ -14,10 +14,8 @@ function SuperBlockIntro(props) {
const { superBlock } = props; const { superBlock } = props;
const superBlockIntroObj = t(`intro:${superBlock}`); const superBlockIntroObj = t(`intro:${superBlock}`);
const { const { title: i18nSuperBlock, intro: superBlockIntroText } =
title: i18nSuperBlock, superBlockIntroObj;
intro: superBlockIntroText
} = superBlockIntroObj;
return ( return (
<> <>

View File

@ -8,10 +8,8 @@ import htmlTestValues from './__fixtures/curriculum-helpers-html';
import whiteSpaceTestValues from './__fixtures/curriculum-helpers-remove-white-space'; import whiteSpaceTestValues from './__fixtures/curriculum-helpers-remove-white-space';
/* eslint-enable max-len */ /* eslint-enable max-len */
const { const { stringWithWhiteSpaceChars, stringWithWhiteSpaceCharsRemoved } =
stringWithWhiteSpaceChars, whiteSpaceTestValues;
stringWithWhiteSpaceCharsRemoved
} = whiteSpaceTestValues;
const { cssFullExample, cssCodeWithCommentsRemoved } = cssTestValues; const { cssFullExample, cssCodeWithCommentsRemoved } = cssTestValues;

View File

@ -49,7 +49,9 @@ const getPrevChallengePath = (node, index, nodeArray) => {
const getTemplateComponent = challengeType => views[viewTypes[challengeType]]; const getTemplateComponent = challengeType => views[viewTypes[challengeType]];
exports.createChallengePages = createPage => ({ node }, index, thisArray) => { exports.createChallengePages =
createPage =>
({ node }, index, thisArray) => {
const { const {
superBlock, superBlock,
block, block,

View File

@ -15,9 +15,8 @@ const { isAuditedCert } = require('../utils/is-audited');
const { dasherize } = require('../utils/slugs'); const { dasherize } = require('../utils/slugs');
const { createPoly } = require('../utils/polyvinyl'); const { createPoly } = require('../utils/polyvinyl');
const { helpCategoryMap } = require('../client/utils/challengeTypes'); const { helpCategoryMap } = require('../client/utils/challengeTypes');
const { const { curriculum: curriculumLangs } =
curriculum: curriculumLangs require('../config/i18n/all-langs').availableLangs;
} = require('../config/i18n/all-langs').availableLangs;
const access = util.promisify(fs.access); const access = util.promisify(fs.access);

View File

@ -68,9 +68,10 @@ const TRANSLATABLE_COMMENTS = getTranslatableComments(
); );
// the config files are created during the build, but not before linting // the config files are created during the build, but not before linting
// eslint-disable-next-line import/no-unresolved /* eslint-disable import/no-unresolved */
const testEvaluator = require('../../config/client/test-evaluator.json') const testEvaluator =
.filename; require('../../config/client/test-evaluator.json').filename;
/* eslint-enable import/no-unresolved */
const { inspect } = require('util'); const { inspect } = require('util');
const commentExtractors = { const commentExtractors = {

View File

@ -1,9 +1,8 @@
const path = require('path'); const path = require('path');
require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); require('dotenv').config({ path: path.resolve(__dirname, '../.env') });
const { const { curriculum: curriculumLangs } =
curriculum: curriculumLangs require('../config/i18n/all-langs').availableLangs;
} = require('../config/i18n/all-langs').availableLangs;
exports.testedLang = function testedLang() { exports.testedLang = function testedLang() {
if (process.env.CURRICULUM_LOCALE) { if (process.env.CURRICULUM_LOCALE) {

View File

@ -20,8 +20,7 @@ describe('The Document Metadata', () => {
const scripts = { const scripts = {
mathjax: { mathjax: {
selector: 'body script[id="mathjax"]', selector: 'body script[id="mathjax"]',
src: src: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS_HTML'
'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS_HTML'
} }
}; };
it('landing page has correct <meta> for description', () => { it('landing page has correct <meta> for description', () => {

6
package-lock.json generated
View File

@ -16457,9 +16457,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "2.2.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
"dev": true "dev": true
}, },
"prettier-linter-helpers": { "prettier-linter-helpers": {

View File

@ -117,7 +117,7 @@
"markdownlint": "0.21.0", "markdownlint": "0.21.0",
"npm-run-all": "4.1.5", "npm-run-all": "4.1.5",
"ora": "5.4.0", "ora": "5.4.0",
"prettier": "2.2.1", "prettier": "2.3.0",
"prismjs": "1.23.0", "prismjs": "1.23.0",
"shx": "0.3.3", "shx": "0.3.3",
"sinon": "10.0.0", "sinon": "10.0.0",

View File

@ -44,9 +44,8 @@ const hideNonTranslatedStrings = async projectId => {
const crowdinStrings = await getStrings({ projectId }); const crowdinStrings = await getStrings({ projectId });
if (crowdinStrings && crowdinStrings.length) { if (crowdinStrings && crowdinStrings.length) {
for (let string of crowdinStrings) { for (let string of crowdinStrings) {
const { crowdinFilePath, challengeTitle } = challengeTitleLookup[ const { crowdinFilePath, challengeTitle } =
string.data.fileId challengeTitleLookup[string.data.fileId];
];
await updateFileString({ await updateFileString({
projectId, projectId,
string, string,