Compare commits

..

3 Commits

Author SHA1 Message Date
Chen Asraf
5e175e6815 remove redundent check 2022-04-19 22:43:53 +03:00
Chen Asraf
0742fc8771 fix docs 2022-04-19 22:30:52 +03:00
Chen Asraf
0ecf07de18 accept async beforeWrite callback 2022-04-19 22:25:10 +03:00
6 changed files with 74 additions and 30 deletions

View File

@@ -148,11 +148,11 @@ const scaffold = Scaffold(config)
In addition to all the options available in the command line, there are some Node/JS-specific
options available:
| Option | Type | Description |
| ------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `output` | | In addition to being passed the same as CLI, it may also be passed a function for each input file to output into a dynamic path: `{ output: (fullPath, baseDir, baseName) => path.resolve(baseDir, baseName) }` |
| `helpers` | `Record<string, (string) => string>` | Helpers are simple functions that transform your `data` variables into other values. See [Helpers](#helpers) for the list of default helpers, or add your own to be loaded into the template parser. |
| `beforeWrite` | `(content: Buffer, rawContent: Buffer, outputPath: string) => String \| Buffer \| undefined` | Supply this function to override the final output contents of each of your files. The return value of this function will replace the output content of the respective file, which you may discriminate (if needed) using the `outputPath` argument. |
| Option | Type | Description |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `output` | | In addition to being passed the same as CLI, it may also be passed a function for each input file to output into a dynamic path: `{ output: (fullPath, baseDir, baseName) => path.resolve(baseDir, baseName) }` |
| `helpers` | `Record<string, (string) => string>` | Helpers are simple functions that transform your `data` variables into other values. See [Helpers](#helpers) for the list of default helpers, or add your own to be loaded into the template parser. |
| `beforeWrite` | `(content: Buffer, rawContent: Buffer, outputPath: string) => Promise<String \| Buffer \| undefined> \| String \| Buffer \| undefined` | Supply this function to override the final output contents of each of your files. The return value of this function will replace the output content of the respective file, which you may discriminate (if needed) using the `outputPath` argument. |
## Preparing files

View File

@@ -1,6 +1,6 @@
{
"name": "simple-scaffold",
"version": "1.1.0-alpha.2",
"version": "1.1.0-alpha.5",
"description": "Create files based on templates",
"repository": "https://github.com/chenasraf/simple-scaffold.git",
"author": "Chen Asraf <inbox@casraf.com>",

View File

@@ -11,7 +11,6 @@ import {
makeRelativePath,
registerHelpers,
getTemplateGlobInfo,
ensureFileExists,
getFileList,
getBasePath,
copyFileTransformed,
@@ -64,7 +63,6 @@ export async function Scaffold({ ...options }: ScaffoldConfig): Promise<void> {
options,
_template
)
await ensureFileExists(template, isDirOrGlob)
const files = await getFileList(options, template)
for (const inputFilePath of files) {
if (await isDir(inputFilePath)) {

View File

@@ -130,7 +130,11 @@ export interface ScaffoldConfig {
* @returns `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): string | Buffer | undefined
beforeWrite?(
content: Buffer,
rawContent: Buffer,
outputPath: string
): string | Buffer | undefined | Promise<string | Buffer | undefined>
}
export interface ScaffoldCmdConfig {
name: string

View File

@@ -245,16 +245,6 @@ export async function getTemplateGlobInfo(options: ScaffoldConfig, template: str
return { nonGlobTemplate, origTemplate, isDirOrGlob, isGlob, template: _template }
}
export async function ensureFileExists(template: string, isGlob: boolean): Promise<void> {
if (!isGlob && !(await pathExists(template))) {
const err: NodeJS.ErrnoException = new Error(`ENOENT, no such file or directory ${template}`)
err.code = "ENOENT"
err.path = template
err.errno = -2
throw err
}
}
export interface OutputFileInfo {
inputPath: string
outputPathOpt: string
@@ -299,7 +289,7 @@ export async function copyFileTransformed(
const templateBuffer = await readFile(inputPath)
const unprocessedOutputContents = handlebarsParse(options, templateBuffer)
const finalOutputContents = (
options.beforeWrite?.(unprocessedOutputContents, templateBuffer, outputPath) ?? unprocessedOutputContents
(await options.beforeWrite?.(unprocessedOutputContents, templateBuffer, outputPath)) ?? unprocessedOutputContents
).toString()
if (!options.dryRun) {

View File

@@ -94,7 +94,7 @@ describe("Scaffold", () => {
verbose: 0,
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
test("should create with config", async () => {
@@ -107,7 +107,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
})
)
@@ -133,7 +133,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toBe("Hello, my value is 1")
expect(data.toString()).toEqual("Hello, my value is 1")
})
test("should overwrite with config", async () => {
@@ -155,7 +155,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toBe("Hello, my value is 2")
expect(data.toString()).toEqual("Hello, my value is 2")
})
})
)
@@ -183,6 +183,43 @@ describe("Scaffold", () => {
})
).rejects.toThrow()
await expect(
Scaffold({
name: "app_name",
output: "output",
templates: ["non-existing-input/non-existing-file.txt"],
data: { value: "1" },
verbose: 0,
})
).rejects.toThrow()
expect(() => readFileSync(join(process.cwd(), "output", "app_name.txt"))).toThrow()
})
})
)
describe(
"dry run",
withMock(fileStructNormal, () => {
let consoleMock1: jest.SpyInstance
beforeAll(() => {
consoleMock1 = jest.spyOn(console, "error").mockImplementation(() => void 0)
})
afterAll(() => {
consoleMock1.mockRestore()
})
test("should not write to disk", async () => {
Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
data: { value: "1" },
verbose: 0,
dryRun: true,
})
expect(() => readFileSync(join(process.cwd(), "output", "app_name.txt"))).toThrow()
})
})
@@ -200,7 +237,7 @@ describe("Scaffold", () => {
verbose: 0,
})
const data = readFileSync(join(process.cwd(), "/custom-output/app_name/app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
})
)
@@ -344,7 +381,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
test("should work with default helper", async () => {
@@ -358,7 +395,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "APP_NAME", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
test("should work with custom helper", async () => {
@@ -375,7 +412,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "REPLACED", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
})
)
@@ -394,7 +431,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toBe("Hello, my app is app_name")
expect(data.toString()).toEqual("Hello, my app is app_name")
})
test("should work with custom callback", async () => {
@@ -411,7 +448,7 @@ describe("Scaffold", () => {
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toBe(
expect(data.toString()).toEqual(
[
"Hello, my app is app_name".toUpperCase(),
fileStructNormal.input["{{name}}.txt"],
@@ -419,6 +456,21 @@ describe("Scaffold", () => {
].join(", ")
)
})
test("should work with undefined response custom callback", async () => {
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
verbose: 0,
data: {
value: "value",
},
beforeWrite: () => undefined,
})
const data = readFileSync(join(process.cwd(), "output", "app_name.txt"))
expect(data.toString()).toEqual("Hello, my app is app_name")
})
})
)
})