diff --git a/.gitignore b/.gitignore index 9e6becc..7d7e061 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,9 @@ typings/ # Optional npm cache directory .npm +# NPM +.npmrc + # Optional eslint cache .eslintcache diff --git a/doc-theme/package.json b/doc-theme/package.json index db66955..98ece17 100644 --- a/doc-theme/package.json +++ b/doc-theme/package.json @@ -5,7 +5,9 @@ "typedocplugin" ], "scripts": { - "build": "tsc" + "build": "tsc && yarn copy-files && yarn post-build", + "copy-files": "cp package.json build/", + "postbuild": "rimraf node_modules" }, "main": "build/index.js", "devDependencies": { diff --git a/package.json b/package.json index 779631b..b50451d 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "cmd": "node --trace-warnings dist/cmd.js", "build-test": "yarn build && yarn test", "build-cmd": "yarn build && yarn cmd", + "build-docs": "yarn build && yarn typedoc", + "watch-docs": "yarn typedoc --watch", "audit-fix": "npm_config_yes=true npx yarn-audit-fix --flow=convert" }, "dependencies": { @@ -54,4 +56,4 @@ "typedoc": "^0.22.15", "typescript": "^4.3.5" } -} \ No newline at end of file +} diff --git a/src/scaffold.ts b/src/scaffold.ts index e0c7042..7385c04 100644 --- a/src/scaffold.ts +++ b/src/scaffold.ts @@ -47,11 +47,13 @@ import { LogLevel, ScaffoldConfig } from "./types" * Any functions you provide in `helpers` option will also be available to you to make custom formatting as you see fit * (for example, formatting a date) * - * For available default values, see {@link DefaultHelperKeys}. + * For available default values, see {@link DefaultHelpers}. * * @param {ScaffoldConfig} config The main configuration object * - * @see {@link DefaultHelperKeys} + * @see {@link DefaultHelpers} + * @see {@link CaseHelpers} + * @see {@link DateHelpers} * * @category Main */ @@ -66,7 +68,7 @@ export async function Scaffold(config: ScaffoldConfig): Promise { try { const { nonGlobTemplate, origTemplate, isDirOrGlob, isGlob, template } = await getTemplateGlobInfo( config, - _template + _template, ) const files = await getFileList(config, template) for (const inputFilePath of files) { @@ -101,7 +103,7 @@ export async function Scaffold(config: ScaffoldConfig): Promise { } async function handleTemplateFile( config: ScaffoldConfig, - { templatePath, basePath }: { templatePath: string; basePath: string } + { templatePath, basePath }: { templatePath: string; basePath: string }, ): Promise { return new Promise(async (resolve, reject) => { try { @@ -120,7 +122,7 @@ async function handleTemplateFile( `\nOutput Path Opt: ${outputPathOpt}`, `\nFull output dir: ${outputDir}`, `\nFull output path: ${outputPath}`, - `\n` + `\n`, ) await createDirIfNotExists(path.dirname(outputPath), config) diff --git a/src/types.ts b/src/types.ts index 2b59eb0..8b9763a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,7 +4,9 @@ import { HelperDelegate } from "handlebars/runtime" * The config object for defining a scaffolding group. * * @see https://github.com/chenasraf/simple-scaffold#readme - * @see {@link DefaultHelperKeys} + * @see {@link DefaultHelpers} + * @see {@link CaseHelpers} + * @see {@link DateHelpers} * * @category Config */ @@ -95,7 +97,7 @@ export interface ScaffoldConfig { * Additional helpers to add to the template parser. Provide an object whose keys are the name of the function to add, * and the value is the helper function itself. The signature of helpers is as follows: * ```typescript - * (text: string) => string + * (text: string, ...args: any[]) => string * ``` * * A full example might be: @@ -104,27 +106,47 @@ export interface ScaffoldConfig { * Scaffold({ * //... * helpers: { - * upperCamelCase: (text) => camelCase(text).toUpperCase() + * upperKebabCase: (text) => kebabCase(text).toUpperCase() * } * }) * ``` * - * See {@link DefaultHelperKeys} for a list of all the built-in available helpers. + * Which will allow: * - * @see https://github.com/chenasraf/simple-scaffold#helpers - * @see https://github.com/chenasraf/simple-scaffold#built-in-helpers + * ``` + * {{ upperKebabCase "my value" }} + * ``` + * + * To transform to: + * + * ``` + * MY-VALUE + * ``` + * + * See {@link DefaultHelpers} for a list of all the built-in available helpers. + * + * Simple Scaffold uses Handlebars.js, so all the syntax from there is supported. See + * [their docs](https://handlebarsjs.com/guide/#custom-helpers) for more information. + * + * @see {@link DefaultHelpers} + * @see {@link CaseHelpers} + * @see {@link DateHelpers} + * @see https://casraf.blog/simple-scaffold#helpers + * @see https://casraf.blog/simple-scaffold#built-in-helpers + * @see https://handlebarsjs.com/guide/#custom-helpers */ helpers?: Record /** * Default transformer to apply to subfolder name when using `createSubFolder: true`. Can be one of the default - * capitalization helpers, or a custom one you provide to `helpers`. Defaults to `undefined`, which means no transformation is done. + * capitalization helpers, or a custom one you provide to `helpers`. Defaults to `undefined`, which means no + * transformation is done. * * @see {@link createSubFolder} - * @see {@link CapitalizationHelperKeys} - * @see {@link DefaultHelperKeys} + * @see {@link CaseHelpers} + * @see {@link DefaultHelpers} */ - subFolderNameHelper?: DefaultHelperKeys | string + subFolderNameHelper?: DefaultHelpers | string /** * This callback runs right before content is being written to the disk. If you supply this function, you may return @@ -137,13 +159,13 @@ export interface ScaffoldConfig { * @param rawContent The original template before token replacement * @param outputPath The final output path of the processed file * - * @returns {Promise | String | Buffer | undefined} The final output of the file contents-only, after further modifications - - * or `undefined` to use the original content (i.e. `content.toString()`) + * @returns {Promise | String | Buffer | undefined} The final output of the file + * contents-only, after further modifications - or `undefined` to use the original content (i.e. `content.toString()`) */ beforeWrite?( content: Buffer, rawContent: Buffer, - outputPath: string + outputPath: string, ): string | Buffer | undefined | Promise } @@ -164,13 +186,14 @@ export interface ScaffoldConfig { * | `upperCase` | `{{ upperCase name }}` | MY NAME | * | `lowerCase` | `{{ lowerCase name }}` | my name | * + * @see {@link DefaultHelpers} + * @see {@link DateHelpers} * @see {@link ScaffoldConfig} * @see {@link subFolderNameHelper} - * @see {@link DefaultHelperKeys} * * @category Helpers */ -export type CapitalizationHelperKeys = +export type CaseHelpers = | "camelCase" | "hyphenCase" | "kebabCase" @@ -191,11 +214,33 @@ export type CapitalizationHelperKeys = * | `date` (with offset) | Custom date with format, and with offset | `{{ date "2042-01-01T15:00:00Z" "yyyy-MM-dd HH:mm" -1 "days" }}` | `2041-31-12 15:00` | * | `date` (with date from `--data`) | Custom date with format, with data from the `data` config option | `{{ date myCustomDate "yyyy-MM-dd HH:mm" }}` | `2042-01-01 12:00` | * - * @see {@link DefaultHelperKeys} + * Further details: + * + * - We use [`date-fns`](https://date-fns.org/docs/) for parsing/manipulating the dates. If you want + * more information on the date tokens to use, refer to + * [their format documentation](https://date-fns.org/docs/format). + * + * - The date helper format takes the following arguments: + * + * ```typescript + * ( + * date: string, + * format: string, + * offsetAmount?: number, + * offsetType?: "years" | "months" | "weeks" | "days" | "hours" | "minutes" | "seconds" + * ) + * ``` + * + * - **The now helper** (for current time) takes the same arguments, minus the first one (`date`) as it is implicitly + * the current date. + * + * @see {@link DefaultHelpers} + * @see {@link CaseHelpers} + * @see {@link ScaffoldConfig} * * @category Helpers */ -export type DateHelperKeys = "date" | "now" +export type DateHelpers = "date" | "now" /** * The names of all the available helper functions in templates. @@ -204,12 +249,13 @@ export type DateHelperKeys = "date" | "now" * For example, you may use `{{ snakeCase name }}` inside a template file or filename, and it will * replace `My Name` with `my_name` when producing the final value. * - * @see {@link CapitalizationHelperKeys} - * @see {@link DateHelperKeys} + * @see {@link CaseHelpers} + * @see {@link DateHelpers} + * @see {@link ScaffoldConfig} * * @category Helpers */ -export type DefaultHelperKeys = CapitalizationHelperKeys | DateHelperKeys +export type DefaultHelpers = CaseHelpers | DateHelpers /** * Helper function, see https://handlebarsjs.com/guide/#custom-helpers diff --git a/src/utils.ts b/src/utils.ts index 70f6d16..f679d6c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,6 @@ import path from "path" import { F_OK } from "constants" -import { DefaultHelperKeys, FileResponse, FileResponseHandler, Helper, LogLevel, ScaffoldConfig } from "./types" +import { DefaultHelpers, FileResponse, FileResponseHandler, Helper, LogLevel, ScaffoldConfig } from "./types" import camelCase from "lodash/camelCase" import snakeCase from "lodash/snakeCase" import kebabCase from "lodash/kebabCase" @@ -23,7 +23,7 @@ import { glob } from "glob" import { promisify } from "util" const { readFile, writeFile } = fsPromises -export const defaultHelpers: Record = { +export const defaultHelpers: Record = { camelCase, snakeCase, startCase, @@ -41,13 +41,13 @@ export function _dateHelper( date: Date, formatString: string, durationDifference: number, - durationType: keyof Duration + durationType: keyof Duration, ): string export function _dateHelper( date: Date, formatString: string, durationDifference?: number, - durationType?: keyof Duration + durationType?: keyof Duration, ): string { if (durationType && durationDifference !== undefined) { return dateFns.format(dateFns.add(date, { [durationType]: durationDifference }), formatString) @@ -66,14 +66,14 @@ export function dateHelper( date: string, formatString: string, durationDifference: number, - durationType: keyof Duration + durationType: keyof Duration, ): string export function dateHelper( date: string, formatString: string, durationDifference?: number, - durationType?: keyof Duration + durationType?: keyof Duration, ): string { return _dateHelper(dateFns.parseISO(date), formatString, durationDifference!, durationType!) } @@ -110,8 +110,8 @@ export function log(config: ScaffoldConfig, level: LogLevel, ...obj: any[]): voi ? chalkFn(i, JSON.stringify(i, undefined, 1), i.stack) : typeof i === "object" ? chalkFn(JSON.stringify(i, undefined, 1)) - : chalkFn(i) - ) + : chalkFn(i), + ), ) } @@ -140,7 +140,7 @@ export function getOptionValueForFile( config: ScaffoldConfig, filePath: string, fn: FileResponse, - defaultValue?: T + defaultValue?: T, ): T { if (typeof fn !== "function") { return defaultValue ?? (fn as T) @@ -148,14 +148,14 @@ export function getOptionValueForFile( return (fn as FileResponseHandler)( filePath, path.dirname(handlebarsParse(config, filePath, { isPath: true }).toString()), - path.basename(handlebarsParse(config, filePath, { isPath: true }).toString()) + path.basename(handlebarsParse(config, filePath, { isPath: true }).toString()), ) } export function handlebarsParse( config: ScaffoldConfig, templateBuffer: Buffer | string, - { isPath = false }: { isPath?: boolean } = {} + { isPath = false }: { isPath?: boolean } = {}, ): Buffer { const { data } = config try { @@ -255,7 +255,7 @@ export interface OutputFileInfo { export async function getTemplateFileInfo( config: ScaffoldConfig, - { templatePath, basePath }: { templatePath: string; basePath: string } + { templatePath, basePath }: { templatePath: string; basePath: string }, ): Promise { const inputPath = path.resolve(process.cwd(), templatePath) const outputPathOpt = getOptionValueForFile(config, inputPath, config.output) @@ -279,7 +279,7 @@ export async function copyFileTransformed( overwrite: boolean outputPath: string inputPath: string - } + }, ): Promise { if (!exists || overwrite) { if (exists && overwrite) { @@ -313,7 +313,7 @@ export function getOutputDir(config: ScaffoldConfig, outputPathOpt: string, base ? handlebarsParse(config, `{{ ${config.subFolderNameHelper} name }}`).toString() : config.name : undefined, - ].filter(Boolean) as string[]) + ].filter(Boolean) as string[]), ) } @@ -337,7 +337,7 @@ export function logInputFile( basePath: string isDirOrGlob: boolean isGlob: boolean - } + }, ): void { log( config, @@ -351,7 +351,7 @@ export function logInputFile( `\nbasePath: ${basePath}`, `\nisDirOrGlob: ${isDirOrGlob}`, `\nisGlob: ${isGlob}`, - `\n` + `\n`, ) } @@ -367,7 +367,7 @@ export function logInitStep(config: ScaffoldConfig): void { subFolderTransformHelper: config.subFolderNameHelper, helpers: Object.keys(config.helpers ?? {}), verbose: `${config.verbose} (${Object.keys(LogLevel).find( - (k) => (LogLevel[k as any] as unknown as number) === config.verbose! + (k) => (LogLevel[k as any] as unknown as number) === config.verbose!, )})`, }) log(config, LogLevel.Info, "Data:", config.data)