UNPKG

grunt-generate-view-model

Version:
396 lines 21.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDependencyImportsForImports = exports.mapFileClasses = exports.filterFileMetadata = exports.createFieldMetadata = exports.updateFieldMetadataForViewModelTypeDecorator = exports.updateFieldMetadataForViewModelNameDecorator = exports.updateFieldMetadataForIgnoreViewModelDecorator = exports.updateFieldMetadataForIgnoreDecorators = exports.getInfoFromImports = exports.createClassMeta = void 0; /* eslint-disable @typescript-eslint/no-unsafe-assignment */ const fs = __importStar(require("fs")); const ts_file_parser_1 = require("ts-file-parser"); const _1 = require("."); const decorators_1 = require("../model/decorators"); const enums_1 = require("./enums"); const classmetadata_1 = require("../model/classmetadata"); const fieldmetadata_1 = require("../model/fieldmetadata"); const pipes_1 = require("../pipes"); const ignoreDecorators_1 = require("../../tasks/constants/ignoreDecorators"); const transformer_1 = require("./transformer"); const arrayType = '[]'; const baseTypes = ['string', 'number', 'boolean', 'undefined', 'null', 'object']; const filterOnlyIgnoreDecorators = (dec) => dec.name === decorators_1.Decorators.IgnoreDecorators; const whiteListClassDecorators = (dec) => !ignoreDecorators_1.ignoreDecorators.includes(dec.name); const addExtendClassFieldsToClass = (classExtends, baseClass, imports, { currentExtendLevel, maxExtendedLevel }) => { const fields = []; classExtends.forEach((extend) => { const importBaseClass = imports.find(importNode => importNode.clauses.find(clause => clause === extend.basicName)); const extendFileString = fs.readFileSync(`${importBaseClass.absPathString}.ts`, { encoding: 'utf-8' }); const extendFileStructure = ts_file_parser_1.parseStruct(extendFileString, {}, importBaseClass.absPathString); const extendBaseClass = extendFileStructure.classes.find(possibleClass => possibleClass.name === extend.basicName); if (!extendBaseClass) { return; } extendBaseClass.fields.forEach(f => { const fieldExistInCreatedClass = baseClass.fields.find(ff => ff.name === f.name); if (fieldExistInCreatedClass) { return; } // side effect - update base imports to correct import view file; imports.push(...(extendFileStructure._imports || [])); fields.push(f); }); if (currentExtendLevel < maxExtendedLevel && extendBaseClass.extends) { fields.push(...addExtendClassFieldsToClass(extendBaseClass.extends, baseClass, imports, { currentExtendLevel: currentExtendLevel + 1, maxExtendedLevel })); } }); return fields; }; const createClassMeta = (baseClass_, { type, mapperPath, model }, imports, path, maxExtendedLevel) => { const baseClass = Object.assign({}, baseClass_); const classMeta = new classmetadata_1.ClassMetadata(); classMeta.name = _1.upFirstLetter(model); classMeta.fields = []; classMeta.generateView = true; if (mapperPath) { classMeta.needMapper = true; } classMeta.type = type || 'interface'; classMeta.baseName = baseClass.name; classMeta.baseNamePath = path; const options = { currentExtendLevel: 1, maxExtendedLevel }; baseClass.fields.push(...addExtendClassFieldsToClass(baseClass.extends, baseClass_, imports, options)); classMeta.fields = baseClass.fields.map(fld => exports.createFieldMetadata(fld, classMeta, imports)); classMeta.decorators = []; const ignoreClassDecorators = baseClass.decorators.filter(filterOnlyIgnoreDecorators); let otherClassDecorators = baseClass.decorators.filter(whiteListClassDecorators); if (ignoreClassDecorators.length) { ignoreClassDecorators.forEach(ignoreClassDecorator => { const [decoratorsToIgnore, modelsWhereDecoratorWillIgnore] = ignoreClassDecorator.arguments; const modelInBlackList = (modelsWhereDecoratorWillIgnore || []).includes(model); const classDecorators = otherClassDecorators.filter(d => { const decoratorInBlackList = (decoratorsToIgnore || []).includes(d.name); return !(decoratorInBlackList && modelInBlackList); }); otherClassDecorators = classDecorators; }); } classMeta.decorators = otherClassDecorators; const fieldsWithConvertFunctions = classMeta.fields.filter(f => f.fieldConvertFunction); fieldsWithConvertFunctions.forEach(f => { const func = f.fieldConvertFunction; transformer_1.saveInfoAboutTransformer(enums_1.FuncDirection.toView, func, imports, classMeta); transformer_1.saveInfoAboutTransformer(enums_1.FuncDirection.fromView, func, imports, classMeta); }); return classMeta; }; exports.createClassMeta = createClassMeta; const getInfoFromImports = (imports, typeName) => { let isComplexType = true; let isEnum = false; imports.forEach(repeatImport => { if (repeatImport.isNodeModule) { return; } repeatImport.clauses.forEach(cl => { if (cl !== typeName) { return; } const fileName = repeatImport.absPathNode.join('/') + '.ts'; const fileContent = fs.readFileSync(fileName, 'utf-8'); const parsedFile = ts_file_parser_1.parseStruct(fileContent, {}, fileName); if (!parsedFile.enumDeclarations) { return; } const isEnumType = !!parsedFile.enumDeclarations.find(enm => enm.name === typeName); isComplexType = !isEnumType; isEnum = !!isEnumType; }); }); return { isComplexType, isEnum }; }; exports.getInfoFromImports = getInfoFromImports; const updateFieldMetadataForIgnoreDecorators = (ignoreDecorators_, classMeta, fldMetadata, decoratorsOnField, imports) => { const newFldMetadata = Object.assign({}, fldMetadata); const ignoreAllDecoratorsExist = ignoreDecorators_.find(d => { var _a; return ((_a = d.arguments) === null || _a === void 0 ? void 0 : _a.length) === 0; }); const ignoreDecoratorsForFieldArray = ignoreDecorators_.map(dec => dec.arguments[0]) || []; const allIgnoreCustomFields = []; ignoreDecoratorsForFieldArray.forEach((d) => allIgnoreCustomFields.push(...(d || []))); const fieldIgnoreDecorators = [...allIgnoreCustomFields, ...ignoreDecorators_1.ignoreDecorators]; const fieldIgnoreDecoratorsClasses = (ignoreDecorators_.map(dec => dec.arguments[1]) || []); if (!decoratorsOnField || !decoratorsOnField.length) { newFldMetadata.decorators = []; return { fieldMetadata: newFldMetadata, possibleImports: [], }; } const possibleImports = []; newFldMetadata.decorators = decoratorsOnField.filter(dec => { if (ignoreAllDecoratorsExist) { return false; } const isDecoratorAvailableForField = !fieldIgnoreDecorators.includes(dec.name); const isDecoratorAvailableForClass = !fieldIgnoreDecoratorsClasses.includes(classMeta.name); return isDecoratorAvailableForClass && isDecoratorAvailableForField; }); newFldMetadata.decorators.forEach(dec => { const importNode = imports.find(_import => _import.clauses.find(cl => cl === dec.name)); if (!importNode) { return; } possibleImports.push(importNode); }); newFldMetadata.decorators = newFldMetadata.decorators.map(d => { const updatedDecorator = Object.assign({}, d); if (updatedDecorator.arguments && updatedDecorator.arguments.length) { updatedDecorator.arguments = updatedDecorator.arguments.map(a => { if (typeof a === 'object') { return JSON.stringify(a); } return a; }); } return updatedDecorator; }); return { fieldMetadata: newFldMetadata, possibleImports, }; }; exports.updateFieldMetadataForIgnoreDecorators = updateFieldMetadataForIgnoreDecorators; const updateFieldMetadataForIgnoreViewModelDecorator = (decorators, classMeta, fldMetadata) => { if (!decorators || !decorators.length) { return fldMetadata; } const updatedFldMetadata = Object.assign({}, fldMetadata); decorators.forEach(decorator => { const ignoreViewModelName = decorator.arguments[0]; const setIgnoreNameToClass = ignoreViewModelName && ignoreViewModelName.toString() === classMeta.name; const ignoredInView = setIgnoreNameToClass || !ignoreViewModelName; if (ignoredInView && !updatedFldMetadata.ignoredInView) { updatedFldMetadata.ignoredInView = true; } }); return updatedFldMetadata; }; exports.updateFieldMetadataForIgnoreViewModelDecorator = updateFieldMetadataForIgnoreViewModelDecorator; const updateFieldMetadataForViewModelNameDecorator = (decorators, classMeta, fldMetadata) => { if (!decorators || !decorators.length) { return fldMetadata; } const updatedFldMetadata = Object.assign({}, fldMetadata); decorators.forEach(decorator => { const fieldName = decorator.arguments[0]; const modelName = decorator.arguments[1]; const modelNameSetForClass = modelName && modelName.toString() === classMeta.name; if (modelNameSetForClass || !modelName) { updatedFldMetadata.name = fieldName.toString(); } }); return updatedFldMetadata; }; exports.updateFieldMetadataForViewModelNameDecorator = updateFieldMetadataForViewModelNameDecorator; const updateFieldMetadataForViewModelTypeDecorator = (decorators, classMeta, flMetadata, imports) => { try { if (!decorators || !decorators.length) { return { fieldMetadata: flMetadata, possibleImports: [] }; } const updatedFieldMetadata = Object.assign({}, flMetadata); const possibleImports = []; const decorator = decorators.find(decorator_ => { const decoratorArguments = decorator_.arguments[0].valueOf(); return !decoratorArguments.modelName || decoratorArguments.modelName === classMeta.name; }); if (!decorator) { return { fieldMetadata: updatedFieldMetadata, possibleImports }; } const fieldTypeOptions = decorator.arguments[0].valueOf(); updatedFieldMetadata.nullable = !(fieldTypeOptions && typeof fieldTypeOptions.nullable === 'boolean' && !fieldTypeOptions.nullable); updatedFieldMetadata.type = fieldTypeOptions.type.toString(); const isArray = updatedFieldMetadata.type.indexOf(arrayType) > -1; updatedFieldMetadata.isArray = isArray; updatedFieldMetadata.type = isArray ? updatedFieldMetadata.type.substring(0, updatedFieldMetadata.type.indexOf(arrayType)) : updatedFieldMetadata.type; if (updatedFieldMetadata.type.toLowerCase() === 'string' && updatedFieldMetadata.type !== updatedFieldMetadata.baseModelType) { updatedFieldMetadata.type = 'string'; updatedFieldMetadata.toStringWanted = true; } if (!fieldTypeOptions.transformer) { imports.forEach(i => { const filteredClauses = i.clauses.filter(clause => clause === updatedFieldMetadata.baseModelType); filteredClauses.forEach(clause => { if (i.isNodeModule) { const impNode = { isNodeModule: true, clauses: i.clauses, absPathNode: i.absPathNode, absPathString: i.absPathNode.join('/') }; possibleImports.push(impNode); return; } const path = `${(i.absPathNode || []).join('/')}.ts`; const content = fs.readFileSync(path, 'utf-8'); const innerJsonStructure = ts_file_parser_1.parseStruct(content, {}, ''); const filteredClasses = innerJsonStructure.classes.filter(c => c.name === updatedFieldMetadata.baseModelType); filteredClasses.forEach(c => { const generateViewDecorators = c.decorators.filter(d => d.name === decorators_1.Decorators.GenerateView); const sameModelNameDecorators = generateViewDecorators.filter(d => { const generateOptions = d.arguments[0].valueOf(); const baseType = fieldTypeOptions.type.toString(); const viewModelType = fieldTypeOptions.type.toString().indexOf(arrayType) > -1 ? baseType.substring(0, fieldTypeOptions.type.toString().indexOf(arrayType)) : baseType; return generateOptions.model.toLowerCase() === viewModelType.toLowerCase(); }); sameModelNameDecorators.forEach(d => { const generateOptions = d.arguments[0].valueOf(); const fileName = `${_1.upFirstLetter(generateOptions.model)}Mapper`; const mapperImport = { isNodeModule: false, clauses: [fileName], absPathNode: [`${generateOptions.mapperPath}/${fileName}`], absPathString: `${generateOptions.mapperPath}/${fileName}` }; updatedFieldMetadata.needGeneratedMapper = true; possibleImports.push(mapperImport); }); }); }); }); } const transformerExistAndNoNeedMapper = fieldTypeOptions.transformer && !updatedFieldMetadata.needGeneratedMapper; if (!transformerExistAndNoNeedMapper) { return { fieldMetadata: updatedFieldMetadata, possibleImports }; } updatedFieldMetadata.fieldConvertFunction = !updatedFieldMetadata.ignoredInView ? fieldTypeOptions.transformer : null; return { fieldMetadata: updatedFieldMetadata, possibleImports }; } catch (e) { console.error(enums_1.ConsoleColor.Red, `Generate View: Error: updateFieldMetadataForViewModelTypeDecorator: ${e.message}`); throw e; } }; exports.updateFieldMetadataForViewModelTypeDecorator = updateFieldMetadataForViewModelTypeDecorator; // dirty function - update possible imports; const createFieldMetadata = (field, cm, imports) => { let fldMetadata = new fieldmetadata_1.FieldMetadata(); fldMetadata.baseModelName = field.name; fldMetadata.nullable = true; if (field.type.typeKind === ts_file_parser_1.TypeKind.ARRAY) { fldMetadata.isArray = true; } const typeInfo = field.type.base || field.type; let currentBase = field.type.base; fldMetadata.baseModelType = typeInfo.typeName; while (currentBase && currentBase.base !== undefined) { currentBase = currentBase.base; fldMetadata.baseModelType = currentBase.typeName; } const typeName = fldMetadata.baseModelType; const isBaseTypesIncludeTypeName = baseTypes.find(type => type === typeName); if (!isBaseTypesIncludeTypeName) { const fldInfo = exports.getInfoFromImports(imports, typeName); fldMetadata.isComplexType = fldInfo.isComplexType; fldMetadata.isEnum = fldInfo.isEnum; } fldMetadata.name = field.name; fldMetadata.type = fldMetadata.baseModelType; const fieldDecorators = field.decorators; fldMetadata = exports.updateFieldMetadataForIgnoreViewModelDecorator(fieldDecorators.filter(decorator => decorator.name === decorators_1.Decorators.IgnoreViewModel), cm, fldMetadata); fldMetadata = exports.updateFieldMetadataForViewModelNameDecorator(fieldDecorators.filter(decorator => decorator.name === decorators_1.Decorators.ViewModelName), cm, fldMetadata); const _a = exports.updateFieldMetadataForViewModelTypeDecorator(fieldDecorators.filter(decorator => decorator.name === decorators_1.Decorators.ViewModelType), cm, fldMetadata, imports), { fieldMetadata } = _a, rest = __rest(_a, ["fieldMetadata"]); fldMetadata = fieldMetadata; imports.push(...rest.possibleImports); const decUpdate = exports.updateFieldMetadataForIgnoreDecorators(fieldDecorators === null || fieldDecorators === void 0 ? void 0 : fieldDecorators.filter(decorator => decorator.name === decorators_1.Decorators.IgnoreDecorators), cm, fldMetadata, fieldDecorators === null || fieldDecorators === void 0 ? void 0 : fieldDecorators.filter(decorator => !ignoreDecorators_1.ignoreDecorators.includes(decorator.name)), imports); fldMetadata = decUpdate.fieldMetadata; if (fldMetadata.type !== fldMetadata.baseModelType && !baseTypes.includes(fldMetadata.type)) { const fldInfo = exports.getInfoFromImports(imports, fldMetadata.type); fldMetadata.isComplexType = fldInfo.isComplexType; fldMetadata.isEnum = fldInfo.isEnum; } imports.push(...decUpdate.possibleImports); return fldMetadata; }; exports.createFieldMetadata = createFieldMetadata; const filterFileMetadata = (imports, classes) => { const newImports = imports.filter(imp => { const importArray = imp.type.slice(1, imp.type.length - 1).trim().split(','); return !importArray.find(_imp => _imp === classes.baseName); }); return newImports; }; exports.filterFileMetadata = filterFileMetadata; const mapFileClasses = (classes, fileMetadata) => { const newClass = Object.assign({}, classes); newClass.viewModelFromMapper = _1.getModelNameFromPath(fileMetadata.mapperPath, fileMetadata.filename); newClass.baseModelFromMapper = _1.getModelNameFromPath(fileMetadata.mapperPath, fileMetadata.basePath); return newClass; }; exports.mapFileClasses = mapFileClasses; const getDependencyImportsForImports = (_imports, fileMetadata) => { const mapperFileRegexp = /[a-zA-Z]+Mapper/; let imports = [...(_imports || [])]; imports = imports.reduce((prev, cur) => { const curType = cur.type; if (prev.find(i => i.type === curType)) { return [...prev]; } return [...prev, cur]; }, []).map(imp => { let dependencyMappers = []; // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec const mapperMatch = imp.type.match(mapperFileRegexp); if (!mapperMatch) { imp.dependencyMappers = []; return null; } const mapperName = mapperMatch[0]; fileMetadata.classMetadata.fields.forEach(field => { const condition = mapperName.includes(field.type) && field.needGeneratedMapper && !field.ignoredInView; if (!condition) { return; } dependencyMappers.push(field.type); }); dependencyMappers = pipes_1.unique(dependencyMappers); imp.dependencyMappers = dependencyMappers; return imp; }).filter(i => !!i); return imports; }; exports.getDependencyImportsForImports = getDependencyImportsForImports; //# sourceMappingURL=classmeta.js.map