mirror of
https://gitlab.silvrtree.co.uk/martind2000/ft.git
synced 2025-01-25 20:56:17 +00:00
289 lines
7.3 KiB
JavaScript
289 lines
7.3 KiB
JavaScript
import {inject} from 'aurelia-dependency-injection';
|
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
|
import mkdirp from 'mkdirp';
|
|
|
|
@inject(Project, CLIOptions, UI)
|
|
export default class ElementGenerator {
|
|
constructor(project, options, ui) {
|
|
this.project = project;
|
|
this.options = options;
|
|
this.ui = ui;
|
|
}
|
|
|
|
execute() {
|
|
return this.ui
|
|
.ensureAnswer(this.options.args[0], 'What is the name of the element? (in hyphen format. ft- will be prefixed automatically)')
|
|
.then(name => {
|
|
let area = 'common/';
|
|
let subarea = 'elements/';
|
|
let fileName = this.project.makeFileName(name);
|
|
let className = this.project.makeClassName(name);
|
|
// let funcName = this.project.makeFunctionName(name);
|
|
|
|
let subDir = (subarea) ? area + '/' + subarea : area;
|
|
let relDir = 'components/' + subDir + '/ft-' + fileName;
|
|
let dir = 'src/' + relDir;
|
|
mkdirp.sync(dir);// quick fix incase parent folder doesn't exist.
|
|
|
|
this.project.locations.push(this.project[dir] = ProjectItem.directory(dir));
|
|
this.project[dir].add(
|
|
ProjectItem.text(`ft-${fileName}.js`, this.generateComponentJsSource(className)),
|
|
ProjectItem.text(`ft-${fileName}.spec.js`, this.generateComponentTestJsSource(className, fileName, relDir)),
|
|
ProjectItem.text(`ft-${fileName}.html`, this.generateComponentHtmlSource(fileName)),
|
|
ProjectItem.text(`ft-${fileName}.md`, this.generateComponentMdSource('ft-' + fileName)),
|
|
);
|
|
|
|
return this.project.commitChanges()
|
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* source for top level component js
|
|
* @param className
|
|
* @returns {string}
|
|
*/
|
|
generateComponentJsSource(className) {
|
|
return `import {bindable, inject} from 'aurelia-framework';
|
|
|
|
@inject(Element)
|
|
export class Ft${className} {
|
|
@bindable nameThisBindable;
|
|
|
|
constructor(element) {
|
|
this.element = element;
|
|
}
|
|
|
|
callBackFunction() {
|
|
this.element.innerHTML = this.nameThisBindable;
|
|
}
|
|
}`;
|
|
}
|
|
|
|
/**
|
|
* source for top level component js unit test
|
|
* @param className
|
|
* @param fileName
|
|
* @returns {string}
|
|
*/
|
|
generateComponentTestJsSource(className, fileName, relDir) {
|
|
return `import {StageComponent} from 'aurelia-testing';
|
|
import {LogManager} from 'aurelia-framework';
|
|
import {bootstrap} from 'aurelia-bootstrapper';
|
|
const logger = LogManager.getLogger('${fileName}');
|
|
|
|
describe('${className}', () => {
|
|
let component;
|
|
let mockStore = {
|
|
dispatch: function(action) {
|
|
expect(action.type).toBeDefined();
|
|
logger.info('actions should have a type: ' + action.type);
|
|
},
|
|
subscribe: function(callback) {
|
|
logger.info('subscription request to the store');
|
|
}
|
|
};
|
|
let beans = { // see configuration/en-us-retail/beans.js for example
|
|
component: {
|
|
${className}: []
|
|
},
|
|
bean: {
|
|
}
|
|
};
|
|
|
|
beforeEach(() => {
|
|
component = StageComponent
|
|
.withResources('${relDir}/ft-${fileName}')
|
|
.inView('<ft-${fileName} id="test1" fund-id="817"></ft-${fileName}>');
|
|
component.configure = (aurelia) => {
|
|
aurelia.container.registerInstance('Store', mockStore);
|
|
aurelia.container.registerInstance('Beans', beans);
|
|
aurelia.use.standardConfiguration()
|
|
.feature('components/common')
|
|
.feature('components/products/common');
|
|
};
|
|
});
|
|
|
|
it('should render something', done => {
|
|
component.create(bootstrap).then(() => {
|
|
const testElement = document.getElementById('test1');
|
|
expect(testElement.innerText).toMatch(/replace me/);
|
|
done();
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
component.dispose();
|
|
});
|
|
});
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* source for top level component html
|
|
* @returns {string}
|
|
*/
|
|
generateComponentHtmlSource(fileName) {
|
|
return `<template>
|
|
<div>ft-${fileName}: replace me</div>
|
|
</template>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* source for reducer
|
|
* @param funcName, fileName
|
|
*/
|
|
generateReducerJsSource(funcName, fileName) {
|
|
return `/**
|
|
* Data Reducer for ${funcName}
|
|
* Takes site specific json data and creates model for components
|
|
* after applying business and presentation logic and data mapping
|
|
*/
|
|
import {LogManager} from 'aurelia-framework';
|
|
|
|
const logger = LogManager.getLogger('${fileName}');
|
|
|
|
export function ${funcName}(state, action) {
|
|
switch (action.type) {
|
|
case 'CHANGE_ME_TO_PROPER_ACTION_NAME_SUCCESS':
|
|
logger.debug('Reducing: CHANGE_ME_TO_PROPER_ACTION_NAME_SUCCESS');
|
|
|
|
return Object.assign({}, state, {
|
|
${funcName}: action.data
|
|
});
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* source for reducer unit test
|
|
* @param funcName
|
|
*/
|
|
generateReducerTestJsSource(funcName, fileName) {
|
|
return `import {${funcName}} from './${fileName}.reducer';
|
|
|
|
describe('${funcName}', () => {
|
|
it('should return unchanged state if action does not apply', done => {
|
|
let action = {
|
|
type: 'ANOTHER_ACTION'
|
|
};
|
|
let oldState = {};
|
|
let newState = ${funcName}(oldState, action, {});
|
|
expect(newState).toBe(oldState);
|
|
done();
|
|
});
|
|
|
|
it('should return some stuff', done => {
|
|
let action = {
|
|
type: 'CHANGE_ME_TO_PROPER_ACTION_NAME_SUCCESS',
|
|
data: {
|
|
stuff: 'some stuff'
|
|
}
|
|
};
|
|
let newState = ${funcName}({}, action, {});
|
|
expect(newState.${funcName}.stuff).toBe('some stuff');
|
|
done();
|
|
});
|
|
});
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* source for reducer
|
|
* @param funcName, fileName
|
|
*/
|
|
generateAppStateReducerJsSource(funcName, fileName) {
|
|
return `/**
|
|
* App State Reducer for ${funcName}
|
|
* Takes application state data and creates model for components
|
|
*/
|
|
import {LogManager} from 'aurelia-framework';
|
|
|
|
const logger = LogManager.getLogger('${fileName}');
|
|
|
|
export function ${funcName}(state, action) {
|
|
switch (action.type) {
|
|
case 'SOME_ACTION':
|
|
logger.debug('Reducing: SOME_ACTION');
|
|
|
|
return Object.assign({}, state, {
|
|
${funcName}: action.data
|
|
});
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* source for reducer unit test
|
|
* @param funcName
|
|
*/
|
|
generateAppStateReducerTestJsSource(funcName, fileName) {
|
|
return `import {${funcName}} from './${fileName}.reducer';
|
|
|
|
describe('${funcName}', () => {
|
|
it('should return unchanged state if action does not apply', done => {
|
|
let action = {
|
|
type: 'ANOTHER_ACTION'
|
|
};
|
|
let oldState = {};
|
|
let newState = ${funcName}(oldState, action, {});
|
|
expect(newState).toBe(oldState);
|
|
done();
|
|
});
|
|
|
|
it('should return some stuff', done => {
|
|
let action = {
|
|
type: 'SOME_ACTION',
|
|
data: {
|
|
stuff: 'some stuff'
|
|
}
|
|
};
|
|
let newState = ${funcName}({}, action, {});
|
|
expect(newState.${funcName}.stuff).toBe('some stuff');
|
|
done();
|
|
});
|
|
});
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* generate markdown stub
|
|
* @param fileName
|
|
* @returns {string}
|
|
*/
|
|
generateComponentMdSource(fileName) {
|
|
return `# ${ fileName }
|
|
|
|
## Usage
|
|
${'```'}html
|
|
<${ fileName} fund-id="817" cid="uniqueId"></${ fileName}>
|
|
${'```'}
|
|
*The cid is guaranteed to be unique to this page even if multiple instances of the component are added to the same page.*
|
|
|
|
## Developer notes
|
|
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* generate sass partial stub
|
|
* @param fileName
|
|
* @returns {string}
|
|
*/
|
|
generateComponentSassSource(fileName, name) {
|
|
return `
|
|
// CSS specific to the ${ fileName } component goes here
|
|
[data-fti-component="${ name }"] {
|
|
|
|
}
|
|
`;
|
|
}
|
|
}
|