Compare commits

..

17 Commits

Author SHA1 Message Date
semantic-release-bot
48d5af0fb6 chore(release): 1.5.0-develop.2 [skip ci]
## [1.5.0-develop.2](https://github.com/chenasraf/simple-scaffold/compare/v1.5.0-develop.1...v1.5.0-develop.2) (2023-05-03)

### Bug Fixes

* move dependency to dev dependency ([408a940](408a940853))
2023-05-03 06:44:17 +00:00
Chen Asraf
408a940853 fix: move dependency to dev dependency 2023-05-03 09:42:29 +03:00
Chen Asraf
0256e9282b docs: update docs 2023-05-03 00:34:17 +03:00
Chen Asraf
e0dc643d4e docs: fix link 2023-05-02 18:57:35 +03:00
Chen Asraf
23fcaefdd9 docs: update docs 2023-05-02 18:33:03 +03:00
Chen Asraf
9ea414fe1a docs: fix cli.md page 2023-05-02 18:17:08 +03:00
Chen Asraf
1a3fd3d610 docs: update help text 2023-05-02 10:23:50 +03:00
Chen Asraf
7f10db0d6e chore: bump version number 2023-05-02 10:16:47 +03:00
semantic-release-bot
93f5b4a004 chore(release): 1.5.0-develop.1 [skip ci]
## [1.5.0-develop.1](https://github.com/chenasraf/simple-scaffold/compare/v1.4.0...v1.5.0-develop.1) (2023-05-02)

### Features

* add github remote templates ([f961c13](f961c13da1))
* support for remote template configs ([05487f4](05487f4d1e))
2023-05-02 07:12:11 +00:00
Chen Asraf
b74411ddb8 docs: add docs for remote templates 2023-05-02 10:10:50 +03:00
Chen Asraf
f961c13da1 feat: add github remote templates 2023-05-02 09:46:53 +03:00
Chen Asraf
05487f4d1e feat: support for remote template configs 2023-05-02 09:33:54 +03:00
Chen Asraf
c50518a19c build: fix git/github step order 2023-04-29 17:17:15 +03:00
Chen Asraf
10ea6b4132 chore: fix package version 2023-04-29 17:11:18 +03:00
Chen Asraf
ce399181ab build: always build docs 2023-04-29 17:05:50 +03:00
semantic-release-bot
83d38073f3 chore(release): 1.4.0 [skip ci]
## [1.4.0](https://github.com/chenasraf/simple-scaffold/compare/v1.3.2...v1.4.0) (2023-04-28)

### Features

* add `--key` | `-k` to config loader ([6c5ba0b](6c5ba0bc91))
2023-04-28 23:01:48 +00:00
Chen Asraf
6c5ba0bc91 feat: add --key | -k to config loader 2023-04-29 01:59:39 +03:00
11 changed files with 328 additions and 94 deletions

View File

@@ -2,11 +2,12 @@ name: Build Documentation
on:
push:
branches: [master, develop]
branches: [ master, develop ]
jobs:
docs:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip docs]')"
# if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip docs]')"
if: "!contains(github.event.head_commit.message, '[skip docs]')"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3

View File

@@ -1,5 +1,27 @@
# Change Log
## [1.5.0-develop.2](https://github.com/chenasraf/simple-scaffold/compare/v1.5.0-develop.1...v1.5.0-develop.2) (2023-05-03)
### Bug Fixes
* move dependency to dev dependency ([408a940](https://github.com/chenasraf/simple-scaffold/commit/408a94085366bb4e39391fcfcfa7df78b06a480f))
## [1.5.0-develop.1](https://github.com/chenasraf/simple-scaffold/compare/v1.4.0...v1.5.0-develop.1) (2023-05-02)
### Features
* add github remote templates ([f961c13](https://github.com/chenasraf/simple-scaffold/commit/f961c13da15320b42540773ed958cdc3f97e4502))
* support for remote template configs ([05487f4](https://github.com/chenasraf/simple-scaffold/commit/05487f4d1e3b05f1d695242bb54427ee2fbdf247))
## [1.4.0](https://github.com/chenasraf/simple-scaffold/compare/v1.3.2...v1.4.0) (2023-04-28)
### Features
* add `--key` | `-k` to config loader ([6c5ba0b](https://github.com/chenasraf/simple-scaffold/commit/6c5ba0bc916fb1d59240d2eaa1abedc74527a974))
## [1.3.2](https://github.com/chenasraf/simple-scaffold/compare/v1.3.1...v1.3.2) (2023-04-28)

View File

@@ -3,7 +3,7 @@
<h2 align="center">
[GitHub](https://github.com/chenasraf/simple-scaffold) |
[Documentation](https://casraf.dev/simple-scaffold) |
[Documentation](https://chenasraf.github.io/simple-scaffold) |
[NPM](https://npmjs.com/package/simple-scaffold) | [casraf.dev](https://casraf.dev)
![version](https://img.shields.io/github/package-json/v/chenasraf/simple-scaffold/master?label=version)
@@ -33,6 +33,8 @@ lifting for you and start building your projects faster and more efficiently tod
## Quick Start
### Local Templates
The fastest way to get started is to use `npx` to immediately start a scaffold process.
Prepare any templates you want to use - for example, in the directory `templates/component`; and use
@@ -72,6 +74,28 @@ export default PageWrapper: React.FC = (props) => {
}
```
### Remote Templates
Another quick way to start is to re-use someone else's (or your own) work using a template
repository.
Here is an example for loading the example component templates in this very repository:
```shell
npx simple-scaffold@latest \
-gh chenasraf/simple-scaffold#examples/test-input/scaffold.config.js:component \
PageWrapper
# equivalent to:
npx simple-scaffold@latest \
-c https://github.com/chenasraf/simple-scaffold.git#examples/test-input/scaffold.config.js:component \
PageWrapper
```
When template name (`:component`) is omitted, `default` is used.
See more at the [CLI documentation](https://chenasraf.github.io/simple-scaffold/pages/cli.html)
## Documentation
See full documentation [here](https://chenasraf.github.io/simple-scaffold).

View File

@@ -7,7 +7,7 @@ module.exports = {
},
component: {
templates: ["examples/test-input/Component"],
output: "examples/test-output",
output: "examples/test-output/component",
data: { property: "myProp", value: "10" },
},
}

View File

@@ -1,8 +1,8 @@
{
"name": "simple-scaffold",
"version": "1.3.1",
"version": "1.5.0",
"description": "A simple command to generate any file structure, from single components to entire app boilerplates.",
"homepage": "https://casraf.dev/simple-scaffold",
"homepage": "https://chenasraf.github.io/simple-scaffold",
"repository": "https://github.com/chenasraf/simple-scaffold.git",
"author": "Chen Asraf <inbox@casraf.com>",
"license": "MIT",
@@ -40,7 +40,6 @@
"handlebars": "^4.7.7",
"lodash": "^4.17.21",
"massarg": "^1.0.7-pre.1",
"semantic-release-conventional-commits": "^3.0.0",
"util.promisify": "^1.1.1"
},
"devDependencies": {
@@ -59,6 +58,7 @@
"mock-fs": "^5.2.0",
"rimraf": "^5.0.0",
"semantic-release": "^21.0.1",
"semantic-release-conventional-commits": "^3.0.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"typedoc": "^0.24.6",

View File

@@ -1,68 +1,73 @@
## Available flags
The following is the help text from the `simple-scaffold` binary. To see this and more information
anytime, add the `-h` or `--help` flag to your call, e.g. `npx simple-scaffold@latest -h`.
```text
Usage: simple-scaffold [options]
Create structured files based on templates.
Options:
--help|-h Display help information
--name|-n Name to be passed to the generated files. {{name}} and
{{Name}} inside contents and file names will be replaced
accordingly.
--config|-c Filename to load config from instead of passing
arguments to CLI or using a Node.js script. You may pass a
JSON or JS file, with a relative or absolute path.
--output|-o Path to output to. If --create-sub-folder is enabled,
the subfolder will be created inside this path.
(default: current dir)
--templates|-t 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.
--overwrite|-w Enable to override output files, even if they already
exist. (default: false)
--data|-d Add custom data to the templates. By default, only your
app name is included.
--append-data|-D Append additional custom data to the templates, which
will overwrite --data, using an alternate syntax, which is
easier to use with CLI: -D key1=string -D key2:=raw
--create-sub-folder|-s Create subfolder with the input name
(default: false)
--sub-folder-name-helper|-sh Default helper to apply to subfolder name when using
`--create-sub-folder true`.
--quiet|-q Suppress output logs (Same as --verbose 0)
(default: false)
--verbose|-v Determine amount of logs to display. The values are:
0 (none) | 1 (debug) | 2 (info) | 3 (warn) | 4
(error). The provided level will display messages of
the same level or higher. (default:
2)
--dry-run|-dr Don't emit files. This is good for testing your
scaffolds and making sure they don't fail, without having to
write actual file contents or create directories.
(default: false)
```
To see this and more information anytime, add the `-h` or `--help` flag to your call, e.g.
`npx simple-scaffold@latest -h`.
| Command \| alias | |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--help`\|`-h` | Display help information |
| `--name`\|`-n` | Name to be passed to the generated files. {{name}} and {{Name}} inside contents and file names will be replaced accordingly. |
| `--config`\|`-c` | Filename or HTTPS git URL to load config from instead of passing arguments to CLI or using a Node.js script. |
| `--github`\|`-gh` | GitHub path to load config from instead of passing arguments to CLI or using a Node.js script. |
| `--key`\|`-k` | Key to load inside the config file. This overwrites the config key provided after the colon in --config (e.g. --config scaffold.cmd.js:component) |
| `--output`\|`-o` | Path to output to. If --create-sub-folder is enabled, the subfolder will be created inside this path. (default: current dir) |
| `--templates`\|`-t` | 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. |
| `--overwrite`\|`-w` | Enable to override output files, even if they already exist. (default: false) |
| `--data`\|`-d` | Add custom data to the templates. By default, only your app name is included. |
| `--append-data`\|`-D` | Append additional custom data to the templates, which will overwrite --data, using an alternate syntax, which is easier to use with CLI: -D key1=string -D key2:=raw |
| `--create-sub-folder`\|`-s` | Create subfolder with the input name (default: false) |
| `--sub-folder-name-helper`\|`-sh` | Default helper to apply to subfolder name when using `--create-sub-folder true`. |
| `--quiet`\|`-q` | Suppress output logs (Same as --verbose 0) (default: false) |
| `--verbose`\|`-v` | Determine amount of logs to display. The values are: 0 (none) \| 1 (debug) \| 2 (info) \| 3 (warn) \| 4 (error). The provided level will display messages of the same level or higher. (default: 2) |
| `--dry-run`\|`-dr` | Don't emit files. This is good for testing your scaffolds and making sure they don't fail, without having to write actual file contents or create directories. (default: false) |
## Examples:
> See
> [Configuration Files](https://chenasraf.githun.io/simple-scaffold/pages/docs/configuration_files.md)
> [Configuration Files](https://chenasraf.github.io/simple-scaffold/pages/docs/configuration_files.md)
> for organizing multiple scaffold types into easy-to-maintain files
Usage with config file
```shell
$ simple-scaffold -c scaffold.cmd.js --key component
```
Usage with GitHub config file
```shell
$ simple-scaffold -gh chenasraf/simple-scaffold --key component
```
Usage with https git URL (for non-GitHub)
```shell
$ simple-scaffold -c \
https://example.com/user/template.git#scaffold.cmd.js --key component
```
Full syntax with config path and template key (applicable to all above methods)
```shell
$ simple-scaffold -c scaffold.cmd.js:component MyComponent
```
Excluded template key, assumes 'default' key
```shell
$ simple-scaffold -c scaffold.cmd.js MyComponent
```
Shortest syntax for GitHub, assumes file 'scaffold.cmd.js' and template key 'default'
```shell
$ simple-scaffold -gh chenasraf/simple-scaffold MyComponent
```
You can also add this as a script in your `package.json`:
```json

View File

@@ -60,7 +60,13 @@ module.exports = {
## Using a config file
Once your config is created, you can use it by providing the file name to the `--config` (or `-c`
for brevity), followed by a colon, then your scaffold config name. For example:
for brevity), optionally followed by a colon, then your scaffold config name.
```shell
simple-scaffold -c <file>[:<template_key>]
```
For example:
```shell
simple-scaffold -c scaffold.json:component MyComponentName
@@ -84,3 +90,45 @@ And then:
# will use 'default' template
simple-scaffold -c scaffold.json MyComponentName
```
## Remote Templates
You can load template groups remotely, similar to how you would pass a config normally.
The main difference is the templates will be hosted on a remote location such as a git server, and
not locally in your project. This can be done to easily share & reuse templates.
When passing a git URL to `--config`, you will clone that repo and use the files there as template.
The syntax is as follows:
```shell
simple-scaffold -c <git_url>[#<git_file>][:<template_key>]
```
For example, to use this repository's example as base:
```shell
simple-scaffold -c https://github.com/chenasraf/simple-scaffold.git#examples/test-input/scaffold.config.js:component
```
When the filename is omitted, `/scaffold.config.js` will be used as default.
When the template_key is ommitted, `default` will be used as default.
### GitHub Templates
As a shorter alternative to the above example, you can use `--github` or `-gh` to reference a GitHub
URL without specifying the whole path.
The syntax is as follows:
```shell
simple-scaffold -gh <username>/<project_name>[#<git_file>][:<template_key>]
```
This example is equivalent to the above, just shorter to write:
```shell
simple-scaffold -c chenasraf/simple-scaffold#examples/test-input/scaffold.config.js:component
```

View File

@@ -1,13 +1,12 @@
const releaseRules = [
{ type: "feat", section: "Features", release: "minor" },
{ type: "docs", section: "Misc", release: "patch" },
{ type: "docs", section: "Build", release: false },
{ type: "fix", section: "Bug Fixes", release: "patch" },
{ type: "refactor", section: "Misc", release: "patch" },
{ type: "docs", section: "Build", release: "patch" },
{ type: "perf", section: "Misc", release: "patch" },
{ type: "build", section: "Build", release: "patch" },
{ type: "chore", section: "Misc", release: "patch" },
{ type: "test", section: "Misc", release: "patch" },
{ type: "test", section: "Tests", release: "patch" },
]
/** @type {import('semantic-release').Options} */
@@ -17,6 +16,7 @@ module.exports = {
"master",
"next",
"next-major",
{ name: "develop", prerelease: true },
{ name: "beta", prerelease: true },
{ name: "alpha", prerelease: true },
],
@@ -60,17 +60,17 @@ module.exports = {
pkgRoot: "dist",
},
],
[
"@semantic-release/github",
{
assets: ["package.tgz"],
},
],
[
"@semantic-release/git",
{
assets: ["CHANGELOG.md", "package.json"],
},
],
[
"@semantic-release/github",
{
assets: ["package.tgz"],
},
],
],
}

View File

@@ -9,12 +9,12 @@ import { parseAppendData, parseConfig } from "./utils"
export async function parseCliArgs(args = process.argv.slice(2)) {
const pkg = JSON.parse((await fs.readFile(path.join(__dirname, "package.json"))).toString())
const isConfig = args.includes("--config") || args.includes("-c")
const isConfig = args.includes("--config") || args.includes("-c") || args.includes("--github") || args.includes("-gh")
return (
massarg<ScaffoldCmdConfig>()
.main((config) => {
const _config = parseConfig(config)
.main(async (config) => {
const _config = await parseConfig(config)
return Scaffold(_config)
})
.option({
@@ -29,7 +29,19 @@ export async function parseCliArgs(args = process.argv.slice(2)) {
name: "config",
aliases: ["c"],
description:
"Filename to load config from instead of passing arguments to CLI or using a Node.js script. You may pass a JSON or JS file, with a relative or absolute path.",
"Filename or https git URL to load config from instead of passing arguments to CLI or using a Node.js script. See examples for syntax.",
})
.option({
name: "github",
aliases: ["gh"],
description:
"GitHub path to load config from instead of passing arguments to CLI or using a Node.js script. See examples for syntax.",
})
.option({
name: "key",
aliases: ["k"],
description:
"Key to load inside the config file. This overwrites the config key provided after the colon in --config (e.g. --config scaffold.cmd.js:component)",
})
.option({
name: "output",
@@ -109,16 +121,41 @@ export async function parseCliArgs(args = process.argv.slice(2)) {
// description: "Usage",
// output: "",
// })
.example({
description: "Usage with config file",
input: "simple-scaffold -c scaffold.cmd.js --key component",
})
.example({
description: "Usage with GitHub config file",
input: "simple-scaffold -gh chenasraf/simple-scaffold --key component",
})
.example({
description: "Usage with https git URL (for non-GitHub)",
input: "simple-scaffold -c https://example.com/user/template.git#scaffold.cmd.js --key component",
})
.example({
description: "Full syntax with config path and template key (applicable to all above methods)",
input: "simple-scaffold -c scaffold.cmd.js:component MyComponent",
})
.example({
description: "Excluded template key, assumes 'default' key",
input: "simple-scaffold -c scaffold.cmd.js MyComponent",
})
.example({
description: "Shortest syntax for GitHub, assumes file 'scaffold.cmd.js' and template key 'default'",
input: "simple-scaffold -gh chenasraf/simple-scaffold MyComponent",
})
.help({
binName: "simple-scaffold",
useGlobalColumns: true,
usageExample: "[options]",
printWidth: 100,
header: [`Create structured files based on templates.`].join("\n"),
footer: [
`Version: ${pkg.version}`,
`Copyright © Chen Asraf 2017-${new Date().getFullYear()}`,
``,
`Documentation: ${chalk.underline`https://casraf.dev/simple-scaffold`}`,
`Documentation: ${chalk.underline`https://chenasraf.github.io/simple-scaffold`}`,
`NPM: ${chalk.underline`https://npmjs.com/package/simple-scaffold`}`,
`GitHub: ${chalk.underline`https://github.com/chenasraf/simple-scaffold`}`,
].join("\n"),

View File

@@ -3,7 +3,8 @@ import { HelperDelegate } from "handlebars/runtime"
/**
* The config object for defining a scaffolding group.
*
* @see https://github.com/chenasraf/simple-scaffold#readme
* @see {@link https://chenasraf.github.io/simple-scaffold/pages/node.html | Node.js usage}
* @see {@link https://chenasraf.github.io/simple-scaffold/pages/cli.html | CLI usage}
* @see {@link DefaultHelpers}
* @see {@link CaseHelpers}
* @see {@link DateHelpers}
@@ -131,10 +132,8 @@ export interface ScaffoldConfig {
* @see {@link DefaultHelpers}
* @see {@link CaseHelpers}
* @see {@link DateHelpers}
* @see https://casraf.dev/simple-scaffold#helpers
* @see https://casraf.dev/simple-scaffold#built-in-helpers
* @see https://handlebarsjs.com/guide/#custom-helpers
*/
* @see {@link https://chenasraf.github.io/simple-scaffold/pages/templates.html | Templates}
* */
helpers?: Record<string, Helper>
/**
@@ -337,6 +336,19 @@ export interface ScaffoldCmdConfig {
verbose: LogLevel
dryRun: boolean
config?: string
key?: string
github?: string
}
/**
* A mapping of scaffold template keys to their configurations.
*
* Each configuration is a {@link ScaffoldConfig} object.
*
* The key is the name of the template, and the value is the configuration for that template.
*
* When no template key is provided to the scaffold command, the "default" template is used.
*
* @see {@link ScaffoldConfig}
*/
export type ScaffoldConfigFile = Record<string, ScaffoldConfig>

View File

@@ -23,6 +23,8 @@ import dtFormat from "date-fns/format"
import dtParseISO from "date-fns/parseISO"
import { glob, hasMagic } from "glob"
import { OptionsBase } from "massarg/types"
import { spawn } from "node:child_process"
import os from "node:os"
const dateFns = {
add: dtAdd,
@@ -99,10 +101,14 @@ export function handleErr(err: NodeJS.ErrnoException | null): void {
if (err) throw err
}
export function log(config: ScaffoldConfig, level: LogLevel, ...obj: any[]): void {
/** @internal */
export type LogConfig = Pick<ScaffoldConfig, "quiet" | "verbose">
export function log(config: LogConfig, level: LogLevel, ...obj: any[]): void {
if (config.quiet || config.verbose === LogLevel.None || level < (config.verbose ?? LogLevel.Info)) {
return
}
const levelColor: Record<LogLevel, keyof typeof chalk> = {
[LogLevel.None]: "reset",
[LogLevel.Debug]: "blue",
@@ -110,6 +116,7 @@ export function log(config: ScaffoldConfig, level: LogLevel, ...obj: any[]): voi
[LogLevel.Warning]: "yellow",
[LogLevel.Error]: "red",
}
const chalkFn: any = chalk[levelColor[level]]
const key: "log" | "warn" | "error" = level === LogLevel.Error ? "error" : level === LogLevel.Warning ? "warn" : "log"
const logFn: any = console[key]
@@ -370,16 +377,18 @@ export function logInitStep(config: ScaffoldConfig): void {
name: config.name,
templates: config.templates,
output: config.output,
createSubfolder: config.createSubFolder,
createSubFolder: config.createSubFolder,
data: config.data,
overwrite: config.overwrite,
quiet: config.quiet,
subFolderTransformHelper: config.subFolderNameHelper,
subFolderNameHelper: 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!,
)})`,
})
dryRun: config.dryRun,
beforeWrite: config.beforeWrite,
} as Record<keyof ScaffoldConfig, unknown>)
log(config, LogLevel.Info, "Data:", config.data)
}
@@ -398,20 +407,36 @@ function isWrappedWithQuotes(string: string): boolean {
}
/** @internal */
export function parseConfig(config: ScaffoldCmdConfig & OptionsBase): ScaffoldConfig {
export async function parseConfig(config: ScaffoldCmdConfig & OptionsBase): Promise<ScaffoldConfig> {
let c: ScaffoldConfig = config
if (config.github) {
log(config, LogLevel.Info, `Loading config from github ${config.github}`)
const gitUrl = new URL(`https://github.com/${config.github}`)
if (!gitUrl.pathname.endsWith(".git")) {
gitUrl.pathname += ".git"
}
config.config = gitUrl.toString()
}
if (config.config) {
const [configFile, template = "default"] = config.config.split(":")
const configImport: ScaffoldConfigFile = require(path.resolve(process.cwd(), configFile))
if (!configImport[template]) {
throw new Error(`Template "${template}" not found in ${configFile}`)
const isUrl = config.config.includes("://")
const hasColonToken = (!isUrl && config.config.includes(":")) || (isUrl && count(config.config, ":") > 1)
const colonIndex = config.config.lastIndexOf(":")
const [configFile, templateKey = "default"] = hasColonToken
? [config.config.substring(0, colonIndex), config.config.substring(colonIndex + 1)]
: [config.config, undefined]
const key = (config.key ?? templateKey) || "default"
log(config, LogLevel.Info, `Loading config from ${configFile} with key ${key}`)
const configImport = await getConfig({ config: configFile, quiet: config.quiet, verbose: config.verbose })
if (!configImport[key]) {
throw new Error(`Template "${key}" not found in ${configFile}`)
}
c = {
...config,
...configImport[template],
...configImport[key],
data: {
...configImport[template].data,
...configImport[key].data,
...config.data,
},
}
@@ -421,3 +446,63 @@ export function parseConfig(config: ScaffoldCmdConfig & OptionsBase): ScaffoldCo
delete config.appendData
return c
}
/** @internal */
export async function getConfig(
config: Pick<ScaffoldCmdConfig, "quiet" | "verbose" | "config">,
): Promise<ScaffoldConfigFile> {
const { config: configFile, ...logConfig } = config as Required<typeof config>
const url = new URL(configFile)
if (url.protocol === "file:") {
log(logConfig, LogLevel.Info, `Loading config from file ${configFile}`)
const absolutePath = path.resolve(process.cwd(), configFile)
return import(absolutePath)
}
const isHttp = url.protocol === "http:" || url.protocol === "https:"
const isGit = url.protocol === "git:" || (isHttp && url.pathname.endsWith(".git"))
if (isHttp || isGit) {
if (isGit) {
const repoUrl = `${url.protocol}//${url.host}${url.pathname}`
log(logConfig, LogLevel.Info, `Cloning git repo ${repoUrl}`)
const tmpPath = path.resolve(os.tmpdir(), `scaffold-config-${Date.now()}`)
return new Promise((resolve, reject) => {
const clone = spawn("git", ["clone", "--depth", "1", repoUrl, tmpPath])
clone.on("error", reject)
clone.on("close", async (code) => {
if (code === 0) {
log(logConfig, LogLevel.Info, `Loading config from git repo: ${repoUrl}`)
const hashPath = url.hash?.replace("#", "") || "scaffold.config.js"
const absolutePath = path.resolve(tmpPath, hashPath)
const loadedConfig = (await import(absolutePath)).default as ScaffoldConfigFile
log(logConfig, LogLevel.Info, `Loaded config from git`)
log(logConfig, LogLevel.Debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigFile = Object.fromEntries(
Object.entries(loadedConfig).map(([k, v]) => [
k,
// use absolute paths for template as config is necessarily in another directory
{ ...v, templates: v.templates.map((t) => path.resolve(tmpPath, t)) },
]),
)
resolve(fixedConfig)
} else {
reject(new Error(`Git clone failed with code ${code}`))
}
})
})
}
throw new Error(`Unsupported protocol ${url.protocol}`)
}
return import(path.resolve(process.cwd(), configFile))
}
function count(string: string, substring: string): number {
return string.split(substring).length - 1
}