Chore: remove old translation tools, import parser (#39273)

This commit is contained in:
Oliver Eyton-Williams
2020-07-27 14:41:53 +02:00
committed by GitHub
parent bf9837c1da
commit de3492fded
10 changed files with 860 additions and 1667 deletions

View File

@ -1,7 +1,7 @@
const path = require('path');
const { findIndex } = require('lodash');
const readDirP = require('readdirp-walk');
const { parseMarkdown } = require('@freecodecamp/challenge-md-parser');
const { parseMarkdown } = require('../tools/challenge-md-parser');
const fs = require('fs');
const { dasherize } = require('../utils/slugs');

View File

@ -1,205 +0,0 @@
const fs = require('fs-extra');
const path = require('path');
const YAML = require('js-yaml');
const readDirP = require('readdirp-walk');
const { parseMarkdown } = require('@freecodecamp/challenge-md-parser');
const { Translate } = require('@google-cloud/translate');
const lang = 'pt';
const langFull = 'portuguese';
const outputDir = path.resolve(__dirname, `./challenges/${langFull}`);
fs.ensureDirSync(outputDir);
readDirP({
root: path.resolve(__dirname, './challenges/english')
}).on('data', translateChallenge);
async function translateChallenge(file) {
const { name, path: filePath, fullPath, stat } = file;
if (stat.isDirectory() || name === '.DS_Store') {
return null;
}
const blockName = getBlockNameFromPath(filePath);
const { fileName: superBlock } = superBlockInfoFromPath(filePath);
const outputFile = `${outputDir}/${superBlock}/${blockName}/${name.replace(
'english',
langFull
)}`;
if (fs.existsSync(outputFile)) {
return null;
}
const challenge = await parseMarkdown(fullPath);
const { title, description, instructions, tests } = challenge;
challenge['videoUrl'] = '';
if (challenge['guideUrl']) {
challenge['guideUrl'] = challenge['guideUrl'].replace('www', langFull);
}
const translatePromises = [
translateText(title),
translateText(description),
translateText(instructions),
...tests.map(
test =>
new Promise(async (resolve, reject) => {
const { testString, text } = test;
const translatedText = await translateText(text).catch(reject);
return resolve({
text: translatedText ? translatedText.join(' ').trim() : '',
testString
});
})
)
];
return Promise.all(translatePromises).then(
([title, description, instructions, ...tests]) => {
const { files = {}, solutions = [], ...challengeMeta } = challenge;
const md = `---
${YAML.dump(
Object.assign(challengeMeta, {
localeTitle: title ? title.join(' ').trim() : ''
}),
{ lineWidth: 10000 }
)}---
## Description
${description}
## Instructions
${instructions}
## Tests
<section id='tests'>
\`\`\`yml
${YAML.dump({ tests }, { lineWidth: 10000 })}
\`\`\`
</section>
## Challenge Seed
<section id='challengeSeed'>
${generateChallengeSeed(files)}
</section>
## Solution
<section id='solution'>
${
solutions.length === 0
? `\`\`\`js
// solution required
\`\`\``
: solutions
.map(
solution => `
\`\`\`js
${solution}
\`\`\`
`
)
.join('\n')
}
</section>
`;
console.log(outputFile);
fs.ensureFileSync(outputFile);
fs.writeFile(outputFile, md);
}
);
}
function generateChallengeSeed(files) {
return Object.keys(files)
.map(key => files[key])
.map(file => {
const { ext, contents = [], head = [], tail = [] } = file;
return `
<div id='${ext}-seed'>
\`\`\`${ext}
${contents}
\`\`\`
</div>
${
head.length
? `
### Before Test
<div id='${ext}-setup'>
\`\`\`${ext}
${head}
\`\`\`
</div>`
: ''
}
${
tail.length
? `
### After Test
<div id='${ext}-teardown'>
\`\`\`js
console.info('after the test');
\`\`\`
</div>`
: ''
}
`;
});
}
const createTranslateText = target => text => {
if (!text) {
return '';
}
const translate = new Translate();
return translate
.translate(text, target)
.then(results => {
let translations = results[0];
translations = Array.isArray(translations)
? translations
: [translations];
return translations;
})
.catch(err => {
console.log(err);
});
};
const translateText = createTranslateText(lang);
function superBlockInfoFromPath(filePath) {
const [maybeSuper] = filePath.split('/');
return superBlockInfo(maybeSuper);
}
function superBlockInfo(fileName) {
const [maybeOrder, ...superBlock] = fileName.split('-');
let order = parseInt(maybeOrder, 10);
if (isNaN(order)) {
return {
order: 0,
name: fileName
};
} else {
return {
order: order,
name: superBlock.join('-'),
fileName
};
}
}
function getBlockNameFromPath(filePath) {
const [, block] = filePath.split('/');
return block;
}

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,6 @@
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^7.0.1",
"@commitlint/travis-cli": "^8.3.5",
"@freecodecamp/challenge-md-parser": "^2.0.0",
"@semantic-release/changelog": "^2.0.2",
"@semantic-release/git": "^5.0.0",
"babel-plugin-add-module-exports": "^0.2.1",
@ -49,12 +48,12 @@
"gulp": "^4.0.2",
"joi": "^13.3.0",
"joi-objectid": "^2.0.0",
"jquery": "^3.4.1",
"jquery": "^3.5.1",
"js-yaml": "^3.12.0",
"jsdom": "^12.2.0",
"lint-staged": "^7.2.0",
"live-server": "^1.2.1",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"mocha": "5.2.0",
"puppeteer": "^1.19.0",
"readdirp-walk": "^1.7.0",

View File

@ -1,397 +0,0 @@
const unified = require('unified');
const markdown = require('remark-parse');
const remark2rehype = require('remark-rehype');
const stringify = require('remark-stringify');
const frontmatter = require('remark-frontmatter');
const raw = require('rehype-raw');
const visit = require('unist-util-visit');
const vfile = require('to-vfile');
const path = require('path');
const { Transform } = require('stream');
const { Translate } = require('@google-cloud/translate');
const YAML = require('js-yaml');
const solutionsToData = require('./solution-to-data');
const challengeSeedToData = require('./challengeSeed-to-data');
const transformChallenge = new Transform({
transform(chunk, encoding, callback) {
const fileName = chunk.toString().trim();
rebuildChallengeFile(fileName)
.then(file => callback(null, String(file.contents)))
.catch(err => console.error(err));
}
});
process.stdin.pipe(transformChallenge).pipe(process.stdout);
const processor = unified()
.use(markdown)
.use(frontmatter, ['yaml'])
.use(frontmatterToData)
.use(testsToData)
.use(textToData, ['description', 'instructions'])
.use(remark2rehype, { allowDangerousHTML: true })
.use(raw)
.use(solutionsToData)
.use(challengeSeedToData)
.use(replaceWithReferenceData)
.use(output);
exports.rebuildChallengeFile = rebuildChallengeFile;
async function rebuildChallengeFile(fileName) {
const filePath = path.resolve(fileName);
const lang = detectLang(filePath);
let referenceChallenge;
let translateText;
if (lang !== 'english') {
referenceChallenge = await getReferenceChallengeData(filePath);
translateText = createTranslateText(lang);
}
const file = await vfile.read(filePath);
file.data = {
...file.data,
lang,
referenceChallenge,
translateText
};
return await processor.process(file);
}
async function getReferenceChallengeData(filePath) {
const parts = filePath.split(path.sep);
parts.push(parts.pop().replace(/\.[^.]+\.md$/, '.english.md'));
parts[parts.length - 4] = 'english';
const filePathEnglishChallenge = parts.join(path.sep);
try {
const fileData = await vfile.read(filePathEnglishChallenge);
fileData.data = { ...fileData.data, refData: true };
return (await processor.process(fileData)).data;
} catch (err) {
console.error(err);
return null;
}
}
function detectLang(filePath) {
const match = /\.([^.]+)\.md$/.exec(filePath);
if (!match) {
throw new Error(`Incorrect file path ${filePath}`);
}
return match[1];
}
function frontmatterToData() {
return transformer;
function transformer(tree, file) {
visit(tree, 'yaml', visitor);
function visitor(node) {
const frontmatter = node.value;
file.data = { ...file.data, frontmatter };
}
}
}
function testsToData() {
return (tree, file) => {
visit(tree, 'code', visitor);
function visitor(node) {
const { lang, value } = node;
if (lang === 'yml') {
file.data = {
...file.data,
tests: value
};
}
}
};
}
function textToData(sectionIds) {
return (tree, file) => {
let indexId = 0;
let currentSection = sectionIds[indexId];
let inSection = false;
let nodes = [];
let findSection;
const visitor = (node, index, parent) => {
if (!parent) {
return visit.CONTINUE;
}
if (node.type === 'heading') {
if (inSection) {
findSection = new RegExp(`^<section id=('|")${currentSection}\\1>`);
file.data = {
...file.data,
[currentSection]: new stringify.Compiler(
{ type: 'root', children: nodes },
file
)
.compile()
.trim()
.replace(findSection, '')
.replace(/<\/section>$/, '')
.trim()
};
nodes = [];
indexId++;
if (indexId < sectionIds.length) {
currentSection = sectionIds[indexId];
} else {
return visit.EXIT;
}
}
inSection = true;
} else if (inSection) {
nodes.push(node);
}
return visit.SKIP;
};
visit(tree, visitor);
};
}
function createTranslateText(target, source = 'english') {
const projectId = process.env.GOOGLE_CLOUD_PROJECT_ID;
if (!projectId) {
return async text => text;
}
const languageCodes = {
arabic: 'ar',
chinese: 'zh',
english: 'en',
portuguese: 'pt',
russian: 'ru',
spanish: 'es'
};
const from = languageCodes[source];
const to = languageCodes[target];
return async text => {
if (!text) {
return text;
}
try {
const translate = new Translate({ projectId });
const result = await translate.translate(text, { from, to });
const translations = result[0];
return translations;
} catch (err) {
// console.error(err);
return text;
}
};
}
async function processTests(tests, referenceTests, translateText) {
const testsObject = YAML.load(referenceTests);
if (
!testsObject.tests ||
testsObject.tests.length === 0 ||
!testsObject.tests[0].text
) {
return referenceTests;
}
const newTests = await Promise.all(
testsObject.tests.map(async test => {
const text = await translateText(test.text);
return { ...test, text };
})
);
const testStrings = newTests
.map(
({ text, testString }) =>
` - text: ${dumpToYamlString(text)} testString: ${dumpToYamlString(
testString
)}`
)
.join('');
return `tests:${testStrings ? '\n' + testStrings : ' []\n'}`;
}
function dumpToYamlString(text) {
let fromYaml;
try {
fromYaml = YAML.load(text);
} catch {
// console.error(`YAML load: ${text}`);
}
if (text === fromYaml) {
return text + '\n';
}
return YAML.dump(text, { lineWidth: 10000 });
}
async function processFrontmatter(fileData) {
const { referenceChallenge, lang, translateText } = fileData;
const challengeData = YAML.load(fileData.frontmatter);
let data;
if (referenceChallenge) {
data = YAML.load(referenceChallenge.frontmatter);
} else {
data = challengeData;
}
if (lang && lang !== 'english') {
if (challengeData.localeTitle) {
data.localeTitle = challengeData.localeTitle;
} else {
data.localeTitle = await translateText(data.title);
}
}
fileData.frontmatter = Object.entries(data)
.map(([name, value]) => {
if (typeof value === 'object') {
return `${name}:
${dumpToYamlString(value)
.replace(/\n/, '\n ')
.trimRight()}
`;
}
return `${name}: ${dumpToYamlString(value)}`;
})
.join('')
.trimRight();
}
function replaceWithReferenceData() {
return async (tree, file) => {
if (file.data.refData) {
return;
}
const { referenceChallenge, translateText } = file.data;
await processFrontmatter(file.data);
if (referenceChallenge) {
const { description, instructions } = file.data;
if (!description || description === 'undefined') {
file.data.description = await translateText(
referenceChallenge.description
);
}
if (!instructions || instructions === 'undefined') {
file.data.instructions = await translateText(
referenceChallenge.instructions
);
}
file.data.tests = await processTests(
file.data.tests,
referenceChallenge.tests,
translateText
);
file.data.files = referenceChallenge.files;
file.data.solutions = referenceChallenge.solutions;
}
};
}
function output() {
this.Compiler = function(tree, file) {
let {
frontmatter,
description,
instructions,
tests,
files: [challengeFile = {}]
} = file.data;
const { ext, contents, head, tail } = challengeFile;
let { solutions = [] } = file.data;
solutions = solutions
.map(s => s.trim())
.map(s =>
!s.includes('\n') && /^\/\//.test(s) ? '// solution required' : s
);
return `---
${frontmatter}
---
## Description
<section id='description'>
${description}
</section>
## Instructions
<section id='instructions'>
${instructions}
</section>
## Tests
<section id='tests'>
\`\`\`yml
${tests}
\`\`\`
</section>
${
ext
? `## Challenge Seed
<section id='challengeSeed'>
<div id='${ext}-seed'>
\`\`\`${ext}
${contents}
\`\`\`
</div>${
head
? `
### Before Tests
<div id='${ext}-setup'>
\`\`\`${ext}
${head}
\`\`\`
</div>`
: ''
}${
tail
? `
### After Tests
<div id='${ext}-teardown'>
\`\`\`${ext}
${tail}
\`\`\`
</div>`
: ''
}
</section>
## Solution
${solutions.reduce(
(result, solution) =>
result +
`<section id='solution'>
\`\`\`${ext}
${solution.trim()}
\`\`\`
</section>`,
''
)}
`
: ''
}`;
};
}

View File

@ -217,55 +217,6 @@
"minimist": "^1.2.0"
}
},
"@google-cloud/common": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.31.1.tgz",
"integrity": "sha512-MgaF8VmDaoyIqzZUXIbcohTb5sQn+PYlYmcpb0/E8psUpVe+kaBwLq/Z8pcFtACCr6PNT36n+a6s1kG35bAuCA==",
"requires": {
"@google-cloud/projectify": "^0.3.2",
"@google-cloud/promisify": "^0.4.0",
"@types/duplexify": "^3.5.0",
"@types/request": "^2.47.0",
"arrify": "^1.0.1",
"duplexify": "^3.6.0",
"ent": "^2.2.0",
"extend": "^3.0.1",
"google-auth-library": "^3.0.0",
"pify": "^4.0.0",
"retry-request": "^4.0.0"
},
"dependencies": {
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
}
}
},
"@google-cloud/projectify": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz",
"integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw=="
},
"@google-cloud/promisify": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz",
"integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q=="
},
"@google-cloud/translate": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@google-cloud/translate/-/translate-2.1.4.tgz",
"integrity": "sha512-m9yIGnJg0aTohb1arNGfGYyZd7tt+ncB4xqGj3Saf6fiUgfQ0jCnadDKdVVDN00Ziu5//qS1bz38eb+8wX4Cug==",
"requires": {
"@google-cloud/common": "^0.31.0",
"@google-cloud/promisify": "^0.4.0",
"arrify": "^1.0.1",
"extend": "^3.0.1",
"is": "^3.2.1",
"is-html": "^1.1.0",
"teeny-request": "^3.4.0"
}
},
"@jest/console": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
@ -475,19 +426,6 @@
"@babel/types": "^7.3.0"
}
},
"@types/caseless": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
},
"@types/duplexify": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz",
"integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==",
"requires": {
"@types/node": "*"
}
},
"@types/istanbul-lib-coverage": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
@ -513,45 +451,12 @@
"@types/istanbul-lib-report": "*"
}
},
"@types/node": {
"version": "12.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
"integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg=="
},
"@types/request": {
"version": "2.48.2",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.2.tgz",
"integrity": "sha512-gP+PSFXAXMrd5PcD7SqHeUjdGshAI8vKQ3+AvpQr3ht9iQea+59LOKvKITcQI+Lg+1EIkDP6AFSBUJPWG8GDyA==",
"requires": {
"@types/caseless": "*",
"@types/node": "*",
"@types/tough-cookie": "*",
"form-data": "^2.5.0"
},
"dependencies": {
"form-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.0.tgz",
"integrity": "sha512-WXieX3G/8side6VIqx44ablyULoGruSde5PNTxoUyo5CeyAMX6nVWUd0rgist/EuX655cjhUhTo1Fo3tRYqbcA==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
}
}
},
"@types/stack-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
"dev": true
},
"@types/tough-cookie": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz",
"integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg=="
},
"@types/yargs": {
"version": "13.0.8",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz",
@ -573,14 +478,6 @@
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==",
"dev": true
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"acorn": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
@ -611,14 +508,6 @@
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
"dev": true
},
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"ajv": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
@ -700,11 +589,6 @@
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
"dev": true
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@ -741,7 +625,8 @@
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"atob": {
"version": "2.1.2",
@ -872,11 +757,6 @@
}
}
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bcp-47-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.0.tgz",
@ -891,11 +771,6 @@
"tweetnacl": "^0.14.3"
}
},
"bignumber.js": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz",
"integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ=="
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
@ -982,11 +857,6 @@
"node-int64": "^0.4.0"
}
},
"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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@ -1153,6 +1023,7 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@ -1195,7 +1066,8 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"cross-spawn": {
"version": "6.0.5",
@ -1360,7 +1232,8 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"detab": {
"version": "2.0.1",
@ -1396,17 +1269,6 @@
"webidl-conversions": "^4.0.2"
}
},
"duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
"integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
"requires": {
"end-of-stream": "^1.0.0",
"inherits": "^2.0.1",
"readable-stream": "^2.0.0",
"stream-shift": "^1.0.0"
}
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@ -1417,14 +1279,6 @@
"safer-buffer": "^2.1.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==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@ -1435,15 +1289,11 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"ent": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
"integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0="
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@ -1483,19 +1333,6 @@
"is-symbol": "^1.0.2"
}
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"requires": {
"es6-promise": "^4.0.3"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -1532,11 +1369,6 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"exec-sh": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
@ -1728,11 +1560,6 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fast-text-encoding": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz",
"integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ=="
},
"fault": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fault/-/fault-1.0.2.tgz",
@ -2396,26 +2223,6 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"gaxios": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz",
"integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==",
"requires": {
"abort-controller": "^3.0.0",
"extend": "^3.0.2",
"https-proxy-agent": "^2.2.1",
"node-fetch": "^2.3.0"
}
},
"gcp-metadata": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz",
"integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==",
"requires": {
"gaxios": "^1.0.2",
"json-bigint": "^0.3.0"
}
},
"gensync": {
"version": "1.0.0-beta.1",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
@ -2472,38 +2279,6 @@
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true
},
"google-auth-library": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz",
"integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==",
"requires": {
"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": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz",
"integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==",
"requires": {
"node-forge": "^0.8.0",
"pify": "^4.0.0"
},
"dependencies": {
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
}
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
@ -2516,25 +2291,6 @@
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true
},
"gtoken": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz",
"integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==",
"requires": {
"gaxios": "^1.0.4",
"google-p12-pem": "^1.0.0",
"jws": "^3.1.5",
"mime": "^2.2.0",
"pify": "^4.0.0"
},
"dependencies": {
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
}
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -2758,11 +2514,6 @@
"integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==",
"dev": true
},
"html-tags": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-1.2.0.tgz",
"integrity": "sha1-x43mW1Zjqll5id0rerSSANfk25g="
},
"html-void-elements": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.3.tgz",
@ -2779,30 +2530,6 @@
"sshpk": "^1.7.0"
}
},
"https-proxy-agent": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -2852,11 +2579,6 @@
"loose-envify": "^1.0.0"
}
},
"is": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz",
"integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg=="
},
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@ -2996,14 +2718,6 @@
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz",
"integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A=="
},
"is-html": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-html/-/is-html-1.1.0.tgz",
"integrity": "sha1-4E8cGNOUhRETlvmgJz6rUa8hhGQ=",
"requires": {
"html-tags": "^1.0.0"
}
},
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@ -3093,7 +2807,8 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"isexe": {
"version": "2.0.0",
@ -3690,14 +3405,6 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
"json-bigint": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz",
"integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=",
"requires": {
"bignumber.js": "^7.0.0"
}
},
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@ -3743,25 +3450,6 @@
"verror": "1.10.0"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"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==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@ -3843,14 +3531,6 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -3969,20 +3649,17 @@
"to-regex": "^3.0.2"
}
},
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
},
"mime-db": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
"dev": true
},
"mime-types": {
"version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"dev": true,
"requires": {
"mime-db": "1.40.0"
}
@ -4076,16 +3753,6 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"node-forge": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz",
"integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q=="
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -4258,6 +3925,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
@ -4449,11 +4117,6 @@
"react-is": "^16.8.4"
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"prompts": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.1.tgz",
@ -4527,20 +4190,6 @@
"read-pkg": "^3.0.0"
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"realpath-native": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
@ -4754,30 +4403,6 @@
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"dev": true
},
"retry-request": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz",
"integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==",
"requires": {
"debug": "^4.1.1",
"through2": "^3.0.1"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
@ -4796,7 +4421,8 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"safe-regex": {
"version": "1.1.0",
@ -4839,7 +4465,8 @@
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
@ -5164,11 +4791,6 @@
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
},
"stream-shift": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
},
"string-length": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
@ -5227,14 +4849,6 @@
"function-bind": "^1.1.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"stringify-entities": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz",
@ -5290,16 +4904,6 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true
},
"teeny-request": {
"version": "3.11.3",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz",
"integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==",
"requires": {
"https-proxy-agent": "^2.2.1",
"node-fetch": "^2.2.0",
"uuid": "^3.3.2"
}
},
"test-exclude": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
@ -5318,14 +4922,6 @@
"integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=",
"dev": true
},
"through2": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
"integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
"requires": {
"readable-stream": "2 || 3"
}
},
"tmpl": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
@ -5605,11 +5201,6 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
@ -5625,7 +5216,8 @@
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.4",
@ -5769,7 +5361,8 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"write-file-atomic": {
"version": "2.4.1",
@ -5813,11 +5406,6 @@
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
},
"yargs": {
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",

View File

@ -16,7 +16,6 @@
"jest": "^24.9.0"
},
"dependencies": {
"@google-cloud/translate": "^2.1.3",
"hast-util-select": "^2.1.0",
"hast-util-to-html": "^4.0.1",
"js-yaml": "^3.12.0",

View File

@ -1,180 +0,0 @@
var fs = require('fs');
var lang = 'es';
var langFull = 'spanish';
var dir1 = fs.readdirSync('../../curriculum/challenges/english')[5];
var dir2 = fs.readdirSync('../../curriculum/challenges/english/' + dir1)[3];
var dir = dir1 + '/' + dir2;
fs.readdirSync('../../curriculum/challenges/english/' + dir).forEach(file => {
if (file.includes('.md') && dir) {
let originalFileName =
'../../curriculum/challenges/' +
langFull +
'/' +
dir +
'/' +
file.slice(0, -10) +
langFull +
'.md';
fs.exists(originalFileName, function(exists) {
if (!exists) {
console.log(originalFileName);
getFile(file, dir);
}
});
}
});
// TEST
// var dir1 = fs.readdirSync('../../curriculum/challenges/english')[4];
// var dir2 = fs.readdirSync('../../curriculum/challenges/english/' + dir1)[0];
// var dir = dir1 + '/' + dir2;
// getFile('exercise-tracker.english.md', dir);
// Load in full text, description, instructions, and title
function getFile(file, dir) {
let originalFileName =
'../../curriculum/challenges/english/' + dir + '/' + file;
let fileString = fs.readFileSync(originalFileName).toString();
// Add 'notranslate' class to code so Google Translate API
// will not translate code segments.
fileString = fileString.replace(/<code>/g, '<code class="notranslate">');
fileString = fileString.replace(
/<blockquote>/g,
'<blockquote class="notranslate">'
);
fileString = fileString.replace(/^.*videoUrl.*$/gm, "videoUrl: ''");
fileString = fileString.replace(
/https:\/\/www\.freecodecamp\.org/,
'https://' + langFull + '.freecodecamp.org'
);
let description = fileString.match(
/<section id='description'>(.|\n)*?<\/section>/
)[0];
description = description.replace(/\r?\n/g, '<code>0</code>');
let instructions = fileString.match(
/<section id='instructions'>(.|\n)*?<\/section>/
)[0];
instructions = instructions.replace(/\r?\n/g, '<code>0</code>');
let tests = fileString.match(/<section id='tests'>(.|\n)*?<\/section>/)[0];
let title = fileString.split('\n')[2].split(': ')[1];
processFile(fileString, description, instructions, tests, title, file, dir);
}
// Get translations from Google Translate API and insert into file
function processFile(
fileString,
description,
instructions,
tests,
title,
file,
dir
) {
const translateText = (text, target) => {
return new Promise((resolve, reject) => {
if (typeof text === 'object' && Object.keys(text).length === 0) {
resolve(['']);
} else {
// Imports the Google Cloud client library
const { Translate } = require('@google-cloud/translate');
// Creates a client
const translate = new Translate();
translate
.translate(text, target)
.then(results => {
let translations = results[0];
translations = Array.isArray(translations)
? translations
: [translations];
resolve(translations);
})
.catch(err => {
reject(console.log('!!!!!', err));
});
}
});
};
// FOR TESTING ONLY
// const translateText = (text, target) => {
// return new Promise((resolve, reject) => {
// resolve(['translated', 'translated', 'translated', 'translated']);
// });
// };
const translateTests = () => {
return new Promise((resolve, reject) => {
let testsArray = tests.split('\n');
let testsToTranslate = [];
testsArray.forEach(test => {
if (test.includes('- text: ')) {
testsToTranslate.push(test.slice(10));
}
});
translateText(testsToTranslate, lang)
.then(translation => {
let transIndex = 0;
testsArray.forEach((test, index) => {
if (test.includes('- text')) {
testsArray[index] = ' - text: ' + translation[transIndex];
transIndex++;
}
});
resolve(testsArray.join('\n'));
})
.catch(reject);
});
};
Promise.all([
translateText(description, lang),
translateText(instructions, lang),
translateText(title, lang),
translateTests(tests, lang)
]).then(function(translations) {
// Replace English with translation
fileString = fileString.replace(
/<section id='description'>(.|\n)*?<\/section>/,
translations[0][0].replace(/<code>0<\/code> /g, '\n')
);
fileString = fileString.replace(
/<section id='instructions'>(.|\n)*?<\/section>/,
translations[1][0].replace(/<code>0<\/code> /g, '\n')
);
fileString = fileString.replace(
title,
title + '\nlocaleTitle: ' + translations[2]
);
fileString = fileString.replace(
/<section id='tests'>(.|\n)*?<\/section>/,
translations[3]
);
fileString = fileString.replace(/ class=\"notranslate\"/g, '');
writeFile(fileString, file, dir);
});
}
function writeFile(fileString, file, dir) {
let fullFileName =
'../../curriculum/challenges/' +
langFull +
'/' +
dir +
'/' +
file.slice(0, -10) +
langFull +
'.md';
fs.writeFile(fullFileName, fileString, function(err) {
if (err) {
throw err;
}
console.log('Saved!');
});
}

View File

@ -1,146 +0,0 @@
const fs = require('fs-extra');
const unified = require('unified');
const parse = require('remark-parse');
const parse2 = require('rehype-parse');
const rehype = require('remark-rehype');
const stringify = require('rehype-stringify');
const stringify2 = require('remark-stringify');
const remark = require('rehype-remark');
const path = require('path');
const readDirP = require('readdirp-walk');
const { Translate } = require('@google-cloud/translate');
const lang = 'es';
const langFull = 'spanish';
const mdProcessor = unified()
.use(parse)
.use(rehype, { allowDangerousHTML: true })
.use(stringify);
const htmlProcessor = unified()
.use(parse2)
.use(remark)
.use(stringify2);
readDirP({
root: path.resolve(__dirname, './test')
}).on('data', translateChallenge);
async function translateChallenge(file) {
const { name, fullPath, fullParentDir, stat } = file;
if (stat.isDirectory() || name === '.DS_Store' || file.depth === 1) {
return null;
}
const pathIndex = fullPath.indexOf('guide') + 6;
const outputDir =
fullParentDir.substring(0, pathIndex) +
`${langFull}/` +
fullParentDir.substring(pathIndex + 5);
const outputPath =
fullPath.substring(0, pathIndex) +
`${langFull}/` +
fullPath.substring(pathIndex + 5);
if (fs.existsSync(outputPath)) {
return null;
}
fs.ensureDirSync(outputDir);
const fileString = fs.readFileSync(fullPath).toString();
var i = fileString.indexOf('---', 4);
const meta = fileString.substring(0, i + 4);
const title = fileString.split('\n')[1].split(': ')[1];
var article = fileString.substring(i + 4);
return mdToHtml(article).then(htmlArticle => {
htmlArticle = htmlArticle.replace(/\n/g, '<br>');
htmlArticle = htmlArticle.replace(
/ {8}/g,
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
);
htmlArticle = htmlArticle.replace(/ {4}/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
htmlArticle = htmlArticle.replace(/ {2}/g, '&nbsp;&nbsp;');
translate(htmlArticle, title, meta, outputPath);
});
}
function translate(htmlArticle, title, meta, outputPath) {
Promise.all([translateText(title), translateText(htmlArticle)]).then(function(
translations
) {
// Replace English with translation
let translatedTitle = translations[0][0];
let tempArticle = translations[1][0];
tempArticle = tempArticle.replace(/<br>/g, '\n');
tempArticle = tempArticle.replace(/&#39;/g, "'");
// tempArticle = tempArticle.replace(/language-html">/g,'language-html">\n')
// tempArticle = tempArticle.replace(/<pre> <code/g, '<pre><code')
// tempArticle = tempArticle.replace(/<\/code> <\/pre/g, '</code></pre')
tempArticle = tempArticle.replace(/&nbsp;/g, ' ');
htmlToMd(tempArticle).then(translatedArticle => {
const i = meta.indexOf('---', 4);
let translatedFile =
meta.slice(0, i) +
`localeTitle: ${translatedTitle}\n` +
meta.slice(i) +
translatedArticle;
writeFile(translatedFile, outputPath);
});
});
}
const createTranslateText = target => text => {
if (!text) {
return '';
}
const translate = new Translate();
return translate
.translate(text, target)
.then(results => {
let translations = results[0];
translations = Array.isArray(translations)
? translations
: [translations];
return translations;
})
.catch(err => {
console.log(err);
});
};
const translateText = createTranslateText(lang);
function writeFile(fileString, outputPath) {
fs.writeFile(outputPath, fileString, function(err) {
if (err) {
throw err;
}
console.log('Saved:' + outputPath);
});
}
function mdToHtml(file) {
return new Promise((resolve, reject) =>
mdProcessor.process(file, function(err, file) {
if (err) {
reject(err);
}
return resolve(file.contents);
})
);
}
function htmlToMd(file) {
return new Promise((resolve, reject) =>
htmlProcessor.process(file, function(err, file) {
if (err) {
reject(err);
}
return resolve(file.contents);
})
);
}

View File

@ -1,114 +0,0 @@
const fs = require('fs-extra');
var showdown = require('showdown');
const path = require('path');
const readDirP = require('readdirp-walk');
const { Translate } = require('@google-cloud/translate');
var TurndownService = require('turndown');
var turndownService = new TurndownService({
codeBlockStyle: 'fenced',
headingStyle: 'atx'
});
const converter = new showdown.Converter();
const lang = 'pt';
const langFull = 'portuguese';
readDirP({
root: path.resolve(__dirname, './english')
}).on('data', translateChallenge);
async function translateChallenge(file) {
const { name, fullPath, fullParentDir, stat } = file;
if (stat.isDirectory() || name === '.DS_Store' || file.depth === 1) {
return null;
}
const pathIndex = fullPath.indexOf('guide') + 6;
const outputDir =
fullParentDir.substring(0, pathIndex) +
`${langFull}/` +
fullParentDir.substring(pathIndex + 8);
const outputPath =
fullPath.substring(0, pathIndex) +
`${langFull}/` +
fullPath.substring(pathIndex + 8);
if (fs.existsSync(outputPath)) {
return null;
}
fs.ensureDirSync(outputDir);
const fileString = fs.readFileSync(fullPath).toString();
var i = fileString.indexOf('---', 4);
const meta = fileString.substring(0, i + 4);
const title = fileString.split('\n')[1].split(': ')[1];
var article = fileString.substring(i + 4);
var htmlArticle = converter.makeHtml(article);
htmlArticle = htmlArticle.replace(/\n/g, '<br>');
htmlArticle = htmlArticle.replace(
/ {8}/g,
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
);
htmlArticle = htmlArticle.replace(/ {4}/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
htmlArticle = htmlArticle.replace(/ {2}/g, '&nbsp;&nbsp;');
return Promise.all([translateText(title), translateText(htmlArticle)]).then(
function(translations) {
// Replace English with translation
let translatedTitle = translations[0][0];
let tempArticle = translations[1][0];
tempArticle = tempArticle.replace(/<br>/g, '\n');
tempArticle = tempArticle.replace(/&#39;/g, "'");
tempArticle = tempArticle.replace(
/language-html">/g,
'language-html">\n'
);
tempArticle = tempArticle.replace(/<pre> <code/g, '<pre><code');
tempArticle = tempArticle.replace(/<\/pre> <\/code/g, '</pre></code');
tempArticle = tempArticle.replace(/&nbsp;/g, ' ');
let translatedArticle = turndownService.turndown(tempArticle);
translatedArticle = translatedArticle.replace(/\n\n\`\`\`\n/g, '\n```\n');
let translatedFile =
meta.slice(0, i) +
`localeTitle: ${translatedTitle}\n` +
meta.slice(i) +
translatedArticle;
writeFile(translatedFile, outputPath);
}
);
}
const createTranslateText = target => text => {
if (!text) {
return '';
}
const translate = new Translate();
return translate
.translate(text, target)
.then(results => {
let translations = results[0];
translations = Array.isArray(translations)
? translations
: [translations];
return translations;
})
.catch(err => {
console.log(err);
});
};
const translateText = createTranslateText(lang);
function writeFile(fileString, outputPath) {
fs.writeFile(outputPath, fileString, function(err) {
if (err) {
throw err;
}
console.log('Saved:' + outputPath);
});
}