140 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			140 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								const fs = require('fs-extra');
							 | 
						||
| 
								 | 
							
								const glob = require('glob');
							 | 
						||
| 
								 | 
							
								const ignore = require('ignore');
							 | 
						||
| 
								 | 
							
								const path = require('canonical-path');
							 | 
						||
| 
								 | 
							
								const shelljs = require('shelljs');
							 | 
						||
| 
								 | 
							
								const yargs = require('yargs');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH, STACKBLITZ_CONFIG_FILENAME} =
							 | 
						||
| 
								 | 
							
								    require('./constants');
							 | 
						||
| 
								 | 
							
								const BASIC_SOURCE_PATH = path.resolve(SHARED_PATH, 'example-scaffold');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								shelljs.set('-e');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (require.main === module) {
							 | 
						||
| 
								 | 
							
								  const options =
							 | 
						||
| 
								 | 
							
								      yargs(process.argv.slice(2))
							 | 
						||
| 
								 | 
							
								          .command(
							 | 
						||
| 
								 | 
							
								              '$0 <name> [source]',
							 | 
						||
| 
								 | 
							
								              [
							 | 
						||
| 
								 | 
							
								                'Create a new <name> example.',
							 | 
						||
| 
								 | 
							
								                '',
							 | 
						||
| 
								 | 
							
								                'If [source] is provided then the relevant files from the CLI project at that path are copied into the example.',
							 | 
						||
| 
								 | 
							
								              ].join('\n'))
							 | 
						||
| 
								 | 
							
								          .strict()
							 | 
						||
| 
								 | 
							
								          .version(false)
							 | 
						||
| 
								 | 
							
								          .argv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const exampleName = options.name;
							 | 
						||
| 
								 | 
							
								  const examplePath = path.resolve(EXAMPLES_BASE_PATH, exampleName);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  console.log('Creating new example at', examplePath);
							 | 
						||
| 
								 | 
							
								  createEmptyExample(exampleName, examplePath);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const sourcePath =
							 | 
						||
| 
								 | 
							
								      options.source !== undefined ? path.resolve(options.source) : BASIC_SOURCE_PATH;
							 | 
						||
| 
								 | 
							
								  console.log('Copying files from', sourcePath);
							 | 
						||
| 
								 | 
							
								  copyExampleFiles(sourcePath, examplePath, exampleName);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  console.log(`The new "${exampleName}" example has been created.`);
							 | 
						||
| 
								 | 
							
								  console.log('Now run "yarn boilerplate:add" to set it up for development.');
							 | 
						||
| 
								 | 
							
								  console.log(
							 | 
						||
| 
								 | 
							
								      'You can find more info on working with docs examples in aio/tools/examples/README.md.')
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Create the directory and marker files for the new example.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function createEmptyExample(exampleName, examplePath) {
							 | 
						||
| 
								 | 
							
								  ensureExamplePath(examplePath);
							 | 
						||
| 
								 | 
							
								  writeExampleConfigFile(examplePath);
							 | 
						||
| 
								 | 
							
								  writeStackBlitzFile(exampleName, examplePath);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Ensure that the new example directory exists.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function ensureExamplePath(examplePath) {
							 | 
						||
| 
								 | 
							
								  if (fs.existsSync(examplePath)) {
							 | 
						||
| 
								 | 
							
								    throw new Error(
							 | 
						||
| 
								 | 
							
								        `Unable to create example. The path to the new example already exists: ${examplePath}`);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  fs.ensureDirSync(examplePath);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Write the `example-config.json` file to the new example.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function writeExampleConfigFile(examplePath) {
							 | 
						||
| 
								 | 
							
								  fs.writeFileSync(path.resolve(examplePath, EXAMPLE_CONFIG_FILENAME), '');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Write the `stackblitz.json` file into the new example.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function writeStackBlitzFile(exampleName, examplePath) {
							 | 
						||
| 
								 | 
							
								  const config = {
							 | 
						||
| 
								 | 
							
								    description: titleize(exampleName),
							 | 
						||
| 
								 | 
							
								    files: ['!**/*.d.ts', '!**/*.js', '!**/*.[1,2].*'],
							 | 
						||
| 
								 | 
							
								    tags: [exampleName.split('-')]
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								  fs.writeFileSync(
							 | 
						||
| 
								 | 
							
								      path.resolve(examplePath, STACKBLITZ_CONFIG_FILENAME),
							 | 
						||
| 
								 | 
							
								      JSON.stringify(config, null, 2) + '\n');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copy all the files from the `sourcePath`, which are not ignored by the `.gitignore` file in the
							 | 
						||
| 
								 | 
							
								 * `EXAMPLES_BASE_PATH`, to the `examplePath`.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function copyExampleFiles(sourcePath, examplePath, exampleName) {
							 | 
						||
| 
								 | 
							
								  const gitIgnoreSource = getGitIgnore(sourcePath);
							 | 
						||
| 
								 | 
							
								  const gitIgnoreExamples = getGitIgnore(EXAMPLES_BASE_PATH);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Grab the files in the source folder and filter them based on the gitignore rules.
							 | 
						||
| 
								 | 
							
								  const sourceFiles =
							 | 
						||
| 
								 | 
							
								      glob.sync('**/*', {
							 | 
						||
| 
								 | 
							
								            cwd: sourcePath,
							 | 
						||
| 
								 | 
							
								            dot: true,
							 | 
						||
| 
								 | 
							
								            ignore: ['**/node_modules/**', '.git/**', '.gitignore'],
							 | 
						||
| 
								 | 
							
								            mark: true
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          // Filter out the directories, leaving only files
							 | 
						||
| 
								 | 
							
								          .filter(filePath => !/\/$/.test(filePath))
							 | 
						||
| 
								 | 
							
								          // Filter out files that match the source directory .gitignore rules
							 | 
						||
| 
								 | 
							
								          .filter(filePath => !gitIgnoreSource.ignores(filePath))
							 | 
						||
| 
								 | 
							
								          // Filter out files that match the examples directory .gitignore rules
							 | 
						||
| 
								 | 
							
								          .filter(filePath => !gitIgnoreExamples.ignores(path.join(exampleName, filePath)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (const sourceFile of sourceFiles) {
							 | 
						||
| 
								 | 
							
								    console.log(' - ', sourceFile);
							 | 
						||
| 
								 | 
							
								    const destPath = path.resolve(examplePath, sourceFile)
							 | 
						||
| 
								 | 
							
								    fs.ensureDirSync(path.dirname(destPath));
							 | 
						||
| 
								 | 
							
								    fs.copySync(path.resolve(sourcePath, sourceFile), destPath);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getGitIgnore(directory) {
							 | 
						||
| 
								 | 
							
								  const gitIgnoreMatcher = ignore();
							 | 
						||
| 
								 | 
							
								  const gitignoreFilePath = path.resolve(directory, '.gitignore');
							 | 
						||
| 
								 | 
							
								  if (fs.existsSync(gitignoreFilePath)) {
							 | 
						||
| 
								 | 
							
								    const gitignoreFile = fs.readFileSync(gitignoreFilePath, 'utf8');
							 | 
						||
| 
								 | 
							
								    gitIgnoreMatcher.add(gitignoreFile);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return gitIgnoreMatcher;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convert a kebab-case string to space separated Title Case string.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function titleize(input) {
							 | 
						||
| 
								 | 
							
								  return input.replace(
							 | 
						||
| 
								 | 
							
								      /(-|^)(.)/g, (_, pre, char) => `${pre === '-' ? ' ' : ''}${char.toUpperCase()}`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.createEmptyExample = createEmptyExample;
							 | 
						||
| 
								 | 
							
								exports.ensureExamplePath = ensureExamplePath;
							 | 
						||
| 
								 | 
							
								exports.writeExampleConfigFile = writeExampleConfigFile;
							 | 
						||
| 
								 | 
							
								exports.writeStackBlitzFile = writeStackBlitzFile;
							 | 
						||
| 
								 | 
							
								exports.copyExampleFiles = copyExampleFiles;
							 | 
						||
| 
								 | 
							
								exports.titleize = titleize;
							 |