Skip to content

Instantly share code, notes, and snippets.

@anvilation
Last active August 30, 2021 12:20
Show Gist options
  • Save anvilation/a192dd91ba36e972487503ede3344461 to your computer and use it in GitHub Desktop.
Save anvilation/a192dd91ba36e972487503ede3344461 to your computer and use it in GitHub Desktop.
Smart UI CI / CD - Re-written Yeoman Widget Generator
const chalk = require('chalk');
const esprima = require('esprima');
const escodegen = require('escodegen');
const superb = require('superb');
const yosay = require('yosay');
const _ = require('../shared/lodash-complete');
const Generator = require('yeoman-generator');
-_.extend(Generator.prototype, require('yeoman-generator/lib/actions/install'));
const promptDefaults = {
"widgetDirectory": "hello",
"widgetClassPrefix": "Hello",
"widgetCssClass": "-hello",
"widgetTitle": "Hello",
"widgetDescription": "Simple Widget for the widgets",
"widgetBundle": "drive-all"
}
module.exports = class extends Generator {
constructor(args, opts) {
// Calling the super constructor is important so our generator is correctly set up
super(args, opts);
this.properties = {};
this.option('secret-sauce', {
'default': false
});
// Next, add your custom code
this.option('skip-install', {
desc: 'Skips the "npm install" command after generating the project.',
type: Boolean,
'default': false
});
}
async prompting() {
this.log(yosay(`Let us add a ${superb.random()} ${chalk.red('CS UI Widget')}`));
let modulePrefix = this.config.get('modulePrefix');
let widgetName;
if (this.options['secret-sauce']) {
this.properties = promptDefaults
} else {
this.properties = await this.prompt([
{
type: "input",
name: "projectName",
message: 'CS module name:',
default: 'greetings',
filter: function (value) {
projectName = value;
return _.computerize(value);
}
},
{
type: 'input',
name: 'projectDescription',
message: 'CS module description:',
default: 'CS UI greetings extension module'
},
{
type: 'input',
name: 'modulePrefix',
message: 'RequireJS module prefix:',
default: () => {
return _.computerize(projectName).substring(0, 5);
},
filter: (value) => {
return _.computerize(value);
}
}
]);
}
this.properties = await this.prompt([
{
type: 'input',
name: 'widgetDirectory',
message: 'Widget directory name:',
default: 'hello',
filter: function (value) {
widgetName = _.dottify(value);
return widgetName;
}
},
{
type: 'input',
name: 'widgetClassPrefix',
message: 'Widget class name prefix:',
default: function () {
return _.classify(widgetName);
},
filter: function (value) {
return _.classify(value);
}
},
{
type: 'input',
name: 'widgetCssClass',
message: 'Widget CSS class name:',
default: function () {
return _.dasherize(_.classify(widgetName)).replace(/^-/, '');
},
filter: function (value) {
return _.dasherize(_.classify(value));
}
},
{
type: 'input',
name: 'widgetTitle',
message: 'Widget manifest title:',
default: 'Hello'
},
{
type: 'input',
name: 'widgetDescription',
message: 'Widget manifest descriotion:',
default: 'Welcomes the current user.'
},
{
type: 'input',
name: 'widgetBundle',
message: 'Widget target bundle:',
default: function () {
return modulePrefix + '-all';
}
}
]);
this.properties.modulePrefix = modulePrefix;
}
writing() {
// Widget Files
let name = this.properties.widgetDirectory;
let directory = `src/widgets/${name}`;
this.log(`Writing the widget to "${directory}"`);
this.fs.copy(this.templatePath('src/widgets/widget/widget.manifest.json'), this.destinationPath(`src/widgets/${name}/${name}.manifest.json`));
this.fs.copy(this.templatePath('src/widgets/widget/widget.md'), this.destinationPath(`src/widgets/${name}/${name}.md`));
this.fs.copy(this.templatePath('src/widgets/widget/widget.view.js'), this.destinationPath(`src/widgets/${name}/${name}.view.js`));
this.fs.copy(this.templatePath('src/widgets/widget/impl/widget.css'), this.destinationPath(`src/widgets/${name}/impl/${name}.css`));
this.fs.copy(this.templatePath('src/widgets/widget/impl/widget.hbs'), this.destinationPath(`src/widgets/${name}/impl/${name}.hbs`));
this.fs.copy(this.templatePath('src/widgets/widget/impl/widget.model.factory.js'), this.destinationPath(`src/widgets/${name}/impl/${name}.model.factory.js`));
this.fs.copy(this.templatePath('src/widgets/widget/impl/widget.model.js'), this.destinationPath(`src/widgets/${name}/impl/${name}.model.js`));
this.fs.copy(this.templatePath('src/widgets/widget/impl/nls'), this.destinationPath(`src/widgets/${name}/impl/nls`));
this.fs.copy(this.templatePath('src/widgets/widget/test/widget.mock.js'), this.destinationPath(`src/widgets/${name}/test/${name}.mock.js`));
this.fs.copy(this.templatePath('src/widgets/widget/test/widget.spec.js'), this.destinationPath(`src/widgets/${name}/test/${name}.spec.js`));
this.fs.copy(this.templatePath('src/widgets/widget/test/index.html'), this.destinationPath(`src/widgets/${name}/test/index.html`));
this.log('Widget Files Copied...')
this.log(this.properties)
// extensionsJson
const prefix = this.properties.modulePrefix;
const widgetName = this.properties.widgetDirectory;
const extensionJson = this.destinationPath(`src/${prefix}-extensions.json`);
const content = this.fs.read(extensionJson);
const extensions = JSON.parse(content);
let extension = extensions['csui/models/widget/widget.collection'];
if (!extension) {
extension = extensions['csui/models/widget/widget.collection'] = {};
}
let widgets = extension.widgets;
if (!widgets) {
widgets = extension.widgets = {};
}
let moduleWidgets = widgets[prefix];
if (!moduleWidgets) {
moduleWidgets = widgets[prefix] = []
}
const widgetPath = prefix + '/widgets/' + widgetName
let widget = moduleWidgets.some(function (name) {
return widgetPath === name;
});
if (!widget) {
moduleWidgets.push(widgetPath);
moduleWidgets = moduleWidgets.sort();
}
const extensionsOutput = JSON.stringify(extensions, undefined, 2);
this.fs.write(extensionJson, extensionsOutput);
// bundleIndex
const viewPath = `${widgetPath}/${widgetName}.view`;
const manifestPath = `json!${widgetPath}/${widgetName}.manifest.json`;
const fileName = this.destinationPath(`src/bundles/${this.properties.widgetBundle}.js`);
const bundeIndexContent = this.fs.read(fileName);
var code = esprima.parse(bundeIndexContent, {
tokens: true,
range: true,
comment: true
});
code = escodegen.attachComments(code, code.comments, code.tokens);
traverseCode(code, function (node) {
if (node && node.type === 'CallExpression') {
var callee = node.callee;
if (callee && callee.type === 'Identifier' && callee.name === 'define') {
var parameters = node.arguments;
if (parameters && Array.isArray(parameters) && parameters.length > 0) {
var parameter = parameters[0];
if (parameter && parameter.type === 'ArrayExpression') {
var elements = parameter.elements;
if (!elements) {
elements = parameters.elements = [];
}
if (!elements.some(function (child) {
return child && child.type === 'Literal' && child.value === viewPath;
})) {
elements.push({
type: 'Literal',
value: viewPath,
raw: viewPath
});
}
if (!elements.some(function (child) {
return child && child.type === 'Literal' && child.value === manifestPath;
})) {
elements.push({
type: 'Literal',
value: manifestPath,
raw: manifestPath
});
}
}
}
}
}
});
const output = escodegen.generate(code, {
comment: true,
format: {
indent: { style: ' ' },
preserveBlankLines: true
},
sourceCode: bundeIndexContent
});
this.fs.write(fileName, output);
}
install() {
if (!this.options['skip-install']) {
return;
}
this.installDependencies({
bower: false,
npm: true
})
}
}
function traverseCode(object, visitor) {
if (!object) {
return;
}
if (visitor.call(null, object) === false) {
return false;
}
for (var i = 0, keys = Object.keys(object), count = keys.length; i < count; ++i) {
var child = object[keys[i]];
if (typeof child === 'object' && child !== null) {
if (traverseCode(child, visitor) === false) {
return false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment