diff --git a/.gitignore b/.gitignore index d5a06f7..6c6aadf 100644 --- a/.gitignore +++ b/.gitignore @@ -113,4 +113,8 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +# Custom +token.json +credentials.json \ No newline at end of file diff --git a/package.json b/package.json index e7149d9..b9a9929 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,10 @@ "name": "multi-language-mobile", "version": "0.0.0", "description": "Tool for generating localization files for iOS and Android", - "main": "index.js", + "main": "./src/index.js", + "bin": { + "multi-language": "./src/index.js" + }, "author": "Johnny Gu ", "license": "MIT", "scripts": { @@ -30,19 +33,21 @@ "@commitlint/cli": "^8.3.5", "@commitlint/config-conventional": "^8.3.4", "auto-changelog": "^2.0.0", + "babel-eslint": "^10.0.3", + "babel-plugin-transform-inline-environment-variables": "^0.4.3", "eslint": "^7.2.0", - "husky": "^4.2.5", - "prettier": "^2.0.5", - "jest": "^24.9.0", "eslint-config-prettier": "^6.5.0", "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^23.0.2", "eslint-plugin-prettier": "^3.1.1", - "babel-eslint": "^10.0.3", - "babel-plugin-transform-inline-environment-variables": "^0.4.3" + "husky": "^4.2.5", + "jest": "^24.9.0", + "prettier": "^2.0.5" }, "dependencies": { + "commander": "^5.1.0", "csv-parser": "^2.3.3", + "googleapis": "39", "write": "^2.0.0" } } diff --git a/resources/google.csv b/resources/google.csv new file mode 100644 index 0000000..f730832 --- /dev/null +++ b/resources/google.csv @@ -0,0 +1,4 @@ +key,en,zh +home title,This is home,首页 +alert_ok,OK,好的 +count number,There are %d of them,一共有%d个 \ No newline at end of file diff --git a/src/downloader/google.js b/src/downloader/google.js new file mode 100644 index 0000000..4c4185d --- /dev/null +++ b/src/downloader/google.js @@ -0,0 +1,22 @@ +const google = require('../vendor/google'); +const path = require('path'); +const write = require("write"); + +const outputFileName = 'google.csv'; +const DEFAULT_PATH = path.join(__dirname, '../../output'); +// const fileId = '13PRkyoSfdpRJhTlY8xtyX8jrXuhzAZmS1iPL2c9L8Ek'; + +const downloadCsv = ({destPath = DEFAULT_PATH, credentials, fileId}) => { + const fullPath = path.join(destPath, outputFileName); + return google.generateDrive({destPath, credentials}) + .then(drive => drive.files.export({ + fileId, + mimeType: 'text/csv' + })) + .then(({data}) => write(fullPath, data)) + .then(() => Promise.resolve(fullPath)) +} + +module.exports = { + downloadCsv +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 2dafa1c..31a9319 100644 --- a/src/index.js +++ b/src/index.js @@ -1,48 +1,9 @@ -const csv = require("csv-parser"); -const fs = require("fs"); -const ios = require("./lib/ios"); -const android = require("./lib/android"); +#!/usr/bin/env node -const generators = [ios, android]; +const { run } = require('./run') -const formatKey = (key) => { - const removespace = key.replace(/[_ ]/, "&&&"); - const words = removespace.split("&&&").map((s) => s.toLowerCase()); - return words.join("_"); -}; - -const readFromCsv = (filepath) => { - const results = []; - return new Promise((resolve, reject) => { - fs.createReadStream(filepath) - .pipe(csv()) - .on("data", (data) => { - var { key } = data; - results.push({ - ...data, - key: formatKey(key), - }); - }) - .on("end", () => { - results.sort((lhs, rhs) => lhs.key > rhs.key); - resolve(results); - }) - .on("error", (err) => { - reject(err); - }); - }); -}; - -const main = async (input) => { - const path = input || "./resources/test.csv"; - try { - const array = await readFromCsv(path); - for (var i = 0; i < generators.length; i++) { - await generators[i].generateFile(array); - } - } catch (err) { - console.log(err); - } -}; - -main(); +run(process.argv).catch(error => { + console.log('\n') + console.error(error) + process.exit(1) +}) diff --git a/src/lib/android.js b/src/lib/android.js index 29ac8b6..68f7ff3 100644 --- a/src/lib/android.js +++ b/src/lib/android.js @@ -1,5 +1,6 @@ const generateHeader = require("./header"); const write = require("write"); +const path = require("path"); const generateFilePath = (key) => { switch (key) { @@ -15,12 +16,12 @@ const generateFilePath = (key) => { } }; -const generateFile = (array) => { +const generateFile = (data, basePath) => { const header = generateHeader(); - const languages = Object.keys(array[0]).filter((k) => k !== "key"); + const languages = Object.keys(data[0]).filter((k) => k !== "key"); const generators = languages.map((l) => { - const filepath = generateFilePath(l); - const content = array.reduce((result, next) => { + const filepath = path.join(basePath, generateFilePath(l)); + const content = data.reduce((result, next) => { return result + ` ${next[l]}\n`; }, ""); const fullContent = `\n${content}\n`; diff --git a/src/lib/ios.js b/src/lib/ios.js index 20d6d44..37a3df2 100644 --- a/src/lib/ios.js +++ b/src/lib/ios.js @@ -1,5 +1,6 @@ const generateHeader = require("./header"); const write = require("write"); +const path = require("path"); const generateFilePath = (key) => { switch (key) { @@ -15,12 +16,12 @@ const generateFilePath = (key) => { } }; -const generateFile = (array) => { +const generateFile = (data, basePath) => { const header = generateHeader(); - const languages = Object.keys(array[0]).filter((k) => k !== "key"); + const languages = Object.keys(data[0]).filter((k) => k !== "key"); const generators = languages.map((l) => { - const filepath = generateFilePath(l); - const content = array.reduce((result, next) => { + const filepath = path.join(basePath, generateFilePath(l)); + const content = data.reduce((result, next) => { return result + `"${next.key}" = "${next[l]}";\n`; }, ""); return write(filepath, `${header}\n${content}`); diff --git a/src/run.js b/src/run.js new file mode 100644 index 0000000..c539ed9 --- /dev/null +++ b/src/run.js @@ -0,0 +1,118 @@ +const { Command } = require('commander'); +const { version } = require('../package.json'); +const csv = require("csv-parser"); +const fs = require("fs"); +const ios = require("./lib/ios"); +const android = require("./lib/android"); +const google = require("./downloader/google"); +const readJson = require("./utils/readJson"); + +const DEFAULT_OPTIONS = { + // local + inputPath: null, + // google + googleFileId: null, + googleCredential: './credentials.json', + + outputDir: './output', + platforms: ['ios', 'android'], + config: '.multi-language' +} +const PACKAGE_FILE = 'package.json'; +const PACKAGE_OPTIONS_KEY = 'multi-language'; + +const platformMap = { + 'ios': ios, + 'android': android +}; + +const collect = (value, previous) => { + return previous.concat([value]); +} + +const getOptions = async (argv) => { + const options = new Command() + .option('--output-dir ', `output file base directory, default: ${DEFAULT_OPTIONS.outputDir}`) + .option('--platforms ', `output platforms, default: ${DEFAULT_OPTIONS.platforms}`, collect, []) + // .option('--downloader ', `downloader for input, default: ${DEFAULT_OPTIONS.downloader}`) + .option('--input-path ', `file for local csv input, default: ${DEFAULT_OPTIONS.inputPath}`) + .option('--google-file-id ', 'google file id, you can find it in the url') + .option('--google-credential ', `file for google credentials, default: ${DEFAULT_OPTIONS.googleCredential}`) + .version(version) + .parse(argv) + + const pkg = await readJson(PACKAGE_FILE); + const packageOptions = pkg ? pkg[PACKAGE_OPTIONS_KEY] : null; + const dotOptions = await readJson(options.config || DEFAULT_OPTIONS.config); + + return { + ...DEFAULT_OPTIONS, + ...dotOptions, + ...packageOptions, + ...options + } +} + +const formatKey = (key) => { + const removespace = key.replace(/[_ ]/, "&&&"); + const words = removespace.split("&&&").map((s) => s.toLowerCase()); + return words.join("_"); +}; + +const readFromCsv = (filepath) => { + const results = []; + return new Promise((resolve, reject) => { + fs.createReadStream(filepath) + .pipe(csv()) + .on("data", (data) => { + var { key } = data; + results.push({ + ...data, + key: formatKey(key), + }); + }) + .on("end", () => { + results.sort((lhs, rhs) => lhs.key > rhs.key); + resolve(results); + }) + .on("error", (err) => { + reject(err); + }); + }); +}; + +const run = async (argv) => { + // const path = input || "./resources/test.csv"; + const options = await getOptions(argv); + try { + let path; + if (options.inputPath) { + path = options.inputPath + } else if (options.googleFileId) { + path = await google.downloadCsv({ + destPath: options.outputDir, + credentials: options.googleCredential, + fileId: options.googleFileId + }) + } else { + console.log(`Error: To run this app, you need one of these: + - path to local csv with input-path param + - google file id with google-file-id param + `) + process.exit() + } + const array = await readFromCsv(path); + const platforms = options.platforms; + for (var i = 0; i < platforms.length; i++) { + const generator = platformMap[platforms[i]]; + if (!generator) continue; + await generator.generateFile(array, options.outputDir); + } + } catch (err) { + console.log(err); + } +}; + +module.exports = { + run +} diff --git a/src/utils/readJson.js b/src/utils/readJson.js new file mode 100644 index 0000000..e72ef9e --- /dev/null +++ b/src/utils/readJson.js @@ -0,0 +1,14 @@ +const fs = require('fs') + +const readJson = (path) => { + return new Promise((resolve) => { + fs.readFile(path, (err, content) => { + if (err) { + return resolve() + } + resolve(JSON.parse(content)) + }) + }) +} + +module.exports = readJson \ No newline at end of file diff --git a/src/vendor/google.js b/src/vendor/google.js new file mode 100644 index 0000000..5d27240 --- /dev/null +++ b/src/vendor/google.js @@ -0,0 +1,100 @@ +const fs = require('fs'); +const path = require('path'); +const readline = require('readline'); +const {google} = require('googleapis'); + +// If modifying these scopes, delete token.json. +const SCOPES = [ + 'https://www.googleapis.com/auth/drive.metadata.readonly', + 'https://www.googleapis.com/auth/drive.file', + 'https://www.googleapis.com/auth/drive.readonly' +]; +// The file token.json stores the user's access and refresh tokens, and is +// created automatically when the authorization flow completes for the first +// time. +// const TOKEN_PATH = path.join(__dirname, '../../token.json'); +// const Cridential_PATH = path.join(__dirname, '../../credentials.json'); + +/** + * Create an OAuth2 client with the given credentials, and then execute the + * given callback function. + * @param {Object} credentials The authorization client credentials. + * @param {function} callback The callback to call with the authorized client. + */ +function authorize({destPath, credentials}) { + const {client_secret, client_id, redirect_uris} = credentials.installed; + const oAuth2Client = new google.auth.OAuth2( + client_id, client_secret, redirect_uris[0]); + const tokenPath = path.join(destPath, 'token.json'); + + // Check if we have previously stored a token. + return new Promise((resolve, reject) => { + fs.readFile(tokenPath, (err, token) => { + if (err) { + getAccessToken(oAuth2Client, tokenPath) + .then(client => resolve(client)) + .catch(error => reject(error)); + return + } + oAuth2Client.setCredentials(JSON.parse(token)); + resolve(oAuth2Client); + }); + }); +} + +/** + * Get and store new token after prompting for user authorization, and then + * execute the given callback with the authorized OAuth2 client. + * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for. + * @param {getEventsCallback} callback The callback for the authorized client. + */ +function getAccessToken(oAuth2Client, tokenPath) { + const authUrl = oAuth2Client.generateAuthUrl({ + access_type: 'offline', + scope: SCOPES, + }); + console.log('Authorize this app by visiting this url:', authUrl); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return new Promise((resolve, reject) => { + rl.question('Enter the code from that page here: ', (code) => { + rl.close(); + oAuth2Client.getToken(code, (err, token) => { + if (err) { + reject(err); + return console.error('Error retrieving access token', err); + } + oAuth2Client.setCredentials(token); + // Store the token to disk for later program executions + fs.writeFile(tokenPath, JSON.stringify(token), (err) => { + if (err) return console.error(err); + console.log('Token stored to', tokenPath); + }); + resolve(oAuth2Client); + }); + }); + }); +} + +// Load client secrets from a local file. +const generateDrive = ({destPath, credentials}) => { + return new Promise((resolve, reject) => { + fs.readFile(credentials, (err, content) => { + if (err) { + reject(err); + return console.log('Error loading client secret file:', err); + } + // Authorize a client with credentials, then call the Google Drive API. + authorize({destPath, credentials: JSON.parse(content)}).then(client => { + const result = google.drive({version: 'v3', auth: client}); + resolve(result); + }).catch(error => reject(error)); + }); + }) +} + +module.exports = { + generateDrive +}; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ca8d2c3..a246103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -620,6 +620,13 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-globals@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" @@ -660,6 +667,13 @@ add-filename-increment@^1.0.0: dependencies: strip-filename-increment "^2.0.1" +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: version "6.12.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" @@ -925,6 +939,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -945,6 +964,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bignumber.js@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" + integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== + bindings@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" @@ -995,6 +1019,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -1194,7 +1223,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^5.0.0: +commander@^5.0.0, commander@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== @@ -1380,6 +1409,13 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -1491,6 +1527,13 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1541,6 +1584,18 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1719,6 +1774,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + exec-sh@^0.3.2: version "0.3.4" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" @@ -1782,7 +1842,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -1840,6 +1900,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-text-encoding@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" + integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -1968,6 +2033,24 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gaxios@^1.0.2, gaxios@^1.0.4, gaxios@^1.2.1, gaxios@^1.2.2: + version "1.8.4" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-1.8.4.tgz#e08c34fe93c0a9b67a52b7b9e7a64e6435f9a339" + integrity sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw== + dependencies: + abort-controller "^3.0.0" + extend "^3.0.2" + https-proxy-agent "^2.2.1" + node-fetch "^2.3.0" + +gcp-metadata@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-1.0.0.tgz#5212440229fa099fc2f7c2a5cdcb95575e9b2ca6" + integrity sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ== + dependencies: + gaxios "^1.0.2" + json-bigint "^0.3.0" + gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" @@ -2056,6 +2139,49 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +google-auth-library@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-3.1.2.tgz#ff2f88cd5cd2118a57bd3d5ad3c093c8837fc350" + integrity sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ== + dependencies: + base64-js "^1.3.0" + fast-text-encoding "^1.0.0" + gaxios "^1.2.1" + gcp-metadata "^1.0.0" + gtoken "^2.3.2" + https-proxy-agent "^2.2.1" + jws "^3.1.5" + lru-cache "^5.0.0" + semver "^5.5.0" + +google-p12-pem@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-1.0.4.tgz#b77fb833a2eb9f7f3c689e2e54f095276f777605" + integrity sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA== + dependencies: + node-forge "^0.8.0" + pify "^4.0.0" + +googleapis-common@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/googleapis-common/-/googleapis-common-0.7.2.tgz#a694f55d979cb7c2eac21a0e0439af12f9b418ba" + integrity sha512-9DEJIiO4nS7nw0VE1YVkEfXEj8x8MxsuB+yZIpOBULFSN9OIKcUU8UuKgSZFU4lJmRioMfngktrbkMwWJcUhQg== + dependencies: + gaxios "^1.2.2" + google-auth-library "^3.0.0" + pify "^4.0.0" + qs "^6.5.2" + url-template "^2.0.8" + uuid "^3.2.1" + +googleapis@39: + version "39.2.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-39.2.0.tgz#5c81f721e9da2e80cb0b25821ed60d3bc200c3da" + integrity sha512-66X8TG1B33zAt177sG1CoKoYHPP/B66tEpnnSANGCqotMuY5gqSQO8G/0gqHZR2jRgc5CHSSNOJCnpI0SuDxMQ== + dependencies: + google-auth-library "^3.0.0" + googleapis-common "^0.7.0" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -2066,6 +2192,17 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +gtoken@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-2.3.3.tgz#8a7fe155c5ce0c4b71c886cfb282a9060d94a641" + integrity sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw== + dependencies: + gaxios "^1.0.4" + google-p12-pem "^1.0.0" + jws "^3.1.5" + mime "^2.2.0" + pify "^4.0.0" + handlebars@^4.7.3: version "4.7.6" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" @@ -2175,6 +2312,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + husky@^4.2.5: version "4.2.5" resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36" @@ -2954,6 +3099,13 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-bigint@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-0.3.1.tgz#0c1729d679f580d550899d6a2226c228564afe60" + integrity sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ== + dependencies: + bignumber.js "^9.0.0" + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -3008,6 +3160,23 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.1.5: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -3161,6 +3330,13 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +lru-cache@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -3273,6 +3449,11 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.44.0" +mime@^2.2.0: + version "2.4.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" + integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -3379,11 +3560,16 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@^2.6.0: +node-fetch@^2.3.0, node-fetch@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-forge@^0.8.0: + version "0.8.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee" + integrity sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3721,7 +3907,7 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -pify@^4.0.1: +pify@^4.0.0, pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== @@ -3844,6 +4030,11 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@^6.5.2: + version "6.9.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" + integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -4799,6 +4990,11 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -4819,7 +5015,7 @@ util.promisify@^1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" -uuid@^3.3.2: +uuid@^3.2.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -4988,6 +5184,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yaml@^1.7.2: version "1.10.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"