diff --git a/.gitignore b/.gitignore
index 8265d5fd272b..94c646a04246 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,3 +94,4 @@ storybook-static
# E2E test reports
tests/e2e/results/
+.reassure
diff --git a/android/app/build.gradle b/android/app/build.gradle
index b0fa64f57a50..9227a6b382b9 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -106,8 +106,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001032002
- versionName "1.3.20-2"
+ versionCode 1001032200
+ versionName "1.3.22-0"
}
splits {
diff --git a/assets/images/flag.svg b/assets/images/flag.svg
new file mode 100644
index 000000000000..9b6737459fbd
--- /dev/null
+++ b/assets/images/flag.svg
@@ -0,0 +1,7 @@
+
+
+
diff --git a/assets/images/flag_level_01.svg b/assets/images/flag_level_01.svg
new file mode 100644
index 000000000000..a4259deb0d2c
--- /dev/null
+++ b/assets/images/flag_level_01.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/assets/images/flag_level_02.svg b/assets/images/flag_level_02.svg
new file mode 100644
index 000000000000..9d7010dbb7f9
--- /dev/null
+++ b/assets/images/flag_level_02.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/assets/images/flag_level_03.svg b/assets/images/flag_level_03.svg
new file mode 100644
index 000000000000..14fc80792cc2
--- /dev/null
+++ b/assets/images/flag_level_03.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/dangerfile.js b/dangerfile.js
new file mode 100644
index 000000000000..1fa05fde711f
--- /dev/null
+++ b/dangerfile.js
@@ -0,0 +1,7 @@
+/* eslint-disable import/no-extraneous-dependencies */
+import path from 'path';
+import {dangerReassure} from 'reassure';
+
+dangerReassure({
+ inputFilePath: path.join(__dirname, './.reassure/output.md'),
+});
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index a67bdda052dd..323e7336b19f 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.3.20
+ 1.3.22
CFBundleSignature
????
CFBundleURLTypes
@@ -30,7 +30,7 @@
CFBundleVersion
- 1.3.20.2
+ 1.3.22.0
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 86d52d04cc68..28a5b85a6a97 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.20
+ 1.3.22
CFBundleSignature
????
CFBundleVersion
- 1.3.20.2
+ 1.3.22.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 055d696ec5d8..65bf60c3bd89 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -16,7 +16,7 @@ PODS:
- Airship/Core
- Airship/PreferenceCenter (16.11.3):
- Airship/Core
- - AirshipFrameworkProxy (2.0.5):
+ - AirshipFrameworkProxy (2.0.8):
- Airship (= 16.11.3)
- Airship/MessageCenter (= 16.11.3)
- Airship/PreferenceCenter (= 16.11.3)
@@ -495,8 +495,8 @@ PODS:
- React-jsinspector (0.71.2-alpha.3)
- React-logger (0.71.2-alpha.3):
- glog
- - react-native-airship (15.2.3):
- - AirshipFrameworkProxy (= 2.0.5)
+ - react-native-airship (15.2.6):
+ - AirshipFrameworkProxy (= 2.0.8)
- React-Core
- react-native-blob-util (0.17.3):
- React-Core
@@ -1018,8 +1018,8 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Airship: c70eed50e429f97f5adb285423c7291fb7a032ae
- AirshipFrameworkProxy: 2eefb77bb77b5120b0f48814b0d44439aa3ad415
- boost: 57d2868c099736d80fcd648bf211b4431e51a558
+ AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99
+ boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f
@@ -1062,7 +1062,7 @@ SPEC CHECKSUMS:
Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4
Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
- RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
+ RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be
RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30
React: a71c8e1380f07e01de721ccd52bcf9c03e81867d
@@ -1076,7 +1076,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 6f986feb67cf66edff7f98090ca797a67d0a44fb
React-jsinspector: 31517b1de3fadf93ad8558840a8974c7a7160bd3
React-logger: b90aa6ed0dbc30717dc72d843af3cf4550297b22
- react-native-airship: 25045092934bf6eabf483e803af0a6e31826b8b9
+ react-native-airship: 5d19f4ba303481cf4101ff9dee9249ef6a8a6b64
react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6
react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151
react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e
diff --git a/package-lock.json b/package-lock.json
index f67e98694149..80dd7c471541 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.20-2",
+ "version": "1.3.22-0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.20-2",
+ "version": "1.3.22-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -35,13 +35,13 @@
"@react-navigation/native": "6.0.13",
"@react-navigation/stack": "6.3.1",
"@react-ng/bounds-observer": "^0.2.1",
- "@ua/react-native-airship": "^15.2.3",
+ "@ua/react-native-airship": "^15.2.6",
"awesome-phonenumber": "^5.4.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-polyfill": "^6.26.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#68abe48ad71a98604fdbf5e8e960023ed5807ec2",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#c898563fe851d9a4d594fa9afbdd1ddab5971636",
"fbjs": "^3.0.2",
"html-entities": "^1.3.1",
"htmlparser2": "^7.2.0",
@@ -142,6 +142,7 @@
"concurrently": "^5.3.0",
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^6.7.2",
+ "danger": "^11.2.6",
"diff-so-fancy": "^1.3.0",
"dotenv": "^16.0.3",
"electron": "22.3.7",
@@ -171,6 +172,7 @@
"react-native-performance-flipper-reporter": "^2.0.0",
"react-native-svg-transformer": "^1.0.0",
"react-test-renderer": "18.1.0",
+ "reassure": "^0.9.0",
"setimmediate": "^1.0.5",
"shellcheck": "^1.1.0",
"style-loader": "^2.0.0",
@@ -2043,10 +2045,11 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.18.9",
- "license": "MIT",
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz",
+ "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==",
"dependencies": {
- "regenerator-runtime": "^0.13.4"
+ "regenerator-runtime": "^0.13.11"
},
"engines": {
"node": ">=6.9.0"
@@ -2131,6 +2134,252 @@
"integrity": "sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==",
"dev": true
},
+ "node_modules/@callstack/reassure-cli": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-cli/-/reassure-cli-0.9.0.tgz",
+ "integrity": "sha512-auoxqyilxkT5mDdEPJqRRY+ZGlrihJjFQpopcFd/15ng76OPVka3L48RMEY2wXkFXLaOOs6enNGb596jYPuEtQ==",
+ "dev": true,
+ "dependencies": {
+ "@callstack/reassure-compare": "0.5.0",
+ "@callstack/reassure-logger": "0.3.0",
+ "chalk": "4.1.2",
+ "simple-git": "^3.16.0",
+ "yargs": "^17.6.2"
+ },
+ "bin": {
+ "reassure": "lib/commonjs/bin.js"
+ }
+ },
+ "node_modules/@callstack/reassure-cli/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/@callstack/reassure-cli/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/@callstack/reassure-cli/node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@callstack/reassure-cli/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/@callstack/reassure-cli/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/@callstack/reassure-cli/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/@callstack/reassure-cli/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/@callstack/reassure-cli/node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@callstack/reassure-cli/node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@callstack/reassure-cli/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@callstack/reassure-compare": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-compare/-/reassure-compare-0.5.0.tgz",
+ "integrity": "sha512-3sBeJ/+Hxjdb01KVb8LszO1kcJ8TXcrVnerUj+LYn2dkBOohAMqGYaOvCeoWsVEHJ+MIOzmvAGBJQRu69RoJdQ==",
+ "dev": true,
+ "dependencies": {
+ "@callstack/reassure-logger": "0.3.0",
+ "markdown-builder": "^0.9.0",
+ "markdown-table": "^2.0.0",
+ "zod": "^3.20.2"
+ }
+ },
+ "node_modules/@callstack/reassure-danger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-danger/-/reassure-danger-0.1.1.tgz",
+ "integrity": "sha512-lfza+qBdvVYtP7WvMTT+LfjBfuYsXZ4RxuBldsL8wJArGeCl3OZwUg+9bTo8v6kk/nY8memk5HxrCwWDSO24UA==",
+ "dev": true
+ },
+ "node_modules/@callstack/reassure-logger": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-logger/-/reassure-logger-0.3.0.tgz",
+ "integrity": "sha512-JX5o+8qkIbIRL+cQn9XlQYdv9p/3L6J70zZX6NYi9j0VrSS9PZIRfo8ujMdLSqUNV6HZN1ay59RzuncLjVu0aQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "4.1.2"
+ }
+ },
+ "node_modules/@callstack/reassure-logger/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/@callstack/reassure-logger/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/@callstack/reassure-logger/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/@callstack/reassure-logger/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/@callstack/reassure-logger/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/@callstack/reassure-logger/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/@callstack/reassure-measure": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-measure/-/reassure-measure-0.5.0.tgz",
+ "integrity": "sha512-KwlmNYcspBOp7FIw6XOz5O9mnKB4cWCCyM6vG4nFUPHSWQ6yVdRkawVvoPIV5qJ2hw7zCzdtqRrLWQSTF4eKlg==",
+ "dev": true,
+ "dependencies": {
+ "@callstack/reassure-logger": "0.3.0",
+ "mathjs": "^11.5.0"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/@cnakazawa/watch": {
"version": "1.0.4",
"dev": true,
@@ -2571,6 +2820,70 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@gitbeaker/core": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-21.7.0.tgz",
+ "integrity": "sha512-cw72rE7tA27wc6JJe1WqeAj9v/6w0S7XJcEji+bRNjTlUfE1zgfW0Gf1mbGUi7F37SOABGCosQLfg9Qe63aIqA==",
+ "dev": true,
+ "dependencies": {
+ "@gitbeaker/requester-utils": "^21.7.0",
+ "form-data": "^3.0.0",
+ "li": "^1.3.0",
+ "xcase": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@gitbeaker/node": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/node/-/node-21.7.0.tgz",
+ "integrity": "sha512-OdM3VcTKYYqboOsnbiPcO0XimXXpYK4gTjARBZ6BWc+1LQXKmqo+OH6oUbyxOoaFu9hHECafIt3WZU3NM4sZTg==",
+ "deprecated": "Please use its successor @gitbeaker/rest",
+ "dev": true,
+ "dependencies": {
+ "@gitbeaker/core": "^21.7.0",
+ "@gitbeaker/requester-utils": "^21.7.0",
+ "form-data": "^3.0.0",
+ "got": "^11.1.4",
+ "xcase": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@gitbeaker/requester-utils": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-21.7.0.tgz",
+ "integrity": "sha512-eLTaVXlBnh8Qimj6QuMMA06mu/mLcJm3dy8nqhhn/Vm/D25sPrvpGwmbfFyvzj6QujPqtHvFfsCHtyZddL01qA==",
+ "dev": true,
+ "dependencies": {
+ "form-data": "^3.0.0",
+ "query-string": "^6.12.1",
+ "xcase": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@gitbeaker/requester-utils/node_modules/query-string": {
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
+ "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==",
+ "dev": true,
+ "dependencies": {
+ "decode-uri-component": "^0.2.0",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@gorhom/portal": {
"version": "1.0.14",
"license": "MIT",
@@ -4230,6 +4543,21 @@
"react-native": "*"
}
},
+ "node_modules/@kwsites/file-exists": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+ "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1"
+ }
+ },
+ "node_modules/@kwsites/promise-deferred": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+ "dev": true
+ },
"node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.4",
"dev": true,
@@ -4585,6 +4913,15 @@
"@octokit/core": ">=4"
}
},
+ "node_modules/@octokit/plugin-request-log": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+ "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
+ "dev": true,
+ "peerDependencies": {
+ "@octokit/core": ">=3"
+ }
+ },
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"dev": true,
@@ -4667,6 +5004,101 @@
"@octokit/openapi-types": "^13.1.0"
}
},
+ "node_modules/@octokit/rest": {
+ "version": "18.12.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
+ "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/core": "^3.5.1",
+ "@octokit/plugin-paginate-rest": "^2.16.8",
+ "@octokit/plugin-request-log": "^1.0.4",
+ "@octokit/plugin-rest-endpoint-methods": "^5.12.0"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/core": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+ "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.3",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": {
+ "version": "2.21.3",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+ "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/types": "^6.40.0"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=2"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/rest/node_modules/@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
"node_modules/@octokit/types": {
"version": "6.41.0",
"dev": true,
@@ -15634,9 +16066,9 @@
}
},
"node_modules/@ua/react-native-airship": {
- "version": "15.2.3",
- "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.3.tgz",
- "integrity": "sha512-94fgHJcxc4qUy9OmBqt6VuuWggoeCMNIosz3/qwiUNsUVoE1deWcOEG9vULmXcTKX+O9Wal/mKsuPGiFCALTDQ==",
+ "version": "15.2.6",
+ "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.6.tgz",
+ "integrity": "sha512-dVlBPPYXD/4SEshv/X7mmt3xF8WfnNqiSNzCyqJSLAZ1aJuPpP9Z5WemCYsa2iv6goRZvtJSE4P79QKlfoTwXw==",
"engines": {
"node": ">= 16.0.0"
},
@@ -16755,6 +17187,24 @@
"version": "1.0.1",
"license": "MIT"
},
+ "node_modules/async-retry": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.2.3.tgz",
+ "integrity": "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q==",
+ "dev": true,
+ "dependencies": {
+ "retry": "0.12.0"
+ }
+ },
+ "node_modules/async-retry/node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"dev": true,
@@ -18337,6 +18787,12 @@
"node": ">=0.4.0"
}
},
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "dev": true
+ },
"node_modules/buffer-fill": {
"version": "1.0.0",
"dev": true,
@@ -19378,6 +19834,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/complex.js": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
+ "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://www.patreon.com/infusion"
+ }
+ },
"node_modules/component-emitter": {
"version": "1.3.0",
"license": "MIT"
@@ -20542,6 +21011,92 @@
"dev": true,
"license": "BSD-2-Clause"
},
+ "node_modules/danger": {
+ "version": "11.2.6",
+ "resolved": "https://registry.npmjs.org/danger/-/danger-11.2.6.tgz",
+ "integrity": "sha512-EEeuDmUcxPGJ166q7Zzz1WEiV+e0qbPopaX4sXxds8U5doGMdw/8oOUOVye7JiHIBuss3KvQWt4YHZeD3jSCfw==",
+ "dev": true,
+ "dependencies": {
+ "@gitbeaker/node": "^21.3.0",
+ "@octokit/rest": "^18.12.0",
+ "async-retry": "1.2.3",
+ "chalk": "^2.3.0",
+ "commander": "^2.18.0",
+ "core-js": "^3.8.2",
+ "debug": "^4.1.1",
+ "fast-json-patch": "^3.0.0-1",
+ "get-stdin": "^6.0.0",
+ "http-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^5.0.1",
+ "hyperlinker": "^1.0.0",
+ "json5": "^2.1.0",
+ "jsonpointer": "^5.0.0",
+ "jsonwebtoken": "^9.0.0",
+ "lodash.find": "^4.6.0",
+ "lodash.includes": "^4.3.0",
+ "lodash.isobject": "^3.0.2",
+ "lodash.keys": "^4.0.8",
+ "lodash.mapvalues": "^4.6.0",
+ "lodash.memoize": "^4.1.2",
+ "memfs-or-file-map-to-github-branch": "^1.2.1",
+ "micromatch": "^4.0.4",
+ "node-cleanup": "^2.1.2",
+ "node-fetch": "^2.6.7",
+ "override-require": "^1.1.1",
+ "p-limit": "^2.1.0",
+ "parse-diff": "^0.7.0",
+ "parse-git-config": "^2.0.3",
+ "parse-github-url": "^1.0.2",
+ "parse-link-header": "^2.0.0",
+ "pinpoint": "^1.1.0",
+ "prettyjson": "^1.2.1",
+ "readline-sync": "^1.4.9",
+ "regenerator-runtime": "^0.13.9",
+ "require-from-string": "^2.0.2",
+ "supports-hyperlinks": "^1.0.1"
+ },
+ "bin": {
+ "danger": "distribution/commands/danger.js",
+ "danger-ci": "distribution/commands/danger-ci.js",
+ "danger-init": "distribution/commands/danger-init.js",
+ "danger-js": "distribution/commands/danger.js",
+ "danger-local": "distribution/commands/danger-local.js",
+ "danger-pr": "distribution/commands/danger-pr.js",
+ "danger-process": "distribution/commands/danger-process.js",
+ "danger-reset-status": "distribution/commands/danger-reset-status.js",
+ "danger-runner": "distribution/commands/danger-runner.js"
+ },
+ "engines": {
+ "node": ">=14.13.1"
+ }
+ },
+ "node_modules/danger/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/danger/node_modules/fast-json-patch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz",
+ "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==",
+ "dev": true
+ },
+ "node_modules/danger/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/data-urls": {
"version": "3.0.2",
"dev": true,
@@ -21254,6 +21809,15 @@
"stream-shift": "^1.0.0"
}
},
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"license": "MIT"
@@ -21920,6 +22484,12 @@
"version": "1.0.3",
"license": "MIT"
},
+ "node_modules/escape-latex": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
+ "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==",
+ "dev": true
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"license": "MIT",
@@ -23402,6 +23972,18 @@
"version": "2.0.0",
"license": "MIT"
},
+ "node_modules/expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+ "dev": true,
+ "dependencies": {
+ "homedir-polyfill": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/expect": {
"version": "29.4.1",
"license": "MIT",
@@ -23520,8 +24102,8 @@
},
"node_modules/expensify-common": {
"version": "1.0.0",
- "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#68abe48ad71a98604fdbf5e8e960023ed5807ec2",
- "integrity": "sha512-OhM2d7W++k0RVscwBpl0cvKXp3aZmflVawQ9Ebh2RBTdy98VZUwq2iZyCDISGNyETthqqsRq8vxy2lFQZZ19RA==",
+ "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#c898563fe851d9a4d594fa9afbdd1ddab5971636",
+ "integrity": "sha512-WjxHYpqebNsPKJC+SBhgsYNSib+8LptZv/BKt8hc67psJjO9JdrTpAHuoZ0n1lCTQ2DhpDERjqTsQbpUqWbgIg==",
"license": "MIT",
"dependencies": {
"classnames": "2.3.1",
@@ -24512,6 +25094,19 @@
"node": ">= 0.6"
}
},
+ "node_modules/fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://www.patreon.com/infusion"
+ }
+ },
"node_modules/fragment-cache": {
"version": "0.2.1",
"license": "MIT",
@@ -24542,6 +25137,15 @@
"readable-stream": "^2.0.0"
}
},
+ "node_modules/fs-exists-sync": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
+ "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fs-extra": {
"version": "9.1.0",
"license": "MIT",
@@ -24728,6 +25332,41 @@
"node": ">=6"
}
},
+ "node_modules/git-config-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
+ "integrity": "sha512-KcJ2dlrrP5DbBnYIZ2nlikALfRhKzNSX0stvv3ImJ+fvC4hXKoV+U+74SV0upg+jlQZbrtQzc0bu6/Zh+7aQbg==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "fs-exists-sync": "^0.1.0",
+ "homedir-polyfill": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/git-config-path/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/git-config-path/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/github-slugger": {
"version": "1.4.0",
"dev": true,
@@ -25296,6 +25935,18 @@
"react-is": "^16.7.0"
}
},
+ "node_modules/homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "dependencies": {
+ "parse-passwd": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/hosted-git-info": {
"version": "4.1.0",
"dev": true,
@@ -25566,6 +26217,299 @@
"node": ">=10.17.0"
}
},
+ "node_modules/husky": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz",
+ "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "cosmiconfig": "^5.0.7",
+ "execa": "^1.0.0",
+ "find-up": "^3.0.0",
+ "get-stdin": "^6.0.0",
+ "is-ci": "^2.0.0",
+ "pkg-dir": "^3.0.0",
+ "please-upgrade-node": "^3.1.1",
+ "read-pkg": "^4.0.1",
+ "run-node": "^1.0.0",
+ "slash": "^2.0.0"
+ },
+ "bin": {
+ "husky-upgrade": "lib/upgrader/bin.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "node_modules/husky/node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "dependencies": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ },
+ "engines": {
+ "node": ">=4.8"
+ }
+ },
+ "node_modules/husky/node_modules/execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dev": true,
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "dev": true,
+ "dependencies": {
+ "ci-info": "^2.0.0"
+ },
+ "bin": {
+ "is-ci": "bin.js"
+ }
+ },
+ "node_modules/husky/node_modules/is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/husky/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/husky/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/husky/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/husky/node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/husky/node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/husky/node_modules/slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/husky/node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/hyperlinker": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz",
+ "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/hyphenate-style-name": {
"version": "1.0.4",
"license": "BSD-3-Clause"
@@ -25786,6 +26730,12 @@
"version": "2.0.4",
"license": "ISC"
},
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
"node_modules/inline-style-parser": {
"version": "0.1.1",
"dev": true,
@@ -26748,6 +27698,12 @@
"node": ">=8"
}
},
+ "node_modules/javascript-natural-sort": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
+ "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==",
+ "dev": true
+ },
"node_modules/jest": {
"version": "29.4.1",
"license": "MIT",
@@ -29883,6 +30839,31 @@
"version": "0.0.0",
"license": "Public Domain"
},
+ "node_modules/jsonpointer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
+ "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
+ "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
+ "dev": true,
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash": "^4.17.21",
+ "ms": "^2.1.1",
+ "semver": "^7.3.8"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.3",
"dev": true,
@@ -29903,6 +30884,27 @@
"node": ">=8"
}
},
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dev": true,
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dev": true,
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.2",
"dev": true,
@@ -30027,6 +31029,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/li": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/li/-/li-1.3.0.tgz",
+ "integrity": "sha512-z34TU6GlMram52Tss5mt1m//ifRIpKH5Dqm7yUVOdHI+BQCs9qGPHFaCUTIzsWX7edN30aa2WrPwR7IO10FHaw==",
+ "dev": true
+ },
"node_modules/lie": {
"version": "3.1.1",
"license": "MIT",
@@ -30138,10 +31146,46 @@
"version": "4.0.8",
"license": "MIT"
},
+ "node_modules/lodash.find": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz",
+ "integrity": "sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg==",
+ "dev": true
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "dev": true
+ },
"node_modules/lodash.isequal": {
"version": "4.5.0",
"license": "MIT"
},
+ "node_modules/lodash.isobject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
+ "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==",
+ "dev": true
+ },
+ "node_modules/lodash.keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz",
+ "integrity": "sha512-J79MkJcp7Df5mizHiVNpjoHXLi4HLjh9VLS/M7lQSGoQ+0oQ+lWEigREkqKyizPB1IawvQLLKY8mzEcm1tkyxQ==",
+ "dev": true
+ },
+ "node_modules/lodash.mapvalues": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
+ "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==",
+ "dev": true
+ },
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"dev": true,
@@ -30596,6 +31640,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/markdown-builder": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/markdown-builder/-/markdown-builder-0.9.0.tgz",
+ "integrity": "sha512-UovCyEEzMeKE7l88fbOk9SIJkOG7KXkg+TdudN8rvOtCtBO5uu1X27HSnM7LS/xH+vaShJLGpkBcYYcojWNx/g==",
+ "dev": true,
+ "dependencies": {
+ "husky": "^1.0.0-rc.14"
+ }
+ },
"node_modules/markdown-escapes": {
"version": "1.0.4",
"dev": true,
@@ -30605,6 +31658,19 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "dependencies": {
+ "repeat-string": "^1.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/matcher": {
"version": "3.0.0",
"dev": true,
@@ -30616,6 +31682,29 @@
"node": ">=10"
}
},
+ "node_modules/mathjs": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-11.8.0.tgz",
+ "integrity": "sha512-I7r8HCoqUGyEiHQdeOCF2m2k9N+tcOHO3cZQ3tyJkMMBQMFqMR7dMQEboBMJAiFW2Um3PEItGPwcOc4P6KRqwg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "^7.21.0",
+ "complex.js": "^2.1.1",
+ "decimal.js": "^10.4.3",
+ "escape-latex": "^1.2.0",
+ "fraction.js": "^4.2.0",
+ "javascript-natural-sort": "^0.7.1",
+ "seedrandom": "^3.0.5",
+ "tiny-emitter": "^2.1.0",
+ "typed-function": "^4.1.0"
+ },
+ "bin": {
+ "mathjs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/md5.js": {
"version": "1.3.5",
"license": "MIT",
@@ -30728,6 +31817,15 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/memfs-or-file-map-to-github-branch": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.1.tgz",
+ "integrity": "sha512-I/hQzJ2a/pCGR8fkSQ9l5Yx+FQ4e7X6blNHyWBm2ojeFLT3GVzGkTj7xnyWpdclrr7Nq4dmx3xrvu70m3ypzAQ==",
+ "dev": true,
+ "dependencies": {
+ "@octokit/rest": "^16.43.0 || ^17.11.0 || ^18.12.0"
+ }
+ },
"node_modules/memoizerific": {
"version": "1.11.3",
"dev": true,
@@ -32424,6 +33522,12 @@
"license": "MIT",
"optional": true
},
+ "node_modules/node-cleanup": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
+ "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==",
+ "dev": true
+ },
"node_modules/node-dir": {
"version": "0.1.17",
"license": "MIT",
@@ -33163,6 +34267,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/override-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/override-require/-/override-require-1.1.1.tgz",
+ "integrity": "sha512-eoJ9YWxFcXbrn2U8FKT6RV+/Kj7fiGAB1VvHzbYKt8xM5ZuKZgCGvnHzDxmreEjcBH28ejg5MiOH4iyY1mQnkg==",
+ "dev": true
+ },
"node_modules/p-all": {
"version": "2.1.0",
"dev": true,
@@ -33353,6 +34463,12 @@
"safe-buffer": "^5.1.1"
}
},
+ "node_modules/parse-diff": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.7.1.tgz",
+ "integrity": "sha512-1j3l8IKcy4yRK2W4o9EYvJLSzpAVwz4DXqCewYyx2vEwk2gcf3DBPqc8Fj4XV3K33OYJ08A8fWwyu/ykD/HUSg==",
+ "dev": true
+ },
"node_modules/parse-entities": {
"version": "2.0.0",
"dev": true,
@@ -33370,6 +34486,32 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/parse-git-config": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-2.0.3.tgz",
+ "integrity": "sha512-Js7ueMZOVSZ3tP8C7E3KZiHv6QQl7lnJ+OkbxoaFazzSa2KyEHqApfGbU3XboUgUnq4ZuUmskUpYKTNx01fm5A==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.2",
+ "git-config-path": "^1.0.1",
+ "ini": "^1.3.5"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-github-url": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+ "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
+ "dev": true,
+ "bin": {
+ "parse-github-url": "cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/parse-json": {
"version": "5.2.0",
"license": "MIT",
@@ -33386,6 +34528,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse-link-header": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz",
+ "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==",
+ "dev": true,
+ "dependencies": {
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/parse5": {
"version": "6.0.1",
"dev": true,
@@ -33764,6 +34924,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/pinpoint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pinpoint/-/pinpoint-1.1.0.tgz",
+ "integrity": "sha512-+04FTD9x7Cls2rihLlo57QDCcHoLBGn5Dk51SwtFBWkUWLxZaBXyNVpCw1S+atvE7GmnFjeaRZ0WLq3UYuqAdg==",
+ "dev": true
+ },
"node_modules/pirates": {
"version": "4.0.5",
"license": "MIT",
@@ -33841,6 +35007,15 @@
"node": ">=6"
}
},
+ "node_modules/please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "dependencies": {
+ "semver-compare": "^1.0.0"
+ }
+ },
"node_modules/plist": {
"version": "3.0.6",
"license": "MIT",
@@ -34137,6 +35312,28 @@
"node": ">= 0.8"
}
},
+ "node_modules/prettyjson": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz",
+ "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==",
+ "dev": true,
+ "dependencies": {
+ "colors": "1.4.0",
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "prettyjson": "bin/prettyjson"
+ }
+ },
+ "node_modules/prettyjson/node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/process": {
"version": "0.11.10",
"license": "MIT",
@@ -36223,6 +37420,26 @@
"resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz",
"integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg=="
},
+ "node_modules/readline-sync": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
+ "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/reassure": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/reassure/-/reassure-0.9.0.tgz",
+ "integrity": "sha512-FIf0GPchyPGItsrW5Wwff/NWVrfOcCUuJJSs4Nur6iRdQt8yvmCpcba4UyemdZ1KaFTIW1gKbAV3u2tuA7zmtQ==",
+ "dev": true,
+ "dependencies": {
+ "@callstack/reassure-cli": "0.9.0",
+ "@callstack/reassure-danger": "0.1.1",
+ "@callstack/reassure-measure": "0.5.0"
+ }
+ },
"node_modules/recast": {
"version": "0.20.5",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz",
@@ -36282,8 +37499,9 @@
}
},
"node_modules/regenerator-runtime": {
- "version": "0.13.9",
- "license": "MIT"
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/regenerator-transform": {
"version": "0.15.0",
@@ -36822,6 +38040,18 @@
"node": ">=0.12.0"
}
},
+ "node_modules/run-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
+ "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==",
+ "dev": true,
+ "bin": {
+ "run-node": "run-node"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"dev": true,
@@ -37614,6 +38844,21 @@
"version": "3.0.7",
"license": "ISC"
},
+ "node_modules/simple-git": {
+ "version": "3.19.0",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.0.tgz",
+ "integrity": "sha512-hyH2p9Ptxjf/xPuL7HfXbpYt9gKhC1yWDh3KYIAYJJePAKV7AEjLN4xhp7lozOdNiaJ9jlVvAbBymVlcS2jRiA==",
+ "dev": true,
+ "dependencies": {
+ "@kwsites/file-exists": "^1.1.1",
+ "@kwsites/promise-deferred": "^1.1.1",
+ "debug": "^4.3.4"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/steveukx/git-js?sponsor=1"
+ }
+ },
"node_modules/simple-plist": {
"version": "1.3.1",
"license": "MIT",
@@ -38707,6 +39952,28 @@
"node": ">=4"
}
},
+ "node_modules/supports-hyperlinks": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz",
+ "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^2.0.0",
+ "supports-color": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/supports-hyperlinks/node_modules/has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"license": "MIT",
@@ -39527,6 +40794,15 @@
"node": ">= 0.6"
}
},
+ "node_modules/typed-function": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.0.tgz",
+ "integrity": "sha512-DGwUl6cioBW5gw2L+6SMupGwH/kZOqivy17E4nsh1JI9fKF87orMmlQx3KISQPmg3sfnOUGlwVkroosvgddrlg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/typedarray": {
"version": "0.0.6",
"dev": true,
@@ -41500,6 +42776,12 @@
"default-browser-id": "^1.0.4"
}
},
+ "node_modules/xcase": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
+ "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==",
+ "dev": true
+ },
"node_modules/xcode": {
"version": "3.0.1",
"license": "Apache-2.0",
@@ -41739,6 +43021,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zod": {
+ "version": "3.21.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
+ "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/zwitch": {
"version": "1.0.5",
"dev": true,
@@ -42851,9 +44142,11 @@
}
},
"@babel/runtime": {
- "version": "7.18.9",
+ "version": "7.22.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz",
+ "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==",
"requires": {
- "regenerator-runtime": "^0.13.4"
+ "regenerator-runtime": "^0.13.11"
}
},
"@babel/runtime-corejs3": {
@@ -42920,6 +44213,196 @@
"integrity": "sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==",
"dev": true
},
+ "@callstack/reassure-cli": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-cli/-/reassure-cli-0.9.0.tgz",
+ "integrity": "sha512-auoxqyilxkT5mDdEPJqRRY+ZGlrihJjFQpopcFd/15ng76OPVka3L48RMEY2wXkFXLaOOs6enNGb596jYPuEtQ==",
+ "dev": true,
+ "requires": {
+ "@callstack/reassure-compare": "0.5.0",
+ "@callstack/reassure-logger": "0.3.0",
+ "chalk": "4.1.2",
+ "simple-git": "^3.16.0",
+ "yargs": "^17.6.2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "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,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "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,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "requires": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true
+ }
+ }
+ },
+ "@callstack/reassure-compare": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-compare/-/reassure-compare-0.5.0.tgz",
+ "integrity": "sha512-3sBeJ/+Hxjdb01KVb8LszO1kcJ8TXcrVnerUj+LYn2dkBOohAMqGYaOvCeoWsVEHJ+MIOzmvAGBJQRu69RoJdQ==",
+ "dev": true,
+ "requires": {
+ "@callstack/reassure-logger": "0.3.0",
+ "markdown-builder": "^0.9.0",
+ "markdown-table": "^2.0.0",
+ "zod": "^3.20.2"
+ }
+ },
+ "@callstack/reassure-danger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-danger/-/reassure-danger-0.1.1.tgz",
+ "integrity": "sha512-lfza+qBdvVYtP7WvMTT+LfjBfuYsXZ4RxuBldsL8wJArGeCl3OZwUg+9bTo8v6kk/nY8memk5HxrCwWDSO24UA==",
+ "dev": true
+ },
+ "@callstack/reassure-logger": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-logger/-/reassure-logger-0.3.0.tgz",
+ "integrity": "sha512-JX5o+8qkIbIRL+cQn9XlQYdv9p/3L6J70zZX6NYi9j0VrSS9PZIRfo8ujMdLSqUNV6HZN1ay59RzuncLjVu0aQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "4.1.2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "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,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "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,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@callstack/reassure-measure": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@callstack/reassure-measure/-/reassure-measure-0.5.0.tgz",
+ "integrity": "sha512-KwlmNYcspBOp7FIw6XOz5O9mnKB4cWCCyM6vG4nFUPHSWQ6yVdRkawVvoPIV5qJ2hw7zCzdtqRrLWQSTF4eKlg==",
+ "dev": true,
+ "requires": {
+ "@callstack/reassure-logger": "0.3.0",
+ "mathjs": "^11.5.0"
+ }
+ },
"@cnakazawa/watch": {
"version": "1.0.4",
"dev": true,
@@ -43248,6 +44731,56 @@
"version": "1.1.3",
"dev": true
},
+ "@gitbeaker/core": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-21.7.0.tgz",
+ "integrity": "sha512-cw72rE7tA27wc6JJe1WqeAj9v/6w0S7XJcEji+bRNjTlUfE1zgfW0Gf1mbGUi7F37SOABGCosQLfg9Qe63aIqA==",
+ "dev": true,
+ "requires": {
+ "@gitbeaker/requester-utils": "^21.7.0",
+ "form-data": "^3.0.0",
+ "li": "^1.3.0",
+ "xcase": "^2.0.1"
+ }
+ },
+ "@gitbeaker/node": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/node/-/node-21.7.0.tgz",
+ "integrity": "sha512-OdM3VcTKYYqboOsnbiPcO0XimXXpYK4gTjARBZ6BWc+1LQXKmqo+OH6oUbyxOoaFu9hHECafIt3WZU3NM4sZTg==",
+ "dev": true,
+ "requires": {
+ "@gitbeaker/core": "^21.7.0",
+ "@gitbeaker/requester-utils": "^21.7.0",
+ "form-data": "^3.0.0",
+ "got": "^11.1.4",
+ "xcase": "^2.0.1"
+ }
+ },
+ "@gitbeaker/requester-utils": {
+ "version": "21.7.0",
+ "resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-21.7.0.tgz",
+ "integrity": "sha512-eLTaVXlBnh8Qimj6QuMMA06mu/mLcJm3dy8nqhhn/Vm/D25sPrvpGwmbfFyvzj6QujPqtHvFfsCHtyZddL01qA==",
+ "dev": true,
+ "requires": {
+ "form-data": "^3.0.0",
+ "query-string": "^6.12.1",
+ "xcase": "^2.0.1"
+ },
+ "dependencies": {
+ "query-string": {
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
+ "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==",
+ "dev": true,
+ "requires": {
+ "decode-uri-component": "^0.2.0",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ }
+ }
+ }
+ },
"@gorhom/portal": {
"version": "1.0.14",
"requires": {
@@ -44339,6 +45872,21 @@
"version": "2.3.1",
"requires": {}
},
+ "@kwsites/file-exists": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+ "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1"
+ }
+ },
+ "@kwsites/promise-deferred": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+ "dev": true
+ },
"@leichtgewicht/ip-codec": {
"version": "2.0.4",
"dev": true
@@ -44590,6 +46138,13 @@
"@octokit/types": "^6.41.0"
}
},
+ "@octokit/plugin-request-log": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+ "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
+ "dev": true,
+ "requires": {}
+ },
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"dev": true,
@@ -44653,6 +46208,100 @@
}
}
},
+ "@octokit/rest": {
+ "version": "18.12.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
+ "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
+ "dev": true,
+ "requires": {
+ "@octokit/core": "^3.5.1",
+ "@octokit/plugin-paginate-rest": "^2.16.8",
+ "@octokit/plugin-request-log": "^1.0.4",
+ "@octokit/plugin-rest-endpoint-methods": "^5.12.0"
+ },
+ "dependencies": {
+ "@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "@octokit/core": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+ "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+ "dev": true,
+ "requires": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.3",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "dev": true,
+ "requires": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/plugin-paginate-rest": {
+ "version": "2.21.3",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+ "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^6.40.0"
+ }
+ },
+ "@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "dev": true,
+ "requires": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ }
+ }
+ },
"@octokit/types": {
"version": "6.41.0",
"dev": true,
@@ -52105,9 +53754,9 @@
}
},
"@ua/react-native-airship": {
- "version": "15.2.3",
- "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.3.tgz",
- "integrity": "sha512-94fgHJcxc4qUy9OmBqt6VuuWggoeCMNIosz3/qwiUNsUVoE1deWcOEG9vULmXcTKX+O9Wal/mKsuPGiFCALTDQ==",
+ "version": "15.2.6",
+ "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.6.tgz",
+ "integrity": "sha512-dVlBPPYXD/4SEshv/X7mmt3xF8WfnNqiSNzCyqJSLAZ1aJuPpP9Z5WemCYsa2iv6goRZvtJSE4P79QKlfoTwXw==",
"requires": {}
},
"@vercel/ncc": {
@@ -52899,6 +54548,23 @@
"async-limiter": {
"version": "1.0.1"
},
+ "async-retry": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.2.3.tgz",
+ "integrity": "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q==",
+ "dev": true,
+ "requires": {
+ "retry": "0.12.0"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "dev": true
+ }
+ }
+ },
"asynckit": {
"version": "0.4.0",
"dev": true
@@ -53991,6 +55657,12 @@
"version": "1.0.0",
"dev": true
},
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "dev": true
+ },
"buffer-fill": {
"version": "1.0.0",
"dev": true
@@ -54662,6 +56334,12 @@
"version": "0.1.2",
"dev": true
},
+ "complex.js": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
+ "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==",
+ "dev": true
+ },
"component-emitter": {
"version": "1.3.0"
},
@@ -55443,6 +57121,74 @@
"version": "1.0.8",
"dev": true
},
+ "danger": {
+ "version": "11.2.6",
+ "resolved": "https://registry.npmjs.org/danger/-/danger-11.2.6.tgz",
+ "integrity": "sha512-EEeuDmUcxPGJ166q7Zzz1WEiV+e0qbPopaX4sXxds8U5doGMdw/8oOUOVye7JiHIBuss3KvQWt4YHZeD3jSCfw==",
+ "dev": true,
+ "requires": {
+ "@gitbeaker/node": "^21.3.0",
+ "@octokit/rest": "^18.12.0",
+ "async-retry": "1.2.3",
+ "chalk": "^2.3.0",
+ "commander": "^2.18.0",
+ "core-js": "^3.8.2",
+ "debug": "^4.1.1",
+ "fast-json-patch": "^3.0.0-1",
+ "get-stdin": "^6.0.0",
+ "http-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^5.0.1",
+ "hyperlinker": "^1.0.0",
+ "json5": "^2.1.0",
+ "jsonpointer": "^5.0.0",
+ "jsonwebtoken": "^9.0.0",
+ "lodash.find": "^4.6.0",
+ "lodash.includes": "^4.3.0",
+ "lodash.isobject": "^3.0.2",
+ "lodash.keys": "^4.0.8",
+ "lodash.mapvalues": "^4.6.0",
+ "lodash.memoize": "^4.1.2",
+ "memfs-or-file-map-to-github-branch": "^1.2.1",
+ "micromatch": "^4.0.4",
+ "node-cleanup": "^2.1.2",
+ "node-fetch": "^2.6.7",
+ "override-require": "^1.1.1",
+ "p-limit": "^2.1.0",
+ "parse-diff": "^0.7.0",
+ "parse-git-config": "^2.0.3",
+ "parse-github-url": "^1.0.2",
+ "parse-link-header": "^2.0.0",
+ "pinpoint": "^1.1.0",
+ "prettyjson": "^1.2.1",
+ "readline-sync": "^1.4.9",
+ "regenerator-runtime": "^0.13.9",
+ "require-from-string": "^2.0.2",
+ "supports-hyperlinks": "^1.0.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "fast-json-patch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz",
+ "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ }
+ }
+ },
"data-urls": {
"version": "3.0.2",
"dev": true,
@@ -55917,6 +57663,15 @@
"stream-shift": "^1.0.0"
}
},
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"ee-first": {
"version": "1.1.1"
},
@@ -56367,6 +58122,12 @@
"escape-html": {
"version": "1.0.3"
},
+ "escape-latex": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
+ "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==",
+ "dev": true
+ },
"escape-string-regexp": {
"version": "4.0.0"
},
@@ -57326,6 +59087,15 @@
}
}
},
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
"expect": {
"version": "29.4.1",
"requires": {
@@ -57401,9 +59171,9 @@
}
},
"expensify-common": {
- "version": "git+ssh://git@github.com/Expensify/expensify-common.git#68abe48ad71a98604fdbf5e8e960023ed5807ec2",
- "integrity": "sha512-OhM2d7W++k0RVscwBpl0cvKXp3aZmflVawQ9Ebh2RBTdy98VZUwq2iZyCDISGNyETthqqsRq8vxy2lFQZZ19RA==",
- "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#68abe48ad71a98604fdbf5e8e960023ed5807ec2",
+ "version": "git+ssh://git@github.com/Expensify/expensify-common.git#c898563fe851d9a4d594fa9afbdd1ddab5971636",
+ "integrity": "sha512-WjxHYpqebNsPKJC+SBhgsYNSib+8LptZv/BKt8hc67psJjO9JdrTpAHuoZ0n1lCTQ2DhpDERjqTsQbpUqWbgIg==",
+ "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#c898563fe851d9a4d594fa9afbdd1ddab5971636",
"requires": {
"classnames": "2.3.1",
"clipboard": "2.0.4",
@@ -58066,6 +59836,12 @@
"version": "0.2.0",
"dev": true
},
+ "fraction.js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+ "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+ "dev": true
+ },
"fragment-cache": {
"version": "0.2.1",
"requires": {
@@ -58086,6 +59862,12 @@
"readable-stream": "^2.0.0"
}
},
+ "fs-exists-sync": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
+ "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==",
+ "dev": true
+ },
"fs-extra": {
"version": "9.1.0",
"requires": {
@@ -58196,6 +59978,34 @@
"getenv": {
"version": "1.0.0"
},
+ "git-config-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
+ "integrity": "sha512-KcJ2dlrrP5DbBnYIZ2nlikALfRhKzNSX0stvv3ImJ+fvC4hXKoV+U+74SV0upg+jlQZbrtQzc0bu6/Zh+7aQbg==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "fs-exists-sync": "^0.1.0",
+ "homedir-polyfill": "^1.0.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ }
+ }
+ },
"github-slugger": {
"version": "1.4.0",
"dev": true
@@ -58569,6 +60379,15 @@
"react-is": "^16.7.0"
}
},
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
"hosted-git-info": {
"version": "4.1.0",
"dev": true,
@@ -58736,6 +60555,225 @@
"human-signals": {
"version": "2.1.0"
},
+ "husky": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz",
+ "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^5.0.7",
+ "execa": "^1.0.0",
+ "find-up": "^3.0.0",
+ "get-stdin": "^6.0.0",
+ "is-ci": "^2.0.0",
+ "pkg-dir": "^3.0.0",
+ "please-upgrade-node": "^3.1.1",
+ "read-pkg": "^4.0.1",
+ "run-node": "^1.0.0",
+ "slash": "^2.0.0"
+ },
+ "dependencies": {
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dev": true,
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "dev": true,
+ "requires": {
+ "ci-info": "^2.0.0"
+ }
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "dev": true
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "hyperlinker": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz",
+ "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==",
+ "dev": true
+ },
"hyphenate-style-name": {
"version": "1.0.4"
},
@@ -58857,6 +60895,12 @@
"inherits": {
"version": "2.0.4"
},
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
"inline-style-parser": {
"version": "0.1.1",
"dev": true
@@ -59401,6 +61445,12 @@
}
}
},
+ "javascript-natural-sort": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
+ "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==",
+ "dev": true
+ },
"jest": {
"version": "29.4.1",
"requires": {
@@ -61480,6 +63530,24 @@
"jsonify": {
"version": "0.0.0"
},
+ "jsonpointer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
+ "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
+ "dev": true
+ },
+ "jsonwebtoken": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
+ "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
+ "dev": true,
+ "requires": {
+ "jws": "^3.2.2",
+ "lodash": "^4.17.21",
+ "ms": "^2.1.1",
+ "semver": "^7.3.8"
+ }
+ },
"jsx-ast-utils": {
"version": "3.3.3",
"dev": true,
@@ -61492,6 +63560,27 @@
"version": "3.1.0",
"dev": true
},
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dev": true,
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dev": true,
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"keyv": {
"version": "4.5.2",
"dev": true,
@@ -61575,6 +63664,12 @@
"type-check": "~0.4.0"
}
},
+ "li": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/li/-/li-1.3.0.tgz",
+ "integrity": "sha512-z34TU6GlMram52Tss5mt1m//ifRIpKH5Dqm7yUVOdHI+BQCs9qGPHFaCUTIzsWX7edN30aa2WrPwR7IO10FHaw==",
+ "dev": true
+ },
"lie": {
"version": "3.1.1",
"requires": {
@@ -61651,9 +63746,45 @@
"lodash.debounce": {
"version": "4.0.8"
},
+ "lodash.find": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz",
+ "integrity": "sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg==",
+ "dev": true
+ },
+ "lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "dev": true
+ },
"lodash.isequal": {
"version": "4.5.0"
},
+ "lodash.isobject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
+ "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==",
+ "dev": true
+ },
+ "lodash.keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz",
+ "integrity": "sha512-J79MkJcp7Df5mizHiVNpjoHXLi4HLjh9VLS/M7lQSGoQ+0oQ+lWEigREkqKyizPB1IawvQLLKY8mzEcm1tkyxQ==",
+ "dev": true
+ },
+ "lodash.mapvalues": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
+ "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==",
+ "dev": true
+ },
+ "lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true
+ },
"lodash.merge": {
"version": "4.6.2",
"dev": true
@@ -61973,10 +64104,28 @@
"object-visit": "^1.0.0"
}
},
+ "markdown-builder": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/markdown-builder/-/markdown-builder-0.9.0.tgz",
+ "integrity": "sha512-UovCyEEzMeKE7l88fbOk9SIJkOG7KXkg+TdudN8rvOtCtBO5uu1X27HSnM7LS/xH+vaShJLGpkBcYYcojWNx/g==",
+ "dev": true,
+ "requires": {
+ "husky": "^1.0.0-rc.14"
+ }
+ },
"markdown-escapes": {
"version": "1.0.4",
"dev": true
},
+ "markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "requires": {
+ "repeat-string": "^1.0.0"
+ }
+ },
"matcher": {
"version": "3.0.0",
"dev": true,
@@ -61984,6 +64133,23 @@
"escape-string-regexp": "^4.0.0"
}
},
+ "mathjs": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-11.8.0.tgz",
+ "integrity": "sha512-I7r8HCoqUGyEiHQdeOCF2m2k9N+tcOHO3cZQ3tyJkMMBQMFqMR7dMQEboBMJAiFW2Um3PEItGPwcOc4P6KRqwg==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.21.0",
+ "complex.js": "^2.1.1",
+ "decimal.js": "^10.4.3",
+ "escape-latex": "^1.2.0",
+ "fraction.js": "^4.2.0",
+ "javascript-natural-sort": "^0.7.1",
+ "seedrandom": "^3.0.5",
+ "tiny-emitter": "^2.1.0",
+ "typed-function": "^4.1.0"
+ }
+ },
"md5.js": {
"version": "1.3.5",
"requires": {
@@ -62056,6 +64222,15 @@
"fs-monkey": "^1.0.3"
}
},
+ "memfs-or-file-map-to-github-branch": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.1.tgz",
+ "integrity": "sha512-I/hQzJ2a/pCGR8fkSQ9l5Yx+FQ4e7X6blNHyWBm2ojeFLT3GVzGkTj7xnyWpdclrr7Nq4dmx3xrvu70m3ypzAQ==",
+ "dev": true,
+ "requires": {
+ "@octokit/rest": "^16.43.0 || ^17.11.0 || ^18.12.0"
+ }
+ },
"memoizerific": {
"version": "1.11.3",
"dev": true,
@@ -63246,6 +65421,12 @@
"dev": true,
"optional": true
},
+ "node-cleanup": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
+ "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==",
+ "dev": true
+ },
"node-dir": {
"version": "0.1.17",
"requires": {
@@ -63739,6 +65920,12 @@
"os-tmpdir": {
"version": "1.0.2"
},
+ "override-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/override-require/-/override-require-1.1.1.tgz",
+ "integrity": "sha512-eoJ9YWxFcXbrn2U8FKT6RV+/Kj7fiGAB1VvHzbYKt8xM5ZuKZgCGvnHzDxmreEjcBH28ejg5MiOH4iyY1mQnkg==",
+ "dev": true
+ },
"p-all": {
"version": "2.1.0",
"dev": true,
@@ -63857,6 +66044,12 @@
"safe-buffer": "^5.1.1"
}
},
+ "parse-diff": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.7.1.tgz",
+ "integrity": "sha512-1j3l8IKcy4yRK2W4o9EYvJLSzpAVwz4DXqCewYyx2vEwk2gcf3DBPqc8Fj4XV3K33OYJ08A8fWwyu/ykD/HUSg==",
+ "dev": true
+ },
"parse-entities": {
"version": "2.0.0",
"dev": true,
@@ -63869,6 +66062,23 @@
"is-hexadecimal": "^1.0.0"
}
},
+ "parse-git-config": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-2.0.3.tgz",
+ "integrity": "sha512-Js7ueMZOVSZ3tP8C7E3KZiHv6QQl7lnJ+OkbxoaFazzSa2KyEHqApfGbU3XboUgUnq4ZuUmskUpYKTNx01fm5A==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "git-config-path": "^1.0.1",
+ "ini": "^1.3.5"
+ }
+ },
+ "parse-github-url": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+ "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
+ "dev": true
+ },
"parse-json": {
"version": "5.2.0",
"requires": {
@@ -63878,6 +66088,21 @@
"lines-and-columns": "^1.1.6"
}
},
+ "parse-link-header": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz",
+ "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==",
+ "dev": true,
+ "requires": {
+ "xtend": "~4.0.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+ "dev": true
+ },
"parse5": {
"version": "6.0.1",
"dev": true
@@ -64125,6 +66350,12 @@
"pinkie": "^2.0.0"
}
},
+ "pinpoint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pinpoint/-/pinpoint-1.1.0.tgz",
+ "integrity": "sha512-+04FTD9x7Cls2rihLlo57QDCcHoLBGn5Dk51SwtFBWkUWLxZaBXyNVpCw1S+atvE7GmnFjeaRZ0WLq3UYuqAdg==",
+ "dev": true
+ },
"pirates": {
"version": "4.0.5"
},
@@ -64173,6 +66404,15 @@
}
}
},
+ "please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "requires": {
+ "semver-compare": "^1.0.0"
+ }
+ },
"plist": {
"version": "3.0.6",
"requires": {
@@ -64364,6 +66604,24 @@
"version": "1.0.3",
"dev": true
},
+ "prettyjson": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.5.tgz",
+ "integrity": "sha512-rksPWtoZb2ZpT5OVgtmy0KHVM+Dca3iVwWY9ifwhcexfjebtgjg3wmrUt9PvJ59XIYBcknQeYHD8IAnVlh9lAw==",
+ "dev": true,
+ "requires": {
+ "colors": "1.4.0",
+ "minimist": "^1.2.0"
+ },
+ "dependencies": {
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ }
+ }
+ },
"process": {
"version": "0.11.10"
},
@@ -65752,6 +68010,23 @@
"resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz",
"integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg=="
},
+ "readline-sync": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
+ "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
+ "dev": true
+ },
+ "reassure": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/reassure/-/reassure-0.9.0.tgz",
+ "integrity": "sha512-FIf0GPchyPGItsrW5Wwff/NWVrfOcCUuJJSs4Nur6iRdQt8yvmCpcba4UyemdZ1KaFTIW1gKbAV3u2tuA7zmtQ==",
+ "dev": true,
+ "requires": {
+ "@callstack/reassure-cli": "0.9.0",
+ "@callstack/reassure-danger": "0.1.1",
+ "@callstack/reassure-measure": "0.5.0"
+ }
+ },
"recast": {
"version": "0.20.5",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz",
@@ -65794,7 +68069,9 @@
}
},
"regenerator-runtime": {
- "version": "0.13.9"
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"regenerator-transform": {
"version": "0.15.0",
@@ -66142,6 +68419,12 @@
"version": "2.4.1",
"dev": true
},
+ "run-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
+ "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==",
+ "dev": true
+ },
"run-parallel": {
"version": "1.2.0",
"dev": true,
@@ -66697,6 +68980,17 @@
"signal-exit": {
"version": "3.0.7"
},
+ "simple-git": {
+ "version": "3.19.0",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.0.tgz",
+ "integrity": "sha512-hyH2p9Ptxjf/xPuL7HfXbpYt9gKhC1yWDh3KYIAYJJePAKV7AEjLN4xhp7lozOdNiaJ9jlVvAbBymVlcS2jRiA==",
+ "dev": true,
+ "requires": {
+ "@kwsites/file-exists": "^1.1.1",
+ "@kwsites/promise-deferred": "^1.1.1",
+ "debug": "^4.3.4"
+ }
+ },
"simple-plist": {
"version": "1.3.1",
"requires": {
@@ -67447,6 +69741,24 @@
"has-flag": "^3.0.0"
}
},
+ "supports-hyperlinks": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz",
+ "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^2.0.0",
+ "supports-color": "^5.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==",
+ "dev": true
+ }
+ }
+ },
"supports-preserve-symlinks-flag": {
"version": "1.0.0"
},
@@ -67974,6 +70286,12 @@
"mime-types": "~2.1.24"
}
},
+ "typed-function": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.0.tgz",
+ "integrity": "sha512-DGwUl6cioBW5gw2L+6SMupGwH/kZOqivy17E4nsh1JI9fKF87orMmlQx3KISQPmg3sfnOUGlwVkroosvgddrlg==",
+ "dev": true
+ },
"typedarray": {
"version": "0.0.6",
"dev": true
@@ -69236,6 +71554,12 @@
"default-browser-id": "^1.0.4"
}
},
+ "xcase": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
+ "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==",
+ "dev": true
+ },
"xcode": {
"version": "3.0.1",
"requires": {
@@ -69389,6 +71713,12 @@
"yocto-queue": {
"version": "0.1.0"
},
+ "zod": {
+ "version": "3.21.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
+ "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
+ "dev": true
+ },
"zwitch": {
"version": "1.0.5",
"dev": true
diff --git a/package.json b/package.json
index a8b1e5b9e22f..8cea35e7b955 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.20-2",
+ "version": "1.3.22-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.",
@@ -70,13 +70,13 @@
"@react-navigation/native": "6.0.13",
"@react-navigation/stack": "6.3.1",
"@react-ng/bounds-observer": "^0.2.1",
- "@ua/react-native-airship": "^15.2.3",
+ "@ua/react-native-airship": "^15.2.6",
"awesome-phonenumber": "^5.4.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-polyfill": "^6.26.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#68abe48ad71a98604fdbf5e8e960023ed5807ec2",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#c898563fe851d9a4d594fa9afbdd1ddab5971636",
"fbjs": "^3.0.2",
"html-entities": "^1.3.1",
"htmlparser2": "^7.2.0",
@@ -177,6 +177,7 @@
"concurrently": "^5.3.0",
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^6.7.2",
+ "danger": "^11.2.6",
"diff-so-fancy": "^1.3.0",
"dotenv": "^16.0.3",
"electron": "22.3.7",
@@ -206,6 +207,7 @@
"react-native-performance-flipper-reporter": "^2.0.0",
"react-native-svg-transformer": "^1.0.0",
"react-test-renderer": "18.1.0",
+ "reassure": "^0.9.0",
"setimmediate": "^1.0.5",
"shellcheck": "^1.1.0",
"style-loader": "^2.0.0",
diff --git a/src/CONST.js b/src/CONST.js
index 182548b4d99e..4557c66a42cc 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -799,6 +799,8 @@ const CONST = {
},
ATTACHMENT_MESSAGE_TEXT: '[Attachment]',
+ // This is a placeholder for attachment which is uploading
+ ATTACHMENT_UPLOADING_MESSAGE_HTML: 'Uploading attachment...',
ATTACHMENT_SOURCE_ATTRIBUTE: 'data-expensify-source',
ATTACHMENT_PREVIEW_ATTRIBUTE: 'src',
ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE: 'data-name',
@@ -2432,8 +2434,14 @@ const CONST = {
MODERATION: {
MODERATOR_DECISION_PENDING: 'pending',
MODERATOR_DECISION_PENDING_HIDE: 'pendingHide',
+ MODERATOR_DECISION_APPROVED: 'approved',
+ MODERATOR_DECISION_HIDDEN: 'hidden',
FLAG_SEVERITY_SPAM: 'spam',
FLAG_SEVERITY_INCONSIDERATE: 'inconsiderate',
+ FLAG_SEVERITY_INTIMIDATION: 'intimidation',
+ FLAG_SEVERITY_BULLYING: 'bullying',
+ FLAG_SEVERITY_HARASSMENT: 'harassment',
+ FLAG_SEVERITY_ASSAULT: 'assault',
},
};
diff --git a/src/Expensify.js b/src/Expensify.js
index ff61485bc8f2..e7c830ff2029 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -92,9 +92,15 @@ function Expensify(props) {
const [isNavigationReady, setIsNavigationReady] = useState(false);
const [isOnyxMigrated, setIsOnyxMigrated] = useState(false);
const [isSplashHidden, setIsSplashHidden] = useState(false);
+ const [hasAttemptedToOpenPublicRoom, setAttemptedToOpenPublicRoom] = useState(false);
+
+ useEffect(() => {
+ if (props.isCheckingPublicRoom) return;
+ setAttemptedToOpenPublicRoom(true);
+ }, [props.isCheckingPublicRoom]);
const isAuthenticated = useMemo(() => Boolean(lodashGet(props.session, 'authToken', null)), [props.session]);
- const shouldInit = isNavigationReady && (!isAuthenticated || props.isSidebarLoaded) && !props.isCheckingPublicRoom;
+ const shouldInit = isNavigationReady && (!isAuthenticated || props.isSidebarLoaded) && hasAttemptedToOpenPublicRoom;
const shouldHideSplash = shouldInit && !isSplashHidden;
const initializeClient = () => {
@@ -197,7 +203,7 @@ function Expensify(props) {
>
)}
- {!props.isCheckingPublicRoom && (
+ {hasAttemptedToOpenPublicRoom && (
`flag/${reportID}/${reportActionID}`,
SEARCH: 'search',
SET_PASSWORD_WITH_VALIDATE_CODE: 'setpassword/:accountID/:validateCode',
DETAILS: 'details',
diff --git a/src/components/AttachmentCarousel/index.js b/src/components/AttachmentCarousel/index.js
index 56f592bc5865..6ae3214cd32a 100644
--- a/src/components/AttachmentCarousel/index.js
+++ b/src/components/AttachmentCarousel/index.js
@@ -3,6 +3,7 @@ import {View, FlatList, PixelRatio} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
+import {Parser as HtmlParser} from 'htmlparser2';
import * as Expensicons from '../Icon/Expensicons';
import styles from '../../styles/styles';
import themeColors from '../../styles/themes/default';
@@ -10,7 +11,6 @@ import CarouselActions from './CarouselActions';
import Button from '../Button';
import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
import AttachmentView from '../AttachmentView';
-import addEncryptedAuthTokenToURL from '../../libs/addEncryptedAuthTokenToURL';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
import CONST from '../../CONST';
import ONYXKEYS from '../../ONYXKEYS';
@@ -62,28 +62,13 @@ class AttachmentCarousel extends React.Component {
this.updateZoomState = this.updateZoomState.bind(this);
this.toggleArrowsVisibility = this.toggleArrowsVisibility.bind(this);
- this.state = this.makeInitialState();
+ this.state = this.createInitialState();
}
componentDidMount() {
this.autoHideArrow();
}
- /**
- * Helps to navigate between next/previous attachments
- * @param {Object} attachmentItem
- * @returns {Object}
- */
- getAttachment(attachmentItem) {
- const source = _.get(attachmentItem, 'source', '');
- const file = _.get(attachmentItem, 'file', {name: ''});
-
- return {
- source,
- file,
- };
- }
-
/**
* Calculate items layout information to optimize scrolling performance
* @param {*} data
@@ -159,39 +144,39 @@ class AttachmentCarousel extends React.Component {
}
/**
- * Map report actions to attachment items and sets the initial carousel state
+ * Constructs the initial component state from report actions
* @returns {{page: Number, attachments: Array, shouldShowArrow: Boolean, containerWidth: Number, isZoomed: Boolean}}
*/
- makeInitialState() {
- let page = 0;
- const actions = ReportActionsUtils.getSortedReportActions(_.values(this.props.reportActions), true);
-
- /**
- * Looping to filter out attachments and retrieve the src URL and name of attachments.
- */
+ createInitialState() {
+ const actions = ReportActionsUtils.getSortedReportActions(_.values(this.props.reportActions));
const attachments = [];
- _.forEach(actions, ({originalMessage, message}) => {
- // Check for attachment which hasn't been deleted
- if (!originalMessage || !originalMessage.html || _.some(message, (m) => m.isEdited)) {
- return;
- }
- const matches = [...originalMessage.html.matchAll(CONST.REGEX.ATTACHMENT_DATA)];
-
- // matchAll captured both source url and name of the attachment
- if (matches.length === 2) {
- const [originalSource, name] = _.map(matches, (m) => m[2]);
-
- // Update the image URL so the images can be accessed depending on the config environment.
- // Eg: while using Ngrok the image path is from an Ngrok URL and not an Expensify URL.
- const source = tryResolveUrlFromApiRoot(originalSource);
- if (source === this.props.source) {
- page = attachments.length;
+
+ const htmlParser = new HtmlParser({
+ onopentag: (name, attribs) => {
+ if (name !== 'img' || !attribs.src) {
+ return;
}
- attachments.push({source, file: {name}});
- }
+ const expensifySource = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE];
+
+ // By iterating actions in chronological order and prepending each attachment
+ // we ensure correct order of attachments even across actions with multiple attachments.
+ attachments.unshift({
+ source: tryResolveUrlFromApiRoot(expensifySource || attribs.src),
+ isAuthTokenRequired: Boolean(expensifySource),
+ file: {name: attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || attribs.src.split('/').pop()},
+ });
+ },
});
+ _.forEach(actions, (action) => htmlParser.write(_.get(action, ['message', 0, 'html'])));
+ htmlParser.end();
+
+ const page = _.findIndex(attachments, (a) => a.source === this.props.source);
+ if (page === -1) {
+ throw new Error('Attachment not found');
+ }
+
return {
page,
attachments,
@@ -220,7 +205,7 @@ class AttachmentCarousel extends React.Component {
/**
* Updates the page state when the user navigates between attachments
- * @param {Array<{item: *, index: Number}>} viewableItems
+ * @param {Array<{item: {source, file}, index: Number}>} viewableItems
*/
updatePage({viewableItems}) {
// Since we can have only one item in view at a time, we can use the first item in the array
@@ -231,8 +216,7 @@ class AttachmentCarousel extends React.Component {
}
const page = entry.index;
- const {source, file} = this.getAttachment(entry.item);
- this.props.onNavigate({source: addEncryptedAuthTokenToURL(source), file});
+ this.props.onNavigate(entry.item);
this.setState({page, isZoomed: false});
}
@@ -258,26 +242,17 @@ class AttachmentCarousel extends React.Component {
/**
* Defines how a single attachment should be rendered
- * @param {{ source: String, file: { name: String } }} item
+ * @param {{ isAuthTokenRequired: Boolean, source: String, file: { name: String } }} item
* @returns {JSX.Element}
*/
renderItem({item}) {
- const authSource = addEncryptedAuthTokenToURL(item.source);
- if (!this.canUseTouchScreen) {
- return (
-
- );
- }
-
return (
);
}
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index 642004913303..24a6ecfb3152 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -22,6 +22,7 @@ import withLocalize, {withLocalizePropTypes} from './withLocalize';
import ConfirmModal from './ConfirmModal';
import HeaderGap from './HeaderGap';
import SafeAreaConsumer from './SafeAreaConsumer';
+import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL';
/**
* Modal render prop component that exposes modal launching triggers that can be used
@@ -84,6 +85,7 @@ class AttachmentModal extends PureComponent {
isModalOpen: false,
shouldLoadAttachment: false,
isAttachmentInvalid: false,
+ isAuthTokenRequired: props.isAuthTokenRequired,
attachmentInvalidReasonTitle: null,
attachmentInvalidReason: null,
source: props.source,
@@ -100,17 +102,17 @@ class AttachmentModal extends PureComponent {
this.submitAndClose = this.submitAndClose.bind(this);
this.closeConfirmModal = this.closeConfirmModal.bind(this);
this.onNavigate = this.onNavigate.bind(this);
+ this.downloadAttachment = this.downloadAttachment.bind(this);
this.validateAndDisplayFileToUpload = this.validateAndDisplayFileToUpload.bind(this);
this.updateConfirmButtonVisibility = this.updateConfirmButtonVisibility.bind(this);
}
/**
- * Helps to navigate between next/previous attachments
- * by setting sourceURL and file in state
- * @param {Object} attachmentData
+ * Keeps the attachment source in sync with the attachment displayed currently in the carousel.
+ * @param {{ source: String, isAuthTokenRequired: Boolean, file: { name: string } }} attachment
*/
- onNavigate(attachmentData) {
- this.setState(attachmentData);
+ onNavigate(attachment) {
+ this.setState(attachment);
}
/**
@@ -126,11 +128,15 @@ class AttachmentModal extends PureComponent {
}
/**
- * @param {String} sourceURL
+ * Download the currently viewed attachment.
*/
- downloadAttachment(sourceURL) {
- const originalFileName = lodashGet(this.state, 'file.name') || this.props.originalFileName;
- fileDownload(sourceURL, originalFileName);
+ downloadAttachment() {
+ let sourceURL = this.state.source;
+ if (this.state.isAuthTokenRequired) {
+ sourceURL = addEncryptedAuthTokenToURL(sourceURL);
+ }
+
+ fileDownload(sourceURL, this.state.file.name);
// At ios, if the keyboard is open while opening the attachment, then after downloading
// the attachment keyboard will show up. So, to fix it we need to dismiss the keyboard.
@@ -274,7 +280,7 @@ class AttachmentModal extends PureComponent {
title={this.props.headerTitle || this.props.translate('common.attachment')}
shouldShowBorderBottom
shouldShowDownloadButton={this.props.allowDownload}
- onDownloadButtonPress={() => this.downloadAttachment(this.state.source)}
+ onDownloadButtonPress={this.downloadAttachment}
onCloseButtonPress={() => this.setState({isModalOpen: false})}
/>
@@ -291,7 +297,7 @@ class AttachmentModal extends PureComponent {
diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
index 6a3e766175a4..b5758680619a 100644
--- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
+++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
@@ -44,6 +44,7 @@ const BaseAutoCompleteSuggestions = (props) => {
);
const rowHeight = measureHeightOfSuggestionRows(props.suggestions.length, props.isSuggestionPickerLarge);
+ const innerHeight = CONST.AUTO_COMPLETE_SUGGESTER.ITEM_HEIGHT * props.suggestions.length;
return (
{
renderItem={renderSuggestionMenuItem}
keyExtractor={props.keyExtractor}
removeClippedSubviews={false}
- style={{height: rowHeight}}
+ showsVerticalScrollIndicator={innerHeight > rowHeight}
+ style={{flex: 1}}
/>
);
diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js
index 298f1252d48a..a11af52f6887 100644
--- a/src/components/CheckboxWithLabel.js
+++ b/src/components/CheckboxWithLabel.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState, useEffect} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import _ from 'underscore';
@@ -9,6 +9,11 @@ import FormHelpMessage from './FormHelpMessage';
import variables from '../styles/variables';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
+/**
+ * Returns an error if the required props are not provided
+ * @param {Object} props
+ * @returns {Error|null}
+ */
const requiredPropsCheck = (props) => {
if (!props.label && !props.LabelComponent) {
return new Error('One of "label" or "LabelComponent" must be provided');
@@ -73,55 +78,55 @@ const defaultProps = {
forwardedRef: () => {},
};
-class CheckboxWithLabel extends React.Component {
- constructor(props) {
- super(props);
-
- // We need to pick the first value that is strictly a boolean
- // https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
- this.isChecked = _.find([props.value, props.defaultValue, props.isChecked], (value) => _.isBoolean(value));
-
- this.LabelComponent = props.LabelComponent;
-
- this.toggleCheckbox = this.toggleCheckbox.bind(this);
- }
-
- toggleCheckbox() {
- this.props.onInputChange(!this.isChecked);
- this.isChecked = !this.isChecked;
- }
-
- render() {
- return (
-
-
-
-
- {this.props.label && {this.props.label}}
- {this.LabelComponent && }
-
-
-
+const CheckboxWithLabel = (props) => {
+ // We need to pick the first value that is strictly a boolean
+ // https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
+ const [isChecked, setIsChecked] = useState(_.find([props.value, props.defaultValue, props.isChecked], (value) => _.isBoolean(value)));
+
+ const toggleCheckbox = () => {
+ const newState = !isChecked;
+ props.onInputChange(newState);
+ setIsChecked(newState);
+ };
+
+ useEffect(() => {
+ setIsChecked(props.isChecked);
+ }, [props.isChecked]);
+
+ const LabelComponent = props.LabelComponent;
+
+ return (
+
+
+
+
+ {props.label && {props.label}}
+ {LabelComponent && }
+
- );
- }
-}
+
+
+ );
+};
CheckboxWithLabel.propTypes = propTypes;
CheckboxWithLabel.defaultProps = defaultProps;
+CheckboxWithLabel.displayName = 'CheckboxWithLabel';
export default React.forwardRef((props, ref) => (
{
+ setIsSkinToneListVisible((prev) => !prev);
+ }, []);
/**
* Pass the skinTone to props and hide the picker
* @param {object} skinToneEmoji
*/
- updateSelectedSkinTone(skinToneEmoji) {
- this.setState((prev) => ({isSkinToneListVisible: !prev.isSkinToneListVisible, highlightedIndex: skinToneEmoji.skinTone}));
- this.props.updatePreferredSkinTone(skinToneEmoji.skinTone);
+ function updateSelectedSkinTone(skinToneEmoji) {
+ toggleIsSkinToneListVisible();
+ setHighlightedIndex(skinToneEmoji.skinTone);
+ props.updatePreferredSkinTone(skinToneEmoji.skinTone);
}
- render() {
- const selectedEmoji = getSkinToneEmojiFromIndex(this.props.preferredSkinTone);
- return (
-
- {!this.state.isSkinToneListVisible && (
- this.setState((prev) => ({isSkinToneListVisible: !prev.isSkinToneListVisible}))}
- style={[styles.flex1, styles.flexRow, styles.alignSelfCenter, styles.justifyContentStart, styles.alignItemsCenter]}
- >
-
- {selectedEmoji.code}
-
- {this.props.translate('emojiPicker.skinTonePickerLabel')}
-
- )}
- {this.state.isSkinToneListVisible && (
-
- {_.map(Emojis.skinTones, (skinToneEmoji) => (
- this.updateSelectedSkinTone(skinToneEmoji)}
- onHoverIn={() => this.setState({highlightedIndex: skinToneEmoji.skinTone})}
- onHoverOut={() => this.setState({highlightedIndex: selectedEmoji.skinTone})}
- key={skinToneEmoji.code}
- emoji={skinToneEmoji.code}
- isHighlighted={skinToneEmoji.skinTone === this.state.highlightedIndex || skinToneEmoji.skinTone === selectedEmoji.skinTone}
- />
- ))}
+ const currentSkinTone = getSkinToneEmojiFromIndex(props.preferredSkinTone);
+ return (
+
+ {!isSkinToneListVisible && (
+
+
+ {currentSkinTone.code}
- )}
-
- );
- }
+ {props.translate('emojiPicker.skinTonePickerLabel')}
+
+ )}
+ {isSkinToneListVisible && (
+
+ {_.map(Emojis.skinTones, (skinToneEmoji) => (
+ updateSelectedSkinTone(skinToneEmoji)}
+ onHoverIn={() => setHighlightedIndex(skinToneEmoji.skinTone)}
+ onHoverOut={() => setHighlightedIndex(null)}
+ key={skinToneEmoji.code}
+ emoji={skinToneEmoji.code}
+ isHighlighted={skinToneEmoji.skinTone === highlightedIndex || skinToneEmoji.skinTone === currentSkinTone.skinTone}
+ />
+ ))}
+
+ )}
+
+ );
}
EmojiSkinToneList.propTypes = propTypes;
+EmojiSkinToneList.displayName = 'EmojiSkinToneList';
export default withLocalize(EmojiSkinToneList);
diff --git a/src/components/Form.js b/src/components/Form.js
index 5bcf97cf3547..578081ad0678 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -1,5 +1,5 @@
+import React, {useState, useEffect, useCallback, useRef} from 'react';
import lodashGet from 'lodash/get';
-import React from 'react';
import {Keyboard, ScrollView, StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
@@ -87,120 +87,99 @@ const defaultProps = {
style: [],
};
-class Form extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- errors: {},
- inputValues: {
- ...props.draftValues,
- },
- };
-
- this.formRef = React.createRef(null);
- this.formContentRef = React.createRef(null);
- this.inputRefs = {};
- this.touchedInputs = {};
-
- this.setTouchedInput = this.setTouchedInput.bind(this);
- this.validate = this.validate.bind(this);
- this.submit = this.submit.bind(this);
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.preferredLocale === this.props.preferredLocale) {
- return;
- }
+const Form = (props) => {
+ const [errors, setErrors] = useState({});
+ const [inputValues, setInputValues] = useState({...props.draftValues});
+ const formRef = useRef(null);
+ const formContentRef = useRef(null);
+ const inputRefs = useRef({});
+ const touchedInputs = useRef({});
- // Update the error messages if the language changes
- this.validate(this.state.inputValues);
- }
+ const {validate, translate, onSubmit, children} = props;
- getErrorMessage() {
- const latestErrorMessage = ErrorUtils.getLatestErrorMessage(this.props.formState);
- return this.props.formState.error || (typeof latestErrorMessage === 'string' ? latestErrorMessage : '');
- }
+ /**
+ * @param {Object} values - An object containing the value of each inputID, e.g. {inputID1: value1, inputID2: value2}
+ * @returns {Object} - An object containing the errors for each inputID, e.g. {inputID1: error1, inputID2: error2}
+ */
+ const onValidate = useCallback(
+ (values) => {
+ const trimmedStringValues = {};
+ _.each(values, (inputValue, inputID) => {
+ if (_.isString(inputValue)) {
+ trimmedStringValues[inputID] = inputValue.trim();
+ } else {
+ trimmedStringValues[inputID] = inputValue;
+ }
+ });
- getFirstErroredInput() {
- const hasStateErrors = !_.isEmpty(this.state.errors);
- const hasErrorFields = !_.isEmpty(this.props.formState.errorFields);
+ FormActions.setErrors(props.formID, null);
+ FormActions.setErrorFields(props.formID, null);
- if (!hasStateErrors && !hasErrorFields) {
- return;
- }
+ // Run any validations passed as a prop
+ const validationErrors = validate(trimmedStringValues);
+
+ // Validate the input for html tags. It should supercede any other error
+ _.each(trimmedStringValues, (inputValue, inputID) => {
+ // Return early if there is no value OR the value is not a string OR there are no HTML characters
+ if (!inputValue || !_.isString(inputValue) || inputValue.search(CONST.VALIDATE_FOR_HTML_TAG_REGEX) === -1) {
+ return;
+ }
+
+ // Add a validation error here because it is a string value that contains HTML characters
+ validationErrors[inputID] = translate('common.error.invalidCharacter');
+ });
+
+ if (!_.isObject(validationErrors)) {
+ throw new Error('Validate callback must return an empty object or an object with shape {inputID: error}');
+ }
+
+ const touchedInputErrors = _.pick(validationErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID]));
+
+ if (!_.isEqual(errors, touchedInputErrors)) {
+ setErrors(touchedInputErrors);
+ }
+
+ return touchedInputErrors;
+ },
+ [errors, touchedInputs, props.formID, validate, translate],
+ );
- return _.first(_.keys(hasStateErrors ? this.state.erorrs : this.props.formState.errorFields));
- }
+ useEffect(() => {
+ onValidate(inputValues);
+ }, [onValidate, inputValues]);
+
+ const getErrorMessage = useCallback(() => {
+ const latestErrorMessage = ErrorUtils.getLatestErrorMessage(props.formState);
+ return props.formState.error || (typeof latestErrorMessage === 'string' ? latestErrorMessage : '');
+ }, [props.formState]);
/**
* @param {String} inputID - The inputID of the input being touched
*/
- setTouchedInput(inputID) {
- this.touchedInputs[inputID] = true;
- }
+ const setTouchedInput = useCallback(
+ (inputID) => {
+ touchedInputs.current[inputID] = true;
+ },
+ [touchedInputs],
+ );
- submit() {
+ const submit = useCallback(() => {
// Return early if the form is already submitting to avoid duplicate submission
- if (this.props.formState.isLoading) {
+ if (props.formState.isLoading) {
return;
}
// Touches all form inputs so we can validate the entire form
- _.each(this.inputRefs, (inputRef, inputID) => (this.touchedInputs[inputID] = true));
+ _.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true));
// Validate form and return early if any errors are found
- if (!_.isEmpty(this.validate(this.state.inputValues))) {
+ if (!_.isEmpty(onValidate(inputValues))) {
return;
}
// Call submit handler
- this.props.onSubmit(this.state.inputValues);
- }
-
- /**
- * @param {Object} values - An object containing the value of each inputID, e.g. {inputID1: value1, inputID2: value2}
- * @returns {Object} - An object containing the errors for each inputID, e.g. {inputID1: error1, inputID2: error2}
- */
- validate(values) {
- const trimmedStringValues = {};
- _.each(values, (inputValue, inputID) => {
- if (_.isString(inputValue)) {
- trimmedStringValues[inputID] = inputValue.trim();
- } else {
- trimmedStringValues[inputID] = inputValue;
- }
- });
-
- FormActions.setErrors(this.props.formID, null);
- FormActions.setErrorFields(this.props.formID, null);
-
- // Run any validations passed as a prop
- const validationErrors = this.props.validate(trimmedStringValues);
-
- // Validate the input for html tags. It should supercede any other error
- _.each(trimmedStringValues, (inputValue, inputID) => {
- // Return early if there is no value OR the value is not a string OR there are no HTML characters
- if (!inputValue || !_.isString(inputValue) || inputValue.search(CONST.VALIDATE_FOR_HTML_TAG_REGEX) === -1) {
- return;
- }
-
- // Add a validation error here because it is a string value that contains HTML characters
- validationErrors[inputID] = this.props.translate('common.error.invalidCharacter');
- });
-
- if (!_.isObject(validationErrors)) {
- throw new Error('Validate callback must return an empty object or an object with shape {inputID: error}');
- }
-
- const errors = _.pick(validationErrors, (inputValue, inputID) => Boolean(this.touchedInputs[inputID]));
-
- if (!_.isEqual(errors, this.state.errors)) {
- this.setState({errors});
- }
-
- return errors;
- }
+ onSubmit(inputValues);
+ }, [props.formState, onSubmit, inputRefs, inputValues, onValidate, touchedInputs]);
/**
* Loops over Form's children and automatically supplies Form props to them
@@ -208,154 +187,152 @@ class Form extends React.Component {
* @param {Array | Function | Node} children - An array containing all Form children
* @returns {React.Component}
*/
- childrenWrapperWithProps(children) {
- return React.Children.map(children, (child) => {
- // Just render the child if it is not a valid React element, e.g. text within a component
- if (!React.isValidElement(child)) {
- return child;
- }
+ const childrenWrapperWithProps = useCallback(
+ (childNodes) =>
+ React.Children.map(childNodes, (child) => {
+ // Just render the child if it is not a valid React element, e.g. text within a component
+ if (!React.isValidElement(child)) {
+ return child;
+ }
- // Depth first traversal of the render tree as the input element is likely to be the last node
- if (child.props.children) {
- return React.cloneElement(child, {
- children: this.childrenWrapperWithProps(child.props.children),
- });
- }
+ // Depth first traversal of the render tree as the input element is likely to be the last node
+ if (child.props.children) {
+ return React.cloneElement(child, {
+ children: childrenWrapperWithProps(child.props.children),
+ });
+ }
+
+ // Look for any inputs nested in a custom component, e.g AddressForm or IdentityForm
+ if (_.isFunction(child.type)) {
+ const childNode = new child.type(child.props);
- // Look for any inputs nested in a custom component, e.g AddressForm or IdentityForm
- if (_.isFunction(child.type)) {
- const childNode = new child.type(child.props);
+ // If the custom component has a render method, use it to get the nested children
+ const nestedChildren = _.isFunction(childNode.render) ? childNode.render() : childNode;
- // If the custom component has a render method, use it to get the nested children
- const nestedChildren = _.isFunction(childNode.render) ? childNode.render() : childNode;
+ // Render the custom component if it's a valid React element
+ // If the custom component has nested children, Loop over them and supply From props
+ if (React.isValidElement(nestedChildren) || lodashGet(nestedChildren, 'props.children')) {
+ return childrenWrapperWithProps(nestedChildren);
+ }
- // Render the custom component if it's a valid React element
- // If the custom component has nested children, Loop over them and supply From props
- if (React.isValidElement(nestedChildren) || lodashGet(nestedChildren, 'props.children')) {
- return this.childrenWrapperWithProps(nestedChildren);
+ // Just render the child if it's custom component not a valid React element, or if it hasn't children
+ return child;
}
- // Just render the child if it's custom component not a valid React element, or if it hasn't children
- return child;
- }
+ // We check if the child has the inputID prop.
+ // We don't want to pass form props to non form components, e.g. View, Text, etc
+ if (!child.props.inputID) {
+ return child;
+ }
- // We check if the child has the inputID prop.
- // We don't want to pass form props to non form components, e.g. View, Text, etc
- if (!child.props.inputID) {
- return child;
- }
+ // We clone the child passing down all form props
+ const inputID = child.props.inputID;
+ let defaultValue;
+
+ // We need to make sure that checkboxes have correct
+ // value assigned from the list of draft values
+ // https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
+ if (_.isBoolean(props.draftValues[inputID])) {
+ defaultValue = props.draftValues[inputID];
+ } else {
+ defaultValue = props.draftValues[inputID] || child.props.defaultValue;
+ }
- // We clone the child passing down all form props
- const inputID = child.props.inputID;
- let defaultValue;
-
- // We need to make sure that checkboxes have correct
- // value assigned from the list of draft values
- // https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
- if (_.isBoolean(this.props.draftValues[inputID])) {
- defaultValue = this.props.draftValues[inputID];
- } else {
- defaultValue = this.props.draftValues[inputID] || child.props.defaultValue;
- }
+ // We want to initialize the input value if it's undefined
+ if (_.isUndefined(inputValues[inputID])) {
+ inputValues[inputID] = defaultValue;
+ }
- // We want to initialize the input value if it's undefined
- if (_.isUndefined(this.state.inputValues[inputID])) {
- this.state.inputValues[inputID] = defaultValue;
- }
+ // We force the form to set the input value from the defaultValue props if there is a saved valid value
+ if (child.props.shouldUseDefaultValue) {
+ inputValues[inputID] = child.props.defaultValue;
+ }
- // We force the form to set the input value from the defaultValue props if there is a saved valid value
- if (child.props.shouldUseDefaultValue) {
- this.state.inputValues[inputID] = child.props.defaultValue;
- }
+ if (!_.isUndefined(child.props.value)) {
+ inputValues[inputID] = child.props.value;
+ }
- if (!_.isUndefined(child.props.value)) {
- this.state.inputValues[inputID] = child.props.value;
- }
+ const errorFields = lodashGet(props.formState, 'errorFields', {});
+ const fieldErrorMessage =
+ _.chain(errorFields[inputID])
+ .keys()
+ .sortBy()
+ .reverse()
+ .map((key) => errorFields[inputID][key])
+ .first()
+ .value() || '';
- const errorFields = lodashGet(this.props.formState, 'errorFields', {});
- const fieldErrorMessage =
- _.chain(errorFields[inputID])
- .keys()
- .sortBy()
- .reverse()
- .map((key) => errorFields[inputID][key])
- .first()
- .value() || '';
-
- return React.cloneElement(child, {
- ref: (node) => {
- this.inputRefs[inputID] = node;
-
- const {ref} = child;
- if (_.isFunction(ref)) {
- ref(node);
- }
- },
- value: this.state.inputValues[inputID],
- errorText: this.state.errors[inputID] || fieldErrorMessage,
- onBlur: (event) => {
- // We delay the validation in order to prevent Checkbox loss of focus when
- // the user are focusing a TextInput and proceeds to toggle a CheckBox in
- // web and mobile web platforms.
- setTimeout(() => {
- this.setTouchedInput(inputID);
- this.validate(this.state.inputValues);
- }, 200);
-
- if (_.isFunction(child.props.onBlur)) {
- child.props.onBlur(event);
- }
- },
- onTouched: () => {
- this.setTouchedInput(inputID);
- },
- onInputChange: (value, key) => {
- const inputKey = key || inputID;
- this.setState(
- (prevState) => ({
- inputValues: {
- ...prevState.inputValues,
+ return React.cloneElement(child, {
+ ref: (node) => {
+ inputRefs.current[inputID] = node;
+
+ const {ref} = child;
+ if (_.isFunction(ref)) {
+ ref(node);
+ }
+ },
+ value: inputValues[inputID],
+ errorText: errors[inputID] || fieldErrorMessage,
+ onBlur: (event) => {
+ // We delay the validation in order to prevent Checkbox loss of focus when
+ // the user are focusing a TextInput and proceeds to toggle a CheckBox in
+ // web and mobile web platforms.
+ setTimeout(() => {
+ setTouchedInput(inputID);
+ onValidate(inputValues);
+ }, 200);
+
+ if (_.isFunction(child.props.onBlur)) {
+ child.props.onBlur(event);
+ }
+ },
+ onTouched: () => {
+ setTouchedInput(inputID);
+ },
+ onInputChange: (value, key) => {
+ const inputKey = key || inputID;
+ setInputValues((prevState) => {
+ const newState = {
+ ...prevState,
[inputKey]: value,
- },
- }),
- () => this.validate(this.state.inputValues),
- );
-
- if (child.props.shouldSaveDraft) {
- FormActions.setDraftValues(this.props.formID, {[inputKey]: value});
- }
-
- if (child.props.onValueChange) {
- child.props.onValueChange(value);
- }
- },
- });
- });
- }
+ };
+ onValidate(newState);
+ return newState;
+ });
+
+ if (child.props.shouldSaveDraft) {
+ FormActions.setDraftValues(props.formID, {[inputKey]: value});
+ }
+
+ if (child.props.onValueChange) {
+ child.props.onValueChange(value);
+ }
+ },
+ });
+ }),
+ [errors, inputRefs, inputValues, onValidate, props.draftValues, props.formID, props.formState, setTouchedInput],
+ );
- render() {
- const scrollViewContent = (safeAreaPaddingBottomStyle) => (
+ const scrollViewContent = useCallback(
+ (safeAreaPaddingBottomStyle) => (
- {this.childrenWrapperWithProps(_.isFunction(this.props.children) ? this.props.children({inputValues: this.state.inputValues}) : this.props.children)}
- {this.props.isSubmitButtonVisible && (
+ {childrenWrapperWithProps(_.isFunction(children) ? children({inputValues}) : children)}
+ {props.isSubmitButtonVisible && (
0 || Boolean(this.getErrorMessage()) || !_.isEmpty(this.props.formState.errorFields)}
- isLoading={this.props.formState.isLoading}
- message={_.isEmpty(this.props.formState.errorFields) ? this.getErrorMessage() : null}
- onSubmit={this.submit}
- footerContent={this.props.footerContent}
+ buttonText={props.submitButtonText}
+ isAlertVisible={_.size(errors) > 0 || Boolean(getErrorMessage()) || !_.isEmpty(props.formState.errorFields)}
+ isLoading={props.formState.isLoading}
+ message={_.isEmpty(props.formState.errorFields) ? getErrorMessage() : null}
+ onSubmit={submit}
+ footerContent={props.footerContent}
onFixTheErrorsLinkPressed={() => {
- const errors = !_.isEmpty(this.state.errors) ? this.state.errors : this.props.formState.errorFields;
- const focusKey = _.find(_.keys(this.inputRefs), (key) => _.keys(errors).includes(key));
- const focusInput = this.inputRefs[focusKey];
-
- const formRef = this.formRef.current;
- const formContentRef = this.formContentRef.current;
+ const errorFields = !_.isEmpty(errors) ? errors : props.formState.errorFields;
+ const focusKey = _.find(_.keys(inputRefs.current), (key) => _.keys(errorFields).includes(key));
+ const focusInput = inputRefs.current[focusKey];
// Start with dismissing the keyboard, so when we focus a non-text input, the keyboard is hidden
Keyboard.dismiss();
@@ -364,7 +341,7 @@ class Form extends React.Component {
if (focusInput.measureLayout && typeof focusInput.measureLayout === 'function') {
// We measure relative to the content root, not the scroll view, as that gives
// consistent results across mobile and web
- focusInput.measureLayout(formContentRef, (x, y) => formRef.scrollTo({y: y - 10, animated: false}));
+ focusInput.measureLayout(formContentRef.current, (x, y) => formRef.current.scrollTo({y: y - 10, animated: false}));
}
// Focus the input after scrolling, as on the Web it gives a slightly better visual result
@@ -373,42 +350,61 @@ class Form extends React.Component {
}
}}
containerStyles={[styles.mh0, styles.mt5, styles.flex1]}
- enabledWhenOffline={this.props.enabledWhenOffline}
- isSubmitActionDangerous={this.props.isSubmitActionDangerous}
+ enabledWhenOffline={props.enabledWhenOffline}
+ isSubmitActionDangerous={props.isSubmitActionDangerous}
disablePressOnEnter
/>
)}
- );
-
- return (
-
- {({safeAreaPaddingBottomStyle}) =>
- this.props.scrollContextEnabled ? (
-
- {scrollViewContent(safeAreaPaddingBottomStyle)}
-
- ) : (
-
- {scrollViewContent(safeAreaPaddingBottomStyle)}
-
- )
- }
-
- );
- }
-}
+ ),
+ [
+ childrenWrapperWithProps,
+ errors,
+ formContentRef,
+ formRef,
+ getErrorMessage,
+ inputRefs,
+ inputValues,
+ submit,
+ props.style,
+ children,
+ props.formState,
+ props.footerContent,
+ props.enabledWhenOffline,
+ props.isSubmitActionDangerous,
+ props.isSubmitButtonVisible,
+ props.submitButtonText,
+ ],
+ );
+
+ return (
+
+ {({safeAreaPaddingBottomStyle}) =>
+ props.scrollContextEnabled ? (
+
+ {scrollViewContent(safeAreaPaddingBottomStyle)}
+
+ ) : (
+
+ {scrollViewContent(safeAreaPaddingBottomStyle)}
+
+ )
+ }
+
+ );
+};
+Form.displayName = 'Form';
Form.propTypes = propTypes;
Form.defaultProps = defaultProps;
diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js
index 70503706f112..db093d2bc4df 100644
--- a/src/components/Icon/Expensicons.js
+++ b/src/components/Icon/Expensicons.js
@@ -41,6 +41,10 @@ import ExpensifyWordmark from '../../../assets/images/expensify-wordmark.svg';
import Expand from '../../../assets/images/expand.svg';
import Eye from '../../../assets/images/eye.svg';
import EyeDisabled from '../../../assets/images/eye-disabled.svg';
+import Flag from '../../../assets/images/flag.svg';
+import FlagLevelOne from '../../../assets/images/flag_level_01.svg';
+import FlagLevelTwo from '../../../assets/images/flag_level_02.svg';
+import FlagLevelThree from '../../../assets/images/flag_level_03.svg';
import Gallery from '../../../assets/images/gallery.svg';
import Gear from '../../../assets/images/gear.svg';
import Globe from '../../../assets/images/globe.svg';
@@ -162,6 +166,10 @@ export {
EyeDisabled,
FallbackAvatar,
FallbackWorkspaceAvatar,
+ Flag,
+ FlagLevelOne,
+ FlagLevelTwo,
+ FlagLevelThree,
Gallery,
Gear,
Globe,
diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js
index f1ec25485991..7138f4087ed4 100644
--- a/src/components/ImageView/index.js
+++ b/src/components/ImageView/index.js
@@ -282,6 +282,7 @@ class ImageView extends PureComponent {
>
-
+
{decomposeString(props.value, props.maxLength)[index] || ''}
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index 66536b796eea..21195a9f4ca2 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -21,6 +21,7 @@ import PressableWithSecondaryInteraction from './PressableWithSecondaryInteracti
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
import * as DeviceCapabilities from '../libs/DeviceCapabilities';
import ControlSelection from '../libs/ControlSelection';
+import variables from '../styles/variables';
const propTypes = {
...menuItemPropTypes,
@@ -62,6 +63,9 @@ const defaultProps = {
shouldStackHorizontally: false,
avatarSize: undefined,
shouldBlockSelection: false,
+ hoverAndPressStyle: [],
+ furtherDetails: '',
+ furtherDetailsIcon: undefined,
};
const MenuItem = (props) => {
@@ -112,6 +116,7 @@ const MenuItem = (props) => {
props.style,
!props.interactive && styles.cursorDefault,
StyleUtils.getButtonBackgroundColorStyle(getButtonState(props.focused || hovered, pressed, props.success, props.disabled, props.interactive), true),
+ (hovered || pressed) && props.hoverAndPressStyle,
...(_.isArray(props.wrapperStyle) ? props.wrapperStyle : [props.wrapperStyle]),
]}
disabled={props.disabled}
@@ -187,6 +192,22 @@ const MenuItem = (props) => {
{props.description}
)}
+ {Boolean(props.furtherDetails) && (
+
+
+
+ {props.furtherDetails}
+
+
+ )}
diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js
index ab706197351a..902c724aa614 100644
--- a/src/components/ReportActionItem/IOUPreview.js
+++ b/src/components/ReportActionItem/IOUPreview.js
@@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import _ from 'underscore';
-import Str from 'expensify-common/lib/str';
import compose from '../../libs/compose';
import styles from '../../styles/styles';
import ONYXKEYS from '../../ONYXKEYS';
@@ -141,7 +140,7 @@ const IOUPreview = (props) => {
const requestAmount = moneyRequestAction.amount;
const requestCurrency = moneyRequestAction.currency;
- const requestComment = Str.htmlDecode(moneyRequestAction.comment).trim();
+ const requestComment = moneyRequestAction.comment.trim();
const getSettledMessage = () => {
switch (lodashGet(props.action, 'originalMessage.paymentType', '')) {
diff --git a/src/components/ReportTransaction.js b/src/components/ReportTransaction.js
deleted file mode 100644
index 166921cb3845..000000000000
--- a/src/components/ReportTransaction.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import {View} from 'react-native';
-import styles from '../styles/styles';
-import * as IOU from '../libs/actions/IOU';
-import * as ReportActions from '../libs/actions/ReportActions';
-import reportActionPropTypes from '../pages/home/report/reportActionPropTypes';
-import ReportActionItemSingle from '../pages/home/report/ReportActionItemSingle';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import OfflineWithFeedback from './OfflineWithFeedback';
-import Text from './Text';
-import Button from './Button';
-
-const propTypes = {
- /** The chatReport which the transaction is associated with */
- /* eslint-disable-next-line react/no-unused-prop-types */
- chatReportID: PropTypes.string.isRequired,
-
- /** ID for the IOU report */
- /* eslint-disable-next-line react/no-unused-prop-types */
- iouReportID: PropTypes.string.isRequired,
-
- /** The report action which we are displaying */
- action: PropTypes.shape(reportActionPropTypes).isRequired,
-
- /** Can this transaction be deleted? */
- canBeDeleted: PropTypes.bool,
-
- /** Indicates whether pressing the delete button should hide the details sidebar */
- shouldCloseOnDelete: PropTypes.bool,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- canBeDeleted: false,
- shouldCloseOnDelete: false,
-};
-
-class ReportTransaction extends Component {
- constructor(props) {
- super(props);
-
- this.deleteMoneyRequest = this.deleteMoneyRequest.bind(this);
- }
-
- deleteMoneyRequest() {
- IOU.deleteMoneyRequest(this.props.chatReportID, this.props.iouReportID, this.props.action, this.props.shouldCloseOnDelete);
- }
-
- render() {
- return (
- ReportActions.clearReportActionErrors(this.props.chatReportID, this.props.action)}
- pendingAction={this.props.action.pendingAction}
- errors={this.props.action.errors}
- errorRowStyles={[styles.ml10, styles.mr2]}
- >
-
-
- {this.props.action.message[0].text}
-
- {this.props.canBeDeleted && (
-
-
-
- )}
-
-
- );
- }
-}
-
-ReportTransaction.defaultProps = defaultProps;
-ReportTransaction.propTypes = propTypes;
-export default withLocalize(ReportTransaction);
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index 5403cf3055b1..616f548136a0 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -51,6 +51,9 @@ class Tooltip extends PureComponent {
* @param {Object} bounds - updated bounds
*/
updateBounds(bounds) {
+ if (bounds.width === 0) {
+ this.setState({isRendered: false});
+ }
this.setState({
wrapperWidth: bounds.width,
wrapperHeight: bounds.height,
diff --git a/src/components/ValidateCode/ValidateCodeModal.js b/src/components/ValidateCode/ValidateCodeModal.js
index c356458dc877..344c3107b8cf 100644
--- a/src/components/ValidateCode/ValidateCodeModal.js
+++ b/src/components/ValidateCode/ValidateCodeModal.js
@@ -39,7 +39,7 @@ const defaultProps = {
};
function ValidateCodeModal(props) {
- const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code, null, props.preferredLocale), [props.accountID, props.code, props.preferredLocale]);
+ const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code, props.preferredLocale), [props.accountID, props.code, props.preferredLocale]);
return (
diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js
index c66c15e383e0..57266831377f 100644
--- a/src/components/menuItemPropTypes.js
+++ b/src/components/menuItemPropTypes.js
@@ -107,6 +107,15 @@ const propTypes = {
/** The ref to the menu item */
forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
+
+ /** Any adjustments to style when menu item is hovered or pressed */
+ hoverAndPressStyle: PropTypes.arrayOf(PropTypes.object),
+
+ /** Text to display under the main item */
+ furtherDetails: PropTypes.string,
+
+ /** An icon to display under the main item */
+ furtherDetailsIcon: PropTypes.oneOfType([PropTypes.elementType, PropTypes.string]),
};
export default propTypes;
diff --git a/src/languages/en.js b/src/languages/en.js
index 5302eb77b183..77638749d904 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -270,6 +270,7 @@ export default {
deleteConfirmation: ({action}) => `Are you sure you want to delete this ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}?`,
onlyVisible: 'Only visible to',
replyInThread: 'Reply in thread',
+ flagAsOffensive: 'Flag as offensive',
},
emojiReactions: {
addReactionTooltip: 'Add reaction',
@@ -1405,4 +1406,26 @@ export default {
copyUrlToClipboard: 'Copy URL to clipboard',
copied: 'Copied!',
},
+ moderation: {
+ flagDescription: 'All flagged messages will be sent to a moderator for review.',
+ chooseAReason: 'Choose a reason for flagging below:',
+ spam: 'Spam',
+ spamDescription: 'Unsolicited off-topic promotion',
+ inconsiderate: 'Inconsiderate',
+ inconsiderateDescription: 'Insulting or disrespectful phrasing, with questionable intentions',
+ intimidation: 'Intimidation',
+ intimidationDescription: 'Aggressively pursuing an agenda over valid objections',
+ bullying: 'Bullying',
+ bullyingDescription: 'Targeting an individual to obtain obedience',
+ harassment: 'Harassment',
+ harassmentDescription: 'Racist, misogynistic, or other broadly discriminatory behavior',
+ assault: 'Assault',
+ assaultDescription: 'Specifically targeted emotional attack with the intention of harm',
+ flaggedContent: 'This message has been flagged as violating our community rules and the content has been hidden.',
+ hideMessage: 'Hide message',
+ revealMessage: 'Reveal message',
+ levelOneResult: 'Sends anonymous warning and message is reported for review.',
+ levelTwoResult: 'Message hidden from channel, plus anonymous warning and message is reported for review.',
+ levelThreeResult: 'Message removed from channel plus anonymous warning and message is reported for review.',
+ },
};
diff --git a/src/languages/es.js b/src/languages/es.js
index 26b919ab5511..2a0631bf9703 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -269,6 +269,7 @@ export default {
deleteConfirmation: ({action}) => `¿Estás seguro de que quieres eliminar este ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`,
onlyVisible: 'Visible sólo para',
replyInThread: 'Responder en el hilo',
+ flagAsOffensive: 'Marcar como ofensivo',
},
emojiReactions: {
addReactionTooltip: 'Añadir una reacción',
@@ -1871,4 +1872,26 @@ export default {
copyUrlToClipboard: 'Copiar URL al portapapeles',
copied: '¡Copiado!',
},
+ moderation: {
+ flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
+ chooseAReason: 'Elige abajo un motivo para reportarlo:',
+ spam: 'Spam',
+ spamDescription: 'Promoción fuera de tema no solicitada',
+ inconsiderate: 'Desconsiderado',
+ inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables',
+ intimidation: 'Intimidación',
+ intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas',
+ bullying: 'Bullying',
+ bullyingDescription: 'Apunta a un individuo para obtener obediencia',
+ harassment: 'Acoso',
+ harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio',
+ assault: 'Agresion',
+ assaultDescription: 'Ataque emocional especÃficamente dirigido con la intención de hacer daño',
+ flaggedContent: 'Este mensaje ha sido marcado por violar las reglas de nuestra comunidad y el contenido se ha ocultado.',
+ hideMessage: 'Ocultar mensaje',
+ revealMessage: 'Revelar mensaje',
+ levelOneResult: 'Envia una advertencia anónima y el mensaje es reportado para revisión.',
+ levelTwoResult: 'Mensaje ocultado del canal, más advertencia anónima y mensaje reportado para revisión.',
+ levelThreeResult: 'Mensaje eliminado del canal, más advertencia anónima y mensaje reportado para revisión.',
+ },
};
diff --git a/src/libs/BootSplash/index.js b/src/libs/BootSplash/index.js
index b9b8692f687c..ff7ab5562b1f 100644
--- a/src/libs/BootSplash/index.js
+++ b/src/libs/BootSplash/index.js
@@ -9,9 +9,10 @@ function hide() {
return document.fonts.ready.then(() => {
const splash = document.getElementById('splash');
- splash.style.opacity = 0;
+ if (splash) splash.style.opacity = 0;
return resolveAfter(250).then(() => {
+ if (!splash || !splash.parentNode) return;
splash.parentNode.removeChild(splash);
});
});
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 0e523002a939..397e970ed1f6 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -157,7 +157,7 @@ class AuthScreens extends React.Component {
}
shouldComponentUpdate(nextProps) {
- return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
+ return nextProps.windowHeight !== this.props.windowHeight || nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
}
componentWillUnmount() {
@@ -184,7 +184,10 @@ class AuthScreens extends React.Component {
};
const modalScreenOptions = {
...commonModalScreenOptions,
- cardStyle: getNavigationModalCardStyle(this.props.isSmallScreenWidth),
+ cardStyle: getNavigationModalCardStyle({
+ windowHeight: this.props.windowHeight,
+ isSmallScreenWidth: this.props.isSmallScreenWidth,
+ }),
cardStyleInterpolator: (props) => modalCardStyleInterpolator(this.props.isSmallScreenWidth, false, props),
cardOverlayEnabled: true,
@@ -370,6 +373,12 @@ class AuthScreens extends React.Component {
component={ModalStackNavigators.YearPickerStackNavigator}
listeners={modalScreenListeners}
/>
+
0;
}
+ componentDidMount() {
+ if (!this.props.lastOpenedPublicRoomID || Session.isAnonymousUser()) {
+ return;
+ }
+ // Re-open the last opened public room if the user logged in
+ Report.setLastOpenedPublicRoom('');
+ Report.openReport(this.props.lastOpenedPublicRoomID);
+ }
+
shouldComponentUpdate(nextProps) {
const initialNextParams = getInitialReportScreenParams(
nextProps.reports,
@@ -172,4 +187,7 @@ export default withOnyx({
isFirstTimeNewExpensifyUser: {
key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
},
+ lastOpenedPublicRoomID: {
+ key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID,
+ },
})(MainDrawerNavigator);
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 3322ff6fdeb2..966d40f9f7d0 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -702,6 +702,16 @@ const YearPickerStackNavigator = createModalStackNavigator([
},
]);
+const FlagCommentStackNavigator = createModalStackNavigator([
+ {
+ getComponent: () => {
+ const FlagCommentPage = require('../../../pages/FlagCommentPage').default;
+ return FlagCommentPage;
+ },
+ name: 'FlagComment_Root',
+ },
+]);
+
export {
IOUBillStackNavigator,
IOURequestModalStackNavigator,
@@ -723,4 +733,5 @@ export {
ReimbursementAccountModalStackNavigator,
WalletStatementStackNavigator,
YearPickerStackNavigator,
+ FlagCommentStackNavigator,
};
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index 4659477c2df9..7a45266b0355 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -327,6 +327,11 @@ export default {
YearPicker_Root: ROUTES.SELECT_YEAR,
},
},
+ Flag_Comment: {
+ screens: {
+ FlagComment_Root: ROUTES.FLAG_COMMENT,
+ },
+ },
[SCREENS.NOT_FOUND]: '*',
},
},
diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js
index d5551e06ba4a..6b6a9d5637c6 100644
--- a/src/libs/ReportActionsUtils.js
+++ b/src/libs/ReportActionsUtils.js
@@ -30,6 +30,14 @@ Onyx.connect({
callback: (val) => (isNetworkOffline = lodashGet(val, 'isOffline', false)),
});
+/**
+ * @param {Object} reportAction
+ * @returns {Boolean}
+ */
+function isCreatedAction(reportAction) {
+ return lodashGet(reportAction, 'actionName') === CONST.REPORT.ACTIONS.TYPE.CREATED;
+}
+
/**
* @param {Object} reportAction
* @returns {Boolean}
@@ -229,6 +237,10 @@ function getLastVisibleMessageText(reportID, actionsToMerge = {}) {
return CONST.ATTACHMENT_MESSAGE_TEXT;
}
+ if (isCreatedAction(lastVisibleAction)) {
+ return '';
+ }
+
const messageText = lodashGet(message, 'text', '');
return String(messageText).replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim();
}
diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index 249e862b753d..aeb170ddbd44 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -192,6 +192,24 @@ function canEditReportAction(reportAction) {
);
}
+/**
+ * Can only flag if:
+ *
+ * - It was written by someone else
+ * - It's an ADDCOMMENT that is not an attachment
+ *
+ * @param {Object} reportAction
+ * @returns {Boolean}
+ */
+function canFlagReportAction(reportAction) {
+ return (
+ reportAction.actorEmail !== sessionEmail &&
+ reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT &&
+ !ReportActionsUtils.isDeletedAction(reportAction) &&
+ !ReportActionsUtils.isCreatedTaskReportAction(reportAction)
+ );
+}
+
/**
* Whether the Money Request report is settled
*
@@ -455,6 +473,11 @@ function isAllowedToComment(report) {
return true;
}
+ // If unauthenticated user opens public chat room using deeplink, they do not have policies available and they cannot comment
+ if (!allPolicies) {
+ return false;
+ }
+
// If we've made it here, commenting on this report is restricted.
// If the user is an admin, allow them to post.
const policy = allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`];
@@ -1080,7 +1103,7 @@ function buildOptimisticAddCommentReportAction(text, file) {
const commentText = getParsedComment(text);
const isAttachment = _.isEmpty(text) && file !== undefined;
const attachmentInfo = isAttachment ? file : {};
- const htmlForNewComment = isAttachment ? 'Uploading attachment...' : commentText;
+ const htmlForNewComment = isAttachment ? CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML : commentText;
// Remove HTML from text when applying optimistic offline comment
const textForNewComment = isAttachment ? CONST.ATTACHMENT_MESSAGE_TEXT : parser.htmlToText(htmlForNewComment);
@@ -1264,7 +1287,7 @@ function getIOUReportActionMessage(type, total, comment, currency, paymentType =
return [
{
- html: getParsedComment(iouMessage),
+ html: iouMessage,
text: iouMessage,
isEdited: false,
type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
@@ -1289,13 +1312,10 @@ function getIOUReportActionMessage(type, total, comment, currency, paymentType =
*/
function buildOptimisticIOUReportAction(type, amount, currency, comment, participants, transactionID, paymentType = '', iouReportID = '', isSettlingUp = false, isSendMoneyFlow = false) {
const IOUReportID = iouReportID || generateReportID();
- const parser = new ExpensiMark();
- const commentText = getParsedComment(comment);
- const textForNewComment = parser.htmlToText(commentText);
- const textForNewCommentDecoded = Str.htmlDecode(textForNewComment);
+
const originalMessage = {
amount,
- comment: textForNewComment,
+ comment,
currency,
IOUTransactionID: transactionID,
IOUReportID,
@@ -1325,7 +1345,7 @@ function buildOptimisticIOUReportAction(type, amount, currency, comment, partici
avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserEmail)),
isAttachment: false,
originalMessage,
- message: getIOUReportActionMessage(type, amount, textForNewCommentDecoded, currency, paymentType, isSettlingUp),
+ message: getIOUReportActionMessage(type, amount, comment, currency, paymentType, isSettlingUp),
person: [
{
style: 'strong',
@@ -2111,11 +2131,25 @@ function isReportDataReady() {
return !_.isEmpty(allReports) && _.some(_.keys(allReports), (key) => allReports[key].reportID);
}
+/**
+ * Returns the parentReport if the given report is a thread.
+ *
+ * @param {Object} report
+ * @returns {Object}
+ */
+function getParentReport(report) {
+ if (!report || !report.parentReportID) {
+ return {};
+ }
+ return lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, {});
+}
+
export {
getReportParticipantsTitle,
isReportMessageAttachment,
findLastAccessedReport,
canEditReportAction,
+ canFlagReportAction,
canDeleteReportAction,
canLeaveRoom,
sortReportsByLastRead,
@@ -2197,4 +2231,5 @@ export {
isAllowedToComment,
getMoneyRequestAction,
getBankAccountRoute,
+ getParentReport,
};
diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js
index 2f710d5a88a5..26ddd30bceb3 100644
--- a/src/libs/actions/IOU.js
+++ b/src/libs/actions/IOU.js
@@ -348,14 +348,13 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment
);
// STEP 6: Make the request
- const parsedComment = ReportUtils.getParsedComment(comment);
API.write(
'RequestMoney',
{
debtorEmail: payerEmail,
amount,
currency,
- comment: parsedComment,
+ comment,
iouReportID: iouReport.reportID,
chatReportID: chatReport.reportID,
transactionID: optimisticTransaction.transactionID,
@@ -628,7 +627,6 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment
*/
function splitBill(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID = '') {
const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID);
- const parsedComment = ReportUtils.getParsedComment(comment);
API.write(
'SplitBill',
@@ -637,7 +635,7 @@ function splitBill(participants, currentUserLogin, amount, comment, currency, ex
amount,
splits: JSON.stringify(splits),
currency,
- comment: parsedComment,
+ comment,
transactionID: groupData.transactionID,
reportActionID: groupData.reportActionID,
createdReportActionID: groupData.createdReportActionID,
@@ -657,7 +655,6 @@ function splitBill(participants, currentUserLogin, amount, comment, currency, ex
*/
function splitBillAndOpenReport(participants, currentUserLogin, amount, comment, currency) {
const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency);
- const parsedComment = ReportUtils.getParsedComment(comment);
API.write(
'SplitBillAndOpenReport',
@@ -666,7 +663,7 @@ function splitBillAndOpenReport(participants, currentUserLogin, amount, comment,
amount,
splits: JSON.stringify(splits),
currency,
- comment: parsedComment,
+ comment,
transactionID: groupData.transactionID,
reportActionID: groupData.reportActionID,
createdReportActionID: groupData.createdReportActionID,
@@ -825,12 +822,11 @@ function buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency) {
*/
function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) {
const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login);
- const parsedComment = ReportUtils.getParsedComment(comment);
const newIOUReportDetails = JSON.stringify({
amount,
currency,
requestorEmail: recipientEmail,
- comment: parsedComment,
+ comment,
idempotencyKey: Str.guid(),
});
diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 0d512cafe916..7910f0e5e798 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -582,51 +582,6 @@ function readOldestAction(reportID, reportActionID) {
);
}
-/**
- * Gets the IOUReport and the associated report actions.
- *
- * @param {String} chatReportID
- * @param {Number} iouReportID
- */
-function openPaymentDetailsPage(chatReportID, iouReportID) {
- API.read(
- 'OpenPaymentDetailsPage',
- {
- reportID: chatReportID,
- iouReportID,
- },
- {
- optimisticData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.IOU,
- value: {
- loading: true,
- },
- },
- ],
- successData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.IOU,
- value: {
- loading: false,
- },
- },
- ],
- failureData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.IOU,
- value: {
- loading: false,
- },
- },
- ],
- },
- );
-}
-
/**
* Gets transactions and data associated with the linked report (expense or IOU report)
*
@@ -1728,30 +1683,34 @@ function setLastOpenedPublicRoom(reportID) {
* @param {String} severity
*/
function flagComment(reportID, reportAction, severity) {
- let newDecision;
+ const message = reportAction.message[0];
+ let updatedDecision;
if (severity === CONST.MODERATION.FLAG_SEVERITY_SPAM || severity === CONST.MODERATION.FLAG_SEVERITY_INCONSIDERATE) {
- newDecision = {
- decision: CONST.MODERATION.MODERATOR_DECISION_PENDING,
- };
+ if (_.isEmpty(message.moderationDecisions) || message.moderationDecisions[message.moderationDecisions.length - 1].decision !== CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE) {
+ updatedDecision = [
+ {
+ decision: CONST.MODERATION.MODERATOR_DECISION_PENDING,
+ },
+ ];
+ }
} else {
- newDecision = {
- decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE,
- };
+ updatedDecision = [
+ {
+ decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE,
+ },
+ ];
}
- const message = reportAction.message[0];
const reportActionID = reportAction.reportActionID;
- const updatedDecisions = [...(message.moderationDecisions || []), newDecision];
-
const updatedMessage = {
...message,
- moderationDecisions: updatedDecisions,
+ moderationDecisions: updatedDecision,
};
const optimisticData = [
{
- onyxMethod: CONST.ONYX.METHOD.MERGE,
+ onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[reportActionID]: {
@@ -1764,7 +1723,7 @@ function flagComment(reportID, reportAction, severity) {
const failureData = [
{
- onyxMethod: CONST.ONYX.METHOD.MERGE,
+ onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[reportActionID]: {
@@ -1777,7 +1736,7 @@ function flagComment(reportID, reportAction, severity) {
const successData = [
{
- onyxMethod: CONST.ONYX.METHOD.MERGE,
+ onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[reportActionID]: {
@@ -1826,7 +1785,6 @@ export {
openReportFromDeepLink,
navigateToAndOpenReport,
navigateToAndOpenChildReport,
- openPaymentDetailsPage,
updatePolicyRoomNameAndNavigate,
openMoneyRequestsReportPage,
clearPolicyRoomNameErrors,
diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js
index 4bcccaa08ddc..9cb3c127b287 100644
--- a/src/libs/actions/Session/index.js
+++ b/src/libs/actions/Session/index.js
@@ -419,7 +419,7 @@ function signIn(password, validateCode, twoFactorAuthCode, preferredLocale = CON
});
}
-function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) {
+function signInWithValidateCode(accountID, code, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') {
// If this is called from the 2fa step, get the validateCode directly from onyx
// instead of the one passed from the component state because the state is changing when this method is called.
const validateCode = twoFactorAuthCode ? credentials.validateCode : code;
@@ -495,8 +495,8 @@ function signInWithValidateCode(accountID, code, twoFactorAuthCode, preferredLoc
});
}
-function signInWithValidateCodeAndNavigate(accountID, validateCode, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) {
- signInWithValidateCode(accountID, validateCode, twoFactorAuthCode, preferredLocale);
+function signInWithValidateCodeAndNavigate(accountID, validateCode, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') {
+ signInWithValidateCode(accountID, validateCode, preferredLocale, twoFactorAuthCode);
Navigation.navigate(ROUTES.HOME);
}
diff --git a/src/libs/isReportMessageAttachment.js b/src/libs/isReportMessageAttachment.js
index db7df0df6c89..b449c72eaa0d 100644
--- a/src/libs/isReportMessageAttachment.js
+++ b/src/libs/isReportMessageAttachment.js
@@ -13,5 +13,5 @@ export default function isReportMessageAttachment({text, html}) {
}
const regex = new RegExp(` ${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}="(.*)"`, 'i');
- return text === CONST.ATTACHMENT_MESSAGE_TEXT && !!html.match(regex);
+ return text === CONST.ATTACHMENT_MESSAGE_TEXT && (!!html.match(regex) || html === CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML);
}
diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js
new file mode 100644
index 000000000000..5cbda92c814e
--- /dev/null
+++ b/src/pages/FlagCommentPage.js
@@ -0,0 +1,182 @@
+import React from 'react';
+import _ from 'underscore';
+import {View, ScrollView} from 'react-native';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
+import reportPropTypes from './reportPropTypes';
+import reportActionPropTypes from './home/report/reportActionPropTypes';
+import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
+import compose from '../libs/compose';
+import ONYXKEYS from '../ONYXKEYS';
+import ScreenWrapper from '../components/ScreenWrapper';
+import HeaderWithCloseButton from '../components/HeaderWithCloseButton';
+import styles from '../styles/styles';
+import Navigation from '../libs/Navigation/Navigation';
+import Text from '../components/Text';
+import * as Expensicons from '../components/Icon/Expensicons';
+import MenuItem from '../components/MenuItem';
+import * as Report from '../libs/actions/Report';
+import CONST from '../CONST';
+import * as ReportUtils from '../libs/ReportUtils';
+import * as ReportActionsUtils from '../libs/ReportActionsUtils';
+import * as Session from '../libs/actions/Session';
+
+const propTypes = {
+ /** Array of report actions for this report */
+ reportActions: PropTypes.shape(reportActionPropTypes),
+
+ /** The active report */
+ report: reportPropTypes,
+
+ /** Route params */
+ route: PropTypes.shape({
+ params: PropTypes.shape({
+ /** Report ID passed via route r/:reportID/:reportActionID */
+ reportID: PropTypes.string,
+
+ /** ReportActionID passed via route r/:reportID/:reportActionID */
+ reportActionID: PropTypes.string,
+ }),
+ }).isRequired,
+
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ reportActions: {},
+ report: {},
+};
+
+/**
+ * Get the reportID for the associated chatReport
+ *
+ * @param {Object} route
+ * @param {Object} route.params
+ * @param {String} route.params.reportID
+ * @returns {String}
+ */
+function getReportID(route) {
+ return route.params.reportID.toString();
+}
+
+function FlagCommentPage(props) {
+ let reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`];
+ const severities = [
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_SPAM,
+ name: props.translate('moderation.spam'),
+ icon: Expensicons.FlagLevelOne,
+ description: props.translate('moderation.spamDescription'),
+ furtherDetails: props.translate('moderation.levelOneResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelOne,
+ },
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_INCONSIDERATE,
+ name: props.translate('moderation.inconsiderate'),
+ icon: Expensicons.FlagLevelOne,
+ description: props.translate('moderation.inconsiderateDescription'),
+ furtherDetails: props.translate('moderation.levelOneResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelOne,
+ },
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_INTIMIDATION,
+ name: props.translate('moderation.intimidation'),
+ icon: Expensicons.FlagLevelTwo,
+ description: props.translate('moderation.intimidationDescription'),
+ furtherDetails: props.translate('moderation.levelTwoResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelTwo,
+ },
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_BULLYING,
+ name: props.translate('moderation.bullying'),
+ icon: Expensicons.FlagLevelTwo,
+ description: props.translate('moderation.bullyingDescription'),
+ furtherDetails: props.translate('moderation.levelTwoResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelTwo,
+ },
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_HARASSMENT,
+ name: props.translate('moderation.harassment'),
+ icon: Expensicons.FlagLevelThree,
+ description: props.translate('moderation.harassmentDescription'),
+ furtherDetails: props.translate('moderation.levelThreeResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelThree,
+ },
+ {
+ severity: CONST.MODERATION.FLAG_SEVERITY_ASSAULT,
+ name: props.translate('moderation.assault'),
+ icon: Expensicons.FlagLevelThree,
+ description: props.translate('moderation.assaultDescription'),
+ furtherDetails: props.translate('moderation.levelThreeResult'),
+ furtherDetailsIcon: Expensicons.FlagLevelThree,
+ },
+ ];
+
+ const flagComment = (severity) => {
+ let reportID = getReportID(props.route);
+
+ // Handle threads if needed
+ if (reportAction === undefined) {
+ reportID = ReportUtils.getParentReport(props.report).reportID;
+ reportAction = ReportActionsUtils.getParentReportAction(props.report);
+ }
+ Report.flagComment(reportID, reportAction, severity);
+ Navigation.dismissModal();
+ };
+
+ const severityMenuItems = _.map(severities, (item, index) => (
+
);
diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js
index 75cd18743822..b10134b2ceb7 100644
--- a/src/pages/home/report/ReportActionsList.js
+++ b/src/pages/home/report/ReportActionsList.js
@@ -115,8 +115,11 @@ const ReportActionsList = (props) => {
// When the new indicator should not be displayed we explicitly set it to null
const shouldDisplayNewMarker = reportAction.reportActionID === newMarkerReportActionID;
const shouldDisplayParentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && ReportUtils.isThread(report);
+ const shouldHideThreadDividerLine =
+ shouldDisplayParentAction && sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === newMarkerReportActionID;
return shouldDisplayParentAction ? (
action.originalMessage && action.originalMessage.type && Number(action.originalMessage.IOUReportID) === Number(this.props.iouReportID),
- );
-
- const deletedTransactionIDs = _.chain(actionsForIOUReport)
- .filter((action) => _.contains([CONST.IOU.REPORT_ACTION_TYPE.CANCEL, CONST.IOU.REPORT_ACTION_TYPE.DECLINE, CONST.IOU.REPORT_ACTION_TYPE.DELETE], action.originalMessage.type))
- .map((deletedAction) => lodashGet(deletedAction, 'originalMessage.IOUTransactionID', ''))
- .compact()
- .value();
-
- return _.chain(actionsForIOUReport)
- .filter((action) => action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE)
- .filter((action) => !_.contains(deletedTransactionIDs, action.originalMessage.IOUTransactionID))
- .filter((action) => this.props.userEmail === action.actorEmail)
- .map((action) => lodashGet(action, 'originalMessage.IOUTransactionID', ''))
- .compact()
- .value();
- }
-
- render() {
- const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(this.props.reportActions);
- return (
-
- {_.map(sortedReportActions, (reportAction) => {
- // iouReportIDs should be strings, but we still have places that send them as ints so we convert them both to Numbers for comparison
- if (
- !reportAction.originalMessage ||
- reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU ||
- Number(reportAction.originalMessage.IOUReportID) !== Number(this.props.iouReportID)
- ) {
- return;
- }
-
- const deletableTransactions = this.getDeletableTransactions();
- const canBeDeleted = _.contains(deletableTransactions, reportAction.originalMessage.IOUTransactionID);
- return (
-
- );
- })}
-
- );
- }
-}
-
-IOUTransactions.defaultProps = defaultProps;
-IOUTransactions.propTypes = propTypes;
-export default withOnyx({
- reportActions: {
- key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`,
- canEvict: false,
- },
-})(IOUTransactions);
diff --git a/src/pages/signin/ChangeExpensifyLoginLink.js b/src/pages/signin/ChangeExpensifyLoginLink.js
index 4e033d947710..0ea56a176af2 100755
--- a/src/pages/signin/ChangeExpensifyLoginLink.js
+++ b/src/pages/signin/ChangeExpensifyLoginLink.js
@@ -1,5 +1,5 @@
import React from 'react';
-import {TouchableOpacity, View} from 'react-native';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import PropTypes from 'prop-types';
@@ -8,6 +8,7 @@ import styles from '../../styles/styles';
import ONYXKEYS from '../../ONYXKEYS';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import compose from '../../libs/compose';
+import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
const propTypes = {
/** The credentials of the logged in person */
@@ -31,15 +32,17 @@ const defaultProps = {
const ChangeExpensifyLoginLink = (props) => (
{!_.isEmpty(props.credentials.login) && {props.translate('loginForm.notYou', {user: props.formatPhoneNumber(props.credentials.login)})}}
-
{props.translate('common.goBack')}
{'.'}
-
+
);
diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js
index 78eaf0e0a0e9..26ab6eb1423e 100755
--- a/src/pages/signin/PasswordForm.js
+++ b/src/pages/signin/PasswordForm.js
@@ -1,5 +1,5 @@
import React from 'react';
-import {TouchableOpacity, View} from 'react-native';
+import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
@@ -23,6 +23,7 @@ import {withNetwork} from '../../components/OnyxProvider';
import networkPropTypes from '../../components/networkPropTypes';
import FormHelpMessage from '../../components/FormHelpMessage';
import Terms from './Terms';
+import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
const propTypes = {
/* Onyx Props */
@@ -191,12 +192,15 @@ class PasswordForm extends React.Component {
hasError={passwordFieldHasError}
/>
-
{this.props.translate('passwordForm.forgot')}
-
+
diff --git a/src/pages/signin/ResendValidationForm.js b/src/pages/signin/ResendValidationForm.js
index a5874d2421dc..c17e19099b7f 100755
--- a/src/pages/signin/ResendValidationForm.js
+++ b/src/pages/signin/ResendValidationForm.js
@@ -1,6 +1,6 @@
import React from 'react';
import _ from 'underscore';
-import {TouchableOpacity, View} from 'react-native';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
@@ -17,6 +17,7 @@ import * as UserUtils from '../../libs/UserUtils';
import networkPropTypes from '../../components/networkPropTypes';
import {withNetwork} from '../../components/OnyxProvider';
import DotIndicatorMessage from '../../components/DotIndicatorMessage';
+import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
import CONST from '../../CONST';
const propTypes = {
@@ -91,9 +92,16 @@ const ResendValidationForm = (props) => {
/>
)}
- redirectToSignIn()}>
+ redirectToSignIn()}
+ accessibilityRole="button"
+ accessibilityLabel={props.translate('common.back')}
+ // disable hover dim for switch
+ hoverDimmingValue={1}
+ pressDimmingValue={0.2}
+ >
{props.translate('common.back')}
-
+