templates-mo
Version:
Templates is a scaffolding framework that makes code generation simple, dynamic, and reusable. Generate files, parts of your app, or whole project structures—without the repetitive copy-pasting
177 lines (152 loc) • 4.44 kB
text/typescript
import fs from 'fs';
import { MAIN_DIR, TPS_FOLDER, USER_HOME } from '@tps/utilities/constants';
import { CommandModule } from 'yargs';
import Templates from '@tps/templates';
import logger from '@tps/utilities/logger';
import path from 'path';
import { flatten, unique } from '@tps/utilities/helpers';
interface ListArgv {
global: boolean;
local: boolean;
default: boolean;
nodeModules: boolean;
}
const removeConfigFileNames = (arr: string[]) => {
const configFilesMap = Templates.tpsrcConfigNames.reduce<
Record<string, boolean>
>((mapping, name) => {
// eslint-disable-next-line no-param-reassign -- adding to object not reassigning
mapping[name] = true;
return mapping;
}, {});
return arr.filter((item) => {
// if item is not a config file
return !configFilesMap[item];
});
};
export const BANNED_TEMPLATES: string[] = [
'init',
'new-template',
'new-test',
'tps-docs',
];
export default {
command: ['list', 'ls'],
description: 'Show all available templates',
builder: {
global: {
type: 'boolean',
description: 'List out global files',
alias: 'g',
default: true,
},
local: {
type: 'boolean',
description: 'List out local files',
alias: 'l',
default: true,
},
default: {
type: 'boolean',
description: 'List out default templates',
alias: 'd',
default: true,
},
nodeModules: {
type: 'boolean',
description: 'List out 3rd party templates',
alias: 'n',
default: true,
},
},
async handler(argv) {
const { local, default: defaultTemplates, global, nodeModules } = argv;
logger.cli.info('Args: %n', {
local,
default: defaultTemplates,
global,
nodeModules,
});
/**
* All template locations
*/
const templateLocations = Templates.getTemplateLocations();
logger.cli.info('Template locations: %n', templateLocations);
/**
* Filter out local, global, default, 3rd party templates depending
* on what the user supplies
*/
const filteredTemplates = templateLocations.filter((dir) => {
const isDefaultTemplate = dir.startsWith(path.join(MAIN_DIR, TPS_FOLDER));
const isNodeModulesTemplate = path.parse(dir).base === 'node_modules';
const isGlobalTemplates =
dir.startsWith(path.join(USER_HOME, TPS_FOLDER)) ||
dir.startsWith(path.join(USER_HOME, 'node_modules'));
const isLocalTemplate = !isDefaultTemplate && !isGlobalTemplates;
logger.cli.info('%s %n', dir, {
isDefaultTemplate,
isGlobalTemplates,
isLocalTemplate,
isNodeModulesTemplate,
});
if (!defaultTemplates && isDefaultTemplate) return false;
if (!global && isGlobalTemplates) return false;
if (!nodeModules && isNodeModulesTemplate) return false;
if (!local && isLocalTemplate) return false;
return true;
});
logger.cli.info('Templates after filter: %n\n', filteredTemplates);
/**
* Fetch templates in each directories still present
*/
const templatesNested = await Promise.all(
filteredTemplates.map(async (templateDir) => {
let directoryTemplates: string[] = [];
try {
/**
* readdir throws error when not present. To prevent
* making multiple call (existence, readdir) for each directory
* well just return empty array here.
*/
directoryTemplates = await fs.promises.readdir(templateDir, {});
} catch (err) {
/**
* log any errors that dont have to do with the directory existing
*/
if (err?.code !== 'ENOENT') {
logger.cli.error('Template readdir error %n', {
templateDir,
err,
});
}
return [];
}
if (path.parse(templateDir).base === 'node_modules') {
/**
* Only print out packages that start with `tps`
*/
directoryTemplates = directoryTemplates.filter((template) => {
return template.startsWith('tps-');
});
}
if (templateDir.startsWith(path.join(MAIN_DIR))) {
/**
* Removed banned templates. Banned templates are
* this repos internal templates
*/
directoryTemplates = directoryTemplates.filter((template) => {
return !BANNED_TEMPLATES.includes(template);
});
}
/**
* Remove `.tpsrc` file
*/
return removeConfigFileNames(directoryTemplates);
}),
);
const templates = unique(flatten(templatesNested));
templates.forEach((template) => {
console.log(template.replace(/^tps-/, ''));
});
},
} as CommandModule<object, ListArgv>;