build(docs-infra): remove boilerplate file listings in example-boilerplate.js (#38173)

To avoid unnecessary code duplication in docs examples, we have some
boilerplate files for various example types (in
`aio/tools/examples/shared/boilerplate/`). These files are copied to
each example project in `aio/content/examples/` (according to the
example's type, as specified in its `example-config.json` file).

Previously, the `example-boilerplate.js`, which is responsible for
copying the boilerplate files, had lists for files to be copied for each
project type and only copied the listed files from the boilerplate
directory to the example directory. This approach had some drawbacks:
- Files need to be updated in two separate locations: in the boilerplate
  directory that includes the files and the file list in
  `example-boilerplate.js`.
- It is easy to add a file in the boilerplate directory but forget to
  add it in `example-boilerplate.js` and not realize that it is not
  being included in the example project (including the generated
  StackBlitz project and ZIP archive).

This commit changes the approach by removing the boilerplate file
listings from `example-boilerplate.js` and copying all files from a
boilerplate directory to example directories. This addresses the above
drawbacks and simplifies the `example-boilerplate.js` script.

I have verified that the resulting code example doc regions as well as
the generated StackBlitz projects and ZIP archives are identical to the
ones generated before this commit.

PR Close #38173
This commit is contained in:
George Kalpakas
2020-07-22 14:40:03 +03:00
committed by Andrew Kushnir
parent 65da87722d
commit 5a733629b5
2 changed files with 247 additions and 157 deletions

View File

@ -6,65 +6,13 @@ const yargs = require('yargs');
const SHARED_PATH = path.resolve(__dirname, 'shared');
const SHARED_NODE_MODULES_PATH = path.resolve(SHARED_PATH, 'node_modules');
const BOILERPLATE_BASE_PATH = path.resolve(SHARED_PATH, 'boilerplate');
const BOILERPLATE_COMMON_BASE_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'common');
const BOILERPLATE_CLI_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'cli');
const BOILERPLATE_COMMON_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'common');
const BOILERPLATE_VIEWENGINE_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'viewengine');
const EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
const BOILERPLATE_PATHS = {
cli: [
'src/environments/environment.prod.ts', 'src/environments/environment.ts',
'src/assets/.gitkeep', 'browserslist', 'src/favicon.ico', 'karma.conf.js',
'src/polyfills.ts', 'src/test.ts', 'tsconfig.app.json', 'tsconfig.spec.json',
'tslint.json', 'e2e/src/app.po.ts', 'e2e/protractor-puppeteer.conf.js',
'e2e/protractor.conf.js', 'e2e/tsconfig.json', '.editorconfig', '.gitignore', 'angular.json',
'package.json', 'tsconfig.json', 'tslint.json'
],
systemjs: [
'src/systemjs-angular-loader.js', 'src/systemjs.config.js', 'src/tsconfig.json',
'bs-config.json', 'bs-config.e2e.json', 'package.json', 'tslint.json'
],
common: ['src/styles.css']
};
// All paths in this tool are relative to the current boilerplate folder, i.e boilerplate/i18n
// This maps the CLI files that exists in a parent folder
const cliRelativePath = BOILERPLATE_PATHS.cli.map(file => `../cli/${file}`);
BOILERPLATE_PATHS.elements = [...cliRelativePath, 'package.json', 'src/polyfills.ts'];
BOILERPLATE_PATHS.i18n = [...cliRelativePath, 'angular.json', 'package.json', 'src/polyfills.ts'];
BOILERPLATE_PATHS['service-worker'] = [...cliRelativePath, 'angular.json', 'package.json'];
BOILERPLATE_PATHS.testing = [
...cliRelativePath,
'angular.json',
'tsconfig.app.json',
'tsconfig.spec.json'
];
BOILERPLATE_PATHS.universal = [...cliRelativePath, 'angular.json', 'package.json'];
BOILERPLATE_PATHS['getting-started'] = [
...cliRelativePath,
'src/styles.css'
];
BOILERPLATE_PATHS.schematics = [
...cliRelativePath,
'angular.json'
];
BOILERPLATE_PATHS['cli-ajs'] = [
...cliRelativePath,
'package.json'
];
BOILERPLATE_PATHS.viewengine = {
systemjs: ['rollup-config.js', 'tsconfig-aot.json'],
cli: ['tsconfig.json']
};
const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
class ExampleBoilerPlate {
@ -96,24 +44,26 @@ class ExampleBoilerPlate {
const boilerPlateType = exampleConfig.projectType || 'cli';
const boilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, boilerPlateType);
// Copy the boilerplate specific files
BOILERPLATE_PATHS[boilerPlateType].forEach(
filePath => this.copyFile(boilerPlateBasePath, exampleFolder, filePath));
// All example types other than `cli` and `systemjs` are based on `cli`. Copy over the `cli`
// boilerplate files first.
// (Some of these files might be later overwritten by type-specific files.)
if (boilerPlateType !== 'cli' && boilerPlateType !== 'systemjs') {
this.copyDirectoryContents(BOILERPLATE_CLI_PATH, exampleFolder);
}
// Copy the boilerplate common files
const useCommonBoilerplate = exampleConfig.useCommonBoilerplate !== false;
// Copy the type-specific boilerplate files.
this.copyDirectoryContents(boilerPlateBasePath, exampleFolder);
if (useCommonBoilerplate) {
BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath));
// Copy the common boilerplate files (unless explicitly not used).
if (exampleConfig.useCommonBoilerplate !== false) {
this.copyDirectoryContents(BOILERPLATE_COMMON_PATH, exampleFolder);
}
// Copy ViewEngine (pre-Ivy) specific files
if (viewengine) {
const veBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli';
const veBoilerPlateBasePath =
path.resolve(BOILERPLATE_BASE_PATH, 'viewengine', veBoilerPlateType);
BOILERPLATE_PATHS.viewengine[veBoilerPlateType].forEach(
filePath => this.copyFile(veBoilerPlateBasePath, exampleFolder, filePath));
const veBoilerPlateBasePath = path.resolve(BOILERPLATE_VIEWENGINE_PATH, veBoilerPlateType);
this.copyDirectoryContents(veBoilerPlateBasePath, exampleFolder);
}
});
}
@ -137,22 +87,28 @@ class ExampleBoilerPlate {
return glob.sync(pattern, {ignore: [ignorePattern]}).map(file => path.dirname(file));
}
copyFile(sourceFolder, destinationFolder, filePath) {
const sourcePath = path.resolve(sourceFolder, filePath);
// normalize path if needed
filePath = this.normalizePath(filePath);
const destinationPath = path.resolve(destinationFolder, filePath);
fs.copySync(sourcePath, destinationPath, {overwrite: true});
fs.chmodSync(destinationPath, 444);
}
loadJsonFile(filePath) { return fs.readJsonSync(filePath, {throws: false}) || {}; }
normalizePath(filePath) {
// transform for example ../cli/src/tsconfig.app.json to src/tsconfig.app.json
return filePath.replace(/\.{2}\/\w+\//, '');
copyDirectoryContents(srcDir, dstDir) {
shelljs.ls('-Al', srcDir).forEach(stat => {
const srcPath = path.resolve(srcDir, stat.name);
const dstPath = path.resolve(dstDir, stat.name);
if (stat.isDirectory()) {
// `srcPath` is a directory: Recursively copy it to `dstDir`.
shelljs.mkdir('-p', dstPath);
return this.copyDirectoryContents(srcPath, dstPath);
} else {
// `srcPath` is a file: Copy it to `dstDir`.
// (Also make the file non-writable to avoid accidental editing of boilerplate files).
if (shelljs.test('-f', dstPath)) {
// If the file already exists, ensure it is writable (so it can be overwritten).
shelljs.chmod(666, dstPath);
}
shelljs.cp(srcPath, dstDir);
shelljs.chmod(444, dstPath);
}
});
}
}