Compare commits

...

9 Commits

Author SHA1 Message Date
semantic-release-bot
f666c357f4 chore(release): 1.8.0 [skip ci]
## [1.8.0](https://github.com/chenasraf/simple-scaffold/compare/v1.7.2...v1.8.0) (2023-11-29)

### Bug Fixes

* **config:** fn config load ([457c904](457c90470b)), closes [#63](https://github.com/chenasraf/simple-scaffold/issues/63)
2023-11-29 22:16:52 +00:00
f5d55f234a docs: update configuration files docs 2023-11-30 00:12:11 +02:00
semantic-release-bot
746f924a22 chore(release): 1.8.0-pre.1 [skip ci]
## [1.8.0-pre.1](https://github.com/chenasraf/simple-scaffold/compare/v1.7.2...v1.8.0-pre.1) (2023-11-27)

### Bug Fixes

* **config:** fn config load ([457c904](457c90470b)), closes [#63](https://github.com/chenasraf/simple-scaffold/issues/63)
2023-11-30 00:12:11 +02:00
807c3e27e2 ci: update release config 2023-11-28 00:49:28 +02:00
b048841dac chore: update dependencies 2023-11-28 00:49:28 +02:00
457c90470b fix(config): fn config load
closes #63
2023-11-28 00:49:28 +02:00
dependabot[bot]
0fa1ad4db7 build(deps-dev): bump @babel/traverse from 7.21.5 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.5 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-28 00:49:28 +02:00
semantic-release-bot
d62eeeb8e4 chore(release): 1.7.2 [skip ci]
## [1.7.2](https://github.com/chenasraf/simple-scaffold/compare/v1.7.1...v1.7.2) (2023-08-20)

### Bug Fixes

* windows path resolution ([98ee000](98ee00031f))
2023-08-20 10:09:48 +00:00
Chen Asraf
565d1f33aa Merge pull request #61 from chenasraf/pre
v1.7.2
2023-08-20 13:08:25 +03:00
14 changed files with 1580 additions and 2111 deletions

View File

@@ -8,14 +8,22 @@ jobs:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip docs]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build-docs
- uses: peaceiris/actions-gh-pages@v3
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Docs
run: pnpm build-docs
- name: Deploy on GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs

View File

@@ -2,17 +2,25 @@ name: Pull Requests
on:
pull_request:
branches: [master, develop]
branches: [master, pre, develop]
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build
- run: pnpm test
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Tests
run: pnpm test
- name: Build Package
run: pnpm build

View File

@@ -2,11 +2,18 @@ name: Test & Build
on:
push:
branches: [ master, develop, pre, feat/*, fix/* ]
branches: [master, pre, develop]
permissions:
contents: read # for checkout
jobs:
test:
name: Test
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
@@ -15,22 +22,36 @@ jobs:
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm test
if: "!contains(github.event.head_commit.message, '[skip test]')"
build:
name: Build
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
needs: test
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build
- run: cd ./dist && pnpm pack --pack-destination=../
- run: pnpm semantic-release
if: "!contains(github.event.head_commit.message, '[skip publish]')"
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Tests
run: pnpm test
- name: Build Package
run: pnpm build
- name: Pack
run: cd ./dist && pnpm pack --pack-destination=../
- name: Semantic Release
run: npx semantic-release
env:
NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -1,5 +1,26 @@
# Change Log
## [1.8.0](https://github.com/chenasraf/simple-scaffold/compare/v1.7.2...v1.8.0) (2023-11-29)
### Bug Fixes
* **config:** fn config load ([457c904](https://github.com/chenasraf/simple-scaffold/commit/457c90470b0f138862469ff878c7e061c7afd18a)), closes [#63](https://github.com/chenasraf/simple-scaffold/issues/63)
## [1.8.0-pre.1](https://github.com/chenasraf/simple-scaffold/compare/v1.7.2...v1.8.0-pre.1) (2023-11-27)
### Bug Fixes
* **config:** fn config load ([457c904](https://github.com/chenasraf/simple-scaffold/commit/457c90470b0f138862469ff878c7e061c7afd18a)), closes [#63](https://github.com/chenasraf/simple-scaffold/issues/63)
## [1.7.2](https://github.com/chenasraf/simple-scaffold/compare/v1.7.1...v1.7.2) (2023-08-20)
### Bug Fixes
* windows path resolution ([98ee000](https://github.com/chenasraf/simple-scaffold/commit/98ee00031fc1ad67a53797a9e28e5c4759bc8bce))
## [1.7.2-pre.1](https://github.com/chenasraf/simple-scaffold/compare/v1.7.1...v1.7.2-pre.1) (2023-08-15)

View File

@@ -1,6 +1,6 @@
{
"name": "simple-scaffold",
"version": "1.7.2-pre.1",
"version": "1.8.0",
"description": "Generate any file structure - from single components to entire app boilerplates, with a single command.",
"homepage": "https://chenasraf.github.io/simple-scaffold",
"repository": "https://github.com/chenasraf/simple-scaffold.git",
@@ -44,6 +44,7 @@
"devDependencies": {
"@knodes/typedoc-plugin-pages": "^0.23.4",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/release-notes-generator": "^10.0.3",
"@types/jest": "^29.5.1",

View File

@@ -45,7 +45,7 @@ interface ScaffoldConfig {
If you want to supply functions inside the configurations, you must use a `.js` file as JSON does
not support non-primitives.
A `.js` file is just like a `.json` file, make sure to export the final configuration:
A `.js` file can be just like a `.json` file, make sure to export the final configuration:
```js
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
@@ -57,6 +57,23 @@ module.exports = {
}
```
Another feature of using a JS file is you can export a function which will be loaded with the CMD
config provided to Simple Scaffold. The `extras` key contains any values not consumed by built-in
flags, so you can pre-process your args before outputting a config:
```js
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
module.exports = (config) => {
console.log("Config:", config)
return {
component: {
templates: ["templates/component"],
output: "src/components",
},
}
}
```
## Using a config file
Once your config is created, you can use it by providing the file name to the `--config` (or `-c`

3432
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,8 @@
const releaseRules = [
{ type: "feat", section: "Features", release: "minor" },
{ type: "revert", section: "Features", release: "minor" },
{ type: "fix", section: "Bug Fixes", release: "patch" },
{ type: "chore", section: "Misc", release: "patch" },
{ type: "refactor", section: "Misc", release: "patch" },
{ type: "perf", section: "Misc", release: "patch" },
{ type: "build", section: "Build", release: "patch" },
{ type: "docs", section: "Build", release: false },
{ type: "test", section: "Tests", release: "patch" },
]
/** @type {import('semantic-release').Options} */
module.exports = {
branches: ["+([0-9])?(.{+([0-9]),x}).x", "master", "next", "next-major", { name: "pre", prerelease: true }],
branches: ["master", { name: "pre", prerelease: true }],
analyzeCommits: {
path: "semantic-release-conventional-commits",
majorTypes: releaseRules.filter((x) => x.release === "major").map((x) => x.type),
minorTypes: releaseRules.filter((x) => x.release === "minor").map((x) => x.type),
patchTypes: releaseRules.filter((x) => x.release === "patch").map((x) => x.type),
},
plugins: [
[
@@ -27,7 +12,6 @@ module.exports = {
parserOpts: {
noteKeywords: ["breaking:", "breaking-fix:", "breaking-feat:"],
},
releaseRules: releaseRules,
},
],
[
@@ -36,7 +20,6 @@ module.exports = {
preset: "conventionalcommits",
parserOpts: {
noteKeywords: ["breaking", "major"],
types: releaseRules,
},
},
],

View File

@@ -1,13 +1,16 @@
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
module.exports = {
default: {
templates: ["examples/test-input/Component"],
output: "examples/test-output",
data: { property: "myProp", value: "10" },
},
component: {
templates: ["examples/test-input/Component"],
output: "examples/test-output/component",
data: { property: "myProp", value: "10" },
},
module.exports = (conf) => {
console.log("Config:", conf)
return {
default: {
templates: ["examples/test-input/Component"],
output: "examples/test-output",
data: { property: "myProp", value: "10" },
},
component: {
templates: ["examples/test-input/Component"],
output: "examples/test-output/component",
data: { property: "myProp", value: "10" },
},
}
}

View File

@@ -5,7 +5,7 @@ import { LogLevel, ScaffoldCmdConfig } from "./types"
import { Scaffold } from "./scaffold"
import path from "node:path"
import fs from "node:fs/promises"
import { parseAppendData, parseConfig } from "./config"
import { parseAppendData, parseConfigFile } from "./config"
export async function parseCliArgs(args = process.argv.slice(2)) {
const pkgFile = await fs.readFile(path.join(__dirname, "package.json"))
@@ -16,7 +16,7 @@ export async function parseCliArgs(args = process.argv.slice(2)) {
return (
massarg<ScaffoldCmdConfig>()
.main(async (config) => {
const _config = await parseConfig(config)
const _config = await parseConfigFile(config)
return Scaffold(_config)
})
.option({

View File

@@ -8,7 +8,6 @@ import {
ScaffoldConfig,
ScaffoldConfigFile,
} from "./types"
import { OptionsBase } from "massarg/types"
import { handlebarsParse } from "./parser"
import { log } from "./logger"
import { resolve, wrapNoopResolver } from "./utils"
@@ -30,7 +29,7 @@ export function getOptionValueForFile<T>(
)
}
export function parseAppendData(value: string, options: ScaffoldCmdConfig & OptionsBase): unknown {
export function parseAppendData(value: string, options: ScaffoldCmdConfig): unknown {
const data = options.data ?? {}
const [key, val] = value.split(/\:?=/)
// raw
@@ -45,7 +44,7 @@ function isWrappedWithQuotes(string: string): boolean {
}
/** @internal */
export async function parseConfig(config: ScaffoldCmdConfig & OptionsBase): Promise<ScaffoldConfig> {
export async function parseConfigFile(config: ScaffoldCmdConfig): Promise<ScaffoldConfig> {
let c: ScaffoldConfig = config
if (config.github) {
log(config, LogLevel.Info, `Loading config from github ${config.github}`)
@@ -61,16 +60,19 @@ export async function parseConfig(config: ScaffoldCmdConfig & OptionsBase): Prom
quiet: config.quiet,
verbose: config.verbose,
})
const configImport = await resolve(configPromise, config)
let configImport = await resolve(configPromise, config)
if (typeof configImport.default === "function" || configImport.default instanceof Promise) {
configImport = await resolve(configImport.default, config)
}
if (!configImport[key]) {
throw new Error(`Template "${key}" not found in ${configFile}`)
}
const importedKey = configImport[key]
c = {
...config,
...configImport[key],
...importedKey,
data: {
...configImport[key].data,
...(importedKey as any).data,
...config.data,
},
}

View File

@@ -1,9 +1,9 @@
import path from "node:path"
import os from "node:os"
import { log } from "./logger"
import { AsyncResolver, LogConfig, LogLevel, ScaffoldCmdConfig, ScaffoldConfigMap } from "./types"
import { AsyncResolver, LogConfig, LogLevel, ScaffoldCmdConfig, ScaffoldConfig, ScaffoldConfigMap } from "./types"
import { spawn } from "node:child_process"
import { wrapNoopResolver } from "./utils"
import { resolve, wrapNoopResolver } from "./utils"
export async function getGitConfig(
url: URL,
@@ -15,7 +15,7 @@ export async function getGitConfig(
const tmpPath = path.resolve(os.tmpdir(), `scaffold-config-${Date.now()}`)
return new Promise((resolve, reject) => {
return new Promise((res, reject) => {
const clone = spawn("git", ["clone", "--depth", "1", repoUrl, tmpPath])
clone.on("error", reject)
@@ -24,18 +24,21 @@ export async function getGitConfig(
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 ScaffoldConfigMap
log(logConfig, LogLevel.Info, `Loaded config from git`)
log(logConfig, LogLevel.Debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigMap = 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)) },
]),
const loadedConfig = await resolve(
async () => (await import(absolutePath)).default as ScaffoldConfigMap,
logConfig,
)
resolve(wrapNoopResolver(fixedConfig))
log(logConfig, LogLevel.Info, `Loaded config from git`)
log(logConfig, LogLevel.Debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigMap = {}
for (const [k, v] of Object.entries(loadedConfig)) {
fixedConfig[k] = {
...v,
templates: v.templates.map((t) => path.resolve(tmpPath, t)),
}
}
res(wrapNoopResolver(fixedConfig))
return
}

View File

@@ -16,10 +16,9 @@ import {
handleTemplateFile,
} from "./file"
import { LogLevel, MinimalConfig, Resolver, ScaffoldCmdConfig, ScaffoldConfig } from "./types"
import { OptionsBase } from "massarg/types"
import { defaultHelpers, registerHelpers } from "./parser"
import { log, logInitStep, logInputFile } from "./logger"
import { parseConfig } from "./config"
import { parseConfigFile } from "./config"
/**
* Create a scaffold using given `options`.
@@ -110,7 +109,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 */
@@ -118,7 +117,7 @@ Scaffold.fromConfig = async function (
/** Any overrides to the loaded config */
overrides?: Resolver<ScaffoldCmdConfig, Partial<Omit<ScaffoldConfig, "name">>>,
): Promise<void> {
const _cmdConfig: ScaffoldCmdConfig & OptionsBase = {
const _cmdConfig: ScaffoldCmdConfig = {
dryRun: false,
output: process.cwd(),
verbose: LogLevel.Info,
@@ -126,13 +125,11 @@ Scaffold.fromConfig = async function (
templates: [],
createSubFolder: false,
quiet: false,
help: false,
extras: [],
config: pathOrUrl,
...config,
}
const _overrides = resolve(overrides, _cmdConfig)
const _config = await parseConfig(_cmdConfig)
const _config = await parseConfigFile(_cmdConfig)
return Scaffold({ ..._config, ..._overrides })
}

View File

@@ -1,5 +1,4 @@
import { ScaffoldCmdConfig } from "../src/types"
import { OptionsBase } from "massarg/types"
import * as config from "../src/config"
import { resolve } from "../src/utils"
// @ts-ignore
@@ -10,14 +9,14 @@ jest.mock("../src/git", () => {
__esModule: true,
...jest.requireActual("../src/git"),
getGitConfig: () => {
return Promise.resolve({ default: blankCliConf })
return Promise.resolve(blankCliConf)
},
}
})
const { githubPartToUrl, parseAppendData, parseConfig, parseConfigSelection } = config
const { githubPartToUrl, parseAppendData, parseConfigFile, parseConfigSelection } = config
const blankCliConf: ScaffoldCmdConfig & OptionsBase = {
const blankCliConf: ScaffoldCmdConfig = {
verbose: 0,
name: "",
output: "",
@@ -27,8 +26,6 @@ const blankCliConf: ScaffoldCmdConfig & OptionsBase = {
createSubFolder: false,
dryRun: false,
quiet: false,
extras: [],
help: false,
}
describe("config", () => {
@@ -99,24 +96,24 @@ describe("config", () => {
})
})
describe("parseConfig", () => {
describe("parseConfigFile", () => {
test("normal config does not change", async () => {
expect(
await parseConfig({
await parseConfigFile({
...blankCliConf,
}),
).toEqual(blankCliConf)
})
describe("appendData", () => {
test("appends", async () => {
const result = await parseConfig({
const result = await parseConfigFile({
...blankCliConf,
appendData: { key: "value" },
})
expect(result?.data?.key).toEqual("value")
})
test("overwrites existing value", async () => {
const result = await parseConfig({
const result = await parseConfigFile({
...blankCliConf,
data: { num: "123" },
appendData: { num: "1234" },
@@ -135,7 +132,7 @@ describe("config", () => {
verbose: 0,
})
const result = await resolve(resultFn, blankCliConf)
expect(result).toEqual({ default: blankCliConf })
expect(result).toEqual(blankCliConf)
})
test("gets local file config", async () => {