Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/subTemplates/___ClassName___.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Operations } from '../../helpers';

class ___ClassName___ extends Operations {
constructor(start, ___interfaceList___) {
super(start, { ___interfaceList___ });
}
}

export default ___ClassName___;
12 changes: 12 additions & 0 deletions examples/subTemplates/__tests__/___ClassName___.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ___ClassName___ from '../../src/___ClassName___';

let chain = null;

describe.only('___ClassName___', () => {
beforeEach(() => {
chain = new ___ClassName___(_START_, ___interfaceStubs___);
});
it('chain is not null', () => {
expect(chain).not.toBeNull();
});
});
1 change: 1 addition & 0 deletions examples/subTemplates/subTemplates/objectStub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{/*___item___*/}
1 change: 1 addition & 0 deletions examples/subTemplates/subTemplates/plain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
___item___
32 changes: 32 additions & 0 deletions examples/subTemplates/template.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "Operations With Tests",
"variables": [
{
"name": "className",
"style": {
"case": "auto"
}
},
{
"name": "interfaces",
"style": {
"noTransformation": true
},
"subTemplates": [
{
"file": "plain.js",
"as": "interfaceList",
"variableAlias": "item",
"joinChars": ","
},
{
"file": "objectStub.js",
"as": "interfaceStubs",
"variableAlias": "item",
"joinChars": ","
}
]
}
],
"allowExistingFolder": true
}
23 changes: 22 additions & 1 deletion src/model/Variable.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import config from '../utils/config';
import { duplicate } from '../utils/string';
import { AUTO, toCamelCase } from '../utils/identifier';
import { IVariable, IVariableConfigDTO, IIdentifierStyleDTO } from './types';
import {
IVariable,
IVariableConfigDTO,
IIdentifierStyleDTO,
ISubTemplateVariableConfigDTO,
} from './types';

/**
* A variable will be uniquely identified by it's `name` property.
Expand All @@ -15,6 +20,7 @@ export default class Variable implements IVariable {
case: variableCase = AUTO,
prefixUnderscore = 0,
suffixUnderscore = 0,
subTemplates,
} = variableConfigDTO;
const {
noTransformation = void 0,
Expand All @@ -33,6 +39,12 @@ export default class Variable implements IVariable {
prefix: prefix || duplicate('_', prefixUnderscore),
suffix: suffix || duplicate('_', suffixUnderscore),
};

if (subTemplates && subTemplates.length > 0) {
subTemplates.forEach(template => this._subTemplates.set(template.as, template));
}

this.getSubTemplates = this.getSubTemplates.bind(this);
}

public get name(): string {
Expand All @@ -51,11 +63,20 @@ export default class Variable implements IVariable {
this._value = val;
}

public get hasSubTemplates() {
return this._subTemplates.size > 0;
}

public getSubTemplates() {
return this._subTemplates;
}

private normalizeName(name: string): string {
return toCamelCase(name);
}

private _name: string;
private _value: string | undefined;
private _style: IIdentifierStyleDTO;
private _subTemplates = new Map<string, ISubTemplateVariableConfigDTO>();
}
14 changes: 14 additions & 0 deletions src/model/VariableTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@ import { toCamelCase } from '../utils/identifier';
import { IVariableTable, IVariableValueDTO, IVariable } from './types';

export default class VariableTable implements IVariableTable {
constructor() {
this.get = this.get.bind(this);
this.getAliases = this.getAliases.bind(this);
}
public get(variableName: string): IVariable | undefined {
return this._table.get(this.normalizeName(variableName));
}

public getAliases(alias: string): IVariable | undefined {
return this._aliases.get(this.normalizeName(alias));
}

/**
* Add a variable into the variable table.
* If the variable table already has the same variable, cover it with the new one.
*/
public add(variable: IVariable): void {
if (variable.hasSubTemplates) {
variable.getSubTemplates().forEach(subTemplate => {
this._aliases.set(this.normalizeName(subTemplate.as), variable);
});
}
this._table.set(this.normalizeName(variable.name), variable);
}

Expand All @@ -36,4 +49,5 @@ export default class VariableTable implements IVariableTable {
}

private _table = new Map<string, IVariable>();
private _aliases = new Map<string, IVariable>();
}
11 changes: 11 additions & 0 deletions src/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ export interface IIdentifierStyleDTO {
suffix: string;
}

export interface ISubTemplateVariableConfigDTO {
file: string;
as: string;
variableAlias: string;
joinChars: string;
}

export interface IVariableConfigDTO {
name: string;
defaultValue?: string;
Expand All @@ -15,6 +22,7 @@ export interface IVariableConfigDTO {
case?: string;
prefixUnderscore?: number;
suffixUnderscore?: number;
subTemplates?: ISubTemplateVariableConfigDTO[];
}

export interface ITemplateConfigDTO {
Expand All @@ -32,6 +40,8 @@ export interface IVariableValueDTO {

export interface IVariableDTO extends IVariableValueDTO {
style: IIdentifierStyleDTO;
hasSubTemplates: boolean;
getSubTemplates: () => Map<string, ISubTemplateVariableConfigDTO>;
}

export interface IUserInputRequestDTO {
Expand All @@ -57,6 +67,7 @@ export interface IVariable extends IVariableDTO {}

export interface IVariableTable {
get(variableName: string): IVariable | undefined;
getAliases(alias: string): IVariable | undefined;
add(variable: IVariable): void;
delete(variableName: string): void;
variables(): IVariable[];
Expand Down
147 changes: 131 additions & 16 deletions src/worker/CodesGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,33 @@ import { convertIdentifierStyle } from '../utils/identifier';
import { FileAlreadyExistsError } from '../utils/error';
import { trimStart, trimEnd, escapeRegExpSpecialChars } from '../utils/string';
import config from '../utils/config';
import { ITemplate, IVariableTable } from '../model/types';
import { ITemplate, IVariableTable, IVariable, IIdentifierStyleDTO } from '../model/types';
import Variable from '../model/Variable';

const subTemplatesDir = 'subTemplates';
export default class CodesGenerator {
private _template: ITemplate;
private _destDirPath: string;
private _subTemplates: Map<string, string>;

public constructor(template: ITemplate, destDirPath: string) {
this._template = template;
this._destDirPath = destDirPath;
this._subTemplates = new Map();

this.resolveSubTemplate = this.resolveSubTemplate.bind(this);
}

public async execute(): Promise<void> {
const template = this._template;
const baseNames = await this.globDir(template.rootPath);
const srcBaseNames = baseNames.filter(
(fileName: string): boolean => fileName !== config.configFile
(fileName: string): boolean =>
fileName !== config.configFile && fileName.indexOf(subTemplatesDir) < 0
);

await this.loadSubTemplates();

await Promise.all(
srcBaseNames.map((srcBaseName: string) => {
const srcPath = resolvePath(template.rootPath, srcBaseName);
Expand All @@ -34,6 +43,24 @@ export default class CodesGenerator {
);
}

private async loadSubTemplates() {
const encoding = config.encoding;
const template = this._template;
const subTemplatesPath = resolvePath(template.rootPath, subTemplatesDir);
const subTemplateNames = await this.globDir(subTemplatesPath);
if (subTemplateNames && subTemplateNames.length > 0) {
await Promise.all(
subTemplateNames.map(async fileName => {
const content = (await readFile(resolvePath(subTemplatesPath, fileName), {
encoding,
})) as string;
this._subTemplates.set(fileName, content);
return content;
})
);
}
}

private async generate(srcPath: string, destPath: string): Promise<void> {
const exist = existsSync(destPath);
if (exist && !this._template.allowExistingFolder) {
Expand Down Expand Up @@ -70,6 +97,7 @@ export default class CodesGenerator {
}

private globDir(dir: string): Promise<string[]> {
//JRM: Add subtemplate as ignored
const ignore = [...config.ignore, ...this._template.ignore];
return new Promise<string[]>((resolve, reject): void => {
glob('*', { dot: true, cwd: dir, ignore }, (err, matches) => {
Expand All @@ -85,28 +113,115 @@ export default class CodesGenerator {
const varLeft = config.variableLeftBoundary;
const varRight = config.variableRightBoundary;
const varStyle = config.variableStyleBoundary;
const varStylePatternStr = escapeRegExpSpecialChars(varStyle);
let pattern;
if (varLeft === '___' && varRight === '___') {
pattern = new RegExp(`___([a-zA-Z\d-${varStylePatternStr}]|[a-zA-Z][_a-zA-Z\d-${varStylePatternStr}]*[a-zA-Z\d-${varStylePatternStr}])___`, "g");
} else {
const varLeftPatternStr = escapeRegExpSpecialChars(varLeft);
const varRightPatternStr = escapeRegExpSpecialChars(varRight);
const patternStr = `${varLeftPatternStr}[_a-zA-Z\\d\\-${varStylePatternStr}]+${varRightPatternStr}`;
pattern = new RegExp(patternStr, 'g');
let pattern = this.buildPattern(varStyle, varLeft, varRight);

const contentWithSubTemplates = this.replaceVariables(
content,
pattern,
variableTable.getAliases,
this.resolveSubTemplate
);

return this.replaceVariables(
contentWithSubTemplates,
pattern,
variableTable.get,
this.convertStyleHelper
);
}

private convertStyleHelper(variable: IVariable, key: string, style: IIdentifierStyleDTO) {
if (!variable) {
return '';
}
if (!variable.value) {
return variable.toString() || '';
}
return convertIdentifierStyle(variable.value, style, key);
}

return content.replace(pattern, (m: string) => {
private replaceVariables(
content: string,
pattern: RegExp,
variableGetter: (key: string) => IVariable | undefined,
resolver: (variable: IVariable, key: string, style: IIdentifierStyleDTO) => string
): string {
const varLeft = config.variableLeftBoundary;
const varRight = config.variableRightBoundary;
const varStyle = config.variableStyleBoundary;
const newContent = content.replace(pattern, (m: string) => {
const key = trimStart(trimEnd(m, varRight), varLeft);
const keyStyle = key.split(varStyle);
const variable = variableTable.get(keyStyle[0]);
const variable = variableGetter(keyStyle[0]) || '';

if (!variable || !variable.value) {
return m;
}

var style = variable.style;
if (keyStyle.length > 1)
style.case = keyStyle[1];
return convertIdentifierStyle(variable.value, style, key);
if (keyStyle.length > 1) style.case = keyStyle[1];

return resolver(variable, key, style);
});
return newContent;
}

private buildPattern(varStyle: string, varLeft: string, varRight: string) {
// const varStylePatternStr = escapeRegExpSpecialChars(varStyle);
let pattern;
if (varLeft === '___' && varRight === '___') {
// /___([a-zA-Zd-:]|[a-zA-Z][_a-zA-Zd-:]*[a-zA-Zd-:])___/;
pattern = /___([a-zA-Z\d-]|[a-zA-Z][_a-zA-Z\d-]*[a-zA-Z\d-])___/g;
// pattern = new RegExp(
// `___([a-zA-Z\d-${varStylePatternStr}]|[a-zA-Z][_a-zA-Z\d-${varStylePatternStr}]*[a-zA-Z\d-${varStylePatternStr}])___`,
// 'g'
// );
} else {
const varLeftPatternStr = escapeRegExpSpecialChars(varLeft);
const varRightPatternStr = escapeRegExpSpecialChars(varRight);
const patternStr = `${varLeftPatternStr}[_a-zA-Z\\d\\-]+${varRightPatternStr}`;
// const patternStr = `${varLeftPatternStr}[_a-zA-Z\\d\\-${varStylePatternStr}]+${varRightPatternStr}`;
pattern = new RegExp(patternStr, 'g');
}
return pattern;
}

private resolveSubTemplate(variable: IVariable, key: string, style: IIdentifierStyleDTO): string {
if (!variable || !variable.value) {
return '';
}
const subTemplateConfig = variable.getSubTemplates().get(key);
if (subTemplateConfig) {
const subTemplateContent =
this._subTemplates.get(subTemplateConfig.file) || 'Bad subtemplate map';
const variableSplits = variable.value.split(',');
const content = variableSplits
.map(v => {
const varName = v.trim();
let pattern = this.buildPattern(
config.variableStyleBoundary,
config.variableLeftBoundary,
config.variableRightBoundary
);

return this.replaceVariables(
subTemplateContent,
pattern,
key =>
(key === subTemplateConfig.variableAlias &&
new Variable({
name: subTemplateConfig.variableAlias,
defaultValue: varName,
style: variable.style,
})) ||
undefined,
this.convertStyleHelper
);
})
.join(subTemplateConfig.joinChars);
console.log('hi');
return content;
}
return '';
}
}
Loading