mirror of
https://github.com/chenasraf/simple-scaffold.git
synced 2026-05-17 17:28:09 +00:00
fix: exclude globs
refactor: split main file iteration to 2 steps
This commit is contained in:
@@ -71,11 +71,10 @@ export function getBasePath(relPath: string): string {
|
||||
.replace(process.cwd(), "")
|
||||
}
|
||||
|
||||
export async function getFileList(_config: ScaffoldConfig, template: string): Promise<string[]> {
|
||||
template = template.replaceAll(/[\\]+/g, "/")
|
||||
log(_config, LogLevel.debug, `Getting file list for ${template}`)
|
||||
export async function getFileList(config: ScaffoldConfig, templates: string[]): Promise<string[]> {
|
||||
log(config, LogLevel.debug, `Getting file list for glob list: ${templates}`)
|
||||
return (
|
||||
await glob(template, {
|
||||
await glob(templates, {
|
||||
dot: true,
|
||||
nodir: true,
|
||||
})
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
getFileList,
|
||||
getBasePath,
|
||||
handleTemplateFile,
|
||||
GlobInfo,
|
||||
} from "./file"
|
||||
import { LogLevel, MinimalConfig, Resolver, ScaffoldCmdConfig, ScaffoldConfig } from "./types"
|
||||
import { registerHelpers } from "./parser"
|
||||
@@ -61,39 +62,45 @@ export async function Scaffold(config: ScaffoldConfig): Promise<void> {
|
||||
try {
|
||||
config.data = { name: config.name, ...config.data }
|
||||
logInitStep(config)
|
||||
for (let _template of config.templates) {
|
||||
const excludes = config.templates.filter((t) => t.startsWith("!"))
|
||||
const includes = config.templates.filter((t) => !t.startsWith("!"))
|
||||
const templates: GlobInfo[] = []
|
||||
for (let _template of includes) {
|
||||
try {
|
||||
const { nonGlobTemplate, origTemplate, isDirOrGlob, isGlob, template } = await getTemplateGlobInfo(
|
||||
config,
|
||||
_template,
|
||||
)
|
||||
const files = await getFileList(config, template)
|
||||
log(config, LogLevel.debug, "Iterating files", { files, template })
|
||||
for (const inputFilePath of files) {
|
||||
if (await isDir(inputFilePath)) {
|
||||
continue
|
||||
}
|
||||
const relPath = makeRelativePath(path.dirname(removeGlob(inputFilePath).replace(nonGlobTemplate, "")))
|
||||
const basePath = getBasePath(relPath)
|
||||
logInputFile(config, {
|
||||
originalTemplate: origTemplate,
|
||||
relativePath: relPath,
|
||||
parsedTemplate: template,
|
||||
inputFilePath,
|
||||
nonGlobTemplate,
|
||||
basePath,
|
||||
isDirOrGlob,
|
||||
isGlob,
|
||||
})
|
||||
await handleTemplateFile(config, {
|
||||
templatePath: inputFilePath,
|
||||
basePath,
|
||||
})
|
||||
}
|
||||
templates.push({ nonGlobTemplate, origTemplate, isDirOrGlob, isGlob, template })
|
||||
} catch (e: any) {
|
||||
handleErr(e)
|
||||
}
|
||||
}
|
||||
for (const tpl of templates) {
|
||||
const files = await getFileList(config, [tpl.template, ...excludes])
|
||||
for (const file of files) {
|
||||
if (await isDir(file)) {
|
||||
continue
|
||||
}
|
||||
log(config, LogLevel.debug, "Iterating files", { files, file })
|
||||
const relPath = makeRelativePath(path.dirname(removeGlob(file).replace(tpl.nonGlobTemplate, "")))
|
||||
const basePath = getBasePath(relPath)
|
||||
logInputFile(config, {
|
||||
originalTemplate: tpl.origTemplate,
|
||||
relativePath: relPath,
|
||||
parsedTemplate: tpl.template,
|
||||
inputFilePath: file,
|
||||
nonGlobTemplate: tpl.nonGlobTemplate,
|
||||
basePath,
|
||||
isDirOrGlob: tpl.isDirOrGlob,
|
||||
isGlob: tpl.isGlob,
|
||||
})
|
||||
await handleTemplateFile(config, {
|
||||
templatePath: file,
|
||||
basePath,
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
log(config, LogLevel.error, e)
|
||||
throw e
|
||||
@@ -111,7 +118,7 @@ export async function Scaffold(config: ScaffoldConfig): Promise<void> {
|
||||
* @category Main
|
||||
* @return {Promise<void>} A promise that resolves when the scaffold is complete
|
||||
*/
|
||||
Scaffold.fromConfig = async function (
|
||||
Scaffold.fromConfig = async function(
|
||||
/** The path or URL to the config file */
|
||||
pathOrUrl: string,
|
||||
/** Information needed before loading the config */
|
||||
|
||||
@@ -22,6 +22,11 @@ export interface ScaffoldConfig {
|
||||
* Template files to use as input. You may provide multiple files, each of which can be a relative or absolute path,
|
||||
* or a glob pattern for multiple file matching easily.
|
||||
*
|
||||
* You may omit files from output by prepending a `!` to their glob pattern.
|
||||
*
|
||||
* For example, `["components/**", "!components/README.md"]` will include everything in the directory `components`
|
||||
* except the `README.md` file inside.
|
||||
*
|
||||
* @default Current working directory
|
||||
*/
|
||||
templates: string[]
|
||||
@@ -331,7 +336,9 @@ export type FileResponse<T> = T | FileResponseHandler<T>
|
||||
|
||||
/**
|
||||
* The Scaffold config for CLI
|
||||
* Contains less and more specific options than {@link ScaffoldConfig}
|
||||
* Contains less and more specific options than {@link ScaffoldConfig}.
|
||||
*
|
||||
* For more information about each option, see {@link ScaffoldConfig}.
|
||||
*/
|
||||
export type ScaffoldCmdConfig = {
|
||||
/** The name of the scaffold template to use. */
|
||||
|
||||
@@ -71,6 +71,14 @@ const fileStructDates = {
|
||||
output: {},
|
||||
}
|
||||
|
||||
const fileStructExcludes = {
|
||||
input: {
|
||||
"include.txt": "This file should be included",
|
||||
"exclude.txt": "This file should be excluded",
|
||||
},
|
||||
output: {},
|
||||
}
|
||||
|
||||
function withMock(fileStruct: FileSystem.DirectoryItems, testFn: jest.EmptyFunction): jest.EmptyFunction {
|
||||
return () => {
|
||||
beforeEach(() => {
|
||||
@@ -268,8 +276,7 @@ describe("Scaffold", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
describe(
|
||||
"output structure",
|
||||
describe("output structure", () => {
|
||||
withMock(fileStructNested, () => {
|
||||
test("should maintain input structure on output", async () => {
|
||||
await Scaffold({
|
||||
@@ -294,8 +301,23 @@ describe("Scaffold", () => {
|
||||
expect(oneDeepFile.toString()).toEqual("Hello, my value is 1")
|
||||
expect(twoDeepFile.toString()).toEqual("Hi! My value is actually NOT 1!")
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
withMock(fileStructExcludes, () => {
|
||||
test("should exclude files", async () => {
|
||||
await Scaffold({
|
||||
name: "app_name",
|
||||
output: "output",
|
||||
templates: ["input", "!exclude.txt"],
|
||||
data: { value: "1" },
|
||||
logLevel: "none",
|
||||
})
|
||||
const includeFile = readFileSync(join(process.cwd(), "output", "app_name.txt"))
|
||||
expect(includeFile.toString()).toEqual("This file should be included")
|
||||
expect(() => readFileSync(join(process.cwd(), "output", "exclude.txt"))).toThrow()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe(
|
||||
"capitalization helpers",
|
||||
|
||||
Reference in New Issue
Block a user