mirror of
https://github.com/chenasraf/simple-scaffold.git
synced 2026-05-17 17:28:09 +00:00
migrate cmd to massarg + update tests
This commit is contained in:
8
.vscode/tasks.json
vendored
8
.vscode/tasks.json
vendored
@@ -25,6 +25,12 @@
|
||||
"type": "npm",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"command": "yarn test --watchAll",
|
||||
"label": "yarn test --watchAll",
|
||||
"type": "shell",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"script": "cmd",
|
||||
"label": "cmd",
|
||||
@@ -44,4 +50,4 @@
|
||||
"problemMatcher": [],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"glob": "^7.1.3",
|
||||
"handlebars": "^4.7.7",
|
||||
"lodash": "^4.17.21",
|
||||
"massarg": "^0.1.2",
|
||||
"util.promisify": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
138
src/cmd.ts
138
src/cmd.ts
@@ -1,60 +1,88 @@
|
||||
import Scaffold from "./scaffold"
|
||||
import args from "args"
|
||||
import massarg from "massarg"
|
||||
import { ScaffoldCmdConfig } from "./types"
|
||||
|
||||
const options = args
|
||||
.command("", "")
|
||||
.option(
|
||||
["n", "name"],
|
||||
"Name to be passed to the generated files. {{name}} and {{Name}} inside contents and file names will be replaced accordingly."
|
||||
)
|
||||
.option(
|
||||
["o", "output"],
|
||||
"Path to output to. If --create-sub-folder is enabled, the subfolder will be created inside this path."
|
||||
)
|
||||
.option(
|
||||
["t", "templates"],
|
||||
"Template files to use as input. You may provide multiple files, each of which can be a relative or absolute path, " +
|
||||
massarg<ScaffoldCmdConfig & { help: boolean; extras: string[] }>()
|
||||
.main(Scaffold)
|
||||
.option({
|
||||
name: "name",
|
||||
aliases: ["n"],
|
||||
isDefault: true,
|
||||
description:
|
||||
"Name to be passed to the generated files. {{name}} and {{Name}} inside contents and file names will be replaced accordingly.",
|
||||
})
|
||||
.option({
|
||||
name: "output",
|
||||
aliases: ["o"],
|
||||
description:
|
||||
"Path to output to. If --create-sub-folder is enabled, the subfolder will be created inside this path.",
|
||||
})
|
||||
.option({
|
||||
name: "templates",
|
||||
aliases: ["t"],
|
||||
description:
|
||||
"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.",
|
||||
[]
|
||||
)
|
||||
.option(["w", "overwrite"], "Enable to override output files, even if they already exist.", false)
|
||||
.option(
|
||||
["d", "data"],
|
||||
"Add custom data to the templates. By default, only your app name is included.",
|
||||
undefined,
|
||||
JSON.parse
|
||||
)
|
||||
.option(["s", "create-sub-folder"], "Create subfolder with the input name", false)
|
||||
.option(["q", "silent"], "Supress output logs", false)
|
||||
.option(
|
||||
["d", "dry-run"],
|
||||
"Don't emit actual files. This is good for testing your scaffolds and making sure they " +
|
||||
defaultValue: [],
|
||||
array: true,
|
||||
})
|
||||
.option({
|
||||
aliases: ["w"],
|
||||
name: "overwrite",
|
||||
description: "Enable to override output files, even if they already exist.",
|
||||
defaultValue: false,
|
||||
boolean: true,
|
||||
})
|
||||
.option({
|
||||
aliases: ["d"],
|
||||
name: "data",
|
||||
description: "Add custom data to the templates. By default, only your app name is included.",
|
||||
parse: (v) => JSON.parse(v),
|
||||
})
|
||||
.option({
|
||||
aliases: ["s"],
|
||||
name: "create-sub-folder",
|
||||
description: "Create subfolder with the input name",
|
||||
defaultValue: false,
|
||||
boolean: true,
|
||||
})
|
||||
.option({ aliases: ["q"], name: "quiet", description: "Supress output logs", defaultValue: false, boolean: true })
|
||||
.option({
|
||||
aliases: ["dr"],
|
||||
name: "dry-run",
|
||||
description:
|
||||
"Don't emit actual files. This is good for testing your scaffolds and making sure they " +
|
||||
"don't fail, without having to write actual files.",
|
||||
false
|
||||
)
|
||||
.example(
|
||||
`yarn cmd -t examples/test-input/Component -o examples/test-output -d '{"property":"myProp","value":"10"}'`,
|
||||
"Usage"
|
||||
)
|
||||
.parse(process.argv, {
|
||||
value: "name",
|
||||
mri: {},
|
||||
mainColor: "yellow",
|
||||
subColor: ["dim"],
|
||||
name: "simple-scaffold",
|
||||
usageFilter: (usage: string) => {
|
||||
usage = usage.replace("[options] [command] ", "").replace("name", "[options] name")
|
||||
const lines = usage.split("\n")
|
||||
usage = [
|
||||
...lines.slice(
|
||||
0,
|
||||
lines.findIndex((l) => l.startsWith(" Commands:"))
|
||||
),
|
||||
...lines.slice(lines.findIndex((l) => l.startsWith(" Options:"))),
|
||||
].join("\n")
|
||||
return usage
|
||||
},
|
||||
}) as ScaffoldCmdConfig
|
||||
|
||||
Scaffold(options)
|
||||
defaultValue: false,
|
||||
boolean: true,
|
||||
})
|
||||
// .example(
|
||||
// `yarn cmd -t examples/test-input/Component -o examples/test-output -d '{"property":"myProp","value":"10"}'`,
|
||||
// "Usage"
|
||||
// )
|
||||
.help({
|
||||
binName: "simple-scaffold",
|
||||
useGlobalColumns: true,
|
||||
usageExample: "[options]",
|
||||
})
|
||||
.parse()
|
||||
// .parse(process.argv, {
|
||||
// value: "name",
|
||||
// mri: {},
|
||||
// mainColor: "yellow",
|
||||
// subColor: ["dim"],
|
||||
// name: "simple-scaffold",
|
||||
// usageFilter: (usage: string) => {
|
||||
// usage = usage.replace("[options] [command] ", "").replace("name", "[options] name")
|
||||
// const lines = usage.split("\n")
|
||||
// usage = [
|
||||
// ...lines.slice(
|
||||
// 0,
|
||||
// lines.findIndex((l) => l.startsWith(" Commands:"))
|
||||
// ),
|
||||
// ...lines.slice(lines.findIndex((l) => l.startsWith(" Options:"))),
|
||||
// ].join("\n")
|
||||
// return usage
|
||||
// },
|
||||
// }
|
||||
// ) as ScaffoldCmdConfig
|
||||
|
||||
@@ -25,15 +25,21 @@ export async function Scaffold(config: ScaffoldConfig) {
|
||||
createSubfolder: options.createSubFolder,
|
||||
data: options.data,
|
||||
overwrite: options.overwrite,
|
||||
silent: options.silent,
|
||||
quiet: options.quiet,
|
||||
})
|
||||
log(options, "Data:", data)
|
||||
for (let template of config.templates) {
|
||||
try {
|
||||
// try {
|
||||
const tplStat = await stat(template)
|
||||
if (tplStat.isDirectory()) {
|
||||
template = template + "/**/*"
|
||||
}
|
||||
// } catch (e) {
|
||||
// if (e.code !== "ENOENT") {
|
||||
// throw e
|
||||
// }
|
||||
// }
|
||||
const files = await promisify(glob)(template, { dot: true })
|
||||
for (const templatePath of files) {
|
||||
await handleTemplateFile(templatePath, options, data)
|
||||
|
||||
4
src/types.d.ts
vendored
4
src/types.d.ts
vendored
@@ -9,7 +9,7 @@ export interface ScaffoldConfig {
|
||||
createSubFolder?: boolean
|
||||
data?: Record<string, string>
|
||||
overwrite?: FileResponse<boolean>
|
||||
silent?: boolean
|
||||
quiet?: boolean
|
||||
dryRun?: boolean
|
||||
}
|
||||
export interface ScaffoldCmdConfig {
|
||||
@@ -19,6 +19,6 @@ export interface ScaffoldCmdConfig {
|
||||
createSubFolder: boolean
|
||||
data?: Record<string, string>
|
||||
overwrite: boolean
|
||||
silent: boolean
|
||||
quiet: boolean
|
||||
dryRun: boolean
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export function handleErr(err: NodeJS.ErrnoException | null) {
|
||||
}
|
||||
|
||||
export function log(options: ScaffoldConfig, ...obj: any[]) {
|
||||
if (options.silent) {
|
||||
if (options.quiet) {
|
||||
return
|
||||
}
|
||||
console.log(...obj)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import mockFs from "mock-fs"
|
||||
import Scaffold from "../scaffold"
|
||||
import { readFileSync } from "fs"
|
||||
import Scaffold from "../src/scaffold"
|
||||
import { readdirSync, readFileSync } from "fs"
|
||||
|
||||
const fileStructNormal = {
|
||||
input: {
|
||||
@@ -16,6 +16,16 @@ const fileStructWithData = {
|
||||
output: {},
|
||||
}
|
||||
|
||||
const fileStructNested = {
|
||||
input: {
|
||||
"{{name}}-1.text": "This should be in root",
|
||||
"{{Name}}": {
|
||||
"{{name}}-2.txt": "Hello, my value is {{value}}",
|
||||
},
|
||||
},
|
||||
output: {},
|
||||
}
|
||||
|
||||
describe("Scaffold", () => {
|
||||
describe("create subfolder", () => {
|
||||
beforeAll(() => {
|
||||
@@ -28,7 +38,7 @@ describe("Scaffold", () => {
|
||||
name: "app_name",
|
||||
output: "output",
|
||||
templates: ["input"],
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
const data = readFileSync(process.cwd() + "/output/app_name.txt")
|
||||
@@ -41,7 +51,7 @@ describe("Scaffold", () => {
|
||||
output: "output",
|
||||
templates: ["input"],
|
||||
createSubFolder: true,
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
const data = readFileSync(process.cwd() + "/output/app_name/app_name.txt")
|
||||
@@ -63,7 +73,7 @@ describe("Scaffold", () => {
|
||||
output: "output",
|
||||
templates: ["input"],
|
||||
data: { value: "1" },
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
await Scaffold({
|
||||
@@ -71,7 +81,7 @@ describe("Scaffold", () => {
|
||||
output: "output",
|
||||
templates: ["input"],
|
||||
data: { value: "2" },
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
const data = readFileSync(process.cwd() + "/output/app_name.txt")
|
||||
@@ -84,7 +94,7 @@ describe("Scaffold", () => {
|
||||
output: "output",
|
||||
templates: ["input"],
|
||||
data: { value: "1" },
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
await Scaffold({
|
||||
@@ -93,7 +103,7 @@ describe("Scaffold", () => {
|
||||
templates: ["input"],
|
||||
data: { value: "2" },
|
||||
overwrite: true,
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
const data = readFileSync(process.cwd() + "/output/app_name.txt")
|
||||
@@ -118,7 +128,7 @@ describe("Scaffold", () => {
|
||||
output: "output",
|
||||
templates: ["non-existing-input"],
|
||||
data: { value: "1" },
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
).rejects.toThrow()
|
||||
|
||||
@@ -143,7 +153,7 @@ describe("Scaffold", () => {
|
||||
output: (fullPath, basedir, basename) => `custom-output/${basename.split(".")[0]}`,
|
||||
templates: ["input"],
|
||||
data: { value: "1" },
|
||||
silent: true,
|
||||
quiet: true,
|
||||
})
|
||||
const data = readFileSync(process.cwd() + "/custom-output/app_name/app_name.txt")
|
||||
expect(data.toString()).toBe("Hello, my app is app_name")
|
||||
@@ -153,4 +163,29 @@ describe("Scaffold", () => {
|
||||
mockFs.restore()
|
||||
})
|
||||
})
|
||||
|
||||
describe("output structure", () => {
|
||||
beforeAll(() => {
|
||||
mockFs.restore()
|
||||
mockFs(fileStructNested)
|
||||
})
|
||||
|
||||
test("should maintain input structure on output", async () => {
|
||||
await Scaffold({
|
||||
name: "app_name",
|
||||
output: "./",
|
||||
templates: ["input"],
|
||||
data: { value: "1" },
|
||||
quiet: true,
|
||||
})
|
||||
|
||||
const dir = readdirSync(process.cwd())
|
||||
console.log({ dir })
|
||||
expect(dir).toHaveProperty("length")
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
mockFs.restore()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -17,6 +17,6 @@
|
||||
"src/cmd.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/tests/*"
|
||||
"tests/*"
|
||||
]
|
||||
}
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@@ -932,7 +932,7 @@ chalk@2.4.2, chalk@^2.0.0:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^4.0.0:
|
||||
chalk@^4.0.0, chalk@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
|
||||
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
|
||||
@@ -2153,6 +2153,14 @@ makeerror@1.0.x:
|
||||
dependencies:
|
||||
tmpl "1.0.x"
|
||||
|
||||
massarg@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/massarg/-/massarg-0.1.2.tgz#f298741318172be14f3d2b701329fbe10eff41bb"
|
||||
integrity sha512-gpFIjsvOoqyQnrqNDytQXPljOGlX5lvJFGYzAIqjxDqiSZwHOvz+/YfjtzrFvokfYsk0uZbE/XOH4LVRiu/1cg==
|
||||
dependencies:
|
||||
chalk "^4.1.1"
|
||||
lodash "^4.17.21"
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
|
||||
Reference in New Issue
Block a user