Compare commits

...

64 Commits

Author SHA1 Message Date
Chen Asraf
48631325c1 fixed release tarball file location 2021-11-18 14:16:58 +02:00
Chen Asraf
045ad0118a fix build output files 2021-11-18 14:09:21 +02:00
Chen Asraf
b4dca7a954 add build step 2021-11-18 13:57:57 +02:00
Chen Asraf
7c42808f63 try to fix workflow 2021-11-18 13:56:24 +02:00
Chen Asraf
fd42013e8b publish: debug mode off, try to fix workflow 2021-11-18 13:55:30 +02:00
Chen Asraf
961a72fcdc publish: debug mode on 2021-11-18 13:51:29 +02:00
Chen Asraf
d6d99cfdf2 try fix workflow 2021-11-18 13:45:37 +02:00
Chen Asraf
ea4ecabe02 Merge pull request #12 from chenasraf/v1.0
v1.0
2021-11-18 13:44:09 +02:00
Chen Asraf
c7749a8d33 update workflows 2021-11-18 13:42:28 +02:00
Chen Asraf
a59f29d71d fix build/publish cmd 2021-11-18 13:38:16 +02:00
Chen Asraf
bc224d93e1 support node 12 for fs package 2021-11-18 13:16:10 +02:00
Chen Asraf
cf923d8889 support node 12 for fs package 2021-11-18 13:14:53 +02:00
Chen Asraf
01e458ee0c update jest config 2021-11-18 13:12:37 +02:00
Chen Asraf
93853712f5 use node 12 2021-11-18 13:08:54 +02:00
Chen Asraf
474a3dcc1f try fix workflow 2021-11-18 13:04:19 +02:00
Chen Asraf
27e84d1093 update workflow 2021-11-18 12:55:07 +02:00
Chen Asraf
a6f25facc0 update workflows 2021-11-18 12:51:16 +02:00
Chen Asraf
3ee66b24f5 build: update workflow 2021-11-18 12:45:37 +02:00
Chen Asraf
0ce19a7e1a build: add workflow 2021-11-18 12:45:37 +02:00
Chen Asraf
7273538d79 fix main field in package.json 2021-11-18 12:45:37 +02:00
Chen Asraf
43b64965e3 v0.7.4 2021-11-18 12:45:37 +02:00
Chen Asraf
4f81654e05 added --quiet flag 2021-11-18 12:45:37 +02:00
Chen Asraf
8fcc7a6dc6 chore: cleanup 2021-11-18 12:45:31 +02:00
Chen Asraf
b4b0de6f2f docs: update README 2021-11-18 12:45:31 +02:00
Chen Asraf
2d5626ca70 improve tests 2021-11-18 12:45:26 +02:00
Chen Asraf
564e821419 maintain directory structure 2021-11-18 12:45:26 +02:00
Chen Asraf
a52f9a0b84 migrate cmd to massarg + update tests 2021-11-18 12:45:26 +02:00
Chen Asraf
aeddd44778 add dry run option 2021-11-18 12:45:26 +02:00
Chen Asraf
7cdf5e461b add cmd args 2021-11-18 12:45:26 +02:00
Chen Asraf
c42a58c2f2 add tests 2021-11-18 12:45:26 +02:00
Chen Asraf
d0c0152717 remove excess files 2021-11-18 12:45:26 +02:00
Chen Asraf
208ee307c8 code splitting 2021-11-18 12:45:16 +02:00
Chen Asraf
54834909b9 major refactor 2021-11-18 12:45:16 +02:00
Chen Asraf
40b592072e Create FUNDING.yml 2021-10-11 18:20:18 +03:00
Chen Asraf
3cb9a6fcd8 fix main field in package.json 2021-09-26 11:42:52 +03:00
Chen Asraf
12974b5561 v0.7.4 2021-09-26 11:37:02 +03:00
Chen Asraf
7f98d469a3 added --quiet flag 2021-09-26 11:28:38 +03:00
Chen Asraf
cd25b04886 Update README.md 2021-05-20 11:03:19 +03:00
Chen Asraf
5cd637f41f Merge pull request #4 from chenasraf/dependabot/npm_and_yarn/handlebars-4.7.7
Bump handlebars from 4.7.6 to 4.7.7
2021-05-20 10:55:41 +03:00
Chen Asraf
0a4467ae5f Merge pull request #5 from chenasraf/dependabot/npm_and_yarn/url-parse-1.5.1
Bump url-parse from 1.4.7 to 1.5.1
2021-05-20 10:55:33 +03:00
Chen Asraf
713a0ed44f Merge pull request #6 from chenasraf/dependabot/npm_and_yarn/lodash-4.17.21
Bump lodash from 4.17.20 to 4.17.21
2021-05-20 10:55:18 +03:00
Chen Asraf
edec2d1c26 Merge pull request #7 from chenasraf/dependabot/npm_and_yarn/hosted-git-info-2.8.9
Bump hosted-git-info from 2.8.8 to 2.8.9
2021-05-20 10:55:03 +03:00
dependabot[bot]
2e12907412 Bump hosted-git-info from 2.8.8 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-09 23:31:02 +00:00
dependabot[bot]
5b7e0e30f1 Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-08 04:50:00 +00:00
dependabot[bot]
09238300cd Bump url-parse from 1.4.7 to 1.5.1
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.4.7 to 1.5.1.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.4.7...1.5.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 10:20:13 +00:00
dependabot[bot]
552614ca3f Bump handlebars from 4.7.6 to 4.7.7
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.7.6 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.7.6...v4.7.7)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 02:51:26 +00:00
Chen Asraf
813f706cf0 update readme 2021-04-19 22:30:22 +03:00
Chen Asraf
1bc2221472 update readme 2021-04-19 22:28:22 +03:00
Chen Asraf
f07affa124 add basename to output config function (fixes #3) 2021-04-19 22:24:21 +03:00
Chen Asraf
ce22a2c34c disable overwriting files + parse JSON for locals 2021-02-28 01:38:51 +02:00
Chen Asraf
7c0c347002 fix: binary files 2021-02-01 15:24:57 +02:00
Chen Asraf
977288ae5a build: upgrade packages 2021-02-01 15:24:26 +02:00
Chen Asraf
4afafa5a4a fix: support deeper file structure 2021-02-01 15:23:50 +02:00
Chen Asraf
7bee2a51c7 0.5.0 2019-02-27 16:53:42 +02:00
Chen Asraf
d4c049baaf v0.5.0 2019-02-27 16:53:33 +02:00
Chen Asraf
06590c4b6e Fixed output argument + updated README 2019-02-27 16:20:33 +02:00
Chen Asraf
c4f2dfb04f v0.4.5 2019-02-27 16:20:12 +02:00
Chen Asraf
a410b79195 Improved docs 2019-02-27 16:14:56 +02:00
Chen Asraf
71d544aff4 v0.4.4 2019-02-27 16:14:22 +02:00
Chen Asraf
20389d7b33 v0.4.3 2019-02-27 16:12:43 +02:00
Chen Asraf
d7a4362725 mapfile 2019-02-25 19:54:12 +02:00
Chen Asraf
0a2d7c08f3 v0.4.2 2019-02-25 18:17:15 +02:00
Chen Asraf
a92c471243 bugfixes 2019-02-25 18:17:03 +02:00
Chen Asraf
07b1c4b1f0 mapfile 2019-02-25 18:01:10 +02:00
40 changed files with 3401 additions and 5855 deletions

5
.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
[*]
tab_width = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: casraf
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

48
.github/workflows/alpha.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Alpha Releases
on:
push:
branches: [alpha]
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "12.x"
- run: yarn install --frozen-lockfile
- run: yarn build
- run: cd ./dist && yarn pack dist/ --filename=../release.tgz
- uses: Klemensas/action-autotag@stable
id: update_tag
with:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
tag_prefix: "v"
- name: Publish on NPM
uses: JS-DevTools/npm-publish@v1
if: "!contains(github.event.head_commit.message, '[skip publish]')"
with:
package: ./dist/package.json
token: "${{ secrets.NPM_TOKEN }}"
- name: Create Release
if: steps.update_tag.outputs.tagname && !contains(github.event.head_commit.message, '[skip publish]')
uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.update_tag.outputs.tagname }}
release_name: Release ${{ steps.update_tag.outputs.tagname }}
- name: Upload Release Asset
if: steps.update_tag.outputs.tagname && !contains(github.event.head_commit.message, '[skip publish]')
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./package.tgz
asset_name: package.tgz
asset_content_type: application/tgz

47
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: Releases
on:
push:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "12.x"
- run: yarn install --frozen-lockfile
- run: yarn build
- run: cd ./dist && yarn pack dist/ --filename=../release.tgz
- uses: Klemensas/action-autotag@stable
id: update_tag
with:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
tag_prefix: "v"
- name: Publish on NPM
uses: JS-DevTools/npm-publish@v1
with:
package: ./dist/package.json
token: "${{ secrets.NPM_TOKEN }}"
- name: Create Release
if: steps.update_tag.outputs.tagname && !contains(github.event.head_commit.message, '[skip publish]')
uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.update_tag.outputs.tagname }}
release_name: Release ${{ steps.update_tag.outputs.tagname }}
- name: Upload Release Asset
if: steps.update_tag.outputs.tagname && !contains(github.event.head_commit.message, '[skip publish]')
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./package.tgz
asset_name: package.tgz
asset_content_type: application/tgz

17
.github/workflows/pull_requests.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Pull Requests
on:
pull_request:
branches: [master, alpha, beta]
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: "12.x"
- run: yarn install --frozen-lockfile
- run: yarn build
- run: yarn test

3
.gitignore vendored
View File

@@ -58,4 +58,5 @@ typings/
.env
examples/test-output/**/*
!examples/test-output/.gitkeep
dist/
.DS_Store

5
.prettierrc Normal file
View File

@@ -0,0 +1,5 @@
{
"semi": false,
"printWidth": 120,
"tabWidth": 2
}

View File

@@ -1,3 +1,7 @@
{
"typescript.tsdk": "./node_modules/typescript/lib"
"typescript.tsdk": "./node_modules/typescript/lib",
"npm.packageManager": "yarn",
"cSpell.words": [
"massarg"
]
}

56
.vscode/tasks.json vendored
View File

@@ -1,7 +1,53 @@
{
"version": "0.1.0",
"command": "webpack",
"isShellCommand": true,
"args": [],
"showOutput": "always"
"version": "2.0.0",
"tasks": [
{
"script": "build",
"label": "build",
"type": "npm",
"problemMatcher": [],
},
{
"script": "dev",
"label": "dev",
"type": "npm",
"problemMatcher": [],
},
{
"script": "start",
"label": "start",
"type": "npm",
"problemMatcher": [],
},
{
"script": "test",
"label": "test",
"type": "npm",
"problemMatcher": [],
},
{
"command": "yarn test --watchAll",
"label": "yarn test --watchAll",
"type": "shell",
"problemMatcher": [],
},
{
"script": "cmd",
"label": "cmd",
"type": "npm",
"problemMatcher": [],
},
{
"script": "build-test",
"label": "build-test",
"type": "npm",
"problemMatcher": [],
},
{
"script": "build-cmd",
"label": "build-cmd",
"type": "npm",
"problemMatcher": [],
},
],
}

213
README.md
View File

@@ -1,7 +1,9 @@
# simple-scaffold
Simple Scaffold allows you to create your structured files based on templates.
## Install
You can either use it as a command line tool or import into your own code and run from there.
```bash
@@ -9,89 +11,157 @@ You can either use it as a command line tool or import into your own code and ru
npm install [-g] simple-scaffold
# yarn
yarn [global] add simple-scaffold
# run without installing
npx simple-scaffold <...args>
```
## Use as a command line tool
The first non-token argument (that has no `--` prefix) will be used as the scaffold name.
The rest is ignored, of course except for the available arguments below.
```bash
simple-scaffold MyComponent --template scaffolds/component/**/* \
--output src/components \
--locals myProp="propname",myVal=123
### Command Line Options
```plaintext
Usage: simple-scaffold [options]
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.
--output|-o Path to output to. If --create-sub-folder is enabled, the
subfolder will be created inside this path.
--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.
--create-sub-folder|-s Create subfolder with the input name (default:
false)
--quiet|-q Suppress output logs (default:
false)
--dry-run|-dr 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. (default: false)
```
You can add this as a script in your `package.json`:
You can also add this as a script in your `package.json`:
```json
{
"scripts": {
"scaffold": "node node_modules/simple-scaffold/dist/cmd.js --template scaffolds/component/**/* --output src/components --locals myProp=\"propname\",myVal=123"
"scaffold": "yarn simple-scaffold --templates scaffolds/component/**/* --output src/components --data '{\"myProp\": \"propName\", \"myVal\": \"123\"}'"
}
}
```
## Scaffolding
Scaffolding will replace {{vars}} in both the file name and its contents and put the transformed files
in `<output>/<{{Name}}`.
## Use in Node.js
Your context will be pre-populated with the following:
- `{{Name}}`: CapitalizedName of the component
- `{{name}}`: camelCasedName of the component
Any `locals` you add in the config will populate with their names wrapped in `{{` and `}}`.
They are all stringified, so be sure to parse them accordingly by creating a script, if necessary.
### Command line options
##### `--template glob [--template glob2 [...]]` (required)
A glob pattern of template files to load.
A template file may be of any type and extension, and supports [Handlebars](https://handlebarsjs.com) as a parsing engine for the file names and contents, so you may customize both with variables from your configuration.
You can load more than one template list by simple adding more `--template` arguments.
##### `--output path` (optional)
The output directory to put the new files in. They will attempt to maintain their regular structure as they are found, if possible.
Your new scaffold will be placed under a directory with the scaffold name from the argumemts.
You may also pass a function to transform the output path for each file individually.
This function takes 2 arguments: filename, and base glob path
##### `--locals key=value[,key=value[,...]]` (optional)
Pass a KV map to the template for parsing.
### Use in Node.js
You can also build the scaffold yourself, if you want to create more complex arguments or scaffold groups.
Simply pass a config object to the constructor, and invoke `run()` when you are ready to start.
The config takes similar arguments to the command line:
```javascript
const SimpleScaffold = require('simple-scaffold').default
const SimpleScaffold = require("simple-scaffold").default
const scaffold = new SimpleScaffold({
name: 'component',
templates: [path.join(__dirname, 'scaffolds', 'component')],
output: path.join(__dirname, 'src', 'components'),
name: "component",
templates: [path.join(__dirname, "scaffolds", "component")],
output: path.join(__dirname, "src", "components"),
createSubFolder: true,
locals: {
property: 'value',
}
property: "value",
},
}).run()
```
## Example Scaffold Input
The exception in the config is that `output`, when used in Node directly, may also be passed a
function for each input file to output into a dynamic path:
### Input Directory structure
```javascript
config.output = (fullPath, baseDir, baseName) => {
console.log({ fullPath, baseDir, baseName })
return [baseDir, baseName].join(path.sep)
}
```
## Preparing files
### Template files
Put your template files anywhere, and fill them with tokens for replacement.
### Variable/token replacement
Scaffolding will replace `{{ varName }}` in both the file name and its contents and put the
transformed files in the output directory.
The data available for the template parser is the data you pass to the `data` config option (or
`--data` argument in CLI).
Your `data` will be pre-populated with the following:
- `{{Name}}`: PascalCase of the component name
- `{{name}}`: raw name of the component
> Simple-Scaffold uses [Handlebars.js](https://handlebarsjs.com/) for outputting the file contents,
> see their documentation for more information on syntax.
> Any `data` you add in the config will be available for use with their names wrapped in
> `{{` and `}}`.
Simple-Scaffold provides some built-in text transformation filters usable by handleBars.
For example, you may use `{{ name | snakeCase }}` inside a template file or filename, and it will
replace `My Name` with `my_name` when producing the final value.
Here are the built-in helpers available for use:
```plaintext
{{ name | camelCase }} => myName
{{ name | snakeCase }} => my_name
{{ name | startCase }} => My Name
{{ name | kebabCase }} => my-name
{{ name | hyphenCase }} => my-name
{{ name | pascalCase }} => MyName
```
**Note:** These helpers are available for any data property, not exclusive to `name`.
## Examples
### Command Example
```bash
simple-scaffold MyComponent \
-t project/scaffold/**/* \
-o src/components \
-d '{"className":"myClassName"}'
```
### Example Scaffold Input
#### Input Directory structure
```plaintext
- project
- scaffold
- {{Name}}.js
- src
- components
- ...
- scaffold
- {{Name}}.js
- src
- components
- ...
```
#### project/scaffold/{{Name}}.js
#### Contents of `project/scaffold/{{Name}}.js`
```js
const React = require('react')
@@ -102,28 +172,33 @@ module.exports = class {{Name}} extends React.Component {
}
```
### Run Example
```bash
simple-scaffold MyComponent \
--template project/scaffold/**/* \
--output src/components \
--locals 'className=my-component`
```
### Example Scaffold Output
## Example Scaffold Output
#### Directory structure
```
### Output directory structure
```plaintext
- project
- src
- components
- MyComponent
- MyComponent.js
- ...
- src
- components
- MyComponent
- MyComponent.js
- ...
```
#### project/scaffold/MyComponent/MyComponent.js
With `createSubfolder = false`:
```plaintext
- project
- src
- components
- MyComponent.js
- ...
```
#### Contents of `project/scaffold/MyComponent/MyComponent.js`
```js
const React = require('react')
const React = require("react")
module.exports = class MyComponent extends React.Component {
render() {

3
babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
plugins: ["@babel/plugin-proposal-nullish-coalescing-operator"],
}

52
cmd.ts
View File

@@ -1,52 +0,0 @@
import SimpleScaffold from './scaffold'
import * as fs from 'fs'
import IScaffold from './index'
import * as cliArgs from 'command-line-args'
import * as cliUsage from 'command-line-usage'
import * as path from 'path'
type Def = cliArgs.OptionDefinition & { description?: string }
function localsParser(content: string) {
const [key, value] = content.split('=')
return { [key]: value }
}
function filePathParser(content: string) {
if (content.startsWith('/')) {
return content
}
return [process.cwd(), content].join(path.sep)
}
const defs: Def[] = [
{ name: 'name', alias: 'n', type: String, description: 'Component output name', defaultOption: true },
{ name: 'templates', alias: 't', type: filePathParser, multiple: true },
{ name: 'output', alias: 'o', type: filePathParser, multiple: true },
{ name: 'locals', alias: 'l', multiple: true, type: localsParser },
{ name: 'create-sub-folder', alias: 'S', type: Boolean },
{ name: 'help', alias: 'h', type: Boolean, description: 'Display this help message' },
]
const args = cliArgs(defs, { camelCase: true })
const help = [
{ header: 'Scaffold Generator', content: 'Generate scaffolds for your project based on file templates.' },
{ header: 'Options', optionList: defs }
]
args.locals = args.locals.reduce((all: object, cur: object) => ({ ...all, ...cur }), {} as IScaffold.Config['locals'])
console.info('Config:', args)
if (args.help || !args.name) {
console.log(cliUsage(help))
process.exit(0)
}
new SimpleScaffold({
name: args.name,
templates: args.templates,
output: args.output,
locals: args.locals,
createSubfolder: args.createSubFolder,
}).run()

289
dist/cmd.js vendored
View File

@@ -1,289 +0,0 @@
#!/usr/bin/env node
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = require("path");
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var fs = __webpack_require__(2);
var path = __webpack_require__(0);
var glob = __webpack_require__(3);
var handlebars = __webpack_require__(4);
var SimpleScaffold = /** @class */ (function () {
function SimpleScaffold(config) {
this.locals = {};
var DefaultConfig = {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = __assign({}, DefaultConfig, config);
var DefaultLocals = {
Name: this.config.name[0].toUpperCase() + this.config.name.slice(1),
name: this.config.name[0].toLowerCase() + this.config.name.slice(1)
};
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
noEscape: true
});
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var output = [];
for (var _i = 0, input_1 = input; _i < input_1.length; _i++) {
var checkPath = input_1[_i];
var files = glob.sync(checkPath, { dot: true })
.map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
var idx = checkPath.indexOf('*');
var cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
for (var _a = 0, files_1 = files; _a < files_1.length; _a++) {
var file = files_1[_a];
output.push({ base: cleanCheckPath, file: file });
}
}
return output;
};
SimpleScaffold.prototype.getFileContents = function (filePath) {
console.log(fs.readFileSync(filePath));
return fs.readFileSync(filePath).toString();
};
SimpleScaffold.prototype.getOutputPath = function (file, basePath) {
var out;
if (typeof this.config.output === 'function') {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
relativeFilePath = file.slice(idx + basePath.length + 1);
}
out = outputDir + relativeFilePath;
}
return this.parseLocals(out);
};
SimpleScaffold.prototype.writeFile = function (filePath, fileContents) {
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFile(filePath, fileContents, { encoding: 'utf-8' }, function (err) {
if (err) {
throw err;
}
});
};
SimpleScaffold.prototype.run = function () {
console.log("Generating scaffold: " + this.config.name + "...");
var templates = this.fileList(this.config.templates);
var fileConf, count = 0;
for (var _i = 0, templates_1 = templates; _i < templates_1.length; _i++) {
fileConf = templates_1[_i];
count++;
var file = fileConf.file, base = fileConf.base;
var outputPath = this.getOutputPath(file, base);
var contents = this.getFileContents(file);
var outputContents = this.parseLocals(contents);
this.writeFile(outputPath, outputContents);
console.info('Parsing:', { file: file, base: base, outputPath: outputPath, outputContents: outputContents.replace("\n", "\\n") });
}
if (!count) {
throw new Error('No files to scaffold!');
}
console.log('Done');
};
return SimpleScaffold;
}());
exports.default = SimpleScaffold;
/***/ }),
/* 2 */
/***/ (function(module, exports) {
module.exports = require("fs");
/***/ }),
/* 3 */
/***/ (function(module, exports) {
module.exports = require("glob");
/***/ }),
/* 4 */
/***/ (function(module, exports) {
module.exports = require("handlebars");
/***/ }),
/* 5 */,
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var scaffold_1 = __webpack_require__(1);
var cliArgs = __webpack_require__(7);
var cliUsage = __webpack_require__(8);
var path = __webpack_require__(0);
function localsParser(content) {
var _a = content.split('='), key = _a[0], value = _a[1];
return _b = {}, _b[key] = value, _b;
var _b;
}
function filePathParser(content) {
if (content.startsWith('/')) {
return content;
}
return [process.cwd(), content].join(path.sep);
}
var defs = [
{ name: 'name', alias: 'n', type: String, description: 'Component output name', defaultOption: true },
{ name: 'templates', alias: 't', type: filePathParser, multiple: true },
{ name: 'output', alias: 'o', type: filePathParser, multiple: true },
{ name: 'locals', alias: 'l', multiple: true, type: localsParser },
{ name: 'create-sub-folder', alias: 'S', type: Boolean },
{ name: 'help', alias: 'h', type: Boolean, description: 'Display this help message' },
];
var args = cliArgs(defs, { camelCase: true });
var help = [
{ header: 'Scaffold Generator', content: 'Generate scaffolds for your project based on file templates.' },
{ header: 'Options', optionList: defs }
];
args.locals = args.locals.reduce(function (all, cur) { return (__assign({}, all, cur)); }, {});
console.info('Config:', args);
if (args.help || !args.name) {
console.log(cliUsage(help));
process.exit(0);
}
new scaffold_1.default({
name: args.name,
templates: args.templates,
output: args.output,
locals: args.locals,
createSubfolder: args.createSubFolder,
}).run();
/***/ }),
/* 7 */
/***/ (function(module, exports) {
module.exports = require("command-line-args");
/***/ }),
/* 8 */
/***/ (function(module, exports) {
module.exports = require("command-line-usage");
/***/ })
/******/ ]);
});
//# sourceMappingURL=cmd.js.map

1
dist/cmd.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,13 +0,0 @@
import IScaffold from './index';
declare class SimpleScaffold {
config: IScaffold.Config;
locals: IScaffold.Config['locals'];
constructor(config: IScaffold.Config);
private parseLocals(text);
private fileList(input);
private getFileContents(filePath);
private getOutputPath(file, basePath);
private writeFile(filePath, fileContents);
run(): void;
}
export default SimpleScaffold;

0
dist/dist/test.d.ts vendored
View File

96
dist/main.js vendored
View File

@@ -1,96 +0,0 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 7);
/******/ })
/************************************************************************/
/******/ ({
/***/ 7:
/***/ (function(module, exports, __webpack_require__) {
(function webpackMissingModule() { throw new Error("Cannot find module \"add\""); }());
module.exports = __webpack_require__(8);
/***/ }),
/***/ 8:
/***/ (function(module, exports) {
module.exports = require("jest");
/***/ })
/******/ });
});
//# sourceMappingURL=main.js.map

1
dist/main.js.map vendored
View File

@@ -1 +0,0 @@
{"version":3,"sources":["webpack/universalModuleDefinition","webpack/bootstrap c994c2c400fa1fc61abe","external \"jest\""],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;AC7DA,iC","file":"main.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"library\"] = factory();\n\telse\n\t\troot[\"library\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 7);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c994c2c400fa1fc61abe","module.exports = require(\"jest\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"jest\"\n// module id = 8\n// module chunks = 3"],"sourceRoot":""}

217
dist/scaffold.js vendored
View File

@@ -1,217 +0,0 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = require("path");
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var fs = __webpack_require__(2);
var path = __webpack_require__(0);
var glob = __webpack_require__(3);
var handlebars = __webpack_require__(4);
var SimpleScaffold = /** @class */ (function () {
function SimpleScaffold(config) {
this.locals = {};
var DefaultConfig = {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = __assign({}, DefaultConfig, config);
var DefaultLocals = {
Name: this.config.name[0].toUpperCase() + this.config.name.slice(1),
name: this.config.name[0].toLowerCase() + this.config.name.slice(1)
};
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
noEscape: true
});
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var output = [];
for (var _i = 0, input_1 = input; _i < input_1.length; _i++) {
var checkPath = input_1[_i];
var files = glob.sync(checkPath, { dot: true })
.map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
var idx = checkPath.indexOf('*');
var cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
for (var _a = 0, files_1 = files; _a < files_1.length; _a++) {
var file = files_1[_a];
output.push({ base: cleanCheckPath, file: file });
}
}
return output;
};
SimpleScaffold.prototype.getFileContents = function (filePath) {
console.log(fs.readFileSync(filePath));
return fs.readFileSync(filePath).toString();
};
SimpleScaffold.prototype.getOutputPath = function (file, basePath) {
var out;
if (typeof this.config.output === 'function') {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
relativeFilePath = file.slice(idx + basePath.length + 1);
}
out = outputDir + relativeFilePath;
}
return this.parseLocals(out);
};
SimpleScaffold.prototype.writeFile = function (filePath, fileContents) {
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFile(filePath, fileContents, { encoding: 'utf-8' }, function (err) {
if (err) {
throw err;
}
});
};
SimpleScaffold.prototype.run = function () {
console.log("Generating scaffold: " + this.config.name + "...");
var templates = this.fileList(this.config.templates);
var fileConf, count = 0;
for (var _i = 0, templates_1 = templates; _i < templates_1.length; _i++) {
fileConf = templates_1[_i];
count++;
var file = fileConf.file, base = fileConf.base;
var outputPath = this.getOutputPath(file, base);
var contents = this.getFileContents(file);
var outputContents = this.parseLocals(contents);
this.writeFile(outputPath, outputContents);
console.info('Parsing:', { file: file, base: base, outputPath: outputPath, outputContents: outputContents.replace("\n", "\\n") });
}
if (!count) {
throw new Error('No files to scaffold!');
}
console.log('Done');
};
return SimpleScaffold;
}());
exports.default = SimpleScaffold;
/***/ }),
/* 2 */
/***/ (function(module, exports) {
module.exports = require("fs");
/***/ }),
/* 3 */
/***/ (function(module, exports) {
module.exports = require("glob");
/***/ }),
/* 4 */
/***/ (function(module, exports) {
module.exports = require("handlebars");
/***/ })
/******/ ]);
});
//# sourceMappingURL=scaffold.js.map

File diff suppressed because one or more lines are too long

246
dist/test.js vendored
View File

@@ -1,246 +0,0 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 5);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = require("path");
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var fs = __webpack_require__(2);
var path = __webpack_require__(0);
var glob = __webpack_require__(3);
var handlebars = __webpack_require__(4);
var SimpleScaffold = /** @class */ (function () {
function SimpleScaffold(config) {
this.locals = {};
var DefaultConfig = {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = __assign({}, DefaultConfig, config);
var DefaultLocals = {
Name: this.config.name[0].toUpperCase() + this.config.name.slice(1),
name: this.config.name[0].toLowerCase() + this.config.name.slice(1)
};
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
noEscape: true
});
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var output = [];
for (var _i = 0, input_1 = input; _i < input_1.length; _i++) {
var checkPath = input_1[_i];
var files = glob.sync(checkPath, { dot: true })
.map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
var idx = checkPath.indexOf('*');
var cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
for (var _a = 0, files_1 = files; _a < files_1.length; _a++) {
var file = files_1[_a];
output.push({ base: cleanCheckPath, file: file });
}
}
return output;
};
SimpleScaffold.prototype.getFileContents = function (filePath) {
console.log(fs.readFileSync(filePath));
return fs.readFileSync(filePath).toString();
};
SimpleScaffold.prototype.getOutputPath = function (file, basePath) {
var out;
if (typeof this.config.output === 'function') {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
relativeFilePath = file.slice(idx + basePath.length + 1);
}
out = outputDir + relativeFilePath;
}
return this.parseLocals(out);
};
SimpleScaffold.prototype.writeFile = function (filePath, fileContents) {
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFile(filePath, fileContents, { encoding: 'utf-8' }, function (err) {
if (err) {
throw err;
}
});
};
SimpleScaffold.prototype.run = function () {
console.log("Generating scaffold: " + this.config.name + "...");
var templates = this.fileList(this.config.templates);
var fileConf, count = 0;
for (var _i = 0, templates_1 = templates; _i < templates_1.length; _i++) {
fileConf = templates_1[_i];
count++;
var file = fileConf.file, base = fileConf.base;
var outputPath = this.getOutputPath(file, base);
var contents = this.getFileContents(file);
var outputContents = this.parseLocals(contents);
this.writeFile(outputPath, outputContents);
console.info('Parsing:', { file: file, base: base, outputPath: outputPath, outputContents: outputContents.replace("\n", "\\n") });
}
if (!count) {
throw new Error('No files to scaffold!');
}
console.log('Done');
};
return SimpleScaffold;
}());
exports.default = SimpleScaffold;
/***/ }),
/* 2 */
/***/ (function(module, exports) {
module.exports = require("fs");
/***/ }),
/* 3 */
/***/ (function(module, exports) {
module.exports = require("glob");
/***/ }),
/* 4 */
/***/ (function(module, exports) {
module.exports = require("handlebars");
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var scaffold_1 = __webpack_require__(1);
var path = __webpack_require__(0);
var templateDir = path.join(process.cwd(), 'examples');
new scaffold_1.default({
templates: [templateDir + '/test-input/Component/**/*'],
output: templateDir + '/test-output/no-create-subpath',
createSubfolder: false,
locals: {
property: 'myProp',
value: '"value"'
}
}).run();
new scaffold_1.default({
templates: [templateDir + '/test-input/Component/**/*'],
output: templateDir + '/test-output',
locals: {
property: 'myProp',
value: '"value"'
}
}).run();
/***/ })
/******/ ]);
});
//# sourceMappingURL=test.js.map

1
dist/test.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{{name}}

View File

@@ -1,18 +1,16 @@
import * as React from 'react'
import * as css from './{{Name}}.css'
import * as React from "react"
import * as css from "./{{Name}}.css"
class {{Name}} extends React.Component<any> {
private {{property}}
private {{ property }}
constructor(props: any) {
super(props)
this.{{property}} = {{value}}
this.{{ property }} = {{ value }}
}
public render() {
return (
<div className={ css.{{Name}} } />
)
return <div className={ css.{{Name}} } />
}
}

21
index.d.ts vendored
View File

@@ -1,21 +0,0 @@
declare namespace IScaffold {
export interface Config {
name?: string
templates: string[]
output: string | ((path: string, base: string) => string)
locals?: Locals
createSubfolder?: boolean
}
export interface Locals {
[k: string]: string
}
export interface FileRepr {
base: string
file: string
}
}
export default IScaffold

196
jest.config.ts Normal file
View File

@@ -0,0 +1,196 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/
export default {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/private/var/folders/q9/0mns8fgd00b4t5j5lq2wh2yh0000gn/T/jest_dx",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
modulePathIgnorePatterns: ["<rootDir>/dist"],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
preset: "ts-jest",
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: "node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: {},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
// extensionsToTreatAsEsm: [".ts"],
}

View File

@@ -1,45 +1,42 @@
{
"name": "simple-scaffold",
"version": "0.4.1",
"version": "1.0.0-alpha.3",
"description": "Create files based on templates",
"repository": "https://github.com/chenasraf/simple-scaffold.git",
"author": "Chen Asraf <inbox@casraf.com>",
"license": "MIT",
"main": "dist/scaffold.js",
"bin": "dist/cmd.js",
"types": "index.d.ts",
"main": "index.js",
"bin": "cmd.js",
"types": "types.d.ts",
"scripts": {
"build": "NODE_ENV=${NODE_ENV:-production} webpack -p && chmod -R +x ./dist",
"dev": "webpack --watch",
"clean": "rm -rf dist/",
"build": "yarn clean && tsc && chmod -R +x ./dist && cp ./package.json ./dist/ && cp ./README.md ./dist/",
"dev": "tsc --watch",
"start": "node dist/scaffold.js",
"test": "jest",
"cmd": "dist/cmd.js",
"test": "jest --verbose",
"cmd": "node --trace-warnings dist/cmd.js",
"build-test": "yarn build && yarn test",
"build-cmd": "yarn build && yarn cmd"
},
"dependencies": {
"command-line-args": "^5.0.2",
"command-line-usage": "^5.0.5",
"glob": "^7.1.2",
"handlebars": "^4.0.11",
"ts-loader": "^3.1.1",
"typescript": "^2.6.1",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.4",
"webpack-node-externals": "^1.6.0"
"args": "^5.0.1",
"glob": "^7.1.3",
"handlebars": "^4.7.7",
"lodash": "^4.17.21",
"massarg": "^0.1.2",
"util.promisify": "^1.1.1"
},
"devDependencies": {
"@types/command-line-args": "^5.0.0",
"@types/command-line-usage": "^5.0.1",
"@types/glob": "^5.0.34",
"@types/handlebars": "^4.0.36",
"@types/node": "^8.0.50",
"jest": "^22.0.4"
},
"jest": {
"testPathIgnorePatterns": [
"node_modules",
"dist"
]
"@types/args": "^3.0.1",
"@types/glob": "^7.1.1",
"@types/jest": "^26.0.24",
"@types/lodash": "^4.14.171",
"@types/mock-fs": "^4.13.1",
"@types/node": "^14.14.22",
"jest": "^27.0.6",
"mock-fs": "^5.0.0",
"ts-jest": "^27.0.3",
"ts-node": "^10.1.0",
"typescript": "^4.3.5"
}
}

View File

@@ -1,112 +0,0 @@
import * as fs from 'fs'
import * as path from 'path'
import IScaffold from './index'
import * as glob from 'glob'
import * as handlebars from 'handlebars'
class SimpleScaffold {
public config: IScaffold.Config
public locals: IScaffold.Config['locals'] = {} as any
constructor(config: IScaffold.Config) {
const DefaultConfig: IScaffold.Config = {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
}
this.config = { ...DefaultConfig, ...config }
const DefaultLocals = {
Name: this.config.name![0].toUpperCase() + this.config.name!.slice(1),
name: this.config.name![0].toLowerCase() + this.config.name!.slice(1)
}
this.locals = { ...DefaultLocals, ...config.locals }
}
private parseLocals(text: string): string {
const template = handlebars.compile(text, {
noEscape: true
})
return template(this.locals)
}
private fileList(input: string[]): IScaffold.FileRepr[] {
const output: IScaffold.FileRepr[] = []
for (const checkPath of input) {
const files = glob.sync(checkPath, { dot: true })
.map(g => g[0] == '/' ? g : path.join(process.cwd(), g))
const idx = checkPath.indexOf('*')
let cleanCheckPath = checkPath
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1)
}
for (const file of files) {
output.push({ base: cleanCheckPath, file })
}
}
return output
}
private getFileContents(filePath: string): string {
console.log(fs.readFileSync(filePath))
return fs.readFileSync(filePath).toString()
}
private getOutputPath(file: string, basePath: string): string {
let out: string
if (typeof this.config.output === 'function') {
out = this.config.output(file, basePath)
} else {
const outputDir = this.config.output + (this.config.createSubfolder ? `/${this.config.name}/` : '/')
const idx = file.indexOf(basePath)
let relativeFilePath = file
if (idx >= 0) {
relativeFilePath = file.slice(idx + basePath.length + 1)
}
out = outputDir + relativeFilePath
}
return this.parseLocals(out)
}
private writeFile(filePath: string, fileContents: string): void {
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath))
}
console.info('Writing file:', filePath)
fs.writeFile(filePath, fileContents, { encoding: 'utf-8' }, (err) => {
if (err) {
throw err
}
})
}
public run(): void {
console.log(`Generating scaffold: ${this.config.name}...`)
const templates = this.fileList(this.config.templates)
let fileConf, count = 0
for (fileConf of templates) {
count++
const { file, base } = fileConf
const outputPath = this.getOutputPath(file, base)
const contents = this.getFileContents(file)
const outputContents = this.parseLocals(contents)
this.writeFile(outputPath, outputContents)
console.info('Parsing:', { file, base, outputPath, outputContents: outputContents.replace("\n", "\\n") })
}
if (!count) {
throw new Error('No files to scaffold!')
}
console.log('Done')
}
}
export default SimpleScaffold

69
src/cmd.ts Normal file
View File

@@ -0,0 +1,69 @@
import Scaffold from "./scaffold"
import massarg from "massarg"
import { ScaffoldCmdConfig } from "./types"
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.",
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: "Suppress output logs", defaultValue: false, boolean: true })
.option({
aliases: ["dr"],
name: "dry-run",
description:
"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.",
defaultValue: false,
boolean: true,
})
// .example({
// input: `yarn cmd -t examples/test-input/Component -o examples/test-output -d '{"property":"myProp","value":"10"}'`,
// description: "Usage",
// output: "",
// })
.help({
binName: "simple-scaffold",
useGlobalColumns: true,
usageExample: "[options]",
})
.parse()

0
dist/dist/cmd.d.ts → src/filters.ts Executable file → Normal file
View File

3
src/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from "./scaffold"
import Scaffold from "./scaffold"
export default Scaffold

104
src/scaffold.ts Normal file
View File

@@ -0,0 +1,104 @@
import { glob } from "glob"
import path from "path"
import { promisify } from "util"
import { promises as fsPromises } from "fs"
const { readFile, writeFile } = fsPromises
import {
createDirIfNotExists,
getOptionValueForFile,
handleErr,
handlebarsParse,
log,
pathExists,
pascalCase,
isDir,
} from "./utils"
import { ScaffoldConfig } from "./types"
export async function Scaffold(config: ScaffoldConfig) {
try {
const options = { ...config }
const data = { name: options.name, Name: pascalCase(options.name), ...options.data }
log(options, "Config:", {
name: options.name,
templates: options.templates,
output: options.output,
createSubfolder: options.createSubFolder,
data: options.data,
overwrite: options.overwrite,
quiet: options.quiet,
})
log(options, "Data:", data)
for (let template of config.templates) {
try {
const _isDir = await isDir(template)
const basePath = path
.resolve(process.cwd(), _isDir ? template : path.dirname(template.replace("*", "").replace("//", "/")))
.replace(process.cwd(), ".")
if (_isDir) {
template = template + "/**/*"
}
const files = await promisify(glob)(template, { dot: true, debug: false })
for (const templatePath of files) {
if (!(await isDir(templatePath))) {
await handleTemplateFile(templatePath, basePath, options, data)
}
}
} catch (e: any) {
handleErr(e)
}
}
} catch (e: any) {
console.error(e)
throw e
}
}
async function handleTemplateFile(
templatePath: string,
basePath: string,
options: ScaffoldConfig,
data: Record<string, string>
): Promise<void> {
return new Promise(async (resolve, reject) => {
try {
log(options, `Parsing ${templatePath}`)
const inputPath = path.join(process.cwd(), templatePath)
const outputPathOpt = getOptionValueForFile(inputPath, data, options.output)
const outputDir = path.resolve(
process.cwd(),
...([outputPathOpt, options.createSubFolder ? options.name : undefined].filter(Boolean) as string[])
)
const outputPath = path.join(outputDir, handlebarsParse(path.basename(inputPath), data))
const overwrite = getOptionValueForFile(inputPath, data, options.overwrite ?? false)
const exists = await pathExists(outputPath)
await createDirIfNotExists(outputDir, options)
log(options, `Writing to ${outputPath}`)
if (!exists || overwrite) {
if (exists && overwrite) {
log(options, `File ${outputPath} exists, overwriting`)
}
const templateBuffer = await readFile(inputPath)
const outputContents = handlebarsParse(templateBuffer, data)
if (!options.dryRun) {
await writeFile(outputPath, outputContents)
} else {
log(options, "Content output:")
log(options, outputContents)
}
} else if (exists) {
log(options, `File ${outputPath} already exists, skipping`)
}
resolve()
} catch (e: any) {
handleErr(e)
reject(e)
}
})
}
export default Scaffold

25
src/types.ts Normal file
View File

@@ -0,0 +1,25 @@
export type FileResponseFn<T> = (fullPath: string, basedir: string, basename: string) => T
export type FileResponse<T> = T | FileResponseFn<T>
export interface ScaffoldConfig {
/** The name supplied for the output templates */
name: string
templates: string[]
output: FileResponse<string>
createSubFolder?: boolean
data?: Record<string, string>
overwrite?: FileResponse<boolean>
quiet?: boolean
dryRun?: boolean
}
export interface ScaffoldCmdConfig {
name: string
templates: string[]
output: string
createSubFolder: boolean
data?: Record<string, string>
overwrite: boolean
quiet: boolean
dryRun: boolean
}

97
src/utils.ts Normal file
View File

@@ -0,0 +1,97 @@
import path from "path"
import { F_OK } from "constants"
import { FileResponse, FileResponseFn, ScaffoldConfig } from "./types"
import camelCase from "lodash/camelCase"
import snakeCase from "lodash/snakeCase"
import kebabCase from "lodash/kebabCase"
import startCase from "lodash/startCase"
import Handlebars from "handlebars"
import { promises as fsPromises } from "fs"
const { stat, access, mkdir } = fsPromises
const helpers = {
camelCase,
snakeCase,
startCase,
kebabCase,
hyphenCase: kebabCase,
pascalCase,
}
for (const helperName in helpers) {
Handlebars.registerHelper(helperName, helpers[helperName as keyof typeof helpers])
}
export function handleErr(err: NodeJS.ErrnoException | null) {
if (err) throw err
}
export function log(options: ScaffoldConfig, ...obj: any[]) {
if (options.quiet) {
return
}
console["log"](...obj)
}
export async function createDirIfNotExists(dir: string, options: ScaffoldConfig): Promise<void> {
const parentDir = path.dirname(dir)
if (!(await pathExists(parentDir))) {
await createDirIfNotExists(parentDir, options)
}
if (!(await pathExists(dir))) {
try {
await mkdir(dir)
return
} catch (e: any) {
if (e.code !== "EEXIST") {
throw e
}
return
}
}
}
export function getOptionValueForFile<T>(
filePath: string,
data: Record<string, string>,
fn: FileResponse<T>,
defaultValue?: T
): T {
if (typeof fn !== "function") {
return defaultValue ?? (fn as T)
}
return (fn as FileResponseFn<T>)(
filePath,
path.dirname(handlebarsParse(filePath, data)),
path.basename(handlebarsParse(filePath, data))
)
}
export function handlebarsParse(templateBuffer: Buffer | string, data: Record<string, string>) {
const parser = Handlebars.compile(templateBuffer.toString(), { noEscape: true })
const outputContents = parser(data)
return outputContents
}
export async function pathExists(filePath: string): Promise<boolean> {
try {
await access(filePath, F_OK)
return true
} catch (e: any) {
if (e.code === "ENOENT") {
return false
}
throw e
}
}
export function pascalCase(s: string): string {
return startCase(s).replace(/\s+/g, "")
}
export async function isDir(path: string): Promise<boolean> {
const tplStat = await stat(path)
return tplStat.isDirectory()
}

23
test.ts
View File

@@ -1,23 +0,0 @@
import SimpleScaffold from './scaffold'
import * as path from 'path'
const templateDir = path.join(process.cwd(), 'examples')
new SimpleScaffold({
templates: [templateDir + '/test-input/Component/**/*'],
output: templateDir + '/test-output/no-create-subpath',
createSubfolder: false,
locals: {
property: 'myProp',
value: '"value"'
}
}).run()
new SimpleScaffold({
templates: [templateDir + '/test-input/Component/**/*'],
output: templateDir + '/test-output',
locals: {
property: 'myProp',
value: '"value"'
}
}).run()

183
tests/scaffold.test.ts Normal file
View File

@@ -0,0 +1,183 @@
import mockFs from "mock-fs"
import FileSystem from "mock-fs/lib/filesystem"
import Scaffold from "../src/scaffold"
import { readdirSync, readFileSync } from "fs"
const fileStructNormal = {
input: {
"{{name}}.txt": "Hello, my app is {{name}}",
},
output: {},
}
const fileStructWithData = {
input: {
"{{name}}.txt": "Hello, my value is {{value}}",
},
output: {},
}
const fileStructNested = {
input: {
"{{name}}-1.text": "This should be in root",
"{{Name}}": {
"{{name}}-2.txt": "Hello, my value is {{value}}",
},
},
output: {},
}
function withMock(fileStruct: FileSystem.DirectoryItems, testFn: jest.EmptyFunction): jest.EmptyFunction {
return () => {
beforeEach(() => {
mockFs(fileStruct)
})
testFn()
afterEach(() => {
mockFs.restore()
})
}
}
describe("Scaffold", () => {
describe(
"create subfolder",
withMock(fileStructNormal, () => {
test("should not create by default", async () => {
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
quiet: true,
})
const data = readFileSync(process.cwd() + "/output/app_name.txt")
expect(data.toString()).toBe("Hello, my app is app_name")
})
test("should create with config", async () => {
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
createSubFolder: true,
quiet: true,
})
const data = readFileSync(process.cwd() + "/output/app_name/app_name.txt")
expect(data.toString()).toBe("Hello, my app is app_name")
})
})
)
describe(
"overwrite",
withMock(fileStructWithData, () => {
test("should not overwrite by default", async () => {
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
data: { value: "1" },
quiet: true,
})
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
data: { value: "2" },
quiet: true,
})
const data = readFileSync(process.cwd() + "/output/app_name.txt")
expect(data.toString()).toBe("Hello, my value is 1")
})
test("should overwrite with config", async () => {
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
data: { value: "1" },
quiet: true,
})
await Scaffold({
name: "app_name",
output: "output",
templates: ["input"],
data: { value: "2" },
overwrite: true,
quiet: true,
})
const data = readFileSync(process.cwd() + "/output/app_name.txt")
expect(data.toString()).toBe("Hello, my value is 2")
})
})
)
describe(
"errors",
withMock(fileStructNormal, () => {
let consoleMock: jest.SpyInstance
beforeAll(() => {
consoleMock = jest.spyOn(console, "error").mockImplementation(() => void 0)
})
test("should throw for bad input", async () => {
await expect(
Scaffold({
name: "app_name",
output: "output",
templates: ["non-existing-input"],
data: { value: "1" },
quiet: true,
})
).rejects.toThrow()
expect(() => readFileSync(process.cwd() + "/output/app_name.txt")).toThrow()
})
afterAll(() => {
consoleMock.mockRestore()
})
})
)
describe(
"outputPath override",
withMock(fileStructNormal, () => {
test("should allow override function", async () => {
await Scaffold({
name: "app_name",
output: (fullPath, basedir, basename) => `custom-output/${basename.split(".")[0]}`,
templates: ["input"],
data: { value: "1" },
quiet: true,
})
const data = readFileSync(process.cwd() + "/custom-output/app_name/app_name.txt")
expect(data.toString()).toBe("Hello, my app is app_name")
})
})
)
describe(
"output structure",
withMock(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())
expect(dir).toHaveProperty("length")
})
})
)
})

View File

@@ -1,14 +1,23 @@
{
"compilerOptions": {
"target": "es5",
"target": "ES2019",
"module": "commonjs",
"lib": ["es2017", "es6"],
"moduleResolution": "node",
"esModuleInterop": true,
"lib": [
"ES2019",
],
"declaration": true,
"outDir": "dist",
"strict": true,
"sourceMap": true
"sourceMap": true,
"removeComments": false,
},
"include": [
"src/index.ts",
"src/cmd.ts",
],
"exclude": [
"examples"
"tests/*"
]
}

View File

@@ -1,43 +0,0 @@
const path = require('path')
const webpack = require('webpack')
const nodeExternals = require('webpack-node-externals')
module.exports = {
devtool: process.env.NODE_ENV === 'develop' ? 'inline-source-map' : 'source-map',
target: 'node',
entry: {
scaffold: './scaffold.ts',
test: './test.ts',
cmd: './cmd.ts',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
library: 'library',
libraryTarget: 'umd',
},
resolve: {
extensions: ['.ts']
},
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: ['./examples', 'node_modules']
}
]
},
plugins: [
new webpack.DefinePlugin({
'__dirname': '__dirname'
}),
new webpack.BannerPlugin({
banner: '#!/usr/bin/env node',
raw: true,
include: /cmd\.js/,
})
],
}

6963
yarn.lock

File diff suppressed because it is too large Load Diff