///
///
///
const stripBom = require("strip-bom");
import fs = require("fs");
import path = require('path');
import lodash = require('lodash');
import metadata = require('MetadataClasses');
import { ApplicationMenuLocales } from '../flexberry-core/Locales';
import ModelBlueprint from '../flexberry-model/ModelBlueprint';
import CommonUtils from '../flexberry-common/CommonUtils';
const TAB = " ";
const skipConfirmationFunc = require('../utils/skip-confirmation');
module.exports = {
description: 'Generates core entities for flexberry.',
availableOptions: [
{ name: 'metadata-dir', type: String },
{ name: 'skip-confirmation', type: Boolean }
],
supportsAddon: function () {
return false;
},
_files: null,
_generateOnce: [
'.jscsrc',
//'__root__/app.js',
//'__root__/templates/application.hbs',
'__root__/templates/mobile/application.hbs',
],
getFileMap: function() {
let moduleName = this.options.entity && this.options.entity.name || this.packageName;
let fileMapVariables = this._generateFileMapVariables(moduleName, null, this.options);
return this.generateFileMap(fileMapVariables)
},
getTargetFile: function(file: string, fileMap = null): string {
if (!fileMap) {
fileMap = this.getFileMap();
}
let targetFile = String(file);
for (let i of lodash.keys(fileMap)) {
let pattern = new RegExp(i, 'g');
targetFile = targetFile.replace(pattern, fileMap[i]);
}
return targetFile;
},
isDummy: false,
files: function () {
if (this._files) { return this._files; }
this.isDummy = this.options.dummy;
let sitemapFile = path.join(this.options.metadataDir, "application", "sitemap.json");
let sitemap: metadata.Sitemap = JSON.parse(stripBom(fs.readFileSync(sitemapFile, "utf8")));
if (this.project.isEmberCLIAddon() && !this.options.dummy) {
if (sitemap.mobile) {
this._files = CommonUtils.getFilesForGeneration(this, function (v) { return v === "__root__/locales/en/translations.js" || v === "__root__/locales/ru/translations.js"; });
} else {
this._files = CommonUtils.getFilesForGeneration(this, function (v) { return v === "__root__/templates/mobile/application.hbs" || v === "__root__/locales/en/translations.js" || v === "__root__/locales/ru/translations.js"; });
}
} else {
if (sitemap.mobile) {
this._files = CommonUtils.getFilesForGeneration(this, function (v) { return v === "addon/locales/en/translations.js" || v === "addon/locales/ru/translations.js"; });
} else {
this._files = CommonUtils.getFilesForGeneration(this, function (v) { return v === "__root__/templates/mobile/application.hbs" || v === "addon/locales/en/translations.js" || v === "addon/locales/ru/translations.js"; });
}
}
if (this.project.isEmberCLIAddon() || this.options.dummy) {
lodash.remove(this._files, function (v) { return v === "public/assets/images/cat.gif" || v === "public/assets/images/favicon.ico" || v === "public/assets/images/flexberry-logo.png"; });
} else {
lodash.remove(this._files, function (fileName: string) { return fileName.indexOf("tests/dummy/") === 0; });
}
this._excludeIfExists();
return this._files;
},
processFiles(intoDir, templateVariables) {
let skipConfirmation = this.options.skipConfirmation;
if (skipConfirmation) {
return skipConfirmationFunc(this, intoDir, templateVariables);
}
return this._super.processFiles.apply(this, [intoDir, templateVariables]);
},
/**
* Blueprint Hook locals.
* Use locals to add custom template variables. The method receives one argument: options.
*
* @method locals
* @public
*
* @param {Object} options Options is an object containing general and entity-specific options.
* @return {Object} Сustom template variables.
*/
locals: function (options) {
let projectTypeNameCamel = "App";
let projectTypeNameCebab = "app";
if (options.project.pkg.keywords && options.project.pkg.keywords["0"] === "ember-addon") {
options.dummy = true;
projectTypeNameCamel = "Addon";
projectTypeNameCebab = "addon";
}
let coreBlueprint = new CoreBlueprint(this, options);
return lodash.defaults({
projectName: this.project.pkg.name,// for use in files\tests\dummy\app\locales\**\translations.js
children: coreBlueprint.children,// for use in files\__root__\controllers\application.js
routes: coreBlueprint.routes,// for use in files\__root__\router.js
importProperties: coreBlueprint.importProperties,// for use in files\__root__\locales\**\translations.js
formsImportedProperties: coreBlueprint.formsImportedProperties,// for use in files\__root__\locales\**\translations.js
modelsImportedProperties: coreBlueprint.modelsImportedProperties,// for use in files\__root__\locales\**\translations.js
applicationCaption: coreBlueprint.sitemap.applicationCaption,// for use in files\__root__\locales\**\translations.js
applicationTitle: coreBlueprint.sitemap.applicationTitle,// for use in files\__root__\locales\**\translations.js
projectTypeNameCamel: projectTypeNameCamel,// for use in files\ember-cli-build.js
projectTypeNameCebab: projectTypeNameCebab// for use in files\ember-cli-build.js
},
coreBlueprint.lodashVariablesApplicationMenu// for use in files\__root__\locales\**\translations.js
);
},
_excludeIfExists: function () {
let fileMap = this.getFileMap();
let checkIfExists = lodash.intersection(this._files, this._generateOnce);
for (let file of checkIfExists) {
let targetFile = this.getTargetFile(file, fileMap);
if (fs.existsSync(targetFile)) {
lodash.remove(this._files, (v) => v === file);
}
}
}
};
class CoreBlueprint {
children: string;
routes: string;
importProperties: string;
formsImportedProperties: string;
modelsImportedProperties: string;
lodashVariablesApplicationMenu: {};
sitemap: metadata.Sitemap;
constructor(blueprint, options) {
let listFormsDir = path.join(options.metadataDir, "list-forms");
let listForms = fs.readdirSync(listFormsDir);
let editFormsDir = path.join(options.metadataDir, "edit-forms");
let editForms = fs.readdirSync(editFormsDir);
let modelsDir = path.join(options.metadataDir, "models");
let models = fs.readdirSync(modelsDir);
let sitemapFile = path.join(options.metadataDir, "application", "sitemap.json");
let children = [];
let routes = [];
let importProperties = [];
let formsImportedProperties = [];
let modelsImportedProperties = [];
for (let formFileName of listForms) {
let pp: path.ParsedPath = path.parse(formFileName);
if (pp.ext != ".json")
continue;
let listFormFile = path.join(listFormsDir, formFileName);
let content = stripBom(fs.readFileSync(listFormFile, "utf8"));
let listForm: metadata.ListForm = JSON.parse(content);
if (listForm.external)
continue;
let listFormName = pp.name;
routes.push(` this.route('${listFormName}');`);
routes.push(` this.route('${listForm.editForm}',\n { path: '${listForm.editForm}/:id' });`);
routes.push(` this.route('${listForm.newForm}.new',\n { path: '${listForm.newForm}/new' });`);
importProperties.push(`import ${listForm.name}Form from './forms/${listFormName}';`);
formsImportedProperties.push(` '${listFormName}': ${listForm.name}Form`);
}
for (let formFileName of editForms) {
let pp: path.ParsedPath = path.parse(formFileName);
if (pp.ext != ".json")
continue;
let editFormFile = path.join(editFormsDir, formFileName);
let content = stripBom(fs.readFileSync(editFormFile, "utf8"));
let editForm: metadata.EditForm = JSON.parse(content);
if (editForm.external)
continue;
let editFormName = pp.name;
importProperties.push(`import ${editForm.name}Form from './forms/${editFormName}';`);
formsImportedProperties.push(` '${editFormName}': ${editForm.name}Form`);
}
for (let modelFileName of models) {
let pp: path.ParsedPath = path.parse(modelFileName);
if (pp.ext != ".json")
continue;
let model: metadata.Model = ModelBlueprint.loadModel(modelsDir, modelFileName);
if (model.external)
continue;
let modelName = pp.name;
importProperties.push(`import ${model.name}Model from './models/${modelName}';`);
modelsImportedProperties.push(` '${modelName}': ${model.name}Model`);
}
this.sitemap = JSON.parse(stripBom(fs.readFileSync(sitemapFile, "utf8")));
let localePathTemplate: lodash.TemplateExecutor = this.getLocalePathTemplate(options, blueprint.isDummy, "translations.js");
let applicationMenuLocales = new ApplicationMenuLocales("ru", localePathTemplate);
for (let item of this.sitemap.items) {
let childItemExt = new SitemapItemExt(item);
childItemExt.process("forms.application.sitemap", 5);
applicationMenuLocales.push(childItemExt.translation, childItemExt.translationOtherLocales);
children.push(childItemExt.sitemap);
}
this.lodashVariablesApplicationMenu = applicationMenuLocales.getLodashVariablesWithSuffix("ApplicationMenu", 4);
this.children = children.join(", ");
this.routes = routes.join("\n");
this.importProperties = importProperties.join("\n");
this.formsImportedProperties = formsImportedProperties.join(",\n");
this.modelsImportedProperties = modelsImportedProperties.join(",\n");
}
private getLocalePathTemplate(options, isDummy, localePathSuffix: string): lodash.TemplateExecutor {
let targetRoot = "app"
if (options.project.pkg.keywords && options.project.pkg.keywords["0"] === "ember-addon" ) {
targetRoot = isDummy ? path.join("tests/dummy", targetRoot) : "addon";
}
return lodash.template(path.join(targetRoot, "locales", "${ locale }", localePathSuffix));
}
}
class SitemapItemExt {
translation: string;
translationOtherLocales: string;
sitemap: string;
baseItem: metadata.SitemapItem;
constructor(baseItem: metadata.SitemapItem) {
this.baseItem = baseItem;
}
process(parentTranslationProp: string, level: number) {
let translationProp: string
let translationName: string
if (this.baseItem.menuName) {
translationName = this.baseItem.menuName;
} else {
translationName = this.baseItem.link;
}
translationProp = `${parentTranslationProp}.${translationName}`;
let childrenTranslation = [];
let childrenTranslationOtherLocales = [];
let sitemap = [];
if (this.baseItem.children) {
for (let childItem of this.baseItem.children) {
let childItemExt = new SitemapItemExt(childItem);
childItemExt.process(translationProp, level + 1);
childrenTranslation.push(childItemExt.translation);
childrenTranslationOtherLocales.push(childItemExt.translationOtherLocales);
sitemap.push(childItemExt.sitemap);
}
}
let indent: string[] = [];
for (let i = 0; i < level; i++) {
indent.push(TAB);
}
let indentStr = indent.join("");
indent.pop();
let indentStr2 = indent.join("");
let childrenStr = "";
let sitemapChildrenStr = "null";
let childrenOtherLocalesStr = "";
if (childrenTranslation.length>0) {
childrenStr = childrenTranslation.join(",\n");
childrenOtherLocalesStr = childrenTranslationOtherLocales.join(",\n");
sitemapChildrenStr = `[${sitemap.join(", ")}]`;
}
this.translation = `${indentStr2}${this.quote(translationName)}: {\n${indentStr}caption: '${this.escapeValue(this.baseItem.caption)}',\n` +
`${indentStr}title: '${this.escapeValue(this.baseItem.title)}',\n${childrenStr}\n${indentStr2}}`;
this.translationOtherLocales = `${indentStr2}${this.quote(translationName)}: {\n${indentStr}caption: '${this.escapeValue(translationName)}',\n` +
`${indentStr}title: '${this.escapeValue(translationName)}',\n${childrenOtherLocalesStr}\n${indentStr2}}`;
const INDENT = "";
this.sitemap = `{\n${INDENT}${indentStr}link: ${this.quoteIfNotNull(this.baseItem.link)},\n` +
`${INDENT}${indentStr}caption: i18n.t('${translationProp}.caption'),\n` +
`${INDENT}${indentStr}title: i18n.t('${translationProp}.title'),\n` +
`${INDENT}${indentStr}children: ${sitemapChildrenStr}\n${INDENT}${indentStr2}}`;
}
escapeValue(value: string) {
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}
quote(propName: string) {
if (propName.indexOf("-") == -1)
return propName;
return `'${propName}'`;
}
quoteIfNotNull(str: string) {
if (str)
return `'${str}'`;
return "null";
}
}