Socket
Socket
Sign inDemoInstall

light-generator

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

light-generator - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

dist/generator.d.ts

7

package.json
{
"name": "light-generator",
"version": "0.0.1",
"version": "0.0.2",
"description": "light generator for generate a boilerplate",

@@ -12,3 +12,3 @@ "main": "dist/index",

"json-cycle": "^1.3.0",
"lodash": "^4.17.15",
"tar": "^4.4.10",
"untildify": "^4.0.0"

@@ -31,3 +31,4 @@ },

"test": "npm run lint && NODE_ENV=test midway-bin test --ts --full-trace",
"cov": "NODE_ENV=unittest midway-bin cov --ts"
"cov": "NODE_ENV=unittest midway-bin cov --ts",
"prepublishOnly": "npm run build"
},

@@ -34,0 +35,0 @@ "files": [

# light generator
一个非常轻量的模板生成器,用于各种脚手架的生成。
一个非常轻量的脚手架生成器,用于各种脚手架的生成。
## 使用
核心功能:
- 获取模板到本地(支持本地模板,github 地址,或者npm 地址)
- 拷贝到指定的用户路径
- 执行自定义规则(比如替换文件名等)
## Quick Guide
```ts
import {LightGenerator} from 'light-generator';
const generator = new LightGenerator({
templatePath: 'npm://xxxx'
const generator = new LightGenerator().defineNpmPackage({
npmPackage: 'egg-boilerplate-simple',
targetPath
});
await generator.run({

@@ -18,4 +26,140 @@ name: 'demo'

默认会将模板中的下划线前缀的文件替换为正常文件名,并替换模板中的 `{{xxx}}` 变量为传入的参数。
## LightGenerator
### Constructor
- options {object}
- disableDefaultRule {boolean} 可选,默认 false,用于禁止默认规则;
- copyRule { CopyRule[] } 可选,可以通过这个配置,传递自定义拷贝规则
### API
`LightGenerator` 通过定义一系列格式,返回一个特定格式的生成器,执行该生成器即可拿到相应的结果。
```ts
interface LightGenerator {
defineLocalPath(options): CommonGenerator;
defineNpmPackage(options): CommonGenerator;
}
interface CommonGenerator {
async getParameterList(): object;
async run(replaceParameter?: object);
}
```
- getParameterList() 获取该生成器(模板)定义的用户可覆盖的配置
- run() 执行该生成器,在这个时候传入用户覆盖的配置
#### defineLocalPath
生成本地路径的模板
- options {object}
- templatePath { string } 本地模板路径
- targetPath { string } 需要拷贝到的目录
**示例**
```ts
const localGenerator = new LightGenerator().defineLocalPath({
templatePath: join(__dirname, './fixtures/boilerplate-2'),
targetPath
});
```
#### defineNpmPackage
生成一个 npm 包资源类型的模板
- options {object}
- npmPackage { string } npm 包名
- targetPath { string } 需要拷贝到的目录
- npmClient { string } 可选,默认为 npm
**示例**
```ts
const npmGenerator = new LightGenerator().defineNpmPackage({
npmPackage: 'egg-boilerplate-simple',
targetPath
});
```
## Add custom copy rule
生成器可以在生成完模板文件后,做一些自定义的操作,比如替换内容,修改文件名等。
简单的来说,规则是一个函数,参数为当前文件路径,用于对当前文件进行操作。
**示例**
```ts
import {LightGenerator} from 'light-generator';
const customRule = async (currentFilePath) => {
// TODO
}
const generator = new LightGenerator({
copyRule: [customRule]
});
```
内置了一些默认规则,比如
- ignoreRule: 用于一些可能会被忽略的文件,在模板文件前缀加入下划线(_),执行此规则会移除该下划线
- replaceRule: 用于替换文本内容
这些规则默认已经内置,并且生效。
**示例**
```ts
import {LightGenerator, ignoreRule} from 'light-generator';
const generator = new LightGenerator({
copyRule: [ignoreRule]
});
```
如果不希望这些规则生效,请在初始化时关闭,并自行传递规则。
**示例**
```ts
import {LightGenerator, ignoreRule} from 'light-generator';
const generator = new LightGenerator({
disableDefaultRule: true,
copyRule: [ignoreRule]
});
```
## 模板规则
默认情况下,会拷贝整个模板目录的内容到目标目录,但是在 `package.json` 中加入 `boilerplateConfig` 段落可以额外配置这个行为。
```json
{
"boilerplateConfig": {
"root": "template",
"replaceParameter": "index.js",
"replaceFile": [
"src/index.ts"
]
}
}
```
参数
- root { string } 设置模板根路径,相对于包根路径,如果配置了 `boilerplateConfig` 字段,默认为 `boilerplate` 目录
- replaceParameter { string } 用户可替换参数文件路径,相对于包根路径,默认为 `index.js`
- replaceFile { string | string []} 需要替换的文件列表,默认为 `README.md`,相对于 root
## 其他
此模块核心代码从 serverless 模块中抽取。
此模块部分核心代码从 serverless 模块中抽取。

@@ -1,8 +0,7 @@

import untildify from 'untildify';
import { join } from 'path';
import { downloadTemplateFromRepo } from './util/download';
import { dirExistsSync } from './util/dirExistsSync';
import { DirectoryCopyWarker } from './util/copyDirContents';
import { renameService } from './util/renameService';
import { DirectoryCopyWalker } from './util/copyDirContents';
import { CopyRule, CopyWalker } from './interface';
import { NpmPatternGenerator } from './generator/NpmPatternGenerator';
import { UrlPatternGenerator } from './generator/UrlPatternGenerator';
import { LocalPatternGenerator } from './generator/LocalPatternGenerator';
import { ignoreRule, replaceRule } from './rule';

@@ -15,44 +14,44 @@ export class LightGenerator {

constructor(options: {
templatePath: string;
templateUrl: string;
templateName: string;
targetPath: string;
copyRule: CopyRule[];
}) {
disableDefaultRule: boolean;
copyRule?: CopyRule[];
} = { disableDefaultRule: false }) {
this.options = options;
this.copyWalker = new DirectoryCopyWarker(this.options.copyRule);
this.copyWalker = new DirectoryCopyWalker(this.options);
if (!this.options.disableDefaultRule) {
this.addDefaultCopyRule();
}
}
async run(replaceArgs) {
if ('templateUrl' in this.options) {
const serviceName = await downloadTemplateFromRepo(
this.copyWalker,
this.options[ 'templateUrl' ],
this.options.templateName,
this.options.targetPath
);
const message = [
`Successfully installed "${serviceName}" `,
`${this.options.templateName &&
this.options.templateName !== serviceName ? `as "${this.options.templateName}"` : ''}`,
].join('');
addDefaultCopyRule() {
this.copyWalker.addCopyRule(replaceRule);
this.copyWalker.addCopyRule(ignoreRule);
}
console.log(message);
} else if ('templatePath' in this.options) {
// Copying template from a local directory
const servicePath = this.options.targetPath
? untildify(this.options.targetPath)
: join(process.cwd(), this.options.templateName);
if (dirExistsSync(servicePath)) {
const errorMessage = `A folder named "${servicePath}" already exists.`;
throw new Error(errorMessage);
}
await this.copyWalker.copy(untildify(this.options[ 'templatePath' ]), servicePath, {
noLinks: true,
});
if (this.options.templateName) {
renameService(this.options.templateName, servicePath);
}
}
defineLocalPath(options: { templateName?: string; templatePath: string; targetPath: string; }) {
return new LocalPatternGenerator({
templateUri: options.templatePath,
targetPath: options.targetPath,
templateName: options.templateName,
copyWalker: this.copyWalker,
});
}
defineRemoteUrl(options: { templateUrl: string; targetPath: string; templateName: string; }) {
return new UrlPatternGenerator({
templateUri: options.templateUrl,
targetPath: options.targetPath,
templateName: options.templateName,
copyWalker: this.copyWalker,
});
}
defineNpmPackage(options: { npmPackage: string; targetPath: string; npmClient?: string; }) {
return new NpmPatternGenerator({
templateUri: options.npmPackage,
targetPath: options.targetPath,
copyWalker: this.copyWalker,
npmClient: options.npmClient || 'npm'
});
}
}

@@ -1,5 +0,31 @@

export type CopyRule = (currentFile: string) => void;
export type CopyRule = (currentFile: string, copyRuleOptions: CopyRuleOptions) => void;
export interface CopyWalker {
addCopyRule(copyRule: CopyRule);
copy(srcDir, destDir, options?);
}
export interface CommonGeneratorOptions {
templateUri: string;
targetPath: string;
templateName?: string;
copyWalker: CopyWalker;
}
export interface NpmGeneratorOptions extends CommonGeneratorOptions {
npmClient: string;
}
export interface TemplatePackageConfig {
root: string;
replaceFile: string | string[];
replaceParameter: string | object;
}
export interface CopyRuleOptions {
templateDir: string;
targetDir: string;
targetRelativeFile: string;
replaceParameter: object;
templateConfig: TemplatePackageConfig;
}
import * as fse from 'fs-extra';
import { CopyRuleOptions } from './interface';
import { join } from 'path';
export const ignoreRule = async (currentFilePath) => {
if (/^_/.test(currentFilePath)) {
await fse.rename(currentFilePath, currentFilePath.replace('_', ''));
/**
* 移除文件下划线
* @param currentFilePath
*/
export const ignoreRule = async (currentFilePath, copyRuleOptions: CopyRuleOptions) => {
if (/^_/.test(copyRuleOptions.targetRelativeFile)) {
await fse.rename(currentFilePath, join(copyRuleOptions.targetDir, copyRuleOptions.targetRelativeFile.replace('_', '')));
}
};
export const replaceRule = async (currentFilePath) => {
if (/^_/.test(currentFilePath)) {
await fse.rename(currentFilePath, currentFilePath.replace('_', ''));
const pattern = /\{\{(\w*[:]*[=]*\w+)\}\}(?!})/g;
/**
* 替换文本内容包含 {{}} 的字符串模板
* @param currentFilePath
* @param copyRuleOptions
*/
export const replaceRule = async (currentFilePath, copyRuleOptions: CopyRuleOptions) => {
const replaceArgs = copyRuleOptions.replaceParameter || {};
if (copyRuleOptions.templateConfig.replaceFile.includes(copyRuleOptions.targetRelativeFile)) {
const contents = fse.readFileSync(currentFilePath, 'utf-8')
.replace(pattern, (match, key, value) => {
return replaceArgs[ key ];
});
return fse.writeFileSync(currentFilePath, contents);
}
};

@@ -6,19 +6,38 @@ import * as path from 'path';

export class DirectoryCopyWarker implements CopyWalker {
export class DirectoryCopyWalker implements CopyWalker {
rules;
constructor(rules: CopyRule[] = []) {
this.rules = rules;
constructor(options: {
rules?: CopyRule[]
} = {}) {
this.rules = options.rules || [];
}
async copy(srcDir, destDir, options = {}) {
addCopyRule(rule: CopyRule) {
this.rules.push(rule);
}
async copy(srcDir, destDir, options = {
replaceParameter: {},
templateConfig: {}
}) {
const fullFilesPaths = walkDirSync(srcDir, options);
for (const fullFilePath of fullFilesPaths) {
const relativeFilePath = fullFilePath.replace(srcDir, '');
const relativeFilePath = path.relative(srcDir, fullFilePath);
const targetFilePath = path.join(destDir, relativeFilePath);
await fse.copy(fullFilePath, path.join(destDir, relativeFilePath));
for (const rule of this.rules) {
await rule(targetFilePath);
await rule(targetFilePath, {
templateDir: srcDir,
targetDir: destDir,
replaceParameter: options.replaceParameter,
targetRelativeFile: relativeFilePath,
templateConfig: options.templateConfig || {
root: destDir,
replaceFile: [],
replaceParameter: {},
}
});
}

@@ -25,0 +44,0 @@ }

@@ -5,3 +5,3 @@ import * as URL from 'url';

import * as os from 'os';
import { dirExistsSync } from './dirExistsSync';
import { dirExistsSync } from './fs';
import download from 'download';

@@ -169,8 +169,2 @@ import * as qs from 'querystring';

/**
* @param {string} inputUrl
* @param {string} [templateName]
* @param {string} [path]
* @returns {Promise}
*/
export async function downloadTemplateFromRepo(copyWalker: CopyWalker, inputUrl: string, templateName: string, downloadPath: string) {

@@ -177,0 +171,0 @@ const repoInformation = parseRepoURL(inputUrl);

@@ -16,2 +16,11 @@ import * as fse from 'fs-extra';

export function dirExistsSync(dirPath) {
try {
const stats = fse.statSync(dirPath);
return stats.isDirectory();
} catch (e) {
return false;
}
}
export function readFileSync(filePath) {

@@ -18,0 +27,0 @@ const contents = fse.readFileSync(filePath);

import * as jc from 'json-cycle';
import * as YAML from 'js-yaml';
// import * as _ from 'lodash';
// const cloudFormationSchema = require('../../plugins/aws/lib/cloudformationSchema');
const loadYaml = (contents, options) => {

@@ -26,7 +23,3 @@ let data;

};
let result = loadYaml(contents.toString(), options);
if (result.error && result.error.name === 'YAMLException') {
// _.merge(options, { schema: cloudFormationSchema.schema });
result = loadYaml(contents.toString(), options);
}
const result = loadYaml(contents.toString(), options);
if (result.error) {

@@ -33,0 +26,0 @@ throw result.error;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc