Compare commits

..

12 Commits

Author SHA1 Message Date
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
Chen Asraf
ec91fbf639 v0.4.1 2019-02-25 18:00:39 +02:00
Chen Asraf
85aa9f953b Bugfix: dotfiles 2019-02-25 18:00:23 +02:00
Chen Asraf
d6195c6c1d added 'createSubFolder' option, cleaned up CMD file 2019-02-25 17:49:03 +02:00
Chen Asraf
b14e3d2d76 Update README.md 2018-01-15 02:25:29 +02:00
Chen Asraf
fa2ddca57e v0.3.1 2018-01-15 02:23:14 +02:00
Chen Asraf
686b0bf227 Update README.md 2018-01-15 02:23:05 +02:00
21 changed files with 3705 additions and 1194 deletions

3
.gitignore vendored
View File

@@ -57,4 +57,5 @@ typings/
# dotenv environment variables file
.env
examples/test-output
examples/test-output/**/*
!examples/test-output/.gitkeep

102
README.md
View File

@@ -1,20 +1,19 @@
# simple-scaffolder
Scaffolder allows you to create your structured files based on templates.
# 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.
You can install simple-scaffold globally like so:
```bash
# npm
npm install -g simple-scaffold
npm install [-g] simple-scaffold
# yarn
yarn global add simple-scaffold
yarn [global] add simple-scaffold
```
## Use as a command line tool
### Command line options
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/**/* \
@@ -22,15 +21,36 @@ simple-scaffold MyComponent --template scaffolds/component/**/* \
--locals myProp="propname",myVal=123
```
##### `--template glob [--template glob2 [...]]`
A glob pattern of template files to load.
You can 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"
}
}
```
## Scaffolding
Scaffolding will replace {{vars}} in both the file name and its contents and put the transformed files
in `<output>/<{{Name}}`.
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) (alias: -t)
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 may load more than one template list by simple adding more `--template` arguments.
You can load more than one template list by simple adding more `--template` arguments.
##### `--output path`
##### `--output path` (optional) (alias -o)
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.
@@ -38,13 +58,18 @@ Your new scaffold will be placed under a directory with the scaffold name from t
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[,...]]`
##### `--locals key=value [--locals key=value [,...]]` (optional) (alias: -l)
Pass a KV map to the template for parsing.
##### `--create-sub-folder [true|false]` (optional) (alias -S) (default: true)
Whether to create a subfolder for the output with all the files inside, or simply dump them directly in the output folder.
#####
### Use in Node.js
You can also build the scaffold yourself.
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 the same arguments as the command line:
The config takes similar arguments to the command line:
```javascript
const SimpleScaffold = require('simple-scaffold').default
@@ -53,6 +78,7 @@ const scaffold = new SimpleScaffold({
name: 'component',
templates: [path.join(__dirname, 'scaffolds', 'component')],
output: path.join(__dirname, 'src', 'components'),
createSubFolder: true,
locals: {
property: 'value',
}
@@ -60,32 +86,25 @@ const scaffold = new SimpleScaffold({
```
## Example Scaffold Input
Scaffolding will replace interpolations in both the file name and contents.
Your context will be pre-populated with
- `{{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 `}}`.
### Input Directory structure
```
- project
- scaffold
- {{Name}}.css
- {{Name}}.js
- src
- components
- ...
```
#### project/scaffold/{{Name}}.css
```css
.{{className}} {
border: 1px solid black;
}
#### project/scaffold/{{Name}}.js
```js
const React = require('react')
.{{className}}-child {
background: red;
module.exports = class {{Name}} extends React.Component {
render() {
<div className="{{className}}">{{Name}} Component</div>
}
}
```
@@ -104,17 +123,26 @@ simple-scaffold MyComponent \
- src
- components
- MyComponent
- MyComponent.css
- MyComponent.js
- ...
```
#### project/src/components/MyComponent/MyComponent.css
```css
.my-component {
border: 1px solid black;
}
With `createSubfolder = false`:
```
- project
- src
- components
- MyComponent.js
- ...
```
.my-component-child {
background: red;
#### project/scaffold/MyComponent/MyComponent.js
```js
const React = require('react')
module.exports = class MyComponent extends React.Component {
render() {
<div className="my-component">MyComponent Component</div>
}
}
```

127
cmd.ts
View File

@@ -1,86 +1,55 @@
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'
const args = process.argv.slice(2)
type Def = cliArgs.OptionDefinition & { description?: string }
class ScaffoldCmd {
private config: IScaffold.IConfig
constructor() {
this.config = this.getOptionsFromArgs()
}
private getOptionsFromArgs(): IScaffold.IConfig {
let skipNext = false
const options = {} as any
args.forEach((arg, i) => {
if (skipNext) {
skipNext = false
return
}
if (arg.slice(0, 2) == '--') {
skipNext = true
let value: string
if (arg.indexOf('=') >= 0) {
value = arg.split('=').slice(1).join('')
} else if (args.length >= i + 1 && args[i + 1] && args[i + 1].slice(0, 2) !== '--') {
value = args[i + 1]
} else {
value = 'true'
}
const argName = arg.slice(2)
options[argName] = this.getArgValue(argName, value, options)
} else {
if (!options.name) {
options.name = arg
} else {
throw new TypeError(`Invalid argument: ${arg}`)
}
}
})
if (!['name', 'templates'].every(o => options[o] !== undefined)) {
throw new Error(`Config is missing keys: ${JSON.stringify(options)}`)
}
return options
}
private getArgValue(arg: string, value: string, options: IScaffold.IConfig) {
switch (arg) {
case 'templates':
return (options.templates || []).concat([value])
case 'output':
return value
case 'locals':
const split = value.split(',')
const locals = options.locals || {}
for (const item of split) {
const [k, v] = item.split('=')
locals[k] = v
}
return locals
default:
throw TypeError(`arguments invalid for config: arg=\`${arg}\`, value=\`${value}\``)
}
}
public run() {
const config: IScaffold.IConfig = this.config
console.info('Config:', config)
const scf = new SimpleScaffold({
name: config.name,
templates: config.templates,
output: config.output,
locals: config.locals,
}).run()
}
function localsParser(content: string) {
const [key, value] = content.split('=')
return { [key]: value }
}
new ScaffoldCmd().run()
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: (text: string) => text && text.trim().length ? ['true', '1', 'on'].includes(text.trim()) : true },
{ 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'])
if (args.createSubFolder === null) {
args.createSubFolder = true
}
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()

233
dist/cmd.js vendored
View File

@@ -8,7 +8,7 @@
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
@@ -86,32 +86,13 @@ module.exports = require("path");
"use strict";
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
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);
@@ -125,13 +106,14 @@ var SimpleScaffold = /** @class */ (function () {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = Object.assign({}, DefaultConfig, config);
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 = Object.assign({}, DefaultLocals, config.locals);
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
@@ -140,41 +122,25 @@ var SimpleScaffold = /** @class */ (function () {
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var _i, input_1, checkPath, files, idx, cleanCheckPath, _a, files_1, file;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_i = 0, input_1 = input;
_b.label = 1;
case 1:
if (!(_i < input_1.length)) return [3 /*break*/, 6];
checkPath = input_1[_i];
files = glob.sync(checkPath).map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
idx = checkPath.indexOf('*');
cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
_a = 0, files_1 = files;
_b.label = 2;
case 2:
if (!(_a < files_1.length)) return [3 /*break*/, 5];
file = files_1[_a];
return [4 /*yield*/, { base: cleanCheckPath, file: file }];
case 3:
_b.sent();
_b.label = 4;
case 4:
_a++;
return [3 /*break*/, 2];
case 5:
_i++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/];
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) {
@@ -183,7 +149,7 @@ var SimpleScaffold = /** @class */ (function () {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + ("/" + this.config.name + "/");
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
@@ -198,13 +164,18 @@ var SimpleScaffold = /** @class */ (function () {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFileSync(filePath, fileContents, { encoding: 'utf-8' });
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;
while (fileConf = templates.next().value) {
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);
@@ -248,85 +219,73 @@ module.exports = require("handlebars");
"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 args = process.argv.slice(2);
var ScaffoldCmd = /** @class */ (function () {
function ScaffoldCmd() {
this.config = this.getOptionsFromArgs();
var cliArgs = __webpack_require__(7);
var cliUsage = __webpack_require__(8);
var path = __webpack_require__(0);
function localsParser(content) {
var _a;
var _b = content.split('='), key = _b[0], value = _b[1];
return _a = {}, _a[key] = value, _a;
}
function filePathParser(content) {
if (content.startsWith('/')) {
return content;
}
ScaffoldCmd.prototype.getOptionsFromArgs = function () {
var _this = this;
var skipNext = false;
var options = {};
args.forEach(function (arg, i) {
if (skipNext) {
skipNext = false;
return;
}
if (arg.slice(0, 2) == '--') {
skipNext = true;
var value = void 0;
if (arg.indexOf('=') >= 0) {
value = arg.split('=').slice(1).join('');
}
else if (args.length >= i + 1 && args[i + 1] && args[i + 1].slice(0, 2) !== '--') {
value = args[i + 1];
}
else {
value = 'true';
}
var argName = arg.slice(2);
options[argName] = _this.getArgValue(argName, value, options);
}
else {
if (!options.name) {
options.name = arg;
}
else {
throw new TypeError("Invalid argument: " + arg);
}
}
});
if (!['name', 'templates', 'output'].every(function (o) { return options[o] !== undefined; })) {
throw new Error("Config is missing keys: " + JSON.stringify(options));
}
return options;
};
ScaffoldCmd.prototype.getArgValue = function (arg, value, options) {
switch (arg) {
case 'templates':
return (options.templates || []).concat([value]);
case 'output':
return value;
case 'locals':
var split = value.split(',');
var locals = options.locals || {};
for (var _i = 0, split_1 = split; _i < split_1.length; _i++) {
var item = split_1[_i];
var _a = item.split('='), k = _a[0], v = _a[1];
locals[k] = v;
}
return locals;
default:
throw TypeError("arguments invalid for config: arg=`" + arg + "`, value=`" + value + "`");
}
};
ScaffoldCmd.prototype.run = function () {
var config = this.config;
console.info('Config:', config);
var scf = new scaffold_1.default({
name: config.name,
templates: config.templates,
output: config.output,
locals: config.locals,
}).run();
};
return ScaffoldCmd;
}());
new ScaffoldCmd().run();
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: function (text) { return text && text.trim().length ? ['true', '1', 'on'].includes(text.trim()) : true; } },
{ 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)); }, {});
if (args.createSubFolder === null) {
args.createSubFolder = true;
}
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");
/***/ })
/******/ ]);
});

2
dist/cmd.js.map vendored

File diff suppressed because one or more lines are too long

1
dist/dist/cmd.d.ts vendored
View File

@@ -0,0 +1 @@
export {};

View File

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

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

@@ -0,0 +1 @@
export {};

0
dist/main.js vendored Normal file → Executable file
View File

0
dist/main.js.map vendored Normal file → Executable file
View File

97
dist/scaffold.js vendored
View File

@@ -7,7 +7,7 @@
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
@@ -85,32 +85,13 @@ module.exports = require("path");
"use strict";
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
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);
@@ -124,13 +105,14 @@ var SimpleScaffold = /** @class */ (function () {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = Object.assign({}, DefaultConfig, config);
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 = Object.assign({}, DefaultLocals, config.locals);
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
@@ -139,41 +121,25 @@ var SimpleScaffold = /** @class */ (function () {
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var _i, input_1, checkPath, files, idx, cleanCheckPath, _a, files_1, file;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_i = 0, input_1 = input;
_b.label = 1;
case 1:
if (!(_i < input_1.length)) return [3 /*break*/, 6];
checkPath = input_1[_i];
files = glob.sync(checkPath).map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
idx = checkPath.indexOf('*');
cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
_a = 0, files_1 = files;
_b.label = 2;
case 2:
if (!(_a < files_1.length)) return [3 /*break*/, 5];
file = files_1[_a];
return [4 /*yield*/, { base: cleanCheckPath, file: file }];
case 3:
_b.sent();
_b.label = 4;
case 4:
_a++;
return [3 /*break*/, 2];
case 5:
_i++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/];
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) {
@@ -182,7 +148,7 @@ var SimpleScaffold = /** @class */ (function () {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + ("/" + this.config.name + "/");
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
@@ -197,13 +163,18 @@ var SimpleScaffold = /** @class */ (function () {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFileSync(filePath, fileContents, { encoding: 'utf-8' });
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;
while (fileConf = templates.next().value) {
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);

File diff suppressed because one or more lines are too long

106
dist/test.js vendored
View File

@@ -7,7 +7,7 @@
exports["library"] = factory();
else
root["library"] = factory();
})(this, function() {
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
@@ -85,32 +85,13 @@ module.exports = require("path");
"use strict";
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
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);
@@ -124,13 +105,14 @@ var SimpleScaffold = /** @class */ (function () {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
};
this.config = Object.assign({}, DefaultConfig, config);
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 = Object.assign({}, DefaultLocals, config.locals);
this.locals = __assign({}, DefaultLocals, config.locals);
}
SimpleScaffold.prototype.parseLocals = function (text) {
var template = handlebars.compile(text, {
@@ -139,41 +121,25 @@ var SimpleScaffold = /** @class */ (function () {
return template(this.locals);
};
SimpleScaffold.prototype.fileList = function (input) {
var _i, input_1, checkPath, files, idx, cleanCheckPath, _a, files_1, file;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_i = 0, input_1 = input;
_b.label = 1;
case 1:
if (!(_i < input_1.length)) return [3 /*break*/, 6];
checkPath = input_1[_i];
files = glob.sync(checkPath).map(function (g) { return g[0] == '/' ? g : path.join(process.cwd(), g); });
idx = checkPath.indexOf('*');
cleanCheckPath = checkPath;
if (idx >= 0) {
cleanCheckPath = checkPath.slice(0, idx - 1);
}
_a = 0, files_1 = files;
_b.label = 2;
case 2:
if (!(_a < files_1.length)) return [3 /*break*/, 5];
file = files_1[_a];
return [4 /*yield*/, { base: cleanCheckPath, file: file }];
case 3:
_b.sent();
_b.label = 4;
case 4:
_a++;
return [3 /*break*/, 2];
case 5:
_i++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/];
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) {
@@ -182,7 +148,7 @@ var SimpleScaffold = /** @class */ (function () {
out = this.config.output(file, basePath);
}
else {
var outputDir = this.config.output + ("/" + this.config.name + "/");
var outputDir = this.config.output + (this.config.createSubfolder ? "/" + this.config.name + "/" : '/');
var idx = file.indexOf(basePath);
var relativeFilePath = file;
if (idx >= 0) {
@@ -197,13 +163,18 @@ var SimpleScaffold = /** @class */ (function () {
fs.mkdirSync(path.dirname(filePath));
}
console.info('Writing file:', filePath);
fs.writeFileSync(filePath, fileContents, { encoding: 'utf-8' });
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;
while (fileConf = templates.next().value) {
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);
@@ -250,6 +221,15 @@ 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',

2
dist/test.js.map vendored

File diff suppressed because one or more lines are too long

View File

11
index.d.ts vendored
View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "simple-scaffold",
"version": "0.3.0",
"version": "0.4.4",
"description": "Create files based on templates",
"repository": "https://github.com/chenasraf/simple-scaffold.git",
"author": "Chen Asraf <inbox@casraf.com>",
@@ -10,6 +10,7 @@
"types": "index.d.ts",
"scripts": {
"build": "NODE_ENV=${NODE_ENV:-production} webpack -p && chmod -R +x ./dist",
"prepublishOnly": "yarn build",
"dev": "webpack --watch",
"start": "node dist/scaffold.js",
"test": "jest",
@@ -18,9 +19,8 @@
"build-cmd": "yarn build && yarn cmd"
},
"dependencies": {
"@types/glob": "^5.0.34",
"@types/handlebars": "^4.0.36",
"@types/node": "^8.0.50",
"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",
@@ -30,6 +30,11 @@
"webpack-node-externals": "^1.6.0"
},
"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": {

View File

@@ -5,24 +5,25 @@ import * as glob from 'glob'
import * as handlebars from 'handlebars'
class SimpleScaffold {
public config: IScaffold.IConfig
public locals = {} as any
public config: IScaffold.Config
public locals: IScaffold.Config['locals'] = {} as any
constructor(config: IScaffold.IConfig) {
const DefaultConfig: IScaffold.IConfig = {
constructor(config: IScaffold.Config) {
const DefaultConfig: IScaffold.Config = {
name: 'scaffold',
templates: [],
output: process.cwd(),
createSubfolder: true,
}
this.config = (Object as any).assign({}, DefaultConfig, config)
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 = (Object as any).assign({}, DefaultLocals, config.locals)
this.locals = { ...DefaultLocals, ...config.locals }
}
private parseLocals(text: string): string {
@@ -32,18 +33,21 @@ class SimpleScaffold {
return template(this.locals)
}
private *fileList(input: string[]): IterableIterator<IScaffold.IFileRepr> {
private fileList(input: string[]): IScaffold.FileRepr[] {
const output: IScaffold.FileRepr[] = []
for (const checkPath of input) {
const files = glob.sync(checkPath).map(g => g[0] == '/' ? g : path.join(process.cwd(), g))
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) {
yield {base: cleanCheckPath, file}
output.push({ base: cleanCheckPath, file })
}
}
return output
}
private getFileContents(filePath: string): string {
@@ -52,12 +56,12 @@ class SimpleScaffold {
}
private getOutputPath(file: string, basePath: string): string {
let out
let out: string
if (typeof this.config.output === 'function') {
out = this.config.output(file, basePath)
} else {
const outputDir = this.config.output + `/${this.config.name}/`
const outputDir = this.config.output + (this.config.createSubfolder ? `/${this.config.name}/` : '/')
const idx = file.indexOf(basePath)
let relativeFilePath = file
if (idx >= 0) {
@@ -74,7 +78,11 @@ class SimpleScaffold {
fs.mkdirSync(path.dirname(filePath))
}
console.info('Writing file:', filePath)
fs.writeFileSync(filePath, fileContents, { encoding: 'utf-8' })
fs.writeFile(filePath, fileContents, { encoding: 'utf-8' }, (err) => {
if (err) {
throw err
}
})
}
public run(): void {
@@ -82,15 +90,15 @@ class SimpleScaffold {
const templates = this.fileList(this.config.templates)
let fileConf, count = 0
while (fileConf = templates.next().value) {
for (fileConf of templates) {
count++
const {file, base} = fileConf
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")})
console.info('Parsing:', { file, base, outputPath, outputContents: outputContents.replace("\n", "\\n") })
}
if (!count) {

10
test.ts
View File

@@ -3,6 +3,16 @@ 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',

4135
yarn.lock

File diff suppressed because it is too large Load Diff