From e13e630cd6e4fc0b1ff92098a28a770794c7bb9a Mon Sep 17 00:00:00 2001 From: gabrhr <73925454+gabrhr@users.noreply.github.com> Date: Wed, 20 Apr 2022 10:19:29 -0500 Subject: =?UTF-8?q?A=C3=B1adir=20plantilla?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Base para front --- front/odiparpack/internals/scripts/analyze.js | 27 +++ front/odiparpack/internals/scripts/clean.js | 63 +++++++ front/odiparpack/internals/scripts/dependencies.js | 52 ++++++ front/odiparpack/internals/scripts/extract-intl.js | 187 +++++++++++++++++++++ .../scripts/generate-templates-for-linting.js | 119 +++++++++++++ .../internals/scripts/helpers/checkmark.js | 11 ++ .../internals/scripts/helpers/progress.js | 25 +++ .../odiparpack/internals/scripts/helpers/xmark.js | 11 ++ .../internals/scripts/npmcheckversion.js | 8 + 9 files changed, 503 insertions(+) create mode 100644 front/odiparpack/internals/scripts/analyze.js create mode 100644 front/odiparpack/internals/scripts/clean.js create mode 100644 front/odiparpack/internals/scripts/dependencies.js create mode 100644 front/odiparpack/internals/scripts/extract-intl.js create mode 100644 front/odiparpack/internals/scripts/generate-templates-for-linting.js create mode 100644 front/odiparpack/internals/scripts/helpers/checkmark.js create mode 100644 front/odiparpack/internals/scripts/helpers/progress.js create mode 100644 front/odiparpack/internals/scripts/helpers/xmark.js create mode 100644 front/odiparpack/internals/scripts/npmcheckversion.js (limited to 'front/odiparpack/internals/scripts') diff --git a/front/odiparpack/internals/scripts/analyze.js b/front/odiparpack/internals/scripts/analyze.js new file mode 100644 index 0000000..2144e5a --- /dev/null +++ b/front/odiparpack/internals/scripts/analyze.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node + +const shelljs = require('shelljs'); +const animateProgress = require('./helpers/progress'); +const chalk = require('chalk'); +const addCheckMark = require('./helpers/checkmark'); + +const progress = animateProgress('Generating stats'); + +// Generate stats.json file with webpack +shelljs.exec( + 'webpack --config internals/webpack/webpack.prod.babel.js --profile --json > stats.json', + addCheckMark.bind(null, callback), // Output a checkmark on completion +); + +// Called after webpack has finished generating the stats.json file +function callback() { + clearInterval(progress); + process.stdout.write( + '\n\nOpen ' + + chalk.magenta('http://webpack.github.io/analyse/') + + ' in your browser and upload the stats.json file!' + + chalk.blue( + '\n(Tip: ' + chalk.italic('CMD + double-click') + ' the link!)\n\n', + ), + ); +} diff --git a/front/odiparpack/internals/scripts/clean.js b/front/odiparpack/internals/scripts/clean.js new file mode 100644 index 0000000..52a93e0 --- /dev/null +++ b/front/odiparpack/internals/scripts/clean.js @@ -0,0 +1,63 @@ +const shell = require('shelljs'); +const addCheckMark = require('./helpers/checkmark.js'); + +if (!shell.which('git')) { + shell.echo('Sorry, this script requires git'); + shell.exit(1); +} + +if (!shell.test('-e', 'internals/templates')) { + shell.echo('The example is deleted already.'); + shell.exit(1); +} + +process.stdout.write('Cleanup started...'); + +// Reuse existing LanguageProvider and i18n tests +shell.mv( + 'app/containers/LanguageProvider/tests', + 'internals/templates/containers/LanguageProvider', +); +shell.cp('app/tests/i18n.test.js', 'internals/templates/tests/i18n.test.js'); + +// Cleanup components/ +shell.rm('-rf', 'app/components/*'); + +// Handle containers/ +shell.rm('-rf', 'app/containers'); +shell.mv('internals/templates/containers', 'app'); + +// Handle tests/ +shell.mv('internals/templates/tests', 'app'); + +// Handle translations/ +shell.rm('-rf', 'app/translations'); +shell.mv('internals/templates/translations', 'app'); + +// Handle utils/ +shell.rm('-rf', 'app/utils'); +shell.mv('internals/templates/utils', 'app'); + +// Replace the files in the root app/ folder +shell.cp('internals/templates/app.js', 'app/app.js'); +shell.cp('internals/templates/global-styles.js', 'app/global-styles.js'); +shell.cp('internals/templates/i18n.js', 'app/i18n.js'); +shell.cp('internals/templates/index.html', 'app/index.html'); +shell.cp('internals/templates/reducers.js', 'app/reducers.js'); +shell.cp('internals/templates/configureStore.js', 'app/configureStore.js'); + +// Remove the templates folder +shell.rm('-rf', 'internals/templates'); + +addCheckMark(); + +// Commit the changes +if ( + shell.exec('git add . --all && git commit -qm "Remove default example"') + .code !== 0 +) { + shell.echo('\nError: Git commit failed'); + shell.exit(1); +} + +shell.echo('\nCleanup done. Happy Coding!!!'); diff --git a/front/odiparpack/internals/scripts/dependencies.js b/front/odiparpack/internals/scripts/dependencies.js new file mode 100644 index 0000000..4f9f1ed --- /dev/null +++ b/front/odiparpack/internals/scripts/dependencies.js @@ -0,0 +1,52 @@ +// No need to build the DLL in production +if (process.env.NODE_ENV === 'production') { + process.exit(0); +} + +require('shelljs/global'); + +const path = require('path'); +const fs = require('fs'); +const exists = fs.existsSync; +const writeFile = fs.writeFileSync; + +const defaults = require('lodash/defaultsDeep'); +const pkg = require(path.join(process.cwd(), 'package.json')); +const config = require('../config'); +const dllConfig = defaults(pkg.dllPlugin, config.dllPlugin.defaults); +const outputPath = path.join(process.cwd(), dllConfig.path); +const dllManifestPath = path.join(outputPath, 'package.json'); + +/** + * I use node_modules/react-boilerplate-dlls by default just because + * it isn't going to be version controlled and babel wont try to parse it. + */ +mkdir('-p', outputPath); + +echo('Building the Webpack DLL...'); + +/** + * Create a manifest so npm install doesn't warn us + */ +if (!exists(dllManifestPath)) { + writeFile( + dllManifestPath, + JSON.stringify( + defaults({ + name: 'react-boilerplate-dlls', + private: true, + author: pkg.author, + repository: pkg.repository, + version: pkg.version, + }), + null, + 2, + ), + 'utf8', + ); +} + +// the BUILDING_DLL env var is set to avoid confusing the development environment +exec( + 'cross-env BUILDING_DLL=true webpack --display-chunks --color --config internals/webpack/webpack.dll.babel.js --hide-modules', +); diff --git a/front/odiparpack/internals/scripts/extract-intl.js b/front/odiparpack/internals/scripts/extract-intl.js new file mode 100644 index 0000000..087b04e --- /dev/null +++ b/front/odiparpack/internals/scripts/extract-intl.js @@ -0,0 +1,187 @@ +/* eslint-disable */ +/** + * This script will extract the internationalization messages from all components + and package them in the translation json files in the translations file. + */ +const fs = require('fs'); +const nodeGlob = require('glob'); +const transform = require('babel-core').transform; + +const animateProgress = require('./helpers/progress'); +const addCheckmark = require('./helpers/checkmark'); + +const pkg = require('../../package.json'); +const presets = pkg.babel.presets; +const plugins = pkg.babel.plugins || []; + +const i18n = require('../../app/i18n'); + +const DEFAULT_LOCALE = i18n.DEFAULT_LOCALE; + +require('shelljs/global'); + +// Glob to match all js files except test files +const FILES_TO_PARSE = 'app/**/!(*.test).js'; +const locales = i18n.appLocales; + +const newLine = () => process.stdout.write('\n'); + +// Progress Logger +let progress; +const task = message => { + progress = animateProgress(message); + process.stdout.write(message); + + return error => { + if (error) { + process.stderr.write(error); + } + clearTimeout(progress); + return addCheckmark(() => newLine()); + }; +}; + +// Wrap async functions below into a promise +const glob = pattern => + new Promise((resolve, reject) => { + nodeGlob( + pattern, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +const readFile = fileName => + new Promise((resolve, reject) => { + fs.readFile( + fileName, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +const writeFile = (fileName, data) => + new Promise((resolve, reject) => { + fs.writeFile( + fileName, + data, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +// Store existing translations into memory +const oldLocaleMappings = []; +const localeMappings = []; + +// Loop to run once per locale +for (const locale of locales) { + oldLocaleMappings[locale] = {}; + localeMappings[locale] = {}; + // File to store translation messages into + const translationFileName = `app/translations/${locale}.json`; + try { + // Parse the old translation message JSON files + const messages = JSON.parse(fs.readFileSync(translationFileName)); + const messageKeys = Object.keys(messages); + for (const messageKey of messageKeys) { + oldLocaleMappings[locale][messageKey] = messages[messageKey]; + } + } catch (error) { + if (error.code !== 'ENOENT') { + process.stderr.write( + `There was an error loading this translation file: ${translationFileName} + \n${error}`, + ); + } + } +} + +/* push `react-intl` plugin to the existing plugins that are already configured in `package.json` + Example: + ``` + "babel": { + "plugins": [ + ["transform-object-rest-spread", { "useBuiltIns": true }] + ], + "presets": [ + "env", + "react" + ] + } + ``` +*/ +plugins.push(['react-intl']); + +const extractFromFile = fileName => { + return readFile(fileName) + .then(code => { + // Use babel plugin to extract instances where react-intl is used + const { metadata: result } = transform(code, { presets, plugins }); + + for (const message of result['react-intl'].messages) { + for (const locale of locales) { + const oldLocaleMapping = oldLocaleMappings[locale][message.id]; + // Merge old translations into the babel extracted instances where react-intl is used + const newMsg = + locale === DEFAULT_LOCALE ? message.defaultMessage : ''; + localeMappings[locale][message.id] = oldLocaleMapping + ? oldLocaleMapping + : newMsg; + } + } + }) + .catch(error => { + process.stderr.write(`Error transforming file: ${fileName}\n${error}`); + }); +}; + +const memoryTask = glob(FILES_TO_PARSE); +const memoryTaskDone = task('Storing language files in memory'); + +memoryTask.then(files => { + memoryTaskDone(); + + const extractTask = Promise.all( + files.map(fileName => extractFromFile(fileName)), + ); + const extractTaskDone = task('Run extraction on all files'); + // Run extraction on all files that match the glob on line 16 + extractTask.then(result => { + extractTaskDone(); + + // Make the directory if it doesn't exist, especially for first run + mkdir('-p', 'app/translations'); + + let localeTaskDone; + let translationFileName; + + for (const locale of locales) { + translationFileName = `app/translations/${locale}.json`; + localeTaskDone = task( + `Writing translation messages for ${locale} to: ${translationFileName}`, + ); + + // Sort the translation JSON file so that git diffing is easier + // Otherwise the translation messages will jump around every time we extract + let messages = {}; + Object.keys(localeMappings[locale]) + .sort() + .forEach(function(key) { + messages[key] = localeMappings[locale][key]; + }); + + // Write to file the JSON representation of the translation messages + const prettified = `${JSON.stringify(messages, null, 2)}\n`; + + try { + fs.writeFileSync(translationFileName, prettified); + localeTaskDone(); + } catch (error) { + localeTaskDone( + `There was an error saving this translation file: ${translationFileName} + \n${error}`, + ); + } + } + + process.exit(); + }); +}); diff --git a/front/odiparpack/internals/scripts/generate-templates-for-linting.js b/front/odiparpack/internals/scripts/generate-templates-for-linting.js new file mode 100644 index 0000000..cb3904a --- /dev/null +++ b/front/odiparpack/internals/scripts/generate-templates-for-linting.js @@ -0,0 +1,119 @@ +/** + * This script is for internal `react-boilerplate`'s usage. The only purpose of generating all of these templates is + * to be able to lint them and detect critical errors. Every generated component's name has to start with + * 'RbGenerated' so it can be easily excluded from the test coverage reports. + */ + +const nodePlop = require('node-plop'); +const path = require('path'); +const chalk = require('chalk'); +const rimraf = require('rimraf'); + +const xmark = require('./helpers/xmark'); + +process.chdir(path.join(__dirname, '../generators')); + +const prettyStringify = data => JSON.stringify(data, null, 2); + +const checkForErrors = result => { + if (Array.isArray(result.failures) && result.failures.length > 0) { + throw result.failures; + } +}; + +const reportErrorsFor = title => err => { + // TODO Replace with our own helpers/log that is guaranteed to be blocking? + xmark(() => + console.error( + chalk.red(` ERROR generating '${title}': `), + prettyStringify(err), + ), + ); + process.exit(1); +}; + +// Generated tests are designed to fail, which would in turn fail CI builds +const removeTestsDirFrom = relativePath => () => + rimraf.sync(path.join(__dirname, '/../../app/', relativePath, '/tests')); + +const plop = nodePlop('./index.js'); + +const componentGen = plop.getGenerator('component'); +componentGen + .runActions({ + name: 'RbGeneratedComponentEsclass', + type: 'React.Component', + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('components/RbGeneratedComponentEsclass')) + .catch(reportErrorsFor('component/React.Component')); + +componentGen + .runActions({ + name: 'RbGeneratedComponentEsclasspure', + type: 'React.PureComponent', + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('components/RbGeneratedComponentEsclasspure')) + .catch(reportErrorsFor('component/React.PureComponent')); + +componentGen + .runActions({ + name: 'RbGeneratedComponentStatelessfunction', + type: 'Stateless Function', + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('components/RbGeneratedComponentStatelessfunction')) + .catch(reportErrorsFor('component/Stateless Function')); + +const containerGen = plop.getGenerator('container'); +containerGen + .runActions({ + name: 'RbGeneratedContainerPureComponent', + type: 'React.PureComponent', + wantHeaders: true, + wantActionsAndReducer: true, + wantSagas: true, + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('containers/RbGeneratedContainerPureComponent')) + .catch(reportErrorsFor('container/React.PureComponent')); + +containerGen + .runActions({ + name: 'RbGeneratedContainerComponent', + type: 'React.Component', + wantHeaders: true, + wantActionsAndReducer: true, + wantSagas: true, + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('containers/RbGeneratedContainerComponent')) + .catch(reportErrorsFor('container/React.Component')); + +containerGen + .runActions({ + name: 'RbGeneratedContainerStateless', + type: 'Stateless Function', + wantHeaders: true, + wantActionsAndReducer: true, + wantSagas: true, + wantMessages: true, + wantLoadable: true, + }) + .then(checkForErrors) + .then(removeTestsDirFrom('containers/RbGeneratedContainerStateless')) + .catch(reportErrorsFor('container/Stateless')); + +const languageGen = plop.getGenerator('language'); +languageGen.runActions({ language: 'fr' }).catch(reportErrorsFor('language')); diff --git a/front/odiparpack/internals/scripts/helpers/checkmark.js b/front/odiparpack/internals/scripts/helpers/checkmark.js new file mode 100644 index 0000000..ac30dbc --- /dev/null +++ b/front/odiparpack/internals/scripts/helpers/checkmark.js @@ -0,0 +1,11 @@ +const chalk = require('chalk'); + +/** + * Adds mark check symbol + */ +function addCheckMark(callback) { + process.stdout.write(chalk.green(' ✓')); + if (callback) callback(); +} + +module.exports = addCheckMark; diff --git a/front/odiparpack/internals/scripts/helpers/progress.js b/front/odiparpack/internals/scripts/helpers/progress.js new file mode 100644 index 0000000..4353f20 --- /dev/null +++ b/front/odiparpack/internals/scripts/helpers/progress.js @@ -0,0 +1,25 @@ +'use strict'; + +const readline = require('readline'); + +/** + * Adds an animated progress indicator + * + * @param {string} message The message to write next to the indicator + * @param {number} amountOfDots The amount of dots you want to animate + */ +function animateProgress(message, amountOfDots) { + if (typeof amountOfDots !== 'number') { + amountOfDots = 3; + } + + let i = 0; + return setInterval(function() { + readline.cursorTo(process.stdout, 0); + i = (i + 1) % (amountOfDots + 1); + const dots = new Array(i + 1).join('.'); + process.stdout.write(message + dots); + }, 500); +} + +module.exports = animateProgress; diff --git a/front/odiparpack/internals/scripts/helpers/xmark.js b/front/odiparpack/internals/scripts/helpers/xmark.js new file mode 100644 index 0000000..59d137d --- /dev/null +++ b/front/odiparpack/internals/scripts/helpers/xmark.js @@ -0,0 +1,11 @@ +const chalk = require('chalk'); + +/** + * Adds mark cross symbol + */ +function addXMark(callback) { + process.stdout.write(chalk.red(' ✘')); + if (callback) callback(); +} + +module.exports = addXMark; diff --git a/front/odiparpack/internals/scripts/npmcheckversion.js b/front/odiparpack/internals/scripts/npmcheckversion.js new file mode 100644 index 0000000..e3ecd0c --- /dev/null +++ b/front/odiparpack/internals/scripts/npmcheckversion.js @@ -0,0 +1,8 @@ +const exec = require('child_process').exec; +exec('npm -v', function(err, stdout, stderr) { + if (err) throw err; + if (parseFloat(stdout) < 3) { + throw new Error('[ERROR: React Boilerplate] You need npm version @>=3'); + process.exit(1); + } +}); -- cgit v1.2.3