UNPKG

vue-di-loader

Version:

Vue Dependency Injection Webpack Loader

413 lines 18.6 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var classification_1 = require("../classification"); var globalization_1 = require("../globalization"); var path_1 = require("path"); var xmldom_1 = require("xmldom"); var compiler = require("vue-template-compiler"); var sass_1 = require("sass"); var fs_1 = require("fs"); var ts_simple_ast_1 = require("ts-simple-ast"); var typescript_1 = require("typescript"); var _1 = require("../."); var argumenter_1 = require("@joejukan/argumenter"); var web_kit_1 = require("@joejukan/web-kit"); var RENDER_NAME = "__render__"; var STATIC_RENDER_NAME = "__staticrender__"; var COMPONENTS_NAME = "__components__"; var REGEX_KEY = /\'[\w\-\%\_]+\'(?=\:)|\"[\w\-\%\_]+\"(?=\:)/gm; var REGEX_BEGIN_QUOTE = /^(?:\"|\')/gm; var REGEX_END_QUOTE = /(?:\"|\')$/gm; var REGEX_RENDER = /(?:\'|\")\%\%\%RENDER\%\%\%(?:\'|\")/i; var REGEX_STATIC_RENDER = /(?:\'|\")\%\%\%STATICRENDER\%\%\%(?:\'|\")/i; var REGEX_COMPONENTS = /(?:\'|\")\%\%\%COMPONENTS\%\%\%(?:\'|\")/i; var REGEX_EXTRACT_STRING = /^\s*[\'\"\`](.*)[\'\"\`]\s*$/; var ASTClass = /** @class */ (function (_super) { __extends(ASTClass, _super); function ASTClass() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var _this = _super.call(this) || this; var argue = new argumenter_1.Argumenter(args); _this.path = argue.string; return _this; } Object.defineProperty(ASTClass.prototype, "name", { get: function () { var path = this.path; if (path) { var base = path_1.basename(path); var ext = path_1.extname(path); return base + "." + ext; } }, enumerable: true, configurable: true }); ASTClass.prototype.log = function (value) { _1.log("[ast-class] " + value); }; ASTClass.prototype.toImportDeclaration = function (dependency) { var declaration = { moduleSpecifier: dependency.relative(this.path) }; if (dependency.type === _1.DependencyType.VUE) { if (dependency.defaulted) { declaration.defaultImport = dependency.symbol; } else { declaration.namedImports = [{ name: dependency.symbol }]; } } return declaration; }; ASTClass.prototype.processScript = function () { var source = this.source = this.createSourceFile(this.name); source.insertText(0, this.typescript); var parser = new classification_1.ASTParser(source); var classes = source.getClasses(); var template = this.template; var _loop_1 = function (i) { var cls = classes[i]; var symbol = cls.getName(); // handle decorator var decorator = cls.getDecorator(function (dec) { var name = dec.getName(); var isComp = /Component/i.test(name); return isComp; }); if (decorator) { if (!decorator.isDecoratorFactory()) { decorator.setIsDecoratorFactory(true); } var args = decorator.getArguments(); var arg = (args.length > 0 ? args[0] : decorator.addArgument("{}")); var componentName = void 0; var literal = parser.get('name', arg, ts_simple_ast_1.SyntaxKind.StringLiteral); if (literal) { var parts = REGEX_EXTRACT_STRING.exec(literal.getText()); if (parts && parts.length > 1) { componentName = parts[1]; } } else { componentName = web_kit_1.kebab(symbol); } var renders = compiler.compileToFunctions(_1.preCompile(this_1.template)); var statics = renders.staticRenderFns; var staticStrings = "[ "; for (var j = 0; j < statics.length; j++) { var s = statics[j]; if (j > 0) staticStrings += ", "; staticStrings += "function () { " + _1.functionString(s) + " }"; } staticStrings += " ]"; var imports = new Array(); // imports for (var k in globalization_1.dependencies) { var dependency = globalization_1.dependencies[k]; var name_1 = dependency.name; var symbol_1 = dependency.symbol; if (name_1 !== componentName) { if (globalization_1.configuration.domParsing) { var dom = new xmldom_1.DOMParser(); var doc = dom.parseFromString(template, 'text/html'); if (doc) { var elements = doc.getElementsByTagName(dependency.name); if (elements.length > 0) { imports.push(dependency); } } } else { var regexp = new RegExp("\\<\\s*" + name_1.replace(/\-/, '\\-') + "[\\s\\/\\>]+", 'mi'); if (regexp.test(template)) { imports.push(dependency); } } } } // template variable source.insertVariableStatement(0, { declarationKind: ts_simple_ast_1.VariableDeclarationKind.Const, declarations: [ { name: STATIC_RENDER_NAME, type: "Array<Function>", initializer: staticStrings } ] }); source.insertFunction(0, { name: RENDER_NAME, bodyText: _1.functionString(renders.render) }); var componentsDec = source.insertVariableStatement(0, { declarationKind: ts_simple_ast_1.VariableDeclarationKind.Const, declarations: [ { name: COMPONENTS_NAME, initializer: "{}" } ] }).getDeclarations()[0]; var components_1 = componentsDec.getFirstChildByKind(ts_simple_ast_1.SyntaxKind.ObjectLiteralExpression); imports.forEach(function (imp) { components_1.addPropertyAssignment({ name: "'" + imp.name + "'", initializer: imp.symbol }); }); for (var j = 0; j < imports.length; j++) { var imp = imports[j]; source.insertImportDeclaration(0, this_1.toImportDeclaration(imp)); } // TODO: check if components already existing arg.addPropertyAssignment({ name: 'render', initializer: RENDER_NAME }); arg.addPropertyAssignment({ name: 'staticRenderFns', initializer: STATIC_RENDER_NAME }); arg.addPropertyAssignment({ name: 'components', initializer: COMPONENTS_NAME }); this_1.mounted(cls); this_1.injectHMRVue(source, globalization_1.dependencies[componentName]); } }; var this_1 = this; for (var i = classes.length - 1; i >= 0; i--) { _loop_1(i); } try { source.organizeImports(); source.formatText({ indentSize: 4 }); } catch (ex) { } this.typescript = source.getText(); }; ASTClass.prototype.transpile = function () { this.javascript = typescript_1.transpile(this.typescript, { module: typescript_1.ModuleKind.CommonJS, moduleResolution: typescript_1.ModuleResolutionKind.NodeJs, emitDecoratorMetadata: true, experimentalDecorators: true, allowSyntheticDefaultImports: true, noImplicitUseStrict: true }); }; ASTClass.prototype.load = function (content) { var sfc = this.sfc = compiler.parseComponent(content); this.typescript = sfc.script.content; this.template = sfc.template.content; if (sfc.styles.length > 0) { var style = sfc.styles[0]; this.style = (style.content ? style : undefined); } this.processScript(); this.log("loading content from " + this.path + ":\n" + this.typescript); }; ASTClass.prototype.pitch = function (path) { this.log("pitching (" + path + ")"); var content = fs_1.readFileSync(path, 'utf-8'); content = "<source>" + content + "</source>"; var source = this.createSourceFile(web_kit_1.uuid() + ".ts"); source.insertText(0, content); var parser = new classification_1.ASTParser(source); var classes = source.getClasses(); for (var i = 0; i < classes.length; i++) { var cls = classes[i]; var symbol = cls.getName(); var decorators = cls.getDecorators(); for (var j = 0; j < decorators.length; j++) { var decorator = decorators[j]; if (decorator.getName() === "Component") { var args = decorator.getArguments(); var arg = void 0; if (!Array.isArray(args) || args.length === 0) { arg = decorator.addArgument("{}"); } else { arg = args[0]; } var name_2 = undefined; var literal = parser.get('name', arg, ts_simple_ast_1.SyntaxKind.StringLiteral); if (literal) { var parts = REGEX_EXTRACT_STRING.exec(literal.getText()); if (parts && parts.length > 1) { name_2 = parts[1]; } } else { name_2 = web_kit_1.kebab(symbol); } if (name_2) { globalization_1.dependencies[name_2] = new classification_1.DependencyClass(name_2, symbol, path, cls.isDefaultExport()); return; } } } } }; ASTClass.prototype.inject = function (content) { var source = this.createSourceFile(web_kit_1.uuid() + ".ts"); source.replaceWithText(content); if (!source) return; var finder = new classification_1.ASTParser(source); var declaration = finder.findVariableDeclaration('CombinedVueInstance'); if (!declaration) return; var lastChild = declaration.getLastChild(); var expression = declaration.getFirstChildByKind(ts_simple_ast_1.SyntaxKind.NewExpression); if (!expression) return; var args = expression.getArguments(); if (!args || args.length != 1) return; var arg = args[0]; var object = arg.getFirstChildByKind(ts_simple_ast_1.SyntaxKind.SyntaxList); if (!object) return; var pairs = object.getChildren(); if (!pairs) return; var components; pairs.forEach(function (pair) { var key = pair.getFirstChildByKind(ts_simple_ast_1.SyntaxKind.Identifier); var kind = pair.getKind(); if (key && key.getText() === 'components') { if (kind === ts_simple_ast_1.SyntaxKind.ShorthandPropertyAssignment) { pair.replaceWithText('components: {...components}'); } else if (kind === ts_simple_ast_1.SyntaxKind.PropertyAssignment) { } else { pair.replaceWithText('components: {}'); } components = pair.getFirstChildByKind(ts_simple_ast_1.SyntaxKind.ObjectLiteralExpression); } }); if (!components) { if (object.getLastChild().getKind() !== ts_simple_ast_1.SyntaxKind.CommaToken) { object.addChildText(','); } components = object.addChildText('components: {}')[0].getFirstChildByKind(ts_simple_ast_1.SyntaxKind.ObjectLiteralExpression); } for (var k in globalization_1.dependencies) { var dependency = globalization_1.dependencies[k]; source.addImportDeclaration(this.toImportDeclaration(dependency)); if (dependency.type === _1.DependencyType.VUE) { components.addPropertyAssignment({ name: "'" + dependency.name + "'", initializer: dependency.symbol }); } } this.injectHMREntry(source); source.organizeImports(); source.formatText({ indentSize: 4, }); this.typescript = source.getText(); this.log("after injection in (" + this.path + "):\n" + this.typescript); }; ASTClass.prototype.injectHMREntry = function (source) { if (globalization_1.configuration.hot) { source.addStatements("\n declare let module: any;\n if(module.hot){\n module.hot.accept();\n }\n "); } }; ASTClass.prototype.injectHMRVue = function (source, depenency) { if (globalization_1.configuration.hot) { source.addStatements("\n import { HMRClass } from 'vue-di-kit';\n let hmr = new HMRClass('" + depenency.id + "', " + depenency.symbol + ");\n hmr.hot();\n "); source.formatText({ indentSize: 4 }); } }; ASTClass.prototype.mounted = function (cls) { var _this = this; if (this.style) { // TODO: add business logic to search for @Mounted and @Updated when decorators are supported in vue-di-kit. ['created', 'mounted', 'updated'].forEach(function (name) { var method = cls.getMethod(name); if (method) { var body = method.getBody(); var text = undefined; if (body) { var content = body.getLastChildByKind(ts_simple_ast_1.SyntaxKind.SyntaxList); if (content) { text = content.getText(); } } _this.codeEventMethods(method, text); } else { method = cls.addMethod({ name: name, scope: ts_simple_ast_1.Scope.Public }); _this.codeEventMethods(method); } }); } }; ASTClass.prototype.codeEventMethods = function (method, suffix) { switch (method.getName()) { case 'created': this.codeCreateMethod(method, suffix); break; case 'mounted': case 'updated': this.codeMountedUpdatedMethods(method, suffix); break; } }; ASTClass.prototype.codeMountedUpdatedMethods = function (method, suffix) { if (this.style) { var text = '/* auto generated code for DI styles */\n'; text += "if(this.$el.nodeType == 1 && !this.$DI.styled && this.$DI.style){\n"; text += "this.$el.appendChild( this.$DI.style );\n"; text += "}\n"; if (suffix) { text += '\n/* appended code from previous method implementation */\n'; text += suffix; } method.setBodyText(text); method.formatText({ indentStyle: ts_simple_ast_1.ts.IndentStyle.Smart }); } }; ASTClass.prototype.codeCreateMethod = function (method, suffix) { var text = '/* auto generated code for DI object */\n'; text += "this.$DI = { style: undefined };\n"; if (this.style) { var id = "_style_di_" + Math.floor(10 + 100000 * Math.random()); var css = sass_1.renderSync({ data: this.style.content, includePaths: globalization_1.sass.path }).css.toString(); text += "let " + id + " = document.createElement( 'style' );\n"; text += id + ".appendChild( document.createTextNode( `" + css.replace(/\n/g, ' ').replace(/\s{2,}/g, ' ').trim() + "` ) );\n"; text += id + ".setAttribute('id','" + id + "');\n"; if (this.style.scoped) { text += id + ".setAttribute('scoped', '');\n"; } text += "this.$DI.style = " + id + ";\n"; text += "Object.defineProperty(this.$DI, 'styled', { enumerable: true, get: () =>( document.getElementById('" + id + "') ? true : false) } );\n"; } if (suffix) { text += '\n/* appended code from previous method implementation */\n'; text += suffix; } method.setBodyText(text); method.formatText({ indentStyle: ts_simple_ast_1.ts.IndentStyle.Smart }); }; ASTClass.prototype.addFile = function (path) { ASTClass.addFile(path); }; ASTClass.addFile = function (path) { // TODO: consider HOT loading globalization_1.dependencies[web_kit_1.uuid()] = new classification_1.DependencyClass(path_1.basename(path), path_1.extname(path), path, _1.DependencyType.FILE); }; return ASTClass; }(ts_simple_ast_1.default)); exports.ASTClass = ASTClass; //# sourceMappingURL=ast.class.js.map