diff --git a/.eslintignore b/.eslintignore index 5338df11c520..aa8b769dfede 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,3 +9,4 @@ android/**/build/** docs/vendor/** docs/assets/** web/gtm.js +**/.expo/** diff --git a/.eslintrc.js b/.eslintrc.js index 9f839e45ce75..d8f8c15eb878 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,5 @@ +const path = require('path'); + const restrictedImportPaths = [ { name: 'react-native', @@ -96,7 +98,7 @@ module.exports = { plugins: ['@typescript-eslint', 'jsdoc', 'you-dont-need-lodash-underscore', 'react-native-a11y', 'react', 'testing-library'], parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: path.resolve(__dirname, './tsconfig.json'), }, env: { jest: true, @@ -105,10 +107,9 @@ module.exports = { __DEV__: 'readonly', }, rules: { + // TypeScript specific rules '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', - - // TypeScript specific rules '@typescript-eslint/prefer-enum-initializers': 'error', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-non-null-assertion': 'error', @@ -215,6 +216,8 @@ module.exports = { // Other rules curly: 'error', 'you-dont-need-lodash-underscore/throttle': 'off', + // The suggested alternative (structuredClone) is not supported in Hermes:https://github.com/facebook/hermes/issues/684 + 'you-dont-need-lodash-underscore/clone-deep': 'off', 'prefer-regex-literals': 'off', 'valid-jsdoc': 'off', 'jsdoc/no-types': 'error', @@ -257,6 +260,7 @@ module.exports = { // Remove once no JS files are left { files: ['*.js', '*.jsx'], + extends: ['plugin:@typescript-eslint/disable-type-checked'], rules: { '@typescript-eslint/prefer-nullish-coalescing': 'off', '@typescript-eslint/no-unsafe-return': 'off', diff --git a/.github/actions/javascript/authorChecklist/index.js b/.github/actions/javascript/authorChecklist/index.js index 337fe7398fb3..84624b6bfc6f 100644 --- a/.github/actions/javascript/authorChecklist/index.js +++ b/.github/actions/javascript/authorChecklist/index.js @@ -11710,7 +11710,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -17073,13 +17073,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -17099,6 +17097,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -17454,12 +17461,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -17531,27 +17557,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 0e0168fdb7ae..6ec9bbf06aeb 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -7373,7 +7373,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -12314,13 +12314,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -12340,6 +12338,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12695,12 +12702,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12796,27 +12822,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/bumpVersion/bumpVersion.ts b/.github/actions/javascript/bumpVersion/bumpVersion.ts index eba79c7c9edb..ff43ab9ee5c5 100644 --- a/.github/actions/javascript/bumpVersion/bumpVersion.ts +++ b/.github/actions/javascript/bumpVersion/bumpVersion.ts @@ -5,6 +5,7 @@ import type {PackageJson} from 'type-fest'; import {promisify} from 'util'; import {generateAndroidVersionCode, updateAndroidVersion, updateiOSVersion} from '@github/libs/nativeVersionUpdater'; import * as versionUpdater from '@github/libs/versionUpdater'; +import type {SemverLevel} from '@github/libs/versionUpdater'; const exec = promisify(originalExec); @@ -43,7 +44,7 @@ function updateNativeVersions(version: string) { } let semanticVersionLevel = core.getInput('SEMVER_LEVEL', {required: true}); -if (!semanticVersionLevel || !Object.keys(versionUpdater.SEMANTIC_VERSION_LEVELS).includes(semanticVersionLevel)) { +if (!semanticVersionLevel || !versionUpdater.isValidSemverLevel(semanticVersionLevel)) { semanticVersionLevel = versionUpdater.SEMANTIC_VERSION_LEVELS.BUILD; console.log(`Invalid input for 'SEMVER_LEVEL': ${semanticVersionLevel}`, `Defaulting to: ${semanticVersionLevel}`); } @@ -53,7 +54,7 @@ if (!previousVersion) { core.setFailed('Error: Could not read package.json'); } -const newVersion = versionUpdater.incrementVersion(previousVersion ?? '', semanticVersionLevel); +const newVersion = versionUpdater.incrementVersion(previousVersion ?? '', semanticVersionLevel as SemverLevel); console.log(`Previous version: ${previousVersion}`, `New version: ${newVersion}`); updateNativeVersions(newVersion); diff --git a/.github/actions/javascript/bumpVersion/index.js b/.github/actions/javascript/bumpVersion/index.js index e1a5cf13a8d9..93ea47bed2ae 100644 --- a/.github/actions/javascript/bumpVersion/index.js +++ b/.github/actions/javascript/bumpVersion/index.js @@ -3473,7 +3473,7 @@ function updateNativeVersions(version) { } } let semanticVersionLevel = core.getInput('SEMVER_LEVEL', { required: true }); -if (!semanticVersionLevel || !Object.keys(versionUpdater.SEMANTIC_VERSION_LEVELS).includes(semanticVersionLevel)) { +if (!semanticVersionLevel || !versionUpdater.isValidSemverLevel(semanticVersionLevel)) { semanticVersionLevel = versionUpdater.SEMANTIC_VERSION_LEVELS.BUILD; console.log(`Invalid input for 'SEMVER_LEVEL': ${semanticVersionLevel}`, `Defaulting to: ${semanticVersionLevel}`); } @@ -3589,7 +3589,7 @@ exports.updateiOSVersion = updateiOSVersion; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = void 0; +exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = exports.isValidSemverLevel = void 0; const SEMANTIC_VERSION_LEVELS = { MAJOR: 'MAJOR', MINOR: 'MINOR', @@ -3599,6 +3599,10 @@ const SEMANTIC_VERSION_LEVELS = { exports.SEMANTIC_VERSION_LEVELS = SEMANTIC_VERSION_LEVELS; const MAX_INCREMENTS = 99; exports.MAX_INCREMENTS = MAX_INCREMENTS; +function isValidSemverLevel(str) { + return Object.keys(SEMANTIC_VERSION_LEVELS).includes(str); +} +exports.isValidSemverLevel = isValidSemverLevel; /** * Transforms a versions string into a number */ diff --git a/.github/actions/javascript/checkDeployBlockers/index.js b/.github/actions/javascript/checkDeployBlockers/index.js index 842deb1cbb5d..c6518f4e61c9 100644 --- a/.github/actions/javascript/checkDeployBlockers/index.js +++ b/.github/actions/javascript/checkDeployBlockers/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11597,13 +11597,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11623,6 +11621,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11978,12 +11985,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12024,27 +12050,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js index 127fb1fe3dca..260dd0847c8d 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js @@ -9434,7 +9434,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -14401,7 +14401,66 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); const child_process_1 = __nccwpck_require__(2081); const CONST_1 = __importDefault(__nccwpck_require__(9873)); const sanitizeStringForJSONParse_1 = __importDefault(__nccwpck_require__(3902)); -const VERSION_UPDATER = __importStar(__nccwpck_require__(8982)); +const VersionUpdater = __importStar(__nccwpck_require__(8982)); +/** + * Check if a tag exists locally or in the remote. + */ +function tagExists(tag) { + try { + // Check if the tag exists locally + (0, child_process_1.execSync)(`git show-ref --tags ${tag}`, { stdio: 'ignore' }); + return true; // Tag exists locally + } + catch (error) { + // Tag does not exist locally, check in remote + let shouldRetry = true; + let needsRepack = false; + let doesTagExist = false; + while (shouldRetry) { + try { + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + (0, child_process_1.execSync)('git repack -d', { stdio: 'inherit' }); + } + (0, child_process_1.execSync)(`git ls-remote --exit-code --tags origin ${tag}`, { stdio: 'ignore' }); + doesTagExist = true; + shouldRetry = false; + } + catch (e) { + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } + else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } + } + return doesTagExist; + } +} +/** + * This essentially just calls getPreviousVersion in a loop, until it finds a version for which a tag exists. + * It's useful if we manually perform a version bump, because in that case a tag may not exist for the previous version. + * + * @param tag the current tag + * @param level the Semver level to step backward by + */ +function getPreviousExistingTag(tag, level) { + let previousVersion = VersionUpdater.getPreviousVersion(tag, level); + let tagExistsForPreviousVersion = false; + while (!tagExistsForPreviousVersion) { + if (tagExists(previousVersion)) { + tagExistsForPreviousVersion = true; + break; + } + console.log(`Tag for previous version ${previousVersion} does not exist. Checking for an older version...`); + previousVersion = VersionUpdater.getPreviousVersion(previousVersion, level); + } + return previousVersion; +} /** * @param [shallowExcludeTag] When fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ @@ -14444,8 +14503,8 @@ function fetchTag(tag, shallowExcludeTag = '') { * Get merge logs between two tags (inclusive) as a JavaScript object. */ function getCommitHistoryAsJSON(fromTag, toTag) { - // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history - const previousPatchVersion = VERSION_UPDATER.getPreviousVersion(fromTag, VERSION_UPDATER.SEMANTIC_VERSION_LEVELS.PATCH); + // Fetch tags, excluding commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousExistingTag(fromTag, VersionUpdater.SEMANTIC_VERSION_LEVELS.PATCH); fetchTag(fromTag, previousPatchVersion); fetchTag(toTag, previousPatchVersion); console.log('Getting pull requests merged between the following tags:', fromTag, toTag); @@ -14517,6 +14576,7 @@ async function getPullRequestsMergedBetween(fromTag, toTag) { return pullRequestNumbers; } exports["default"] = { + getPreviousExistingTag, getValidMergedPRs, getPullRequestsMergedBetween, }; @@ -14567,13 +14627,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -14593,6 +14651,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -14948,12 +15015,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -15000,7 +15086,7 @@ exports["default"] = sanitizeStringForJSONParse; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = void 0; +exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = exports.isValidSemverLevel = void 0; const SEMANTIC_VERSION_LEVELS = { MAJOR: 'MAJOR', MINOR: 'MINOR', @@ -15010,6 +15096,10 @@ const SEMANTIC_VERSION_LEVELS = { exports.SEMANTIC_VERSION_LEVELS = SEMANTIC_VERSION_LEVELS; const MAX_INCREMENTS = 99; exports.MAX_INCREMENTS = MAX_INCREMENTS; +function isValidSemverLevel(str) { + return Object.keys(SEMANTIC_VERSION_LEVELS).includes(str); +} +exports.isValidSemverLevel = isValidSemverLevel; /** * Transforms a versions string into a number */ @@ -15126,14 +15216,6 @@ function arrayDifference(array1, array2) { exports["default"] = arrayDifference; -/***/ }), - -/***/ 2877: -/***/ ((module) => { - -module.exports = eval("require")("encoding"); - - /***/ }), /***/ 9491: @@ -15160,6 +15242,14 @@ module.exports = require("crypto"); /***/ }), +/***/ 3975: +/***/ ((module) => { + +"use strict"; +module.exports = require("encoding"); + +/***/ }), + /***/ 2361: /***/ ((module) => { diff --git a/.github/actions/javascript/getArtifactInfo/index.js b/.github/actions/javascript/getArtifactInfo/index.js index 77f61f491fec..cde9cf8748db 100644 --- a/.github/actions/javascript/getArtifactInfo/index.js +++ b/.github/actions/javascript/getArtifactInfo/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11558,13 +11558,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11584,6 +11582,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11939,12 +11946,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -11985,27 +12011,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index 8f9f9deea896..6b956f17be25 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -6723,7 +6723,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11665,7 +11665,66 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); const child_process_1 = __nccwpck_require__(2081); const CONST_1 = __importDefault(__nccwpck_require__(9873)); const sanitizeStringForJSONParse_1 = __importDefault(__nccwpck_require__(3902)); -const VERSION_UPDATER = __importStar(__nccwpck_require__(8982)); +const VersionUpdater = __importStar(__nccwpck_require__(8982)); +/** + * Check if a tag exists locally or in the remote. + */ +function tagExists(tag) { + try { + // Check if the tag exists locally + (0, child_process_1.execSync)(`git show-ref --tags ${tag}`, { stdio: 'ignore' }); + return true; // Tag exists locally + } + catch (error) { + // Tag does not exist locally, check in remote + let shouldRetry = true; + let needsRepack = false; + let doesTagExist = false; + while (shouldRetry) { + try { + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + (0, child_process_1.execSync)('git repack -d', { stdio: 'inherit' }); + } + (0, child_process_1.execSync)(`git ls-remote --exit-code --tags origin ${tag}`, { stdio: 'ignore' }); + doesTagExist = true; + shouldRetry = false; + } + catch (e) { + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } + else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } + } + return doesTagExist; + } +} +/** + * This essentially just calls getPreviousVersion in a loop, until it finds a version for which a tag exists. + * It's useful if we manually perform a version bump, because in that case a tag may not exist for the previous version. + * + * @param tag the current tag + * @param level the Semver level to step backward by + */ +function getPreviousExistingTag(tag, level) { + let previousVersion = VersionUpdater.getPreviousVersion(tag, level); + let tagExistsForPreviousVersion = false; + while (!tagExistsForPreviousVersion) { + if (tagExists(previousVersion)) { + tagExistsForPreviousVersion = true; + break; + } + console.log(`Tag for previous version ${previousVersion} does not exist. Checking for an older version...`); + previousVersion = VersionUpdater.getPreviousVersion(previousVersion, level); + } + return previousVersion; +} /** * @param [shallowExcludeTag] When fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ @@ -11708,8 +11767,8 @@ function fetchTag(tag, shallowExcludeTag = '') { * Get merge logs between two tags (inclusive) as a JavaScript object. */ function getCommitHistoryAsJSON(fromTag, toTag) { - // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history - const previousPatchVersion = VERSION_UPDATER.getPreviousVersion(fromTag, VERSION_UPDATER.SEMANTIC_VERSION_LEVELS.PATCH); + // Fetch tags, excluding commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousExistingTag(fromTag, VersionUpdater.SEMANTIC_VERSION_LEVELS.PATCH); fetchTag(fromTag, previousPatchVersion); fetchTag(toTag, previousPatchVersion); console.log('Getting pull requests merged between the following tags:', fromTag, toTag); @@ -11781,6 +11840,7 @@ async function getPullRequestsMergedBetween(fromTag, toTag) { return pullRequestNumbers; } exports["default"] = { + getPreviousExistingTag, getValidMergedPRs, getPullRequestsMergedBetween, }; @@ -11831,13 +11891,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11857,6 +11915,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12212,12 +12279,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12264,7 +12350,7 @@ exports["default"] = sanitizeStringForJSONParse; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = void 0; +exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = exports.isValidSemverLevel = void 0; const SEMANTIC_VERSION_LEVELS = { MAJOR: 'MAJOR', MINOR: 'MINOR', @@ -12274,6 +12360,10 @@ const SEMANTIC_VERSION_LEVELS = { exports.SEMANTIC_VERSION_LEVELS = SEMANTIC_VERSION_LEVELS; const MAX_INCREMENTS = 99; exports.MAX_INCREMENTS = MAX_INCREMENTS; +function isValidSemverLevel(str) { + return Object.keys(SEMANTIC_VERSION_LEVELS).includes(str); +} +exports.isValidSemverLevel = isValidSemverLevel; /** * Transforms a versions string into a number */ @@ -12390,14 +12480,6 @@ function arrayDifference(array1, array2) { exports["default"] = arrayDifference; -/***/ }), - -/***/ 2877: -/***/ ((module) => { - -module.exports = eval("require")("encoding"); - - /***/ }), /***/ 9491: @@ -12424,6 +12506,14 @@ module.exports = require("crypto"); /***/ }), +/***/ 3975: +/***/ ((module) => { + +"use strict"; +module.exports = require("encoding"); + +/***/ }), + /***/ 2361: /***/ ((module) => { diff --git a/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts b/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts index 262b603124fa..a178d4073cbb 100644 --- a/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts +++ b/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts @@ -1,17 +1,29 @@ import * as core from '@actions/core'; import {readFileSync} from 'fs'; import type {PackageJson} from 'type-fest'; +import GitUtils from '@github/libs/GitUtils'; import * as versionUpdater from '@github/libs/versionUpdater'; +import type {SemverLevel} from '@github/libs/versionUpdater'; -const semverLevel = core.getInput('SEMVER_LEVEL', {required: true}); -if (!semverLevel || !Object.values(versionUpdater.SEMANTIC_VERSION_LEVELS).includes(semverLevel)) { - core.setFailed(`'Error: Invalid input for 'SEMVER_LEVEL': ${semverLevel}`); +function run() { + const semverLevel = core.getInput('SEMVER_LEVEL', {required: true}); + if (!semverLevel || !versionUpdater.isValidSemverLevel(semverLevel)) { + core.setFailed(`'Error: Invalid input for 'SEMVER_LEVEL': ${semverLevel}`); + } + + const {version: currentVersion}: PackageJson = JSON.parse(readFileSync('./package.json', 'utf8')); + if (!currentVersion) { + core.setFailed('Error: Could not read package.json'); + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const previousVersion = GitUtils.getPreviousExistingTag(currentVersion!, semverLevel as SemverLevel); + core.setOutput('PREVIOUS_VERSION', previousVersion); + return previousVersion; } -const {version: currentVersion}: PackageJson = JSON.parse(readFileSync('./package.json', 'utf8')); -if (!currentVersion) { - core.setFailed('Error: Could not read package.json'); +if (require.main === module) { + run(); } -const previousVersion = versionUpdater.getPreviousVersion(currentVersion ?? '', semverLevel); -core.setOutput('PREVIOUS_VERSION', previousVersion); +export default run; diff --git a/.github/actions/javascript/getPreviousVersion/index.js b/.github/actions/javascript/getPreviousVersion/index.js index 8eac2f62f03e..29d02cc4dbac 100644 --- a/.github/actions/javascript/getPreviousVersion/index.js +++ b/.github/actions/javascript/getPreviousVersion/index.js @@ -2719,20 +2719,316 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(186)); const fs_1 = __nccwpck_require__(147); +const GitUtils_1 = __importDefault(__nccwpck_require__(547)); const versionUpdater = __importStar(__nccwpck_require__(982)); -const semverLevel = core.getInput('SEMVER_LEVEL', { required: true }); -if (!semverLevel || !Object.values(versionUpdater.SEMANTIC_VERSION_LEVELS).includes(semverLevel)) { - core.setFailed(`'Error: Invalid input for 'SEMVER_LEVEL': ${semverLevel}`); +function run() { + const semverLevel = core.getInput('SEMVER_LEVEL', { required: true }); + if (!semverLevel || !versionUpdater.isValidSemverLevel(semverLevel)) { + core.setFailed(`'Error: Invalid input for 'SEMVER_LEVEL': ${semverLevel}`); + } + const { version: currentVersion } = JSON.parse((0, fs_1.readFileSync)('./package.json', 'utf8')); + if (!currentVersion) { + core.setFailed('Error: Could not read package.json'); + } + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const previousVersion = GitUtils_1.default.getPreviousExistingTag(currentVersion, semverLevel); + core.setOutput('PREVIOUS_VERSION', previousVersion); + return previousVersion; +} +if (require.main === require.cache[eval('__filename')]) { + run(); +} +exports["default"] = run; + + +/***/ }), + +/***/ 873: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +const GITHUB_BASE_URL_REGEX = new RegExp('https?://(?:github\\.com|api\\.github\\.com)'); +const GIT_CONST = { + GITHUB_OWNER: 'Expensify', + APP_REPO: 'App', +}; +const CONST = { + ...GIT_CONST, + APPLAUSE_BOT: 'applausebot', + OS_BOTIFY: 'OSBotify', + LABELS: { + STAGING_DEPLOY: 'StagingDeployCash', + DEPLOY_BLOCKER: 'DeployBlockerCash', + INTERNAL_QA: 'InternalQA', + }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', + PULL_REQUEST_REGEX: new RegExp(`${GITHUB_BASE_URL_REGEX.source}/.*/.*/pull/([0-9]+).*`), + ISSUE_REGEX: new RegExp(`${GITHUB_BASE_URL_REGEX.source}/.*/.*/issues/([0-9]+).*`), + ISSUE_OR_PULL_REQUEST_REGEX: new RegExp(`${GITHUB_BASE_URL_REGEX.source}/.*/.*/(?:pull|issues)/([0-9]+).*`), + POLL_RATE: 10000, + APP_REPO_URL: `https://github.com/${GIT_CONST.GITHUB_OWNER}/${GIT_CONST.APP_REPO}`, + APP_REPO_GIT_URL: `git@github.com:${GIT_CONST.GITHUB_OWNER}/${GIT_CONST.APP_REPO}.git`, +}; +exports["default"] = CONST; + + +/***/ }), + +/***/ 547: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const child_process_1 = __nccwpck_require__(81); +const CONST_1 = __importDefault(__nccwpck_require__(873)); +const sanitizeStringForJSONParse_1 = __importDefault(__nccwpck_require__(902)); +const VersionUpdater = __importStar(__nccwpck_require__(982)); +/** + * Check if a tag exists locally or in the remote. + */ +function tagExists(tag) { + try { + // Check if the tag exists locally + (0, child_process_1.execSync)(`git show-ref --tags ${tag}`, { stdio: 'ignore' }); + return true; // Tag exists locally + } + catch (error) { + // Tag does not exist locally, check in remote + let shouldRetry = true; + let needsRepack = false; + let doesTagExist = false; + while (shouldRetry) { + try { + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + (0, child_process_1.execSync)('git repack -d', { stdio: 'inherit' }); + } + (0, child_process_1.execSync)(`git ls-remote --exit-code --tags origin ${tag}`, { stdio: 'ignore' }); + doesTagExist = true; + shouldRetry = false; + } + catch (e) { + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } + else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } + } + return doesTagExist; + } +} +/** + * This essentially just calls getPreviousVersion in a loop, until it finds a version for which a tag exists. + * It's useful if we manually perform a version bump, because in that case a tag may not exist for the previous version. + * + * @param tag the current tag + * @param level the Semver level to step backward by + */ +function getPreviousExistingTag(tag, level) { + let previousVersion = VersionUpdater.getPreviousVersion(tag, level); + let tagExistsForPreviousVersion = false; + while (!tagExistsForPreviousVersion) { + if (tagExists(previousVersion)) { + tagExistsForPreviousVersion = true; + break; + } + console.log(`Tag for previous version ${previousVersion} does not exist. Checking for an older version...`); + previousVersion = VersionUpdater.getPreviousVersion(previousVersion, level); + } + return previousVersion; } -const { version: currentVersion } = JSON.parse((0, fs_1.readFileSync)('./package.json', 'utf8')); -if (!currentVersion) { - core.setFailed('Error: Could not read package.json'); +/** + * @param [shallowExcludeTag] When fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) + */ +function fetchTag(tag, shallowExcludeTag = '') { + let shouldRetry = true; + let needsRepack = false; + while (shouldRetry) { + try { + let command = ''; + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + command = 'git repack -d'; + console.log(`Running command: ${command}`); + (0, child_process_1.execSync)(command); + } + command = `git fetch origin tag ${tag} --no-tags`; + // Note that this condition is only ever NOT true in the 1.0.0-0 edge case + if (shallowExcludeTag && shallowExcludeTag !== tag) { + command += ` --shallow-exclude=${shallowExcludeTag}`; + } + console.log(`Running command: ${command}`); + (0, child_process_1.execSync)(command); + shouldRetry = false; + } + catch (e) { + console.error(e); + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } + else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } + } +} +/** + * Get merge logs between two tags (inclusive) as a JavaScript object. + */ +function getCommitHistoryAsJSON(fromTag, toTag) { + // Fetch tags, excluding commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousExistingTag(fromTag, VersionUpdater.SEMANTIC_VERSION_LEVELS.PATCH); + fetchTag(fromTag, previousPatchVersion); + fetchTag(toTag, previousPatchVersion); + console.log('Getting pull requests merged between the following tags:', fromTag, toTag); + return new Promise((resolve, reject) => { + let stdout = ''; + let stderr = ''; + const args = ['log', '--format={"commit": "%H", "authorName": "%an", "subject": "%s"},', `${fromTag}...${toTag}`]; + console.log(`Running command: git ${args.join(' ')}`); + const spawnedProcess = (0, child_process_1.spawn)('git', args); + spawnedProcess.on('message', console.log); + spawnedProcess.stdout.on('data', (chunk) => { + console.log(chunk.toString()); + stdout += chunk.toString(); + }); + spawnedProcess.stderr.on('data', (chunk) => { + console.error(chunk.toString()); + stderr += chunk.toString(); + }); + spawnedProcess.on('close', (code) => { + if (code !== 0) { + return reject(new Error(`${stderr}`)); + } + resolve(stdout); + }); + spawnedProcess.on('error', (err) => reject(err)); + }).then((stdout) => { + // Sanitize just the text within commit subjects as that's the only potentially un-parseable text. + const sanitizedOutput = stdout.replace(/(?<="subject": ").*?(?="})/g, (subject) => (0, sanitizeStringForJSONParse_1.default)(subject)); + // Then remove newlines, format as JSON and convert to a proper JS object + const json = `[${sanitizedOutput}]`.replace(/(\r\n|\n|\r)/gm, '').replace('},]', '}]'); + return JSON.parse(json); + }); +} +/** + * Parse merged PRs, excluding those from irrelevant branches. + */ +function getValidMergedPRs(commits) { + const mergedPRs = new Set(); + commits.forEach((commit) => { + const author = commit.authorName; + if (author === CONST_1.default.OS_BOTIFY) { + return; + } + const match = commit.subject.match(/Merge pull request #(\d+) from (?!Expensify\/.*-cherry-pick-staging)/); + if (!Array.isArray(match) || match.length < 2) { + return; + } + const pr = Number.parseInt(match[1], 10); + if (mergedPRs.has(pr)) { + // If a PR shows up in the log twice, that means that the PR was deployed in the previous checklist. + // That also means that we don't want to include it in the current checklist, so we remove it now. + mergedPRs.delete(pr); + return; + } + mergedPRs.add(pr); + }); + return Array.from(mergedPRs); } -const previousVersion = versionUpdater.getPreviousVersion(currentVersion ?? '', semverLevel); -core.setOutput('PREVIOUS_VERSION', previousVersion); +/** + * Takes in two git tags and returns a list of PR numbers of all PRs merged between those two tags + */ +async function getPullRequestsMergedBetween(fromTag, toTag) { + console.log(`Looking for commits made between ${fromTag} and ${toTag}...`); + const commitList = await getCommitHistoryAsJSON(fromTag, toTag); + console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); + // Find which commit messages correspond to merged PR's + const pullRequestNumbers = getValidMergedPRs(commitList).sort((a, b) => a - b); + console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); + return pullRequestNumbers; +} +exports["default"] = { + getPreviousExistingTag, + getValidMergedPRs, + getPullRequestsMergedBetween, +}; + + +/***/ }), + +/***/ 902: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +/* eslint-disable @typescript-eslint/naming-convention */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +const replacer = (str) => ({ + '\\': '\\\\', + '\t': '\\t', + '\n': '\\n', + '\r': '\\r', + '\f': '\\f', + '"': '\\"', +}[str] ?? ''); +/** + * Replace any characters in the string that will break JSON.parse for our Git Log output + * + * Solution partly taken from SO user Gabriel Rodríguez Flores 🙇 + * https://stackoverflow.com/questions/52789718/how-to-remove-special-characters-before-json-parse-while-file-reading + */ +const sanitizeStringForJSONParse = (inputString) => { + if (typeof inputString !== 'string') { + throw new TypeError('Input must me of type String'); + } + // Replace any newlines and escape backslashes + return inputString.replace(/\\|\t|\n|\r|\f|"/g, replacer); +}; +exports["default"] = sanitizeStringForJSONParse; /***/ }), @@ -2743,7 +3039,7 @@ core.setOutput('PREVIOUS_VERSION', previousVersion); "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = void 0; +exports.getPreviousVersion = exports.incrementPatch = exports.incrementMinor = exports.SEMANTIC_VERSION_LEVELS = exports.MAX_INCREMENTS = exports.incrementVersion = exports.getVersionStringFromNumber = exports.getVersionNumberFromString = exports.isValidSemverLevel = void 0; const SEMANTIC_VERSION_LEVELS = { MAJOR: 'MAJOR', MINOR: 'MINOR', @@ -2753,6 +3049,10 @@ const SEMANTIC_VERSION_LEVELS = { exports.SEMANTIC_VERSION_LEVELS = SEMANTIC_VERSION_LEVELS; const MAX_INCREMENTS = 99; exports.MAX_INCREMENTS = MAX_INCREMENTS; +function isValidSemverLevel(str) { + return Object.keys(SEMANTIC_VERSION_LEVELS).includes(str); +} +exports.isValidSemverLevel = isValidSemverLevel; /** * Transforms a versions string into a number */ @@ -2846,6 +3146,14 @@ module.exports = require("assert"); /***/ }), +/***/ 81: +/***/ ((module) => { + +"use strict"; +module.exports = require("child_process"); + +/***/ }), + /***/ 113: /***/ ((module) => { diff --git a/.github/actions/javascript/getPullRequestDetails/index.js b/.github/actions/javascript/getPullRequestDetails/index.js index 14814367e3cd..8fa081de17fa 100644 --- a/.github/actions/javascript/getPullRequestDetails/index.js +++ b/.github/actions/javascript/getPullRequestDetails/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11660,13 +11660,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11686,6 +11684,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12041,12 +12048,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12087,27 +12113,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/getReleaseBody/index.js b/.github/actions/javascript/getReleaseBody/index.js index 6c746e26a4a4..81b73876db95 100644 --- a/.github/actions/javascript/getReleaseBody/index.js +++ b/.github/actions/javascript/getReleaseBody/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11604,13 +11604,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11630,6 +11628,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11985,12 +11992,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12031,27 +12057,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/isStagingDeployLocked/index.js b/.github/actions/javascript/isStagingDeployLocked/index.js index f71b89dc051c..feccd44beb1a 100644 --- a/.github/actions/javascript/isStagingDeployLocked/index.js +++ b/.github/actions/javascript/isStagingDeployLocked/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11558,13 +11558,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11584,6 +11582,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11939,12 +11946,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -11985,27 +12011,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/index.js b/.github/actions/javascript/markPullRequestsAsDeployed/index.js index 804d3ea610f3..ba474583a2fe 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/index.js +++ b/.github/actions/javascript/markPullRequestsAsDeployed/index.js @@ -6723,7 +6723,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11598,15 +11598,25 @@ async function run() { * 1. For regular staging deploys, the person who merged the PR. * 2. For CPs, the person who committed the cherry-picked commit (not necessarily the author of the commit). */ - const { data: pr } = await GithubUtils_1.default.octokit.pulls.get({ - owner: CONST_1.default.GITHUB_OWNER, - repo: CONST_1.default.APP_REPO, - pull_number: prNumber, - }); - const deployer = isCP ? commit.committer.name : pr.merged_by?.login; - const title = pr.title; - const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : ''; - await commentPR(prNumber, deployMessage); + try { + const { data: pr } = await GithubUtils_1.default.octokit.pulls.get({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + pull_number: prNumber, + }); + const deployer = isCP ? commit.committer.name : pr.merged_by?.login; + const title = pr.title; + const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : ''; + await commentPR(prNumber, deployMessage); + } + catch (error) { + if (error.status === 404) { + console.log(`Unable to comment on PR #${prNumber}. GitHub responded with 404.`); + } + else { + throw error; + } + } } } if (require.main === require.cache[eval('__filename')]) { @@ -11755,13 +11765,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11781,6 +11789,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12136,12 +12153,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12182,27 +12218,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts index a312bae7e7df..53018cbb035e 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts +++ b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention, import/no-import-module-exports */ import * as core from '@actions/core'; import {context} from '@actions/github'; +import type {RequestError} from '@octokit/types'; import * as ActionUtils from '@github/libs/ActionUtils'; import CONST from '@github/libs/CONST'; import GithubUtils from '@github/libs/GithubUtils'; @@ -113,16 +114,24 @@ async function run() { * 1. For regular staging deploys, the person who merged the PR. * 2. For CPs, the person who committed the cherry-picked commit (not necessarily the author of the commit). */ - const {data: pr} = await GithubUtils.octokit.pulls.get({ - owner: CONST.GITHUB_OWNER, - repo: CONST.APP_REPO, - pull_number: prNumber, - }); - const deployer = isCP ? commit.committer.name : pr.merged_by?.login; - - const title = pr.title; - const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : ''; - await commentPR(prNumber, deployMessage); + try { + const {data: pr} = await GithubUtils.octokit.pulls.get({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + pull_number: prNumber, + }); + const deployer = isCP ? commit.committer.name : pr.merged_by?.login; + + const title = pr.title; + const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : ''; + await commentPR(prNumber, deployMessage); + } catch (error) { + if ((error as RequestError).status === 404) { + console.log(`Unable to comment on PR #${prNumber}. GitHub responded with 404.`); + } else { + throw error; + } + } } } diff --git a/.github/actions/javascript/postTestBuildComment/index.js b/.github/actions/javascript/postTestBuildComment/index.js index 0b8eb29f1750..68f3b11f45f1 100644 --- a/.github/actions/javascript/postTestBuildComment/index.js +++ b/.github/actions/javascript/postTestBuildComment/index.js @@ -6723,7 +6723,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11657,13 +11657,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11683,6 +11681,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12038,12 +12045,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12084,27 +12110,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/reopenIssueWithComment/index.js b/.github/actions/javascript/reopenIssueWithComment/index.js index d4341ce37dc4..461f576e4691 100644 --- a/.github/actions/javascript/reopenIssueWithComment/index.js +++ b/.github/actions/javascript/reopenIssueWithComment/index.js @@ -6679,7 +6679,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11568,13 +11568,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11594,6 +11592,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11949,12 +11956,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -11995,27 +12021,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/reviewerChecklist/index.js b/.github/actions/javascript/reviewerChecklist/index.js index cc1c0b5a581b..5be97363a21c 100644 --- a/.github/actions/javascript/reviewerChecklist/index.js +++ b/.github/actions/javascript/reviewerChecklist/index.js @@ -6723,7 +6723,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11660,13 +11660,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11686,6 +11684,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12041,12 +12048,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12087,27 +12113,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/actions/javascript/verifySignedCommits/index.js b/.github/actions/javascript/verifySignedCommits/index.js index aea35331b1d0..c932e0c4c618 100644 --- a/.github/actions/javascript/verifySignedCommits/index.js +++ b/.github/actions/javascript/verifySignedCommits/index.js @@ -6723,7 +6723,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = (__nccwpck_require__(2877).convert); + convert = (__nccwpck_require__(3975).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11600,13 +11600,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11626,6 +11624,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11981,12 +11988,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; @@ -12027,27 +12053,27 @@ exports["default"] = arrayDifference; /***/ }), -/***/ 2877: +/***/ 9491: /***/ ((module) => { -module.exports = eval("require")("encoding"); - +"use strict"; +module.exports = require("assert"); /***/ }), -/***/ 9491: +/***/ 6113: /***/ ((module) => { "use strict"; -module.exports = require("assert"); +module.exports = require("crypto"); /***/ }), -/***/ 6113: +/***/ 3975: /***/ ((module) => { "use strict"; -module.exports = require("crypto"); +module.exports = require("encoding"); /***/ }), diff --git a/.github/libs/GitUtils.ts b/.github/libs/GitUtils.ts index dc8ae037be28..ab4a81f96adf 100644 --- a/.github/libs/GitUtils.ts +++ b/.github/libs/GitUtils.ts @@ -1,7 +1,8 @@ import {execSync, spawn} from 'child_process'; import CONST from './CONST'; import sanitizeStringForJSONParse from './sanitizeStringForJSONParse'; -import * as VERSION_UPDATER from './versionUpdater'; +import * as VersionUpdater from './versionUpdater'; +import type {SemverLevel} from './versionUpdater'; type CommitType = { commit: string; @@ -9,6 +10,64 @@ type CommitType = { authorName: string; }; +/** + * Check if a tag exists locally or in the remote. + */ +function tagExists(tag: string) { + try { + // Check if the tag exists locally + execSync(`git show-ref --tags ${tag}`, {stdio: 'ignore'}); + return true; // Tag exists locally + } catch (error) { + // Tag does not exist locally, check in remote + let shouldRetry = true; + let needsRepack = false; + let doesTagExist = false; + while (shouldRetry) { + try { + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + execSync('git repack -d', {stdio: 'inherit'}); + } + execSync(`git ls-remote --exit-code --tags origin ${tag}`, {stdio: 'ignore'}); + doesTagExist = true; + shouldRetry = false; + } catch (e) { + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } + } + return doesTagExist; + } +} + +/** + * This essentially just calls getPreviousVersion in a loop, until it finds a version for which a tag exists. + * It's useful if we manually perform a version bump, because in that case a tag may not exist for the previous version. + * + * @param tag the current tag + * @param level the Semver level to step backward by + */ +function getPreviousExistingTag(tag: string, level: SemverLevel) { + let previousVersion = VersionUpdater.getPreviousVersion(tag, level); + let tagExistsForPreviousVersion = false; + while (!tagExistsForPreviousVersion) { + if (tagExists(previousVersion)) { + tagExistsForPreviousVersion = true; + break; + } + console.log(`Tag for previous version ${previousVersion} does not exist. Checking for an older version...`); + previousVersion = VersionUpdater.getPreviousVersion(previousVersion, level); + } + return previousVersion; +} + /** * @param [shallowExcludeTag] When fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ @@ -53,8 +112,8 @@ function fetchTag(tag: string, shallowExcludeTag = '') { * Get merge logs between two tags (inclusive) as a JavaScript object. */ function getCommitHistoryAsJSON(fromTag: string, toTag: string): Promise { - // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history - const previousPatchVersion = VERSION_UPDATER.getPreviousVersion(fromTag, VERSION_UPDATER.SEMANTIC_VERSION_LEVELS.PATCH); + // Fetch tags, excluding commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousExistingTag(fromTag, VersionUpdater.SEMANTIC_VERSION_LEVELS.PATCH); fetchTag(fromTag, previousPatchVersion); fetchTag(toTag, previousPatchVersion); @@ -138,6 +197,7 @@ async function getPullRequestsMergedBetween(fromTag: string, toTag: string) { } export default { + getPreviousExistingTag, getValidMergedPRs, getPullRequestsMergedBetween, }; diff --git a/.github/libs/GithubUtils.ts b/.github/libs/GithubUtils.ts index f445fc368559..73553cb46bff 100644 --- a/.github/libs/GithubUtils.ts +++ b/.github/libs/GithubUtils.ts @@ -65,13 +65,11 @@ class GithubUtils { static internalOctokit: InternalOctokit | undefined; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token: string) { const Octokit = GitHub.plugin(throttling, paginateRest); - const token = core.getInput('GITHUB_TOKEN', {required: true}); // Save a copy of octokit used in this class this.internalOctokit = new Octokit( @@ -96,6 +94,16 @@ class GithubUtils { ); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', {required: true}); + this.initOctokitWithToken(token); + } + /** * Either give an existing instance of Octokit rest or create a new one * @@ -521,12 +529,32 @@ class GithubUtils { .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName: string): Promise { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { - owner: CONST.GITHUB_OWNER, - repo: CONST.APP_REPO, - per_page: 100, - }).then((artifacts: OctokitArtifact[]) => artifacts.find((artifact) => artifact.name === artefactName)); + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName: string): Promise { + return this.octokit.actions + .listArtifactsForRepo({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId: number): Promise { + return this.octokit.actions + .downloadArtifact({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } diff --git a/.github/libs/versionUpdater.ts b/.github/libs/versionUpdater.ts index 9b60fb82bd43..d9b24f532d8e 100644 --- a/.github/libs/versionUpdater.ts +++ b/.github/libs/versionUpdater.ts @@ -1,11 +1,18 @@ +import type {ValueOf} from 'type-fest'; + const SEMANTIC_VERSION_LEVELS = { MAJOR: 'MAJOR', MINOR: 'MINOR', PATCH: 'PATCH', BUILD: 'BUILD', } as const; +type SemverLevel = ValueOf; + +const MAX_INCREMENTS = 99; -const MAX_INCREMENTS = 99 as const; +function isValidSemverLevel(str: string): str is SemverLevel { + return Object.keys(SEMANTIC_VERSION_LEVELS).includes(str); +} /** * Transforms a versions string into a number @@ -46,7 +53,7 @@ const incrementPatch = (major: number, minor: number, patch: number): string => /** * Increments a build version */ -const incrementVersion = (version: string, level: string): string => { +const incrementVersion = (version: string, level: SemverLevel): string => { const [major, minor, patch, build] = getVersionNumberFromString(version); // Majors will always be incremented @@ -99,7 +106,9 @@ function getPreviousVersion(currentVersion: string, level: string): string { return getVersionStringFromNumber(major, minor, patch, build - 1); } +export type {SemverLevel}; export { + isValidSemverLevel, getVersionNumberFromString, getVersionStringFromNumber, incrementVersion, diff --git a/.github/scripts/buildActions.sh b/.github/scripts/buildActions.sh index 30c284a776be..27d65ca99c9b 100755 --- a/.github/scripts/buildActions.sh +++ b/.github/scripts/buildActions.sh @@ -43,7 +43,7 @@ for ((i=0; i < ${#GITHUB_ACTIONS[@]}; i++)); do ACTION_DIR=$(dirname "$ACTION") # Build the action in the background - ncc build -t "$ACTION" -o "$ACTION_DIR" & + npx ncc build --transpile-only --external encoding "$ACTION" -o "$ACTION_DIR" & ASYNC_BUILDS[i]=$! done diff --git a/.github/scripts/verifyActions.sh b/.github/scripts/verifyActions.sh index ddc8fa0a3226..17316e1aac70 100755 --- a/.github/scripts/verifyActions.sh +++ b/.github/scripts/verifyActions.sh @@ -22,7 +22,7 @@ if [[ EXIT_CODE -eq 0 ]]; then echo -e "${GREEN}Github Actions are up to date!${NC}" exit 0 else - echo -e "${RED}Error: Diff found when Github Actions were rebuilt. Did you forget to run \`npm run gh-actions-build\` after a clean install (\`rm -rf node_modules && npm i\`)? Do you need to merge main? Did you try running \`git config --global core.autocrlf false\` then \`npm run gh-actions-build\` again?${NC}" + echo -e "${RED}Error: Diff found when Github Actions were rebuilt. Did you forget to run \`npm run gh-actions-build\` after a clean install (\`rm -rf node_modules && npm i\`)? Do you need to merge main? Did you try running \`git config --global core.autocrlf false\` then \`npm run gh-actions-build\` again? Did you try running \`npx ncc cache clean\`?${NC}" echo "$DIFF_OUTPUT" | "$LIB_PATH/diff-so-fancy" | less --tabs=4 -RFX exit 1 fi diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index dd169a25c63d..640d1eaa1172 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -372,11 +372,11 @@ jobs: needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) && github.event_name == 'push' }} steps: - - name: Get version - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + - name: Checkout + uses: actions/checkout@v4 - name: 'Deploy HybridApp' - run: gh workflow run --repo Expensify/Mobile-Deploy deploy.yml -f force_build=true -f build_version=${{ env.VERSION }} + run: gh workflow run --repo Expensify/Mobile-Deploy deploy.yml -f force_build=true -f build_version="$(npm run print-version --silent)" env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d6b346cb3995..36d4248fcc3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ on: pull_request: types: [opened, synchronize] branches-ignore: [staging, production] - paths: ['**.js', '**.ts', '**.tsx', '**.sh', 'package.json', 'package-lock.json'] + paths: ['**.js', '**.ts', '**.tsx', 'package.json', 'package-lock.json'] concurrency: group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-jest @@ -54,20 +54,3 @@ jobs: - name: Storybook run run: npm run storybook -- --smoke-test --ci - - shellTests: - if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }} - runs-on: ubuntu-latest - name: Shell tests - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Install ts-node - run: npm i -g ts-node - - - name: Test CI git logic - run: tests/unit/CIGitLogicTest.sh diff --git a/.gitignore b/.gitignore index dcbec8a96e46..aa6aad4cc429 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,6 @@ config/webpack/*.pem .expo dist/ web-build/ + +# Storage location for downloaded app source maps (see scripts/symbolicate-profile.ts) +.sourcemaps/ diff --git a/android/app/build.gradle b/android/app/build.gradle index 18e95556867c..70c06d5bf9f6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -107,8 +107,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009000000 - versionName "9.0.0-0" + versionCode 1009000100 + versionName "9.0.1-0" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/assets/images/simple-illustrations/simple-illustration__treasurechest.svg b/assets/images/simple-illustrations/simple-illustration__treasurechest.svg index 2bdee0c7e90f..622c611a9dc5 100644 --- a/assets/images/simple-illustrations/simple-illustration__treasurechest.svg +++ b/assets/images/simple-illustrations/simple-illustration__treasurechest.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md index aec527edabe0..d6ab46c809ef 100644 --- a/contributingGuides/CONTRIBUTING.md +++ b/contributingGuides/CONTRIBUTING.md @@ -48,7 +48,7 @@ We hire and pay external contributors via [Upwork.com](https://www.upwork.com). Payment for your contributions will be made no less than 7 days after the pull request is deployed to production to allow for [regression](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions) testing. If you have not received payment after 8 days of the PR being deployed to production, and there are no [regressions](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions), please add a comment to the issue mentioning the BugZero team member (Look for the melvin-bot "Triggered auto assignment to... (`Bug`)" to see who this is). -New contributors are limited to working on one job at a time, however experienced contributors may work on numerous jobs simultaneously. +New contributors are limited to working on one job at a time, **do not submit proposals for new jobs until your first PR has been merged**. Experienced contributors may work on numerous jobs simultaneously. Please be aware that compensation for any support in solving an issue is provided **entirely at Expensify’s discretion**. Personal time or resources applied towards investigating a proposal **will not guarantee compensation**. Compensation is only guaranteed to those who **[propose a solution and get hired for that job](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#propose-a-solution-for-the-job)**. We understand there may be cases where a selected proposal may take inspiration from a previous proposal. Unfortunately, it’s not possible for us to evaluate every individual case and we have no process that can efficiently do so. Issues with higher rewards come with higher risk factors so try to keep things civil and make the best proposal you can. Once again, **any information provided may not necessarily lead to you getting hired for that issue or compensated in any way.** diff --git a/docs/articles/new-expensify/expenses/Manually-submit-reports-for-approval.md b/docs/Hidden/Manually-submit-reports-for-approval.md similarity index 100% rename from docs/articles/new-expensify/expenses/Manually-submit-reports-for-approval.md rename to docs/Hidden/Manually-submit-reports-for-approval.md diff --git a/docs/articles/new-expensify/expenses/Connect-a-Business-Bank-Account.md b/docs/articles/new-expensify/expenses/Connect-a-Business-Bank-Account.md index 64ae3997c4f9..516497c9dce7 100644 --- a/docs/articles/new-expensify/expenses/Connect-a-Business-Bank-Account.md +++ b/docs/articles/new-expensify/expenses/Connect-a-Business-Bank-Account.md @@ -20,7 +20,7 @@ To connect a bank account in New Expensify, you must first enable the Make or Tr 2. Select either Connect online with Plaid (preferred) or Connect manually 3. Enter bank details -# Step 4: Upload ID +# Step 3: Upload ID After entering your personal details, you’ll be prompted to click a link or scan a QR code so that you can do the following: 1. Upload a photo of the front and back of your ID (this cannot be a photo of an existing image) 2. Use your device to take a selfie and record a short video of yourself @@ -29,14 +29,14 @@ After entering your personal details, you’ll be prompted to click a link or sc - Issued in the US - Current (ie: the expiration date must be in the future) -# Step 5: Enter company information +# Step 4: Enter company information This is where you’ll add the legal business name as well as several other company details. - **Company address:** The company address must be located in the US and a physical location (If you input a maildrop address, PO box, or UPS Store, the address will be flagged for review, and adding the bank account to Expensify will be delayed) - **Tax Identification Number:** This is the identification number that was assigned to the business by the IRS - **Company website:** A company website is required to use most of Expensify’s payment features. - **Industry Classification Code:** You can locate a list of Industry Classification Codes [here](https://www.census.gov/naics/?input=software&year=2022). -# Step 6: Additional Information +# Step 5: Additional Information Check the appropriate box under Additional Information, accept the agreement terms, and verify that all of the information is true and accurate: - A Beneficial Owner refers to an individual who owns 25% or more of the business. - If you or another individual owns 25% or more of the business, please check the appropriate box diff --git a/docs/articles/new-expensify/expensify-card/Add-Expensify-Card-to-Apple-or-Google-Pay.md b/docs/articles/new-expensify/expensify-card/Add-Expensify-Card-to-Apple-or-Google-Pay.md new file mode 100644 index 000000000000..844a688e0011 --- /dev/null +++ b/docs/articles/new-expensify/expensify-card/Add-Expensify-Card-to-Apple-or-Google-Pay.md @@ -0,0 +1,32 @@ +--- +title: Add Expensify Card to Apple or Google Pay +description: Pay with your Expensify Card from your Apple or Google Pay wallet +--- +
+ +You can use your Expensify Card for contactless in-person payments by adding it to your digital wallet for Apple Pay (for iOS) or Google Pay (for Android). + +{% include selector.html values="mobile" %} + +{% include option.html value="mobile" %} +**Apple Pay** + +1. Open the Apple Pay app. +2. Tap the + button. +3. Tap **Debit or Credit Card**. +4. Tap **Continue**. +5. Follow the steps provided to add your virtual card. + +**Google Pay** + +1. Open the Google Pay app. +2. Tap **Add to Wallet**. +3. Tap **Payment Card**. +4. Tap **Add new debit or credit card**. +5. Add your virtual card details. + +{% include end-option.html %} + +{% include end-selector.html %} + +
diff --git a/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_1.png b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_1.png new file mode 100644 index 000000000000..4487e10d9719 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_2.png b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_2.png new file mode 100644 index 000000000000..600e5a7788ed Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_2.png differ diff --git a/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_3.png b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_3.png new file mode 100644 index 000000000000..dd0996a7eecd Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_CreateWorkspace_3.png differ diff --git a/docs/assets/images/ExpensifyHelp_R1_InviteMembers_1.png b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_1.png new file mode 100644 index 000000000000..874fb307f067 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_R1_InviteMembers_2.png b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_2.png new file mode 100644 index 000000000000..f5dae55fdcd4 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_2.png differ diff --git a/docs/assets/images/ExpensifyHelp_R1_InviteMembers_3.png b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_3.png new file mode 100644 index 000000000000..1d646d3d5001 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R1_InviteMembers_3.png differ diff --git a/docs/assets/images/ExpensifyHelp_R2_Profile_1.png b/docs/assets/images/ExpensifyHelp_R2_Profile_1.png new file mode 100644 index 000000000000..7e3e6ac181be Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R2_Profile_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_R3_Categories_1.png b/docs/assets/images/ExpensifyHelp_R3_Categories_1.png new file mode 100644 index 000000000000..47997df920de Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R3_Categories_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_R4_Tags_1.png b/docs/assets/images/ExpensifyHelp_R4_Tags_1.png new file mode 100644 index 000000000000..c8540d93423f Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R4_Tags_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_R4_Tags_2.png b/docs/assets/images/ExpensifyHelp_R4_Tags_2.png new file mode 100644 index 000000000000..a83d748ea12b Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R4_Tags_2.png differ diff --git a/docs/assets/images/ExpensifyHelp_R5_Wallet_1.png b/docs/assets/images/ExpensifyHelp_R5_Wallet_1.png new file mode 100644 index 000000000000..695dceb52581 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_R5_Wallet_1.png differ diff --git a/docs/redirects.csv b/docs/redirects.csv index 13463327d06d..b4912a629918 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -201,3 +201,4 @@ https://help.expensify.com/articles/expensify-classic/workspaces/reports/Report- https://help.expensify.com/articles/expensify-classic/workspaces/reports/Scheduled-Submit,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports https://help.expensify.com/articles/new-expensify/chat/Expensify-Chat-For-Admins,https://help.expensify.com/new-expensify/hubs/chat/ https://help.expensify.com/articles/new-expensify/bank-accounts-and-payments/Connect-a-Bank-Account.html,https://help.expensify.com/articles/new-expensify/expenses/Connect-a-Business-Bank-Account +https://help.expensify.com/articles/new-expensify/expenses/Manually-submit-reports-for-approval,https://help.expensify.com/new-expensify/hubs/expenses/ diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 23384a1402e5..2f9a259edbd4 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 9.0.0 + 9.0.1 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.0.0 + 9.0.1.0 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 2c4191ab0703..d406249b9a7f 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 9.0.0 + 9.0.1 CFBundleSignature ???? CFBundleVersion - 9.0.0.0 + 9.0.1.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 11eebb990594..c3a760235416 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 9.0.0 + 9.0.1 CFBundleVersion - 9.0.0.0 + 9.0.1.0 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ddab159714fc..35dccc2de393 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1865,7 +1865,7 @@ PODS: - RNGoogleSignin (10.0.1): - GoogleSignIn (~> 7.0) - React-Core - - RNLiveMarkdown (0.1.85): + - RNLiveMarkdown (0.1.88): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -1883,9 +1883,9 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNLiveMarkdown/common (= 0.1.85) + - RNLiveMarkdown/common (= 0.1.88) - Yoga - - RNLiveMarkdown/common (0.1.85): + - RNLiveMarkdown/common (0.1.88): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -2606,7 +2606,7 @@ SPEC CHECKSUMS: RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLiveMarkdown: fff70dc755ed8199a449f61e76cbadec7cd20440 + RNLiveMarkdown: e33d2c97863d5480f8f4b45f8b25f801cc43c7f5 RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c RNPermissions: 0b61d30d21acbeafe25baaa47d9bae40a0c65216 diff --git a/package-lock.json b/package-lock.json index 4db3048e6ab4..9af174f0846b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "new.expensify", - "version": "9.0.0-0", + "version": "9.0.1-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.0-0", + "version": "9.0.1-0", "hasInstallScript": true, "license": "MIT", "dependencies": { "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "0.1.85", + "@expensify/react-native-live-markdown": "0.1.88", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -60,11 +60,12 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.17", + "expensify-common": "2.0.19", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", "expo-image-manipulator": "11.8.0", + "fast-equals": "^4.0.3", "focus-trap-react": "^10.2.3", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", @@ -105,7 +106,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.50", + "react-native-onyx": "2.0.52", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -152,14 +153,14 @@ "@babel/runtime": "^7.20.0", "@babel/traverse": "^7.22.20", "@babel/types": "^7.22.19", - "@dword-design/eslint-plugin-import-alias": "^4.0.8", + "@dword-design/eslint-plugin-import-alias": "^5.0.0", "@electron/notarize": "^2.1.0", "@jest/globals": "^29.5.0", "@ngneat/falso": "^7.1.1", "@octokit/core": "4.0.4", "@octokit/plugin-paginate-rest": "3.1.0", "@octokit/plugin-throttling": "4.1.0", - "@react-native-community/eslint-config": "3.0.0", + "@react-native-community/eslint-config": "3.2.0", "@react-native/babel-preset": "^0.73.21", "@react-native/metro-config": "^0.73.5", "@react-navigation/devtools": "^6.0.10", @@ -187,12 +188,11 @@ "@types/setimmediate": "^1.0.2", "@types/webpack": "^5.28.5", "@types/webpack-bundle-analyzer": "^4.7.0", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", "@vercel/ncc": "0.38.1", "@welldone-software/why-did-you-render": "7.0.1", "ajv-cli": "^5.0.0", - "babel-eslint": "^10.1.0", "babel-jest": "29.4.1", "babel-loader": "^9.1.3", "babel-plugin-module-resolver": "^5.0.0", @@ -208,18 +208,16 @@ "dotenv": "^16.0.3", "electron": "^29.4.1", "electron-builder": "24.13.2", - "eslint": "^7.6.0", - "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-expensify": "^2.0.51", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^24.1.0", + "eslint": "^8.57.0", + "eslint-config-airbnb-typescript": "^18.0.0", + "eslint-config-expensify": "^2.0.52", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", - "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react-native-a11y": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", "eslint-plugin-testing-library": "^6.2.2", - "eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0", + "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0", "html-webpack-plugin": "^5.5.0", "jest": "29.4.1", "jest-circus": "29.4.1", @@ -242,6 +240,7 @@ "time-analytics-webpack-plugin": "^0.1.17", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "type-fest": "^4.10.2", "typescript": "^5.4.5", "wait-port": "^0.2.9", @@ -465,10 +464,10 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.23.10", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.7.tgz", + "integrity": "sha512-SO5E3bVxDuxyNxM5agFv480YA2HO6ohZbGxbazZdIk3KQOPOGVNw6q78I9/lbviIf95eq6tPozeYnJLbjnC8IA==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -479,14 +478,13 @@ }, "peerDependencies": { "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0" + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/eslint-parser/node_modules/semver": { "version": "6.3.1", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -2865,16 +2863,18 @@ }, "node_modules/@dword-design/dedent": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@dword-design/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-OFmAmzKiDUh9m7WRMYcoEOPI7b5tS5hdqQmtKDwF+ZssVJv8a+GHo9VOtFsmlw3h8Roh/9QzFWIsjSFZyQUMdg==", "dev": true, - "license": "MIT", "dependencies": { "babel-plugin-add-module-exports": "^1.0.2" } }, "node_modules/@dword-design/endent": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@dword-design/endent/-/endent-1.4.1.tgz", + "integrity": "sha512-e2sCTzth5kyRdM0o+yEb5wBVzUdJL8Y6HblRGRV0Bif0knf1ZjRLhUjdCrqM+Muirb68X/xJzgdRDJVmLqgXGA==", "dev": true, - "license": "MIT", "dependencies": { "@dword-design/dedent": "^0.7.0", "fast-json-parse": "^1.0.3", @@ -2882,35 +2882,37 @@ } }, "node_modules/@dword-design/eslint-plugin-import-alias": { - "version": "4.0.8", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@dword-design/eslint-plugin-import-alias/-/eslint-plugin-import-alias-5.0.0.tgz", + "integrity": "sha512-QbY2hA+YvhKiPJnAd9fOwT7gNV8OvaGLHdUsC6uVtyoUVjzx55WbUlzlEZzurlwDamXDlIB81IxbHgHT32Lx0w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.10.2", - "@dword-design/functions": "^5.0.22", + "@dword-design/functions": "^6.0.0", "babel-plugin-module-resolver": "^5.0.0", "deepmerge": "^4.3.1", "jiti": "^1.18.2" }, "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/dword-design" } }, "node_modules/@dword-design/functions": { - "version": "5.0.26", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@dword-design/functions/-/functions-6.0.0.tgz", + "integrity": "sha512-22X9eviXAbaz8xdYrp5Tj6KjDPiT+m3fppAP+wEqA3gecAlCyExABesA1bEZ57aXrXrbhNk88M8PvdAO/PLg3A==", "dev": true, - "license": "MIT", "dependencies": { "@dword-design/endent": "^1.0.0", - "delay": "^5.0.0", + "delay": "^6.0.0", "lodash": "^4.17.15", "tinycolor2": "^1.4.1" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/dword-design" @@ -3473,36 +3475,42 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3514,10 +3522,17 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.21.0", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -3528,23 +3543,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3562,9 +3583,9 @@ } }, "node_modules/@expensify/react-native-live-markdown": { - "version": "0.1.85", - "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.85.tgz", - "integrity": "sha512-jeP4JBzN34pGSpjHKM7Zj3d0cqcKbID3//WrqC+SI7SK/1iJT4SdhZptVCxUg+Dcxq5XwzYIhdnhTNimeya0Fg==", + "version": "0.1.88", + "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.88.tgz", + "integrity": "sha512-78X5ACV+OL+aL6pfJAXyHkNuMGUc4Rheo4qLkIwLpmUIAiAxmY0B2lch5XHSNGf1a5ofvVbdQ6kl84+4E6DwlQ==", "workspaces": [ "parser", "example", @@ -5672,13 +5693,15 @@ "license": "Apache-2.0" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -5698,9 +5721,11 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true }, "node_modules/@invertase/react-native-apple-authentication": { "version": "2.2.2", @@ -7386,7 +7411,6 @@ "version": "5.1.1-v1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "eslint-scope": "5.1.1" } @@ -8691,52 +8715,57 @@ } }, "node_modules/@react-native-community/eslint-config": { - "version": "3.0.0", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-3.2.0.tgz", + "integrity": "sha512-ZjGvoeiBtCbd506hQqwjKmkWPgynGUoJspG8/MuV/EfKnkjCtBmeJvq2n+sWbWEvL9LWXDp2GJmPzmvU5RSvKQ==", "dev": true, - "license": "MIT", "dependencies": { + "@babel/core": "^7.14.0", + "@babel/eslint-parser": "^7.18.2", "@react-native-community/eslint-plugin": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^4.22.1", - "@typescript-eslint/parser": "^4.22.1", - "babel-eslint": "^10.1.0", - "eslint-config-prettier": "^6.10.1", - "eslint-plugin-eslint-comments": "^3.1.2", - "eslint-plugin-flowtype": "2.50.3", - "eslint-plugin-jest": "22.4.1", - "eslint-plugin-prettier": "3.1.2", - "eslint-plugin-react": "^7.20.0", - "eslint-plugin-react-hooks": "^4.0.7", - "eslint-plugin-react-native": "^3.10.0", - "prettier": "^2.0.2" + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^26.5.3", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0" }, "peerDependencies": { - "eslint": ">=7" + "eslint": ">=8", + "prettier": ">=2" } }, "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -8745,24 +8774,25 @@ } }, "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/parser": { - "version": "4.33.0", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -8770,29 +8800,153 @@ } } }, - "node_modules/@react-native-community/eslint-config/node_modules/eslint-config-prettier": { - "version": "6.15.0", + "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, - "license": "MIT", "dependencies": { - "get-stdin": "^6.0.0" + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, "bin": { - "eslint-config-prettier-check": "bin/cli.js" + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { - "eslint": ">=3.14.1" + "eslint": ">=7.0.0" } }, "node_modules/@react-native-community/eslint-config/node_modules/eslint-plugin-jest": { - "version": "22.4.1", + "version": "26.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz", + "integrity": "sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng==", "dev": true, - "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": ">=5" + "@typescript-eslint/eslint-plugin": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/@react-native-community/eslint-config/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@react-native-community/eslint-plugin": { @@ -11104,29 +11258,6 @@ "node": ">=14.14" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@storybook/preview": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-8.0.6.tgz", @@ -12475,8 +12606,9 @@ }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -12799,86 +12931,31 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.2", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", + "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", "dev": true, - "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/type-utils": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/type-utils": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -12887,153 +12964,48 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.13.2", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.2", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", + "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -13041,43 +13013,17 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -13085,24 +13031,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.13.2", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", + "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/utils": "7.13.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -13110,49 +13057,58 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.13.2", + "node_modules/@typescript-eslint/types": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, - "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -13164,93 +13120,28 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "6.13.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/utils": { @@ -13366,21 +13257,34 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "7.13.1", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ua/react-native-airship": { "version": "17.2.1", "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-17.2.1.tgz", @@ -13961,14 +13865,6 @@ "version": "1.4.10", "license": "MIT" }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "license": "MIT", @@ -14558,6 +14454,7 @@ "version": "2.0.0", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8" } @@ -15010,8 +14907,9 @@ }, "node_modules/babel-plugin-add-module-exports": { "version": "1.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz", + "integrity": "sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==", + "dev": true }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", @@ -18143,11 +18041,12 @@ } }, "node_modules/delay": { - "version": "5.0.0", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-6.0.0.tgz", + "integrity": "sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -18909,17 +18808,6 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "2.2.0", "license": "BSD-2-Clause", @@ -19235,56 +19123,55 @@ } }, "node_modules/eslint": { - "version": "7.32.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -19337,23 +19224,23 @@ } }, "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-18.0.0.tgz", + "integrity": "sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==", "dev": true, - "license": "MIT", "dependencies": { "eslint-config-airbnb-base": "^15.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" } }, "node_modules/eslint-config-expensify": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.51.tgz", - "integrity": "sha512-qEUPCI9vsAi5c5E6zM4QEYal13hIRHFvonf4U/x0JI4ceMdAejOoq/Zvt9r1ZwKT1RmA8eRoGWWIQ/4O/9hJPg==", + "version": "2.0.52", + "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.52.tgz", + "integrity": "sha512-TUhtgsb+EUsfqhEGhSbUVgIypEhZjloYC8PEPxKKniaaG14SW/z1G3C5E4NJQ05xVdRwJ4H+shF7ZzOYbVcraQ==", "dev": true, "dependencies": { "@lwc/eslint-plugin-lwc": "^1.7.2", @@ -19373,77 +19260,6 @@ "underscore": "^1.13.6" } }, - "node_modules/eslint-config-expensify/node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-expensify/node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/eslint-config-expensify/node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "node_modules/eslint-config-expensify/node_modules/@typescript-eslint/parser": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", - "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/eslint-config-expensify/node_modules/@typescript-eslint/scope-manager": { "version": "7.12.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", @@ -19556,55 +19372,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-config-expensify/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/eslint-config-expensify/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint-config-expensify/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint-config-expensify/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/eslint-config-expensify/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -19614,111 +19381,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/eslint-config-expensify/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint-config-expensify/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint-config-expensify/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint-config-expensify/node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-expensify/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint-config-expensify/node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -19731,114 +19393,11 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-expensify/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-expensify/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint-config-expensify/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-config-expensify/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-config-expensify/node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-config-expensify/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint-config-expensify/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint-config-expensify/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-config-expensify/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-config-prettier": { - "version": "8.10.0", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, - "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -19954,18 +19513,21 @@ "node": ">=0.8.0" } }, - "node_modules/eslint-plugin-flowtype": { - "version": "2.50.3", + "node_modules/eslint-plugin-ft-flow": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz", + "integrity": "sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "lodash": "^4.17.10" + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" }, "engines": { - "node": ">=4" + "node": ">=12.22.0" }, "peerDependencies": { - "eslint": ">=2.0.0" + "@babel/eslint-parser": "^7.12.0", + "eslint": "^8.1.0" } }, "node_modules/eslint-plugin-import": { @@ -20017,6 +19579,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "dev": true, @@ -20025,26 +19599,74 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-import/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/eslint-plugin-jest": { - "version": "24.7.0", + "version": "28.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.6.0.tgz", + "integrity": "sha512-YG28E1/MIKwnz+e2H7VwYPzHUYU4aMa19w0yGcwXnnmJH6EfgHahTJ2un3IyraUxNfnz/KUhJAFXNNwWPo12tg==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "^4.0.1" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": ">= 4", - "eslint": ">=5" + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { "optional": true + }, + "jest": { + "optional": true } } }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, "node_modules/eslint-plugin-jsdoc": { "version": "46.2.6", "dev": true, @@ -20118,18 +19740,24 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "3.1.2", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", "dev": true, - "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=12.0.0" }, "peerDependencies": { - "eslint": ">= 5.0.0", - "prettier": ">= 1.13.0" + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } } }, "node_modules/eslint-plugin-react": { @@ -20173,15 +19801,15 @@ } }, "node_modules/eslint-plugin-react-native": { - "version": "3.11.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz", + "integrity": "sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/traverse": "^7.7.4", "eslint-plugin-react-native-globals": "^0.1.1" }, "peerDependencies": { - "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7" + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" } }, "node_modules/eslint-plugin-react-native-a11y": { @@ -20202,8 +19830,9 @@ }, "node_modules/eslint-plugin-react-native-globals": { "version": "0.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true }, "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", @@ -20291,9 +19920,9 @@ } }, "node_modules/eslint-plugin-you-dont-need-lodash-underscore": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-you-dont-need-lodash-underscore/-/eslint-plugin-you-dont-need-lodash-underscore-6.12.0.tgz", - "integrity": "sha512-WF4mNp+k2532iswT6iUd1BX6qjd3AV4cFy/09VC82GY9SsRtvkxhUIx7JNGSe0/bLyd57oTr4inPFiIaENXhGw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-you-dont-need-lodash-underscore/-/eslint-plugin-you-dont-need-lodash-underscore-6.14.0.tgz", + "integrity": "sha512-3zkkU/O1agczP7szJGHmisZJS/AknfVl6mb0Zqoc95dvFsdmfK+cbhrn+Ffy0UWB1pgDJwQr7kIO3rPstWs3Dw==", "dev": true, "dependencies": { "kebab-case": "^1.0.0" @@ -20320,23 +19949,6 @@ "node": ">=4.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, "node_modules/eslint-visitor-keys": { "version": "2.1.0", "dev": true, @@ -20345,14 +19957,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -20382,6 +19986,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -20413,26 +20023,44 @@ "dev": true, "license": "MIT" }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, "node_modules/eslint/node_modules/globals": { @@ -20457,12 +20085,25 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", + "node_modules/eslint/node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/eslint/node_modules/json-schema-traverse": { @@ -20493,24 +20134,44 @@ } }, "node_modules/espree": { - "version": "7.3.1", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -20770,9 +20431,9 @@ } }, "node_modules/expensify-common": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.17.tgz", - "integrity": "sha512-W7xO10/bYF/p0/cUOtzejXJDiLCB/U6JTXVltzOE70xjGgzTSyRotPkEtEItHTvXOS2Wz8jJ262nrGfFMpfisA==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.19.tgz", + "integrity": "sha512-GdWlYiHOAapy/jxjcvL9NKGOofhoEuKIwvJNGNVHbDXcA+0NxVCNYrHt1yrLnVcE4KtK6PGT6fQ2Lp8NTCoA+g==", "dependencies": { "awesome-phonenumber": "^5.4.0", "classnames": "2.5.0", @@ -22050,11 +21711,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/functions-have-names": { "version": "1.2.3", "dev": true, @@ -23340,8 +22996,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.2.4", - "license": "MIT", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "engines": { "node": ">= 4" } @@ -27690,11 +27347,6 @@ "version": "4.1.1", "license": "MIT" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.union": { "version": "4.6.0", "dev": true, @@ -29167,6 +28819,12 @@ "version": "1.4.0", "license": "MIT" }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/ncp": { "version": "2.0.0", "license": "MIT", @@ -30821,8 +30479,9 @@ }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -31949,9 +31608,9 @@ } }, "node_modules/react-native-onyx": { - "version": "2.0.50", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.50.tgz", - "integrity": "sha512-8pZX3G4GDsJerEOs9Q4srwh3ySg8T0DRt3hzcz0rBpVf0ZQOWJxWVhxgnN/M9bEh0gm5K5b0yfOHDZ/DdgtakA==", + "version": "2.0.52", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.52.tgz", + "integrity": "sha512-uXlNhQg1UStx1W/U+9GYtIhLvx3vTIpN1WwE1gsiVxvimnUzKpQX/JBkgpR9b48ZoxsdiZXOT5kKLlqGCa6O1g==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -35141,6 +34800,12 @@ "node": ">=10" } }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true + }, "node_modules/string-width": { "version": "4.2.3", "license": "MIT", @@ -35582,67 +35247,6 @@ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, - "node_modules/table": { - "version": "6.8.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/table/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/table/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -36086,8 +35690,9 @@ }, "node_modules/tinycolor2": { "version": "1.6.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "dev": true }, "node_modules/tinyqueue": { "version": "2.0.3", @@ -36386,25 +35991,17 @@ "license": "Apache-2.0" }, "node_modules/tsconfig-paths": { - "version": "3.15.0", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, - "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", + "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=6" } }, "node_modules/tsconfig-paths/node_modules/strip-bom": { @@ -37026,11 +36623,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "devOptional": true, diff --git a/package.json b/package.json index 49c8dc84a15d..3d679bd79557 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.0-0", + "version": "9.0.1-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", @@ -53,6 +53,7 @@ "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", "symbolicate-release:ios": "scripts/release-profile.ts --platform=ios", "symbolicate-release:android": "scripts/release-profile.ts --platform=android", + "symbolicate-profile": "scripts/symbolicate-profile.ts", "test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts", "test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", @@ -65,7 +66,7 @@ "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "0.1.85", + "@expensify/react-native-live-markdown": "0.1.88", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -112,11 +113,12 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.17", + "expensify-common": "2.0.19", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", "expo-image-manipulator": "11.8.0", + "fast-equals": "^4.0.3", "focus-trap-react": "^10.2.3", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", @@ -157,7 +159,7 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.50", + "react-native-onyx": "2.0.52", "react-native-pager-view": "6.2.3", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", @@ -204,14 +206,14 @@ "@babel/runtime": "^7.20.0", "@babel/traverse": "^7.22.20", "@babel/types": "^7.22.19", - "@dword-design/eslint-plugin-import-alias": "^4.0.8", + "@dword-design/eslint-plugin-import-alias": "^5.0.0", "@electron/notarize": "^2.1.0", "@jest/globals": "^29.5.0", "@ngneat/falso": "^7.1.1", "@octokit/core": "4.0.4", "@octokit/plugin-paginate-rest": "3.1.0", "@octokit/plugin-throttling": "4.1.0", - "@react-native-community/eslint-config": "3.0.0", + "@react-native-community/eslint-config": "3.2.0", "@react-native/babel-preset": "^0.73.21", "@react-native/metro-config": "^0.73.5", "@react-navigation/devtools": "^6.0.10", @@ -239,12 +241,11 @@ "@types/setimmediate": "^1.0.2", "@types/webpack": "^5.28.5", "@types/webpack-bundle-analyzer": "^4.7.0", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", "@vercel/ncc": "0.38.1", "@welldone-software/why-did-you-render": "7.0.1", "ajv-cli": "^5.0.0", - "babel-eslint": "^10.1.0", "babel-jest": "29.4.1", "babel-loader": "^9.1.3", "babel-plugin-module-resolver": "^5.0.0", @@ -260,18 +261,16 @@ "dotenv": "^16.0.3", "electron": "^29.4.1", "electron-builder": "24.13.2", - "eslint": "^7.6.0", - "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-expensify": "^2.0.51", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^24.1.0", + "eslint": "^8.57.0", + "eslint-config-airbnb-typescript": "^18.0.0", + "eslint-config-expensify": "^2.0.52", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", - "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react-native-a11y": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", "eslint-plugin-testing-library": "^6.2.2", - "eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0", + "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0", "html-webpack-plugin": "^5.5.0", "jest": "29.4.1", "jest-circus": "29.4.1", @@ -294,6 +293,7 @@ "time-analytics-webpack-plugin": "^0.1.17", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "type-fest": "^4.10.2", "typescript": "^5.4.5", "wait-port": "^0.2.9", diff --git a/patches/@expensify+react-native-live-markdown+0.1.85.patch b/patches/@expensify+react-native-live-markdown+0.1.85.patch new file mode 100644 index 000000000000..f745786a088e --- /dev/null +++ b/patches/@expensify+react-native-live-markdown+0.1.85.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@expensify/react-native-live-markdown/lib/module/web/cursorUtils.js b/node_modules/@expensify/react-native-live-markdown/lib/module/web/cursorUtils.js +index e975fb2..6a4b510 100644 +--- a/node_modules/@expensify/react-native-live-markdown/lib/module/web/cursorUtils.js ++++ b/node_modules/@expensify/react-native-live-markdown/lib/module/web/cursorUtils.js +@@ -53,7 +53,7 @@ function setCursorPosition(target, start, end = null) { + // 3. Caret at the end of whole input, when pressing enter + // 4. All other placements + if (prevChar === '\n' && prevTextLength !== undefined && prevTextLength < textCharacters.length) { +- if (nextChar !== '\n') { ++ if (nextChar !== '\n' && i !== n - 1 && nextChar) { + range.setStart(textNodes[i + 1], 0); + } else if (i !== textNodes.length - 1) { + range.setStart(textNodes[i], 1); diff --git a/scripts/.eslintrc.js b/scripts/.eslintrc.js new file mode 100644 index 000000000000..d6d39822b737 --- /dev/null +++ b/scripts/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + rules: { + // For all these Node.js scripts, we do not want to disable `console` statements + 'no-console': 'off', + + '@lwc/lwc/no-async-await': 'off', + 'no-await-in-loop': 'off', + 'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'], + }, +}; diff --git a/scripts/release-profile.ts b/scripts/release-profile.ts index 8ec0979f9f9e..cfc7e2cb8838 100755 --- a/scripts/release-profile.ts +++ b/scripts/release-profile.ts @@ -3,21 +3,7 @@ /* eslint-disable no-console */ import {execSync} from 'child_process'; import fs from 'fs'; - -type ArgsMap = Record; - -// Function to parse command-line arguments into a key-value object -function parseCommandLineArguments(): ArgsMap { - const args = process.argv.slice(2); // Skip node and script paths - const argsMap: ArgsMap = {}; - args.forEach((arg) => { - const [key, value] = arg.split('='); - if (key.startsWith('--')) { - argsMap[key.substring(2)] = value; - } - }); - return argsMap; -} +import parseCommandLineArguments from './utils/parseCommandLineArguments'; // Function to find .cpuprofile files in the current directory function findCpuProfileFiles() { diff --git a/scripts/symbolicate-profile.ts b/scripts/symbolicate-profile.ts new file mode 100755 index 000000000000..a100c05029dd --- /dev/null +++ b/scripts/symbolicate-profile.ts @@ -0,0 +1,174 @@ +#!/usr/bin/env ts-node + +/* eslint-disable @typescript-eslint/naming-convention */ + +/** + * This script helps to symbolicate a .cpuprofile file that was obtained from a specific (staging) app version (usually provided by a user using the app). + * + * @abstract + * + * 1. When creating a new deployment in our github actions, we upload the source map for android and iOS as artifacts. + * 2. The profiles created by the app on the user's device have the app version encoded in the filename. + * 3. This script takes in a .cpuprofile file, reads the app version from the filename, and downloads the corresponding source map from the artifacts using github's API. + * 4. It then uses the source map to symbolicate the .cpuprofile file using the `react-native-release-profiler` cli. + * + * @note For downloading an artifact a github token is required. + */ +import {execSync} from 'child_process'; +import fs from 'fs'; +import https from 'https'; +import path from 'path'; +import GithubUtils from '@github/libs/GithubUtils'; +import * as Logger from './utils/Logger'; +import parseCommandLineArguments from './utils/parseCommandLineArguments'; + +const argsMap = parseCommandLineArguments(); + +/* ============== INPUT VALIDATION ============== */ + +if (Object.keys(argsMap).length === 0 || argsMap.help !== undefined) { + Logger.log('Symbolicates a .cpuprofile file obtained from a specific app version by downloading the source map from the github action runs.'); + Logger.log('Usage: npm run symbolicate-profile -- --profile= --platform='); + Logger.log('Options:'); + Logger.log(' --profile= The .cpuprofile file to symbolicate'); + Logger.log(' --platform= The platform for which the source map was uploaded'); + Logger.log(' --gh-token Token to use for requests send to the GitHub API. By default tries to pick up from the environment variable GITHUB_TOKEN'); + Logger.log(' --help Display this help message'); + process.exit(0); +} + +if (argsMap.profile === undefined) { + Logger.error('Please specify the .cpuprofile file to symbolicate using --profile='); + process.exit(1); +} +if (!fs.existsSync(argsMap.profile)) { + Logger.error(`File ${argsMap.profile} does not exist.`); + process.exit(1); +} + +if (argsMap.platform === undefined) { + Logger.error('Please specify the platform using --platform=ios or --platform=android'); + process.exit(1); +} + +const githubToken = argsMap.ghToken ?? process.env.GITHUB_TOKEN; +if (githubToken === undefined) { + Logger.error('No GitHub token provided. Either set a GITHUB_TOKEN environment variable or pass it using --gh-token'); + process.exit(1); +} + +GithubUtils.initOctokitWithToken(githubToken); + +/* ============= EXTRACT APP VERSION ============= */ + +// Formatted as "Profile_trace_for_1.4.81-9.cpuprofile" +const appVersionRegex = /\d+\.\d+\.\d+(-\d+)?/; +const appVersion = argsMap.profile.match(appVersionRegex)?.[0]; +if (appVersion === undefined) { + Logger.error('Could not extract the app version from the profile filename.'); + process.exit(1); +} +Logger.info(`Found app version ${appVersion} in the profile filename`); + +/* ============== UTILITY FUNCTIONS ============== */ + +async function getWorkflowRunArtifact() { + const artifactName = `${argsMap.platform}-sourcemap-${appVersion}`; + Logger.info(`Fetching sourcemap artifact with name "${artifactName}"`); + const artifact = await GithubUtils.getArtifactByName(artifactName); + if (artifact === undefined) { + throw new Error(`Could not find the artifact ${artifactName}! Are you sure the deploy step succeeded?`); + } + return artifact.id; +} + +const sourcemapDir = path.resolve(__dirname, '../.sourcemaps'); + +function downloadFile(url: string) { + Logger.log(`Downloading file from URL: ${url}`); + if (!fs.existsSync(sourcemapDir)) { + Logger.info(`Creating download directory ${sourcemapDir}`); + fs.mkdirSync(sourcemapDir); + } + + const destination = path.join(sourcemapDir, `${argsMap.platform}-sourcemap-${appVersion}.zip`); + const file = fs.createWriteStream(destination); + return new Promise((resolve, reject) => { + https + .get(url, (response) => { + response.pipe(file); + file.on('finish', () => { + file.close(); + Logger.success(`Downloaded file to ${destination}`); + resolve(destination); + }); + }) + .on('error', (error) => { + fs.unlink(destination, () => { + reject(error); + }); + }); + }); +} + +function unpackZipFile(zipPath: string) { + Logger.info(`Unpacking file ${zipPath}`); + const command = `unzip -o ${zipPath} -d ${sourcemapDir}`; + execSync(command, {stdio: 'inherit'}); + Logger.info(`Deleting zip file ${zipPath}`); + return new Promise((resolve, reject) => { + fs.unlink(zipPath, (error) => (error ? reject(error) : resolve())); + }); +} + +const localSourceMapPath = path.join(sourcemapDir, `${appVersion}-${argsMap.platform}.map`); +function renameDownloadedSourcemapFile() { + const androidName = 'index.android.bundle.map'; + const iosName = 'main.jsbundle.map'; + const downloadSourcemapPath = path.join(sourcemapDir, argsMap.platform === 'ios' ? iosName : androidName); + + if (!fs.existsSync(downloadSourcemapPath)) { + Logger.error(`Could not find the sourcemap file ${downloadSourcemapPath}`); + process.exit(1); + } + + Logger.info(`Renaming sourcemap file to ${localSourceMapPath}`); + fs.renameSync(downloadSourcemapPath, localSourceMapPath); +} + +// Symbolicate using the downloaded source map +function symbolicateProfile() { + const command = `npx react-native-release-profiler --local ${argsMap.profile} --sourcemap-path ${localSourceMapPath}`; + execSync(command, {stdio: 'inherit'}); +} + +async function fetchAndProcessArtifact() { + const artifactId = await getWorkflowRunArtifact(); + const downloadUrl = await GithubUtils.getArtifactDownloadURL(artifactId); + const zipPath = await downloadFile(downloadUrl); + await unpackZipFile(zipPath); + renameDownloadedSourcemapFile(); +} + +/* ============== MAIN SCRIPT ============== */ + +async function runAsyncScript() { + // Step: check if source map locally already exists (if so we can skip the download) + if (fs.existsSync(localSourceMapPath)) { + Logger.success(`Found local source map at ${localSourceMapPath}`); + Logger.info('Skipping download step'); + } else { + // Step: Download the source map for the app version and then symbolicate the profile: + try { + await fetchAndProcessArtifact(); + } catch (error) { + Logger.error(error); + process.exit(1); + } + } + + // Finally, symbolicate the profile + symbolicateProfile(); +} + +runAsyncScript(); diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000000..2d548a3aa2ce --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} diff --git a/scripts/utils/Logger.ts b/scripts/utils/Logger.ts new file mode 100644 index 000000000000..a851f11ff74f --- /dev/null +++ b/scripts/utils/Logger.ts @@ -0,0 +1,37 @@ +const COLOR_DIM = '\x1b[2m'; +const COLOR_RESET = '\x1b[0m'; +const COLOR_YELLOW = '\x1b[33m'; +const COLOR_RED = '\x1b[31m'; +const COLOR_GREEN = '\x1b[32m'; + +const log = (...args: unknown[]) => { + console.debug(...args); +}; + +const info = (...args: unknown[]) => { + log('▶️', ...args); +}; + +const success = (...args: unknown[]) => { + const lines = ['✅', COLOR_GREEN, ...args, COLOR_RESET]; + log(...lines); +}; + +const warn = (...args: unknown[]) => { + const lines = ['⚠️', COLOR_YELLOW, ...args, COLOR_RESET]; + log(...lines); +}; + +const note = (...args: unknown[]) => { + const lines = [COLOR_DIM, ...args, COLOR_RESET]; + log(...lines); +}; + +const error = (...args: unknown[]) => { + const lines = ['🔴', COLOR_RED, ...args, COLOR_RESET]; + log(...lines); +}; + +const formatLink = (name: string | number, url: string) => `\x1b]8;;${url}\x1b\\${name}\x1b]8;;\x1b\\`; + +export {log, info, warn, note, error, success, formatLink}; diff --git a/scripts/utils/parseCommandLineArguments.ts b/scripts/utils/parseCommandLineArguments.ts new file mode 100644 index 000000000000..9bb1d340335e --- /dev/null +++ b/scripts/utils/parseCommandLineArguments.ts @@ -0,0 +1,19 @@ +type ArgsMap = Record; + +// Function to parse command-line arguments into a key-value object +export default function parseCommandLineArguments(): ArgsMap { + const args = process.argv.slice(2); // Skip node and script paths + const argsMap: ArgsMap = {}; + args.forEach((arg) => { + const [key, value] = arg.split('='); + if (key.startsWith('--')) { + const name = key.substring(2); + argsMap[name] = value; + // User may provide a help arg without any value + if (name.toLowerCase() === 'help' && !value) { + argsMap[name] = 'true'; + } + } + }); + return argsMap; +} diff --git a/src/CONST.ts b/src/CONST.ts index 1d6c3a92faa9..c485268b55e2 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -363,6 +363,8 @@ const CONST = { SPOTNANA_TRAVEL: 'spotnanaTravel', ACCOUNTING_ON_NEW_EXPENSIFY: 'accountingOnNewExpensify', XERO_ON_NEW_EXPENSIFY: 'xeroOnNewExpensify', + NETSUITE_ON_NEW_EXPENSIFY: 'netsuiteOnNewExpensify', + REPORT_FIELDS_FEATURE: 'reportFieldsFeature', }, BUTTON_STATES: { DEFAULT: 'default', @@ -1553,6 +1555,7 @@ const CONST = { }, IOU: { + MAX_RECENT_REPORTS_TO_SHOW: 5, // This is the transactionID used when going through the create expense flow so that it mimics a real transaction (like the edit flow) OPTIMISTIC_TRANSACTION_ID: '1', // Note: These payment types are used when building IOU reportAction message values in the server and should @@ -1798,6 +1801,7 @@ const CONST = { // Here we will add other connections names when we add support for them QBO: 'quickbooksOnline', XERO: 'xero', + NETSUITE: 'netsuite', }, SYNC_STAGE_NAME: { STARTING_IMPORT_QBO: 'startingImportQBO', @@ -1830,6 +1834,21 @@ const CONST = { XERO_SYNC_IMPORT_TAX_RATES: 'xeroSyncImportTaxRates', XERO_CHECK_CONNECTION: 'xeroCheckConnection', XERO_SYNC_TITLE: 'xeroSyncTitle', + NETSUITE_SYNC_CONNECTION: 'netSuiteSyncConnection', + NETSUITE_SYNC_CUSTOMERS: 'netSuiteSyncCustomers', + NETSUITE_SYNC_INIT_DATA: 'netSuiteSyncInitData', + NETSUITE_SYNC_IMPORT_TAXES: 'netSuiteSyncImportTaxes', + NETSUITE_SYNC_IMPORT_ITEMS: 'netSuiteSyncImportItems', + NETSUITE_SYNC_DATA: 'netSuiteSyncData', + NETSUITE_SYNC_ACCOUNTS: 'netSuiteSyncAccounts', + NETSUITE_SYNC_CURRENCIES: 'netSuiteSyncCurrencies', + NETSUITE_SYNC_CATEGORIES: 'netSuiteSyncCategories', + NETSUITE_SYNC_IMPORT_EMPLOYEES: 'netSuiteSyncImportEmployees', + NETSUITE_SYNC_REPORT_FIELDS: 'netSuiteSyncReportFields', + NETSUITE_SYNC_TAGS: 'netSuiteSyncTags', + NETSUITE_SYNC_UPDATE_DATA: 'netSuiteSyncUpdateConnectionData', + NETSUITE_SYNC_NETSUITE_REIMBURSED_REPORTS: 'netSuiteSyncNetSuiteReimbursedReports', + NETSUITE_SYNC_EXPENSIFY_REIMBURSED_REPORTS: 'netSuiteSyncExpensifyReimbursedReports', }, SYNC_STAGE_TIMEOUT_MINUTES: 20, }, @@ -2123,6 +2142,8 @@ const CONST = { SETTINGS: 'settings', LEAVE_ROOM: 'leaveRoom', PRIVATE_NOTES: 'privateNotes', + DELETE: 'delete', + MARK_AS_INCOMPLETE: 'markAsIncomplete', }, EDIT_REQUEST_FIELD: { AMOUNT: 'amount', @@ -3732,6 +3753,14 @@ const CONST = { REPORT: 'REPORT', }, + PROMOTED_ACTIONS: { + PIN: 'pin', + SHARE: 'share', + JOIN: 'join', + MESSAGE: 'message', + HOLD: 'hold', + }, + THUMBNAIL_IMAGE: { SMALL_SCREEN: { SIZE: 250, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8a20032b4f91..b5eea4228042 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -339,6 +339,9 @@ const ONYXKEYS = { /** Holds the checks used while transferring the ownership of the workspace */ POLICY_OWNERSHIP_CHANGE_CHECKS: 'policyOwnershipChangeChecks', + /** Stores info during review duplicates flow */ + REVIEW_DUPLICATES: 'reviewDuplicates', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', @@ -719,6 +722,7 @@ type OnyxValuesMapping = { [ONYXKEYS.CACHED_PDF_PATHS]: Record; [ONYXKEYS.POLICY_OWNERSHIP_CHANGE_CHECKS]: Record; [ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE]: OnyxTypes.QuickAction; + [ONYXKEYS.REVIEW_DUPLICATES]: OnyxTypes.ReviewDuplicates; [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: string; [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: string; [ONYXKEYS.NVP_BILLING_FUND_ID]: number; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index c1fdd68951fa..f39e4b5aa431 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -823,6 +823,11 @@ const ROUTES = { route: 'r/:reportID/transaction/:transactionID/receipt', getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, }, + TRANSACTION_DUPLICATE_REVIEW_PAGE: { + route: 'r/:threadReportID/duplicates/review', + getRoute: (threadReportID: string) => `r/${threadReportID}/duplicates/review` as const, + }, + POLICY_ACCOUNTING_XERO_IMPORT: { route: 'settings/workspaces/:policyID/accounting/xero/import', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f884cca94ef5..f89469873ac7 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -138,6 +138,7 @@ const SCREENS = { ROOM_INVITE: 'RoomInvite', REFERRAL: 'Referral', PROCESS_MONEY_REQUEST_HOLD: 'ProcessMoneyRequestHold', + TRANSACTION_DUPLICATE: 'TransactionDuplicate', TRAVEL: 'Travel', SEARCH_REPORT: 'SearchReport', SETTINGS_CATEGORIES: 'SettingsCategories', @@ -179,6 +180,10 @@ const SCREENS = { STATE_SELECTOR: 'Money_Request_State_Selector', }, + TRANSACTION_DUPLICATE: { + REVIEW: 'Transaction_Duplicate_Review', + }, + IOU_SEND: { ADD_BANK_ACCOUNT: 'IOU_Send_Add_Bank_Account', ADD_DEBIT_CARD: 'IOU_Send_Add_Debit_Card', diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index bcc5acf83653..35f5aeecb5a4 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -30,7 +30,7 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} const styles = useThemeStyles(); const {translate} = useLocalize(); - const originalMessage = reportClosedAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED ? reportClosedAction.originalMessage : null; + const originalMessage = ReportActionsUtils.isClosedAction(reportClosedAction) ? ReportActionsUtils.getOriginalMessage(reportClosedAction) : null; const archiveReason = originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; const actorPersonalDetails = personalDetails?.[reportClosedAction?.actorAccountID ?? -1]; let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(actorPersonalDetails); diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index ae09757b66e6..c3b5acafc6fc 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -594,7 +594,7 @@ export default withOnyx({ transaction: { key: ({report}) => { const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1'); - const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage.IOUTransactionID ?? '-1' : '-1'; + const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1'; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts index f2325eda532d..1e9c67cf84ac 100644 --- a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts +++ b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts @@ -4,20 +4,23 @@ import type {ValueOf} from 'type-fest'; import type {Attachment} from '@components/Attachments/types'; import * as FileUtils from '@libs/fileDownload/FileUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import {getReport} from '@libs/ReportUtils'; import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; import CONST from '@src/CONST'; import type {ReportAction, ReportActions} from '@src/types/onyx'; +import type {Note} from '@src/types/onyx/Report'; /** * Constructs the initial component state from report actions */ function extractAttachments( type: ValueOf, - {reportID, accountID, parentReportAction, reportActions}: {reportID?: string; accountID?: number; parentReportAction?: OnyxEntry; reportActions?: OnyxEntry}, + { + privateNotes, + accountID, + parentReportAction, + reportActions, + }: {privateNotes?: Record; accountID?: number; parentReportAction?: OnyxEntry; reportActions?: OnyxEntry}, ) { - const report = getReport(reportID); - const privateNotes = report?.privateNotes; const targetNote = privateNotes?.[Number(accountID)]?.note ?? ''; const attachments: Attachment[] = []; @@ -91,9 +94,9 @@ function extractAttachments( return; } - const decision = action?.message?.[0]?.moderationDecision?.decision; + const decision = ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision; const hasBeenFlagged = decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN; - const html = (action?.message?.[0]?.html ?? '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); + const html = ReportActionsUtils.getReportActionHtml(action).replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); htmlParser.write(html); }); htmlParser.end(); diff --git a/src/components/Attachments/AttachmentCarousel/index.native.tsx b/src/components/Attachments/AttachmentCarousel/index.native.tsx index aad307073c0f..15740725c42e 100644 --- a/src/components/Attachments/AttachmentCarousel/index.native.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.native.tsx @@ -33,7 +33,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const parentReportAction = report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : undefined; let targetAttachments: Attachment[] = []; if (type === CONST.ATTACHMENT_TYPE.NOTE && accountID) { - targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {reportID: report.reportID, accountID}); + targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {privateNotes: report.privateNotes, accountID}); } else { targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.REPORT, {parentReportAction, reportActions}); } diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 947569538d32..eeac97bc5fa5 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -59,7 +59,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const parentReportAction = report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : undefined; let targetAttachments: Attachment[] = []; if (type === CONST.ATTACHMENT_TYPE.NOTE && accountID) { - targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {reportID: report.reportID, accountID}); + targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {privateNotes: report.privateNotes, accountID}); } else { targetAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.REPORT, {parentReportAction, reportActions: reportActions ?? undefined}); } @@ -91,7 +91,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate(targetAttachments[initialPage]); } } - }, [reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate, accountID, report.reportID, type]); + }, [report.privateNotes, reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate, accountID, type]); // Scroll position is affected when window width is resized, so we readjust it on width changes useEffect(() => { diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 3a8a4e724948..d37c4348e510 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -20,6 +20,7 @@ import updateIsFullComposerAvailable from '@libs/ComposerUtils/updateIsFullCompo import * as EmojiUtils from '@libs/EmojiUtils'; import * as FileUtils from '@libs/fileDownload/FileUtils'; import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition'; +import Log from '@libs/Log'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import CONST from '@src/CONST'; import type {ComposerProps} from './types'; @@ -106,11 +107,22 @@ function Composer( const isScrollBarVisible = useIsScrollBarVisible(textInput, value ?? ''); const [prevScroll, setPrevScroll] = useState(); + // Those useEffects track changes of `shouldClear` and `onClear` independently. + useEffect(() => { + Log.info('[Composer] `shouldClear` value changed', true, {shouldClear}); + }, [shouldClear]); + + useEffect(() => { + Log.info('[Composer] `onClear` value changed', true, {shouldClear}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [onClear]); + useEffect(() => { if (!shouldClear) { return; } textInput.current?.clear(); + Log.info('[Composer] `textInput` cleared', true, {shouldClear}); onClear(); }, [shouldClear, onClear]); diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index b6d6bb13213c..315afd2dbddc 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -118,6 +118,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction, isSmallerIcon, shouldHa style={[styles.mapView, shouldHaveBorderRadius && styles.br4]} waypoints={waypointMarkers} styleURL={CONST.MAPBOX.STYLE_URL} + requireRouteToDisplayMap={requireRouteToDisplayMap} /> ) : ( Navigation.goBack()} /> diff --git a/src/components/CustomStylesForChildrenProvider.tsx b/src/components/CustomStylesForChildrenProvider.tsx new file mode 100644 index 000000000000..6fc7efa81ed8 --- /dev/null +++ b/src/components/CustomStylesForChildrenProvider.tsx @@ -0,0 +1,21 @@ +import React, {useMemo} from 'react'; +import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; + +type CustomStylesForChildrenContextType = StyleProp | null; + +const CustomStylesForChildrenContext = React.createContext(null); + +type CustomStylesForChildrenProviderProps = React.PropsWithChildren & { + style: StyleProp | null; +}; + +function CustomStylesForChildrenProvider({children, style}: CustomStylesForChildrenProviderProps) { + const value = useMemo(() => style, [style]); + + return {children}; +} + +CustomStylesForChildrenProvider.displayName = 'CustomStylesForChildrenProvider'; + +export default CustomStylesForChildrenProvider; +export {CustomStylesForChildrenContext}; diff --git a/src/components/DistanceMapView/index.android.tsx b/src/components/DistanceMapView/index.android.tsx index 629b05d7bccf..930b08cad2d5 100644 --- a/src/components/DistanceMapView/index.android.tsx +++ b/src/components/DistanceMapView/index.android.tsx @@ -3,18 +3,21 @@ import {View} from 'react-native'; import BlockingView from '@components/BlockingViews/BlockingView'; import * as Expensicons from '@components/Icon/Expensicons'; import MapView from '@components/MapView'; +import PendingMapView from '@components/MapView/PendingMapView'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type DistanceMapViewProps from './types'; -function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { +function DistanceMapView({overlayStyle, requireRouteToDisplayMap, ...rest}: DistanceMapViewProps) { const styles = useThemeStyles(); const [isMapReady, setIsMapReady] = useState(false); const {isOffline} = useNetwork(); const {translate} = useLocalize(); const theme = useTheme(); + const StyleUtils = useStyleUtils(); return ( <> @@ -29,14 +32,22 @@ function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { }} /> {!isMapReady && ( - - + + {/* The "map pending" text should only be shown in the IOU create flow. In the created IOU preview, only the icon should be shown. */} + {!requireRouteToDisplayMap ? ( + + ) : ( + + )} )} diff --git a/src/components/DistanceMapView/types.ts b/src/components/DistanceMapView/types.ts index 18213235445f..1621870d70ed 100644 --- a/src/components/DistanceMapView/types.ts +++ b/src/components/DistanceMapView/types.ts @@ -3,6 +3,10 @@ import type {MapViewProps} from '@components/MapView/MapViewTypes'; type DistanceMapViewProps = MapViewProps & { overlayStyle?: StyleProp; + + /** Whether it should display the Mapbox map only when the route/coordinates exist otherwise + * it will display pending map icon */ + requireRouteToDisplayMap?: boolean; }; export default DistanceMapViewProps; diff --git a/src/components/FeedbackSurvey.tsx b/src/components/FeedbackSurvey.tsx index 925448046076..a7b0732be1fb 100644 --- a/src/components/FeedbackSurvey.tsx +++ b/src/components/FeedbackSurvey.tsx @@ -92,7 +92,7 @@ function FeedbackSurvey({title, description, onSubmit, optionRowStyles}: Feedbac diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx index bed4cea31829..9df94e4c6114 100644 --- a/src/components/Form/FormProvider.tsx +++ b/src/components/Form/FormProvider.tsx @@ -350,7 +350,7 @@ function FormProvider( }); if (inputProps.shouldSaveDraft && !formID.includes('Draft')) { - FormActions.setDraftValues(formID as OnyxFormKey, {[inputKey]: value}); + FormActions.setDraftValues(formID, {[inputKey]: value}); } inputProps.onValueChange?.(value, inputKey); }, diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx index 345bd338f365..49850d73e2d7 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer.tsx @@ -3,14 +3,13 @@ import React, {useMemo} from 'react'; import type {TextStyle} from 'react-native'; import {StyleSheet} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import type {CustomRendererProps, TPhrasing, TText} from 'react-native-render-html'; import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getReport} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -34,8 +33,7 @@ const getMentionDetails = (htmlAttributeReportID: string, currentReport: OnyxEnt // Get mention details based on reportID from tag attribute if (!isEmpty(htmlAttributeReportID)) { - const report = getReport(htmlAttributeReportID); - + const report = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${htmlAttributeReportID}`]; reportID = report?.reportID ?? htmlAttributeReportID; mentionDisplayText = removeLeadingLTRAndHash(report?.reportName ?? report?.displayName ?? htmlAttributeReportID); // Get mention details from name inside tnode @@ -61,7 +59,8 @@ function MentionReportRenderer({style, tnode, TDefaultRenderer, reports, ...defa const htmlAttributeReportID = tnode.attributes.reportid; const currentReportID = useCurrentReportID(); - const currentReport = getReport(currentReportID?.currentReportID); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [currentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${currentReportID?.currentReportID || -1}`); // When we invite someone to a room they don't have the policy object, but we still want them to be able to see and click on report mentions, so we only check if the policyID in the report is from a workspace const isGroupPolicyReport = useMemo(() => currentReport && !isEmptyObject(currentReport) && !!currentReport.policyID && currentReport.policyID !== CONST.POLICY.ID_FAKE, [currentReport]); diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 60d5bf7034cc..efd67d6c6b50 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -119,7 +119,9 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${itemFullReport?.parentReportID}`]; const itemParentReportAction = itemParentReportActions?.[itemFullReport?.parentReportActionID ?? '-1']; const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${itemFullReport?.policyID}`]; - const transactionID = itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? itemParentReportAction.originalMessage.IOUTransactionID ?? '-1' : '-1'; + const transactionID = ReportActionsUtils.isMoneyRequestAction(itemParentReportAction) + ? ReportActionsUtils.getOriginalMessage(itemParentReportAction)?.IOUTransactionID ?? '-1' + : '-1'; const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const hasDraftComment = DraftCommentUtils.isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]); const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions); @@ -128,8 +130,8 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio // Get the transaction for the last report action let lastReportActionTransactionID = ''; - if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - lastReportActionTransactionID = lastReportAction.originalMessage?.IOUTransactionID ?? '-1'; + if (ReportActionsUtils.isMoneyRequestAction(lastReportAction)) { + lastReportActionTransactionID = ReportActionsUtils.getOriginalMessage(lastReportAction)?.IOUTransactionID ?? '-1'; } const lastReportActionTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${lastReportActionTransactionID}`] ?? {}; diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx index 6e0dbf267151..c7797a37fd12 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.tsx +++ b/src/components/LHNOptionsList/OptionRowLHN.tsx @@ -2,6 +2,7 @@ import {useFocusEffect} from '@react-navigation/native'; import React, {useCallback, useRef, useState} from 'react'; import type {GestureResponderEvent, ViewStyle} from 'react-native'; import {StyleSheet, View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import DisplayNames from '@components/DisplayNames'; import Hoverable from '@components/Hoverable'; import Icon from '@components/Icon'; @@ -26,6 +27,7 @@ import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManag import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {OptionRowLHNProps} from './types'; @@ -37,6 +39,9 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti const isFocusedRef = useRef(true); const {shouldUseNarrowLayout} = useResponsiveLayout(); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${optionItem?.reportID || -1}`); + const {translate} = useLocalize(); const [isContextMenuActive, setIsContextMenuActive] = useState(false); @@ -120,7 +125,6 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti const statusClearAfterDate = optionItem.status?.clearAfter ?? ''; const formattedDate = DateUtils.getStatusUntilDate(statusClearAfterDate); const statusContent = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; - const report = ReportUtils.getReport(optionItem.reportID ?? '-1'); const isStatusVisible = !!emojiCode && ReportUtils.isOneOnOneChat(!isEmptyObject(report) ? report : undefined); const isGroupChat = ReportUtils.isGroupChat(optionItem) || ReportUtils.isDeprecatedGroupDM(optionItem); diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 48d820ae5103..c6be99297182 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -166,8 +166,41 @@ const MapView = forwardRef( }); }, [directionCoordinates, currentPosition, mapPadding, waypoints]); - const centerCoordinate = currentPosition ? [currentPosition.longitude, currentPosition.latitude] : initialState?.location; - return !isOffline && !!accessToken && !!currentPosition ? ( + const centerCoordinate = useMemo(() => (currentPosition ? [currentPosition.longitude, currentPosition.latitude] : initialState?.location), [currentPosition, initialState?.location]); + + const waypointsBounds = useMemo(() => { + if (!waypoints) { + return undefined; + } + const {northEast, southWest} = utils.getBounds( + waypoints.map((waypoint) => waypoint.coordinate), + directionCoordinates, + ); + return {ne: northEast, sw: southWest}; + }, [waypoints, directionCoordinates]); + + const defaultSettings: Mapbox.CameraStop | undefined = useMemo(() => { + if (interactive) { + if (!centerCoordinate) { + return undefined; + } + return { + zoomLevel: initialState?.zoom, + centerCoordinate, + }; + } + if (!waypointsBounds) { + return undefined; + } + return { + bounds: waypointsBounds, + }; + }, [interactive, centerCoordinate, waypointsBounds, initialState?.zoom]); + + const initCenterCoordinate = useMemo(() => (interactive ? centerCoordinate : undefined), [interactive, centerCoordinate]); + const initBounds = useMemo(() => (interactive ? undefined : waypointsBounds), [interactive, waypointsBounds]); + + return !isOffline && !!accessToken && !!defaultSettings ? ( ( > - - - + > + + + )} {waypoints?.map(({coordinate, markerComponent, id}) => { const MarkerComponent = markerComponent; - if (utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0])) { + if (utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]) && interactive) { return null; } return ( @@ -235,15 +268,18 @@ const MapView = forwardRef( {directionCoordinates && } - -