diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e69de29 diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..d77f5a5 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,17 @@ +{ + "extends": "airbnb", + "parser": "babel-eslint", + + "env": { + "mocha": true + }, + + "rules": { + "linebreak-style": 0, + "import/no-extraneous-dependencies": 0, + "import/no-unresolved": 0, + "import/prefer-default-export": 0, + "import/extensions": 0, + "no-multi-spaces": 0 + } +} \ No newline at end of file diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..ab8b857 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,16 @@ +[ignore] +/node_modules/* +/lib/.* +/internals/.* +/test/.* + +[include] + +[options] +module.system.node.resolve_dirname=./src +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable +esproposal.export_star_as=enable +esproposal.decorators=ignore +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..789fa54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# IDE & OS specific +.DS_Store +.idea +icon.png + +# Logs +logs +*.log + +# Dependencies +node_modules + +# Coverage +coverage + +# Types +flow-typed/npm/* +!flow-typed/npm/module_vx.x.x.js + +# Release +#lib + +# dsl file tests +test/* + +src/commands-bak.js diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..7396f62 --- /dev/null +++ b/.npmignore @@ -0,0 +1,30 @@ +# IDE & OS specific +.DS_Store +.idea + +# Logs +logs +*.log + +# Dependencies +node_modules + +# Coverage +coverage + +# Types +flow-typed/* + +# Sources, tests and builder files +builder +src +test +internals +.flowconfig +.babelrc +.eslintignore +.eslintrc +.travis.yml +jest.json +renovate.json +rollup.config.js \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ce4c19f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: node_js +node_js: + - "lts/*" + - "node" + +before_script: npm run lint +script: npm run test +after_success: npm run coveralls + +branches: + only: + - master \ No newline at end of file diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 index 7546b73..1d03466 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,20 @@ -MIT License +Copyright (c) 2020 - 2022 Pablo Schaffner -Copyright (c) 2022 Punto Origen SpA +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.hbs b/README.hbs new file mode 100644 index 0000000..941416e --- /dev/null +++ b/README.hbs @@ -0,0 +1,45 @@ +

+ Concepto DSL Logo +

+

A progressive Node.js framework for visually building efficient and scalable nodejs based applications.

+

+ NPM Version + Package License + NPM Downloads + + +

+ +## Description +VueJS + MF module for Concepto DSL + +## Installation + +``` +$ npm install -g @concepto/vue +``` + +## Usage + +```terminal +vue_dsl -s absolute_or_relative_file_to_compile.dsl +``` +## Help: + +```terminal +vue_dsl --help +``` + +## Stay in touch + +- Website - [http://www.puntorigen.com](http://puntorigen.com/) +- Twitter - [@punt0rigen](https://twitter.com/punt0rigen) + +## License + +Concepto is [MIT licensed](LICENSE). + +Concepto DSL - visually create and maintain modern node.js based apps (@vue). + +* * * +© 2020-2022 Pablo Schaffner <pablo@puntorigen.com>. \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index bdf2cf2..941416e --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# vue_dsl -VueJS DSL compiler. Using this CLI you'll be able to create and deploy complete VueJS + MF SPA webapps, created within Concepto DSL IDE. +

+ Concepto DSL Logo +

+

A progressive Node.js framework for visually building efficient and scalable nodejs based applications.

+

+ NPM Version + Package License + NPM Downloads + + +

+ +## Description +VueJS + MF module for Concepto DSL + +## Installation + +``` +$ npm install -g @concepto/vue +``` + +## Usage + +```terminal +vue_dsl -s absolute_or_relative_file_to_compile.dsl +``` +## Help: + +```terminal +vue_dsl --help +``` + +## Stay in touch + +- Website - [http://www.puntorigen.com](http://puntorigen.com/) +- Twitter - [@punt0rigen](https://twitter.com/punt0rigen) + +## License + +Concepto is [MIT licensed](LICENSE). + +Concepto DSL - visually create and maintain modern node.js based apps (@vue). + +* * * +© 2020-2022 Pablo Schaffner <pablo@puntorigen.com>. \ No newline at end of file diff --git a/bin/cli b/bin/cli new file mode 100755 index 0000000..7ffbf78 --- /dev/null +++ b/bin/cli @@ -0,0 +1,173 @@ +#!/usr/bin/env node +process.env.UV_THREADPOOL_SIZE=8*require('os').cpus().length; +//const cli = require('command-line-args'); +const open_console = require('@concepto/console'); +const pkg = require('../package.json'); +const vue = require('../lib/index'); +const mri = require('mri'); +let myArgs = mri(process.argv, { + alias: { + src: ['s','source'], + clean: ['x','clear'], + cpu: ['c','cpu'], + help: ['h','ayuda'], + debug: 'd', + justgit: ['g','justgit'], + nodeploy: ['n','nodeploy'], + deploy: ['p','deploy'], + watch: ['w','watch'], + folder: ['f','folder'], + aws_region: ['aws_region'], + secrets_pass: ['secrets-pass'], + save_password: ['secrets-pass-save'], + silent: ['silent'], + diff_from: ['diff-from'], + export_html: ['export-html'] + }, + boolean: ['clean','debug','justgit','nodeploy'], + default: { + clean:false, + debug:false, + justgit:false, + nodeploy:false + } +}); +delete myArgs._; +if (myArgs.cpu) { + process.env.UV_THREADPOOL_SIZE=8*parseFloat(myArgs.cpu); + delete myArgs.cpu; +} + +let getSerial = function() { + return new Promise(function(resolve,reject) { + let _serial = require('serial-number'); + _serial(function(err,value) { + if (err) reject(err); + resolve(value); + }); + }); +}; + +/* */ +(async () => { + // testing code here + //let file = (myArgs.length>0)?myArgs[0]:'vue.dsl'; + //let debug = (myArgs.length>1)?eval(myArgs[1].trim()):false; + let x_console = new open_console(); + let serial = await getSerial(); + x_console.title({ title:`Concepto VUE_DSL Compiler v${pkg.version}`, titleColor:'brightYellow', color:'green' }); + // + let exists = async function(dir_or_file) { + let fs = require('fs').promises; + try { + await fs.access(dir_or_file); + return true; + } catch(e) { + return false; + } + } + // + let savePassword = async function(args) { + let path = require('path'), fs = require('fs').promises; + let _secret_file = path.join(process.cwd(),'.secrets-pass'); + if (args.src) { + _secret_file = path.join(path.dirname(path.resolve(args.src)),'.secrets-pass'); + } + let encrypt = require('encrypt-with-password'); + if (args.save_password) { + //save the given password to disk and set myArgs.secrets_pass + args.secrets_pass = args.save_password; + let new_content = encrypt.encrypt(args.save_password,serial); + await fs.writeFile(_secret_file,new_content,'utf-8'); + x_console.out({ message:`secret password saved as requested!\n`, color:'brightGreen'}); + } else { + //test if there is a .secrets-pass file, recover encrypted saved pass + if ((await exists(_secret_file))) { + x_console.out({ message:`.secrets-pass file found on current directory`, color:'dim'}); + try { + let fdata = await fs.readFile(_secret_file,'utf-8'); + args.secrets_pass = encrypt.decrypt(fdata,serial); + x_console.out({ message:`.secret-pass read successfully!\n`, color:'brightGreen' }); + } catch(badpass) { + x_console.out({ message:`error reading .secret-pass file (maybe you changed computer?)\n`, color:'brightRed' }); + } + } + } + return args; + }; + let printUsage = function() { + x_console.out({ message:'Usage:', color:'cyan' }); + x_console.out({ message:'vue_dsl [options]', color:'yellow' }); + console.log(''); + //if (myArgs.help) { + x_console.out({ message:'Options:', color:'brightCyan' }); + x_console.out({ message:'-s, --src vue.dsl\t\t(required) relative/absolute vue.dsl file to parse', color:'cyan' }); + x_console.out({ message:'-x, --clean\t\t\tclear cache before compiling', color:'cyan' }); + x_console.out({ message:'-g, --justgit\t\t\tjust create the vue_git.dsl version', color:'cyan' }); + x_console.out({ message:'-p, --deploy [local,eb:x]\tforce change the deploy value', color:'cyan' }); + x_console.out({ message:'-n, --nodeploy\t\t\tdo everything as requested, except launching the terminal', color:'cyan' }); + x_console.out({ message:'-f, --folder name\t\toutput folder name. default: central node text', color:'cyan' }); + x_console.out({ message:'-c, --cpu [float]\t\tamount of cpus to use. default:'+require('os').cpus().length, color:'cyan' }); + x_console.out({ message:'-w, --watch\t\t\tkeep watching for file changes to given file after compilation', color:'cyan' }); + x_console.out({ message:'-d, --debug\t\t\tturns verbose logging on', color:'cyan' }); + x_console.out({ message:'-h, --help\t\t\tthis console output', color:'cyan' }); + console.log(''); + x_console.out({ message:'Special options:', color:'brightYellow' }); + x_console.out({ message:'--aws_region\t\t\tAWS region overwrite (default:us-east-1)', color:'yellow' }); + x_console.out({ message:'--secrets-pass [string]\t\tSecret password for encrypting / decrypting config->secrets', color:'yellow' }); + x_console.out({ message:'--secrets-pass-save [string]\tSave to disk the given secret password encrypted', color:'yellow' }); + x_console.out({ message:'--diff-from [file]\t\tCreates a vue_diff.dsl file with the differences between the --source file and this one', color:'yellow' }); + x_console.out({ message:'--export-html [file]\t\tCreates an html representation of given dsl file within the specified directory', color:'yellow' }); + x_console.out({ message:'--silent\t\t\tCompiles in the most quiet mode posible (CI default mode)', color:'yellow' }); + console.log(''); + //} + //copyright + x_console.out({ message:`Copyright © 2022, Pablo Schaffner. All rights reserved.`, color:'dim' }); + }; + //detect if there is a vue.dsl file in current dir and src was not specified + if (!myArgs.src) { + let path = require('path'); + let test = path.join(process.cwd(),'vue.dsl'); + if ((await exists(test))) { + myArgs.src = test; + x_console.out({ message:`vue.dsl file found on current directory, using it as source`, color:'dim'}); + } + } + //save or recover password + myArgs = await savePassword(myArgs); + if (myArgs.help || !myArgs.src) { + printUsage(); + } else { + if (myArgs.src) { + let base = new vue(myArgs.src,myArgs); + await base.init(); + await base.addCommands(require('../lib/commands.js')); + await base.process(); + console.log('total time passed, since constructor: '+base.secsPassed_()); + if (myArgs.watch) { + const fs = require('fs'); + x_console.title({ title:`watching for file changes ...`, color:'dim'}); + //console.log('watching for file changes ...'); + fs.watchFile(myArgs.src, async function(curr,prev) { + x_console.clear(); + x_console.out({ message:`file changed, recompiling ...`, color:'yellow'}); + base.abortProcessing(); + let base2 = new vue(myArgs.src,{...myArgs,...{ + nodeploy:true + }}); + await base2.init(); + await base2.addCommands(require('../lib/commands.js')); + await base2.process(); + console.log('total time passed, since constructor: '+base2.secsPassed_()); + x_console.title({ title:`watching for file changes ...`, color:'dim'}); + }.bind(base)); + } + } else { + console.log('--src requires a file to be specified!') + printUsage(); + } + } +})().catch(err => { + console.error(err); +}); +/* */ \ No newline at end of file diff --git a/build/config.gypi b/build/config.gypi new file mode 100644 index 0000000..b15aeb3 --- /dev/null +++ b/build/config.gypi @@ -0,0 +1,86 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [], + "msvs_configuration_platform": "ARM64", + "xcode_configuration_platform": "arm64" + }, + "variables": { + "asan": 0, + "coverage": "false", + "dcheck_always_on": 0, + "debug_nghttp2": "false", + "debug_node": "false", + "enable_lto": "false", + "enable_pgo_generate": "false", + "enable_pgo_use": "false", + "error_on_warn": "false", + "force_dynamic_crt": 0, + "host_arch": "arm64", + "icu_data_in": "../../deps/icu-tmp/icudt69l.dat", + "icu_endianness": "l", + "icu_gyp_path": "tools/icu/icu-generic.gyp", + "icu_path": "deps/icu-small", + "icu_small": "false", + "icu_ver_major": "69", + "is_debug": 0, + "llvm_version": "12.0", + "napi_build_version": "8", + "node_byteorder": "little", + "node_debug_lib": "false", + "node_enable_d8": "false", + "node_install_npm": "true", + "node_module_version": 93, + "node_no_browser_globals": "false", + "node_prefix": "/", + "node_release_urlbase": "https://nodejs.org/download/release/", + "node_shared": "false", + "node_shared_brotli": "false", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_nghttp2": "false", + "node_shared_nghttp3": "false", + "node_shared_ngtcp2": "false", + "node_shared_openssl": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_target_type": "executable", + "node_use_bundled_v8": "true", + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_node_code_cache": "true", + "node_use_node_snapshot": "true", + "node_use_openssl": "true", + "node_use_v8_platform": "true", + "node_with_ltcg": "false", + "node_without_node_options": "false", + "openssl_fips": "", + "openssl_is_fips": "false", + "openssl_quic": "true", + "ossfuzz": "false", + "shlib_suffix": "93.dylib", + "target_arch": "arm64", + "v8_enable_31bit_smis_on_64bit_arch": 0, + "v8_enable_gdbjit": 0, + "v8_enable_i18n_support": 1, + "v8_enable_inspector": 1, + "v8_enable_lite_mode": 0, + "v8_enable_object_print": 1, + "v8_enable_pointer_compression": 0, + "v8_no_strict_aliasing": 1, + "v8_optimized_debug": 1, + "v8_promise_internal_field_count": 1, + "v8_random_seed": 0, + "v8_trace_maps": 0, + "v8_use_siphash": 1, + "want_separate_host_toolset": 0, + "xcode_version": "12.0", + "nodedir": "/Users/pabloschaffner/Library/Caches/node-gyp/16.1.0", + "standalone_static_library": 1 + } +} diff --git a/jest.json b/jest.json new file mode 100644 index 0000000..3a8c161 --- /dev/null +++ b/jest.json @@ -0,0 +1,5 @@ +{ + "collectCoverage": true, + "collectCoverageFrom": ["src/**"], + "coverageReporters": ["json", "lcov", "text-summary", "html"] +} \ No newline at end of file diff --git a/lib/assets/aws.png b/lib/assets/aws.png new file mode 100644 index 0000000..5519ef5 Binary files /dev/null and b/lib/assets/aws.png differ diff --git a/lib/assets/po.png b/lib/assets/po.png new file mode 100644 index 0000000..359fa37 Binary files /dev/null and b/lib/assets/po.png differ diff --git a/lib/commands.js b/lib/commands.js new file mode 100644 index 0000000..79fd791 --- /dev/null +++ b/lib/commands.js @@ -0,0 +1,6636 @@ +module.exports = async function(context) { + // context.x_state; shareable var scope contents between commands and methods. + String.prototype.replaceAll = function(strReplace, strWith) { + // See http://stackoverflow.com/a/3561711/556609 + var esc = strReplace.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + var reg = new RegExp(esc, 'ig'); + return this.replace(reg, strWith); + }; + + String.prototype.cleanLines = function() { + var esc = '\n'.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + var reg = new RegExp(esc, 'ig'); + return this.replace(reg, '').trim(); + }; + + String.prototype.contains = function(test) { + if (typeof this === 'string' && this.indexOf(test) != -1) { + return true; + } else { + return false; + } + }; + + String.prototype.right = function(chars) { + return this.substr(this.length-chars); + }; + + function setImmediatePromise() { + //for preventing freezing node thread within loops (fors) + return new Promise((resolve) => { + setImmediate(() => resolve()); + }); + } + // + let null_template = { + hint: 'Allowed node type that must be ommited', + func: async function(node, state) { + return context.reply_template({ + hasChildren: false, + state + }); + } + }; + const parseInputOutput = async function(node,state) { + //get vars and attrs + let tmp = { var:'', original:'' }; + if (node.text.includes(',')) tmp.var = node.text.split(',').pop().trim(); + //prepare new var + if (tmp.var.includes('$')) { + if (state.from_server) { + tmp.var = tmp.var.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + tmp.var = tmp.var.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$config.', 'this.$config.') + .replaceAll('$store.', 'this.$store.state.'); + if (tmp.var=='this.') tmp.var='this'; + } + } + //prepare original var + tmp.original = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }); + if (tmp.original.includes('**') && node.icons.includes('bell')) { + tmp.original = getTranslatedTextVar(tmp.original); + } else if (tmp.original.includes('$')) { + if (state.from_server) { + tmp.original = tmp.original.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + tmp.original = tmp.original.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$config.', 'this.$config.') + .replaceAll('$store.', 'this.$store.state.'); + if (tmp.original=='this.') tmp.original='this'; + } + } + return { input:tmp.original, output:tmp.var }; + }; + + const getTranslatedTextVar = function(text,keep_if_same=false) { + let vars = context.dsl_parser.findVariables({ + text, + symbol: `**`, + symbol_closing: `**` + }); + //console.log('translated text:'+text,vars); + let new_vars = context.dsl_parser.replaceVarsSymbol({ + text, + from: { + open: `**`, + close: `**` + }, + to: { + open: '${', + close: '}' + } + }); + //console.log('translated new_vars text:'+text,new_vars); + if ('${' + vars + '}' == new_vars) { + if (keep_if_same==true) return text; + return vars; + } else { + return `\`${new_vars}\``; + } + }; + // process our own attributes_aliases to normalize node attributes + const aliases2params = function(x_id, node, escape_vars, variables_to='') { + let params = { + refx: node.id + }, + attr_map = {}; + // read x_id attributes aliases + if ('attributes_aliases' in context.x_commands[x_id]) { + let aliases = context.x_commands[x_id].attributes_aliases; + Object.keys(aliases).map(function(key) { + aliases[key].split(',').map(alternative_key => { + attr_map[alternative_key] = key + }); + }); + } + // process mapped attributes + Object.keys(node.attributes).map(function(key) { + let value = node.attributes[key]; + let key_use = key.trim(); + if (key_use.charAt(0)==':') key_use = key_use.right(key_use.length-1); + let keytest = key_use.toLowerCase(); + let tvalue = value.toString().replaceAll('$variables.', variables_to) + .replaceAll('$vars.', variables_to) + .replaceAll('$params.', variables_to) + .replaceAll('$config.', variables_to+'$config.') + .replaceAll('$store.', variables_to+'$store.state.').trim(); + if (tvalue.charAt(0)=='$' && tvalue.includes('$store')==false && tvalue.includes('$event')==false && tvalue.includes('$config')==false) { + tvalue = tvalue.right(tvalue.length-1); + } + // + //tvalue = getTranslatedTextVar(tvalue); + if (keytest == 'props') { + value.split(' ').map(x => { + params[x] = null + }); + } else if (keytest in attr_map && value != tvalue) { + // value contains a variable + if (attr_map[keytest]=='v-model') { + params[attr_map[keytest]] = tvalue; + } else { + params[`:${attr_map[keytest]}`] = tvalue; + } + } else if (tvalue=='$event') { + params[key_use] = tvalue; + + } else if (keytest in attr_map) { + // literal value + params[attr_map[keytest]] = tvalue; + } else { + // this is an attribute key that is not mapped + if (value != tvalue || value[0]=="$" || value[0]=="!" || key.charAt(0)==':' ) { + if (escape_vars && escape_vars==true) { + tvalue = tvalue.replaceAll('{{','').replaceAll('}}',''); + } + if (keytest!='v-model') { + params[`:${key_use}`] = tvalue; + } else { + params[key_use] = tvalue; + } + } else { + params[key_use] = tvalue; + } + } + //@todo remove : if tvalue is $event + }); + // + return params; + }; + + return { + //'cancel': {...null_template,...{ x_icons:'button_cancel'} }, + 'meta': {...null_template, ...{ + name: 'VueJS / Vuetify / MF', + version: '0.0.1', + x_level: '2000', + language: 'es', + autocomplete: { + theme: { + table_bgcolor: "#AAD3F3", + tr0_bgcolor: "#AAD3F3", + tr_bgcolor: "#AAD3F3", + tr_inherited_bgcolor: "#D2D2D2", + cellpadding: 2, + cellspacing: 0, + } + } + } + }, + 'def_config': {...null_template, + ... { + x_icons: 'desktop_new', + x_level: '2', + x_text_contains: 'config' + } + }, + 'def_modelos': {...null_template, + ... { + x_icons: 'desktop_new', + x_level: '2', + x_text_contains: 'modelos' + } + }, + 'def_assets': {...null_template, + ... { + x_icons: 'desktop_new', + x_level: '2', + x_text_contains: 'assets' + } + }, + + + // ******************** + // Express Methods + // ******************** + + 'def_server': { + x_icons: 'desktop_new', + x_level: '2', + x_text_contains: 'server|servidor|api', + hint: 'Representa a un backend integrado con funciones de express.', + func: async function(node, state) { + let resp = context.reply_template(); + context.x_state.npm = {...context.x_state.npm, + ... { + 'body_parser': '*', + 'cookie-parser': '*' + } + }; + context.x_state.central_config.static = false; + return resp; + } + }, + 'def_server_path': { + x_icons: 'list', + x_level: '3,4', + x_or_hasparent: 'def_server', + x_not_icons: 'button_cancel,desktop_new,help', + hint: 'Carpeta para ubicacion de funcion de servidor', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + //console.log('def_server_path DEBUG',node); + let test1 = await context.isExactParentID(node.id, 'def_server_path'); + if (node.level == 3) { + //state.current_folder = node.text; + resp.state.current_folder = node.text; + } else if (node.level == 4 && test1==true) { + let parent_node = await context.dsl_parser.getParentNode({ + id: node.id + }); + //state.current_folder = `${parent_node.text}/${node.id}`; + resp.state.current_folder = `${parent_node.text}/${node.text}`; + } else { + resp.valid = false; + } + return resp; + } + }, + 'def_server_func': { //@TODO finish incomplete + x_empty: 'icons', + x_level: '3,4,5', + x_or_hasparent: 'def_server', + hint: 'Corresponde a la declaracion de una funcion de servidor', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + context.x_state.central_config.static = false; //server func cannot run in a static site + resp.state.current_func = node.text; + if (node.level != 2) { + let new_name = resp.state.current_folder?resp.state.current_folder.split('/'):[]; + resp.state.current_func = [...new_name,node.text].join('_'); + //console.log('@TODO! def_server_func: new_name',new_name); + } + // set function defaults + if (!context.x_state.functions[resp.state.current_func]) { + context.x_state.functions[resp.state.current_func] = { + tipo: 'web', + acceso: '*', + params: '', + param_doc: {}, + doc: node.text_note, + method: 'get', + return: '', + path: '/' + (resp.state.current_folder?resp.state.current_folder+'/':'') + node.text, + imports: {} + }; + } + // process attributes + Object.keys(node.attributes).map(function(keym) { + let key = keym.toLowerCase(); + if ([':type', 'type', 'tipo', ':tipo',':method','method'].includes(key)) { + context.x_state.functions[resp.state.current_func].method = node.attributes[key]; + } else { + if (key.includes(':')) { + context.x_state.functions[resp.state.current_func].param_doc[key.split(':')[0]] = { type:key.split(':')[1], desc:node.attributes[key] }; + } else { + context.x_state.functions[resp.state.current_func][key.toLowerCase().trim()] = node.attributes[key]; + } + } + // + }); + // write tag code + resp.open = context.tagParams('func_code', { + name: resp.state.current_func, + method: context.x_state.functions[resp.state.current_func].method, + path: context.x_state.functions[resp.state.current_func].path + }, false) + '\n'; + resp.close = ''; + // + return resp; + } + }, + + // ************************* + // VueX STORES definitions + // ************************* + 'def_store': { + x_icons: 'desktop_new', + x_level: '2', + x_text_contains: 'store', + hint: 'Representa una coleccion de stores de Vue', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + return resp; + } + }, + 'def_store_def': { + x_empty: 'icons', + x_level: '3', + x_all_hasparent: 'def_store', + hint: 'Representa a una definicion de store de VueX', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { + type: 'normal', + version: '', + expire: '' + }; + // create store in app state if not already there + resp.state.current_store = node.text; + if (!context.x_state.stores) context.x_state.stores = {}; + if (context.x_state.stores && node.text in context.x_state.stores === false) context.x_state.stores[node.text] = {}; + Object.keys(node.attributes).map(function(keym) { + let key = keym.toLowerCase(); + if ([':type', 'type', 'tipo', ':tipo'].includes(key)) { + // store type value + if (['sesion', 'session'].includes(node.attributes[key])) { + tmp.type = 'session'; + context.x_state.npm['nuxt-vuex-localstorage'] = '*'; // add npm to app package + } else if (['local', 'persistent', 'persistente', 'localstorage', 'storage', 'db', 'bd'].includes(node.attributes[key])) { + tmp.type = 'local'; + context.x_state.npm['nuxt-vuex-localstorage'] = '*'; + } + + } else if (['version', ':version'].includes(key)) { + tmp.version = node.attributes[key]; + + } else if (['expire', ':expire', 'expira', ':expira'].includes(key)) { + tmp.expire = node.attributes[key]; + } + // + }); + // set store type, version and expire attributes for app state + //if (!context.x_state.stores_types) context.x_state.stores_types={ versions:{}, expires:{} }; + // prepare stores_type, and keys local or session. + if (context.x_state.stores_types && tmp.type in context.x_state.stores_types === false) context.x_state.stores_types[tmp.type] = {}; + if (resp.state.current_store in context.x_state.stores_types[tmp.type] === false) context.x_state.stores_types[tmp.type][resp.state.current_store] = {}; + // set version value + if (tmp.version != '') { + if (resp.state.current_store in context.x_state.stores_types['versions'] === false) context.x_state.stores_types['versions'][resp.state.current_store] = tmp.version; + } + // set expire value + if (tmp.expire != '') { + if (resp.state.current_store in context.x_state.stores_types['expires'] === false) context.x_state.stores_types['expires'][resp.state.current_store] = tmp.expire; + } + // return + resp.state.from_script = true; + return resp; + } + }, + + 'def_store_field': { + x_empty: 'icons', + x_level: '>3', + x_all_hasparent: 'def_store_def', + hint: 'Representa al campo de un store de VueX', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { type:'string', default:'', text:node.text.trim() }; + if (node.text.indexOf(':')!=-1) { + tmp.type = tmp.text.split(':').slice(-1)[0]; + tmp.text = tmp.text.split(':')[0]; + } + // parse attributes + Object.keys(node.attributes).map(function(keym) { + let key = keym.toLowerCase(); + if ([':def',':default','valor','value'].includes(key)) { + tmp.default =node.attributes[keym].toLowerCase(); + } else if ([':tipo',':type','tipo','type'].includes(key)) { + tmp.type =node.attributes[keym].toLowerCase(); + } + }); + // set + if (resp.state.current_store in context.x_state.stores) { + context.x_state.stores[resp.state.current_store][tmp.text.trim()] = {default:tmp.default,type:tmp.type}; + } else { + context.x_state.stores[resp.state.current_store] = {}; + context.x_state.stores[resp.state.current_store][tmp.text.trim()] = {default:tmp.default,type:tmp.type}; + } + // return + return resp; + } + }, + + 'def_store_mutation': { + x_level: '>3', + x_icons: 'help', + x_not_text_contains: 'condicion ', + x_all_hasparent: 'def_store', + attributes_aliases: { + 'params': ':params,params' + }, + hint: 'Representa la modificacion de un store de VueX', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let params = aliases2params('def_store_mutation',node); + resp.state.current_store_mutation = node.text.trim(); + let cur_store = context.x_state.stores[resp.state.current_store]; + if (!(':mutations' in cur_store)) { + context.x_state.stores[resp.state.current_store][':mutations']={}; + } + context.x_state.stores[resp.state.current_store][':mutations'][resp.state.current_store_mutation] = params; + resp.open = context.tagParams('store_mutation', { + store: resp.state.current_store, + mutation: resp.state.current_store_mutation, + ...params + }, false) + '\n'; + resp.close = ''; + return resp; + } + }, + + 'def_store_modificar': { + x_level: '>4', + x_icons: 'desktop_new', + x_all_hasparent: 'def_store_mutation', + x_text_contains: 'modificar', + hint: 'Comando para modificar los valores del state del store padre', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let safe = require('safe-eval'); + // parse attributes + Object.keys(node.attributes).map(function(keym) { + let key = keym.trim(); + let value = node.attributes[keym]; + let tmp = { val:'' }; + if (value=='{now}') { + resp.open += `state.${key} = new Date()\n`; + } else if (value=='') { + let val = ''; + if (key in context.x_state.stores[state.current_store]) { + val = context.x_state.stores[state.current_store][key].default; + } + if (val=='') val=`''`; + resp.open += `state.${key} = ${val}\n`; + } else if (value.includes('**')) { + // preprocess value + let val = value.trim(); + if (node.icons.includes('bell')) { + val = getTranslatedTextVar(value); + } + if (val=='') val=`''`; + if (val.includes('this.') || val.includes('params.')) { + val = val.replaceAll('this.','').replaceAll('params.',''); + resp.open += `state.${key} = objeto.${val}\n`; + } else { + resp.open += `state.${key} = ${val}\n`; + } + } else if (value.includes('!')==false && safe(value)!==''+value) { + // if val is string + resp.open += `state.${key} = ${value}\n`; + } else { + //if val is not a string + if (value!='' && value.charAt(0)=='!' && value.includes('.')==false) { + resp.open += `state.${key} = !state.${key}\n`; + } else if (value!='' && value.charAt(0)=='!') { + // @TODO name = !store.name + } + } + }); + return resp; + } + }, + + 'def_store_call': { + x_level: '>1', + x_icons: 'desktop_new', + x_text_contains: 'store:', + x_or_hasparent: 'def_event_element,def_event_method,def_event_server,def_condicion,def_otra_condicion,def_event_mounted,def_variables_watch', + hint: 'Representa al llamdo de un evento de un store', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let store = node.text.split(' ')[0].replaceAll('store:','').trim(); + let params = {}; + //let isProxySon = (context.hasParentID(node.id, 'def_proxy_def')==true)?true:false; + let isProxySon = ('current_proxy' in resp.state)?true:false; + let method = context.dsl_parser.findVariables({ + text: node.text, + symbol: '"', + symbol_closing: '"' + }).trim(); + Object.keys(node.attributes).map(function(keym) { + let key = keym.trim(); + let value = node.attributes[keym]; + value = value.replaceAll('$variables.','this.') + .replaceAll('$vars.','$this.') + .replaceAll('$params.','this.') + .replaceAll('$env.','$config.'); + if (value.includes('$store.')) { + if (isProxySon==true) { + value = value.replaceAll('$store.','store.state.').replaceAll('this.$config.','$config.'); + } else { + value = value.replaceAll('$store.','this.$store.state.').replaceAll('$config.','this.$config.'); + } + } + if (value.includes('$config.')) { + if (isProxySon==false) { + value = value.replaceAll('$config.','this.$config.'); + } + } + params[key] = value; + }); + //let util = require('util'); + let data = context.jsDump(params).replaceAll("'`","`").replaceAll("`'","`"); + resp.open = ((isProxySon==true)?'store.':'this.$store.')+`commit('${store}/${method}', ${data});`; + + return resp; + } + }, + //*def_store_mutation + //*def_store_field + //*def_store_modificar + //*def_store_call + + // ************************** + // VueX PROXIES definitions + // ************************** + 'def_proxies': { + x_icons: 'desktop_new', + x_level: 2, + x_text_contains: 'prox', + hint: 'Representa una coleccion de proxies de Vue', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + resp.state.from_script=true; + return resp; + } + }, + 'def_proxy_def': { + x_level: 3, + x_empty: 'icons', + x_or_isparent: 'def_proxies', + hint: 'Representa una definicion de un proxy (middleware) en Vue', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + resp.state.current_proxy = node.text.trim(); + context.x_state.proxies[resp.state.current_proxy] = { + imports: { + underscore: '_' + }, + code: '' + }; + resp.open = context.tagParams('proxy_code', { + name: resp.state.current_proxy + }, false) + '\n'; + resp.close = ''; + return resp; + } + }, + + // ***************************** + // Vue Pages and View Elements + // ***************************** + + //def_html y otros + //*def_page + //*def_page_seo + //*def_page_estilos + //*def_page_estilos_class + + 'def_page': { + x_level: '2,3', + x_not_icons: 'button_cancel,desktop_new,list,help,xmag,penguin,clanbomber,idea', + x_not_text_contains: 'componente:,layout:', + hint: 'Archivo vue', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.level>3) return {...resp,valid:false }; + resp.state.current_page = node.text; + //context.debug('context.x_state', context.x_state); + context.debug('def_page state', resp.state); + // set global page defaults for current page + if (!context.x_state.pages[resp.state.current_page]) { + context.x_state.pages[resp.state.current_page] = { + tipo: 'page', + acceso: '*', + params: '', + layout: '', + defaults: {}, + imports: {}, + components: {}, + directives: {}, + variables: {}, + seo: {}, + meta: [], + link: [], + head: { + script: [], + meta: [], + seo: {} + }, + var_types: {}, + proxies: '', + return: '', + styles: {}, + script: {}, + mixins: {}, + stories: { '_default':{ events:{} } }, + track_events: {}, + path: '/' + resp.state.current_page + }; + } + if (resp.state.from_def_layout) context.x_state.pages[resp.state.current_page].tipo = 'layout'; + if (resp.state.from_def_componente) { + context.x_state.pages[resp.state.current_page].tipo = 'componente'; + if (resp.state.for_export) { + context.x_state.pages[resp.state.current_page].for_export = resp.state.for_export; + } + } + // is this a 'home' page ? + if (node.icons.includes('gohome')) context.x_state.pages[resp.state.current_page].path = '/'; + // attributes overwrite anything + let params = {}; + Object.keys(node.attributes).map(async function(key) { + let value = node.attributes[key]; + // preprocess value + value = value.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store.', '$store.state.'); + // query attributes + if (['proxy'].includes(key.toLowerCase())) { + context.x_state.pages[resp.state.current_page].proxies = value; + + } else if (['acceso', 'method'].includes(key.toLowerCase())) { + context.x_state.pages[resp.state.current_page].acceso = value; + + } else if (['path', 'url', 'ruta'].includes(key.toLowerCase())) { + context.x_state.pages[resp.state.current_page].path = value; + + } else if (['layout'].includes(key.toLowerCase())) { + context.x_state.pages[resp.state.current_page].layout = value; + + } else if (['meta:title', 'meta:titulo'].includes(key.toLowerCase())) { + context.x_state.pages[resp.state.current_page].xtitle = node.attributes[key].replaceAll('$variables.', 'this.'); + + } else if (['meta:keywords', 'meta:keyword'].includes(key.toLowerCase())) { + context.x_state.pages[state.current_page].meta.push({ + hid: await context.hash(node.attributes[key]), + name: 'keywords', + content: node.attributes[key].replaceAll('$variables.', 'this.') + }); + + } else if (['background', 'fondo'].includes(key.toLowerCase())) { + params.id = 'tapa'; + let background = context.getAsset(value, 'css'); + context.x_state.pages[resp.state.current_page].styles['#tapa'] = { + 'background-image': `url('${background}')`, + 'background-repeat': 'no-repeat', + 'background-size': '100vw' + }; + + } else { + if (key.charAt(0) != ':' && value != node.attributes[key]) { + params[':' + key] = value; + } else { + params[key] = value; + } + //context.x_state.pages[resp.state.current_page].xtitle = value; + + } + if (resp.state.from_def_layout || resp.state.from_def_componente) { + if (key=='params') { + context.x_state.pages[resp.state.current_page].params=value; + } else if (key.includes('params:') || key.includes('param:')) { + let tmpo = key.replaceAll('params:','').replaceAll('param:','').trim(); + context.x_state.pages[resp.state.current_page].defaults[tmpo] = value; + } + //console.log('PABLO COMPONENTE!! o LAYOUT!!',{ key, value }); + } + }.bind(this)); + // has comments ? + if (node.text_note != '') { + resp.open = `\n`; + } + // set code + resp.open += `\n`; + if (state.from_def_dummy_group) { + resp.open = context.tagParams('vue_file',{ title:resp.state.current_page,node_id:node.id,node_text:node.text },false)+`\n` + resp.open; + resp.close += `\n`; + } + // return + return resp; + } + }, + 'def_page_seo': { + x_level: '3,4', + x_icons: 'desktop_new', + x_text_contains: 'seo', + hint: 'Definicion local de SEO', + func: async function(node, state) { + // @TODO check this node runs correctly (currently without testing map aug-20-20) + let resp = context.reply_template({ + state + }); + // process children nodes + let subnodes = await node.getNodes(); + subnodes.map(async function(item) { + let test = item.text.toLowerCase().trim(); + let key_nodes = await item.getNodes(); + // test by subnode names. + if (test == 'keywords') { + // get an array of childrens node text + let keys = []; + if (typeof key_nodes === 'object') { + key_nodes.map(x => { + keys.push(x.text) + }); + // set into current_page state + context.x_state.pages[state.current_page].seo[test] = keys; + keys = keys.join(','); + } else { + keys = key_nodes.replaceAll('$variables.','this.'); + // set into current_page state + context.x_state.pages[state.current_page].seo[test] = keys.split(','); + } + context.x_state.pages[state.current_page].meta.push({ + hid: await context.hash(keys.split(',')), + name: 'keywords', + content: keys + }); + + } else if (test == 'language' && key_nodes.length > 0) { + //@TODO check this meta statement output format, because its not clear how it's supposed to work aug-20-20 + context.x_state.pages[state.current_page].seo[test] = key_nodes[0].text; + context.x_state.pages[state.current_page].meta.push({ + hid: await context.hash(keys), + lang: key_nodes[0].text.toLowerCase().trim(), + content: key_nodes[0].text + }); + + } else if (key_nodes.length > 0) { + context.x_state.pages[state.current_page].seo[test] = key_nodes[0].text; + if (test.includes(':')) { + context.x_state.pages[state.current_page].meta.push({ + property: test, + vmid: test, + content: key_nodes[0].text + }); + } else { + context.x_state.pages[state.current_page].meta.push({ + hid: await context.hash(keys), + name: item.text.trim(), + content: key_nodes[0].text + }); + } + + } + }.bind(this)); + // return + return resp; + } + }, + 'def_page_css': { + x_priority: 10, + x_level: '3,4', + x_icons: 'desktop_new', + x_text_exact: 'css', + hint: 'Definicion local CSSs externos', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren:false + }); + // process children nodes + let subnodes = await node.getNodes(); + subnodes.map(function(item) { + context.x_state.pages[state.current_page].link.push({ rel:'stylesheet', href:item.text.trim() }); + }); + // return + return resp; + } + }, + 'def_page_estilos': { + x_level: '3,4', + x_icons: 'desktop_new', + x_text_contains: 'estilos', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Definicion de estilos/clases locales', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = {...{scoped:true}, ... aliases2params('def_page_estilos', node)}; + resp.open = context.tagParams('page_estilos', params, false); + resp.close = ''; + resp.state.from_estilos=true; + return resp; + } + }, + 'def_page_estilos_class': { + x_level: '4,5', + x_empty: 'icons', + x_all_hasparent: 'def_page_estilos', + hint: 'Definicion de clase CSS en template VUE', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let left_char = node.text.trim().charAt(0); + if (['#', '.', '|'].includes(left_char) === false) { + resp.open = `.${node.text.trim()} {\n`; + } else if (left_char == '|') { + resp.open = `${node.text.trim().substring(1)} {\n`; //removed | from start. + } else { + resp.open = `${node.text.trim()} {\n`; + } + // output attributes + // @TODO improve this; I believe this could behave more like def_variables_field instead, and so support nested styles. + // currently this works as it was in the CFC + Object.keys(node.attributes).map(function(key) { + let value = node.attributes[key]; + if (context.x_state.es6 && !value.includes('!important') && value.slice(-1)!=';') { + resp.open += `\t${key}: ${value} !important;\n`; + } else if (context.x_state.es6 && !value.includes('!important')) { + resp.open += `\t${key}: ${value.slice(0,-1)} !important;\n`; + } else { + resp.open += `\t${key}: ${value};\n`; + } + }); + resp.open += '}\n'; + return resp; + } + }, + + //*def_layout + //*def_layout_view + //*def_layout_contenido (ex. def_contenido_layout) + //*def_componente + //*def_componente_view (instancia) + //*def_componente_emitir (ex: def_llamar_evento, script) + + 'def_layout': { + x_level: '2,3', + x_not_icons: 'button_cancel,desktop_new,list,help,idea', + x_text_contains: 'layout:', + x_empty: 'icons', + hint: 'Archivo vue tipo layout', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + // call def_page for functionality informing we are calling from def_layout using state. + resp = await context.x_commands['def_page'].func(node, {...state, + ... { + from_def_layout: true + } + }); + delete resp.state.from_def_layout; + return resp; + } + }, + 'def_layout_view': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'layout:', + hint: 'Contenedor flexible, layout:flex o layout:wrap', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { + tipo: 'flex', + width: 6 + }; + if (node.text_note != '') resp.open = ``; + if (node.text.includes(':wrap')) tmp.tipo = 'wrap'; + let params = aliases2params('def_layout_view', node); + tmp.params = {...params + }; + // special cases + if (params.width) { + tmp.width = params.width; + if (params.width.includes('%')) { + tmp.width = Math.round((parseInt(params.width.replaceAll('%', '')) * 12) / 100); + } + delete params.width; + } + if (params[':width']) delete params[':width']; + // write output + if (tmp.params.margen && tmp.params.margen == 'true') { + delete params.margen; + if (tmp.params.center && tmp.params.center == 'true') { + //resp.open += `\n`; + resp.open += context.tagParams('v-container', { 'fill-height':null }, false) + '\n'; + resp.open += context.tagParams('v-row', { 'align-center':null, refx:node.id }, false) + '\n'; + } else { + if (tmp.tipo == 'flex') { + resp.open += context.tagParams('v-container', {}, false) + '\n'; + params.row = null; + resp.open += context.tagParams('v-layout', params, false) + '\n'; + } else if (tmp.tipo == 'wrap') { + resp.open += context.tagParams('v-container', { 'fill-height':null, 'container--fluid':null, 'grid-list-xl':null }, false) + '\n'; + params.wrap = null; + resp.open += context.tagParams('v-layout', params, false) + '\n'; + } + } + // part flex + if (tmp.tipo == 'flex' && tmp.params.center && tmp.params.center == 'true') { + params['xs12'] = null; + params['sm' + tmp.width] = null; + params['offset-sm' + Math.round(tmp.width / 2)] = null; + resp.open += context.tagParams('v-flex', params, false) + '\n'; + resp.close += ``; + } + // close layout + if (context.x_state.es6 && tmp.params.center && tmp.params.center == 'true') { + resp.close += '\n'; + } else { + resp.close += '\n'; + } + resp.close += '\n'; + } else { + // without margen + if (tmp.params.center && tmp.params.center == 'true') { + delete params.center; + params = {...params, ...{ wrap:null, 'align-center':null }}; + resp.open += context.tagParams('v-row', params, false) + '\n'; + } else { + params.wrap=null; + resp.open += context.tagParams('v-layout', params, false)+'\n'; + } + // part flex + if (tmp.tipo == 'flex' && tmp.params.center && tmp.params.center == 'true') { + delete params.center; + params['xs12'] = null; + params['sm' + tmp.width] = null; + params['offset-sm' + Math.round(tmp.width / 2)] = null; + resp.open += context.tagParams('v-flex', params, false) + '\n'; + resp.close += ``; + } + // close layout + if (context.x_state.es6 && tmp.params.center && tmp.params.center == 'true') { + resp.close += ''; + } else { + resp.close += ''; + } + } + // return + return resp; + } + }, + 'def_layout_contenido': { + x_level: '3,4', + x_icons: 'idea', + x_text_contains: 'contenido', + x_all_hasparent: 'def_layout', + hint: 'Placeholder para contenidos de paginas en pantallas tipo layouts', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = {}; + if (node.text_note != '') resp.open = ``; + if (context.x_state.central_config['keep-alive']) params['keep-alive'] = null; + // write tag + resp.open += context.tagParams('nuxt', params, true) + `\n`; + return resp; + } + }, + + 'def_dummy_group': { + x_level: 2, + x_not_icons: 'button_cancel,desktop_new,help,idea', + x_icons: 'list', + x_watch: 'def_page,def_componente', + hint: 'Nodo dummy para agrupar archivos visualmente', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + //console.log('dummy node',resp); + resp.state.from_def_dummy_group=true; + return resp; + } + }, + + 'def_componente': { + x_level: '2,3', + x_not_icons: 'button_cancel,desktop_new,list,help,idea', + x_text_contains: 'componente:', + x_empty: 'icons', + // if def_page,def_assets code changes, also recompile def_componente nodes + x_watch: 'def_page,def_assets', + hint: 'Archivo vue tipo componente', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let new_state = {...state, + ... { + from_def_componente: true + } + }; + //add autocomplete 12nov22 + let attrs = {}; + if (node.attributes['params']) { + node.attributes['params'].split(',').forEach((attr) => { + attrs[attr] = { values:'', hint:'' }; + if (node.attributes['param:'+attr]) { + attrs[attr].values = node.attributes['param:'+attr]; + } + }); + } + await context.addAutocompleteDefinition({ text:node.text, + icons:['idea'], + level:[3,4,5,6,7], + hint:'Instancia de componente', + attributes:attrs }); + //context.x_console.out({ message:'DEBUG autocomplete', color:'green', data:test }); + /* */ + if (node.attributes.export) { + let for_export_import = { name:node.text.replace('componente:','').trim() }; + if (node.attributes.export!='') { + for_export_import.name = node.attributes.export; + } + // save node code for bit re-import + for_export_import.source = await context.dsl_parser.getNode({ id:node.id, nodes_raw:false, recurse:true }); + // extract assets defined within source + let search_assets = function(node) { + let assets = []; + for (let att in node.attributes) { + if (node.attributes[att].includes('assets:')) { + assets.push(node.attributes[att].replace('assets:','')); + } + } + for (let no in node.nodes) { + assets = [...assets,...search_assets(node.nodes[no])]; + } + return assets; + }; + let tmp_assets = search_assets(for_export_import.source); + // get real file for assets + for_export_import.assets = {}; + for (let as in tmp_assets) { + let asset_ = tmp_assets[as]; + if (asset_ in context.x_state.assets) { + for_export_import.assets[asset_] = context.x_state.assets[asset_]; + } + } + // export + new_state.for_export = JSON.stringify(for_export_import); + } + // call def_page for functionality informing we are calling from def_componente using state. + resp = await context.x_commands['def_page'].func(node, new_state); + delete resp.state.from_def_componente; + delete resp.state.for_bit; + return resp; + } + }, + 'def_componente_view': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'componente:', + hint: 'Instancia de componente', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + // prepare vars + let file_name = node.text.trim().split(':').pop(); + let tag_name = `c-${file_name}`; + let var_name = file_name.replaceAll('-', ''); + // add import to page + context.x_state.pages[state.current_page].imports[`@/components/${file_name}/${file_name}.vue`] = var_name; + context.x_state.pages[state.current_page].components[tag_name] = var_name; + // process attributes and write output + let params = aliases2params('def_componente_view', node); + //translate asset if defined + for (let x in params) { + if (params[x] && params[x].includes('assets:')) { + let pre_x = x, valu = params[x]; + delete params[x]; + if (pre_x.charAt(0)!=':') pre_x = ':'+pre_x; + params[pre_x] = context.getAsset(valu, 'js'); + } + await setImmediatePromise(); //@improved + } + // transform numeric valuas as :key + let isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + for (let key in params) { + if (key.charAt(0)!=':' && (params[key].charAt(0)!='0' || params[key]=='0') && ( + isNumeric(params[key])==true || params[key]=='true' || params[key]=='false')) { + params[':'+key] = params[key]; + delete params[key]; + } + } + // + if (node.text_note != '') resp.open = `\n`; + if (!params.ref) params.ref=node.id; + resp.open += context.tagParams(tag_name, params, false) + '\n'; + resp.close = `\n`; + resp.state.friendly_name = tag_name.split('-').splice(-1)[0].trim(); + resp.state.from_componente=true; + return resp; + } + }, + 'def_componente_emitir': { + //@oldname: def_llamar_evento + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'llamar evento|emitir evento', + //@idea x_text_contains: `llamar evento "{evento}"|emitir evento "{evento}"`, + x_all_hasparent: 'def_componente', + hint: 'Emite un evento desde el componente a sus instancias', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let event_name = context.dsl_parser.findVariables({ + text: node.text, + symbol: '"', + symbol_closing: '"' + }).trim(); + // pass attributes as data to parent of component + let params = []; + Object.keys(node.attributes).map(function(key) { + let value = node.attributes[key]; + // preprocess value + if (value.includes('**') && node.icons.includes('bell')) { + value = getTranslatedTextVar(value); + } else if (value == 'true' || value == 'false') { + value = (value == 'true') ? true : value; + value = (value == 'false') ? false : value; + } else if (value.includes('$')) { + value = value.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + } else if (value.includes('this.') == false) { + //@TODO add i18n support here + if (value.includes(`'`) == false) { + value = `'${value}'`; + } + } + params.push(`${key}: ${value}`); + }); + // add event name to _default story + context.x_state.pages[resp.state.current_page].stories['_default'].events[event_name]=''; //@todo add capitalized name as value + // write output and return + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += `this.$emit('${event_name}',{${params.join(',')}});\n`; + return resp; + } + }, + + // CARDs + + 'def_card': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'card', + x_not_text_contains: ':text,:texto,:title,:action,:image,:media,html:,:subtitle,componente:', + attributes_aliases: { + 'width': 'width,ancho', + 'height': 'height,alto' + }, + hint: 'Card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card', node); + // write tag + resp.open += context.tagParams('v-card', params, false) + '\n'; + resp.close += `\n`; + return resp; + } + }, + 'def_card_title': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'card:title', + x_all_hasparent: 'def_card', + hint: 'Titulo de card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card_title', node); + resp.open += context.tagParams('v-card-title', params, false) + '\n'; + resp.close += `\n`; + resp.state.from_card_title=true; + return resp; + } + }, + 'def_card_subtitle': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'card:subtitle', + x_all_hasparent: 'def_card', + hint: 'Sub-titulo de card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card_subtitle', node); + resp.open += context.tagParams('v-card-subtitle', params, false) + '\n'; + resp.close += `\n`; + resp.state.from_card_title=true; + return resp; + } + }, + 'def_card_text': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'card:text', + x_all_hasparent: 'def_card', + hint: 'Contenido de card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card_text', node); + resp.open += context.tagParams('v-card-text', params, false) + '\n'; + resp.close += `\n`; + return resp; + } + }, + 'def_card_actions': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'card:action', + x_all_hasparent: 'def_card', + hint: 'Acciones de card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card_actions', node); + resp.open += context.tagParams('v-card-actions', params, false) + '\n'; + resp.close += `\n`; + return resp; + } + }, + 'def_card_media': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'card:media', + x_all_hasparent: 'def_card', + hint: 'Contenido multimedia para card de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_card_media', node); + if (context.x_state.es6) { + resp.open += context.tagParams('v-img', params, false) + '\n'; + resp.close += `\n`; + } else { + resp.open += context.tagParams('v-card-media', params, false) + '\n'; + resp.close += `\n`; + } + return resp; + } + }, + + //*def_card + //*def_card_title + //*def_card_text + //*def_card_actions + //*def_card_media + + // FORMs + 'def_form': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'form', + attributes_aliases: { + 'v-model': 'valid,value' + }, + hint: 'Formulario de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form', node); + resp.open += context.tagParams('v-form', params, false) + '\n'; + resp.close += `\n`; + return resp; + } + }, + 'def_form_field': { + x_level: '>2', + x_icons: 'pencil', + x_not_icons: 'calendar,clock,attach,freemind_butterfly', + x_not_text_contains: 'google:', + attributes_aliases: { + 'placeholder': 'hint,ayuda', + 'mask': 'mask,mascara,formato', + 'prepend-icon': 'pre:icon', + 'append-icon': 'post:icon', + 'type': 'type,tipo', + 'value': 'value,valor', + 'counter': 'counter,maxlen,maxlength,max' + }, + hint: 'Campo de entrada (text,textarea,checkbox,radio,combo,select,switch,toogle,autocomplete) para usar en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = {}; + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form_field', node); + tmp = {... { + type: 'text' + }, + ...params + }; + // add v-model as node.text. + if (node.text.includes('$')) { + let vmodel = node.text.trim(); + vmodel = vmodel.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store', '$store.state.'); + params['v-model'] = vmodel; + } else if (node.text.trim()!='') { + params['v-model'] = node.text.trim(); + } + // render by type + delete params.type; + if (tmp.type == 'combo') { + resp.open += context.tagParams('v-combobox', params, false) + '\n'; + resp.close += `\n`; + } else if (tmp.type == 'toggle') { + resp.open += context.tagParams('v-btn-toggle', params, false) + '\n'; + resp.close += `\n`; + } else if ('textarea,checkbox,radio,switch'.split(',').includes(tmp.type)) { + resp.open += context.tagParams(`v-${tmp.type}`, params, false) + '\n'; + resp.close += `\n`; + } else if ('autocomplete,autocompletar,auto,select'.split(',').includes(tmp.type)) { + // item-text + if ('item-text' in params && params['item-text'].includes('{{')) { + // suppport for values like '{{ name }} - ({{ tracks.total }})' + let new_val = params['item-text']; + let vars = context.dsl_parser.findVariables({ + text: params['item-text'], + symbol: '{{', + symbol_closing: '}}', + array: true + }); + // replace {{ x }} with {{ item.x }} + vars.map(old => { + let oldt = old.trim(); + new_val = new_val.replaceAll(oldt, `item.${oldt}`); + }); + // if starts with "{{ ", remove + if (new_val.slice(0, 3) == '{{ ') new_val = new_val.slice(3); + // if ends with " }}", remove + if (new_val.slice(-3) == ' }}') { + new_val = new_val.slice(0, -3); + } else { + // add quote at the end + new_val += `'`; + } + // replace " }}" with "+'" and replace "{{ " with "'+" + new_val = new_val.replaceAll(' }}', `+'`).replaceAll('{{ ', `'+`); + // ready + new_val = new_val.replaceAll('{{','').replaceAll('}}',''); + params[':item-text'] = `(item)=>${new_val}`; + delete params['item-text']; + + } else if ('item-text' in params && params['item-text'].includes(' ')) { + let new_val = []; + params['item-text'].split(' ').map(nv => { + new_val.push(`item.${nv}`); + }); + params[':item-text'] = '(item)=>' + new_val.join(`+' '+`); + delete params['item-text']; + } + // item-value + if ('item-value' in params && params['item-value'].includes(' ')) { + let new_val = []; + params['item-value'].split(' ').map(nv => { + new_val.push(`item.${nv}`); + }); + params[':item-value'] = '(item)=>' + new_val.join(`+' '+`); + delete params['item-value']; + } + // + if ('autocomplete,autocompletar,auto'.split(',').includes(tmp.type)) { + resp.open += context.tagParams('v-autocomplete', params, false) + '\n'; + resp.close += `\n`; + } else if (tmp.type == 'select') { + if ('item-value' in params === false && + 'return-object' in params === false && ':return-object' in params === false) { + params[':return-object'] = true; + } + resp.open += context.tagParams('v-select', params, false) + '\n'; + resp.close += '\n'; + } + } else { + // text type or any other type + let mask_map = { + 'tarjeta,visa,mastercard,credito': '****-****-****-****', + 'fechahora,datetime': '**/**/**** **:**', + 'telefono,phone': '(***)****-****', + 'rut': '**.***.***-N', + 'hora,time': '**:**', + 'hora-seg,hora-segs,hora-s,time-secs,time-s': '**:**:**' + }; + let getRealMask = function(key) { + let resp = key; + let mask_keys = Object.keys(mask_map).join(',').split(','); + if (mask_keys.includes(key)) { + for (let mask_key in mask_map) { + if (key==mask_key) { + resp = mask_map[mask_key]; + break; + } + } + } + return key.replaceAll('*','#'); + }; + if (tmp[':mask']) { + tmp['v-mask'] = getRealMask(tmp[':mask']); + delete tmp[':mask']; delete params[':mask']; + } else if (tmp.mask) { + tmp['v-mask'] = `'${getRealMask(tmp['mask'])}'`; + delete tmp.mask; + delete params.mask; + } + tmp = {...tmp, ...params}; + if (tmp[':type']) delete tmp.type; + resp.open += context.tagParams('v-text-field', tmp, false) + '\n'; + resp.close += `\n`; + } + //event friendly name + if (params.label) resp.state.friendly_name = params.label; + // return + return resp; + } + }, + 'def_form_field_image': { + x_level: '>2', + x_icons: 'pencil,attach', + x_not_icons: 'calendar,clock,freemind_butterfly', + x_not_text_contains: 'google:', + hint: 'Campo de entrada de imagen (subir imagen) para usar en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form_field', node); + params = {...params,...aliases2params('def_form_field_image', node)}; + params['refx'] = node.id; + // add node.text (var) as image prefill + if (node.text.trim() != '-') { + if (node.text.includes('$')) { + let vmodel = node.text.trim(); + vmodel = vmodel.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store', '$store.state.'); + params[':prefill'] = vmodel; + } else { + params['prefill'] = node.text.trim(); + } + } + // image defaults + params[':removable'] = false; + params[':hideChangeButton'] = true; + if (params.placeholder) { + params[':customStrings'] = { drag: params.placeholder }; + delete params.placeholder; + } + // transform numeric valuas as :key + let isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + for (let key in params) { + if (key.charAt(0)!=':' && + (params[key].charAt(0)!='0' || params[key]=='0') && ( + isNumeric(params[key])==true || + params[key]=='true' || + params[key]=='false' + ) + ) { + params[':'+key] = params[key]; + delete params[key]; + } else if (!isNaN(params[key]) && params[key].toString().indexOf('.') != -1) { + params[':'+key] = params[key]; + delete params[key]; + } + } + // add plugin + context.x_state.plugins['vue-picture-input'] = { + global: true, + mode: 'client', + npm: { + 'vue-picture-input': '*' + }, + tag: 'picture-input' + }; + if (params.type) delete params.type; + // write output + resp.open += context.tagParams('picture-input', params, false) + '\n'; + resp.close = `\n`; + if (params.placeholder) { + resp.state.friendly_name = params.placeholder; + } else if (params.ref && params.ref.includes('ID_')==false) { + resp.state.friendly_name = params.ref; + } + return resp; + } + }, + 'def_form_field_galery': { + x_level: '>2', + x_icons: 'pencil,freemind_butterfly', + x_not_icons: 'calendar,clock,attach', + x_not_text_contains: 'google:', + attributes_aliases: { + 'dataImages': 'imagenes,images,fotos' + }, + hint: 'Campo de entrada de galeria de imagenes (elegir una o varias imagenes) para usar en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form_field', node); + params = {...params,...aliases2params('def_form_field_galery', node)}; + params['refx'] = node.id; + // add node.text (var) as image prefill + if (node.text.trim() != '') { + let vmodel = node.text.trim(); + if (node.text.includes('$')) { + //vmodel = vmodel.split(',').pop(); + vmodel = vmodel.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store', '$store.state.'); + } + params['@onselectimage'] = `(item)=>${vmodel}=[item]`; + params['@onselectmultipleimage'] = `(item)=>${vmodel}=item`; + params[':selectedImages'] = vmodel; + } + // add plugin + context.x_state.plugins['vue-select-image'] = { + global: true, + mode: 'client', + npm: { + 'vue-select-image': '*' + }, + tag: 'vue-select-image', + requires: ['vue-select-image/dist/vue-select-image.css'] + }; + if (params.type) delete params.type; + // write output. + resp.open += context.tagParams('vue-select-image', params, false) + '\n'; + resp.close = `\n`; + return resp; + } + }, + 'def_form_field_date': { + x_level: '>2', + x_icons: 'pencil,calendar', + x_not_icons: 'clock,attach,freemind_butterfly', + x_not_text_contains: 'google:', + attributes_aliases: { + 'okText': 'ok,aceptar,accept', + 'clearText': 'clear,cancel,cancelar' + }, + hint: 'Campo de entrada con selector de fecha (sin hora) para usar en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form_field_date', node); + if (node.text.trim() != '') { + let vmodel = node.text.trim(); + if (node.text.includes('$')) { + //vmodel = vmodel.split(',').pop(); + vmodel = vmodel.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store', '$store.state.'); + } + params['v-model'] = vmodel; + } + // add plugin + context.x_state.npm['luxon'] = '*'; // for i18n support + context.x_state.plugins['vue-datetime'] = { + global: true, + mode: 'client', + npm: { + 'vue-datetime': '*' + } + }; + params.type = 'date'; + // write output.datetime + resp.open += context.tagParams('datetime', params, false) + '\n'; + resp.close = `\n`; + return resp; + } + }, + 'def_form_field_datetime': { + x_level: '>2', + x_icons: 'pencil,calendar,clock', + x_not_icons: 'attach,freemind_butterfly', + x_not_text_contains: 'google:', + hint: 'Campo de entrada con selector de fecha y hora para usar en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_form_field_datetime', node); + if (node.text.trim() != '') { + let vmodel = node.text.trim(); + if (node.text.includes('$')) { + //vmodel = vmodel.split(',').pop(); + vmodel = vmodel.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store', '$store.state.'); + } + params['v-model'] = vmodel; + } + // add plugin + context.x_state.plugins['vuetify-datetime-picker'] = { + global: true, + npm: { + 'vuetify-datetime-picker': '2.0.3' + }, + styles: [{ + file: 'dtpicker.styl', + lang: 'styl', + content: `@require '~vuetify-datetime-picker/src/stylus/main.styl'` + }] + }; + if (params.type) delete params.type; + // write output + resp.open += context.tagParams('v-datetime-picker', params, false) + '\n'; + resp.close = `\n`; + return resp; + } + }, + 'def_form_google_autocomplete': { + x_level: '>2', + x_icons: 'pencil', + x_text_contains: 'google:autocomplet', + attributes_aliases: { + 'apiKey': 'key,llave', + 'language': 'lang,language,lenguaje', + 'id': 'id', + 'placeholder': 'hint,ayuda' + }, + hint: 'Campo autocompletar para direcciones en formulario vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let config = { + language: 'es' + }; + let params = aliases2params('def_form_google_autocomplete', node); + if (params.apiKey) { + config.apiKey = params.apiKey; + delete params.apiKey; + } + if (params.language) { + config.language = params.language; + delete params.language; + } + context.x_state.plugins['vuetify-google-autocomplete'] = { + global: true, + npm: { + 'vuetify-google-autocomplete': '*' + }, + config: JSON.stringify(config) + }; + // return output + if (node.text_note != '') resp.open = ``; + resp.open += context.tagParams('vuetify-google-autocomplete', params, false) + '\n'; + resp.close = `\n`; + return resp; + } + }, + //*def_form + //*def_form_field (ex. def_textfield) + //*def_form_field_image + //*def_form_field_galery + //*def_form_field_date + //*def_form_field_datetime + //*def_form_google_autocomplete (ex. def_google_autocomplete) - IN @PROGRESS + + 'def_margen': { + x_icons: 'idea', + x_text_contains: 'margen', + hint: 'Define un margen alrededor del contenido', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = aliases2params('def_margen', node); + // code + if (node.text_note != '') resp.open = `\n`; + resp.open += context.tagParams('v-container', params, false) + '\n'; + resp.close += '\n'; + // + return resp; + } + }, + + 'def_contenedor': { + x_icons: 'idea', + x_text_contains: 'contenedor', + x_level: '>2', + hint: 'Vue Container', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = aliases2params('def_contenedor', node); + // code + if (node.text_note != '') resp.open = `\n`; + resp.open += context.tagParams('v-container', params, false) + '\n'; + resp.close = '\n'; + // return + return resp; + } + }, + + 'def_flex': { + x_icons: 'idea', + x_text_contains: 'flex', + x_not_text_contains: ':', + hint: 'Columna de ancho flexible', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + refx: node.id + }; + if (node.text_note != '') resp.open = ``; + // process attributes + Object.keys(node.attributes).map(function(key) { + let value = node.attributes[key]; + let keytest = key.toLowerCase().trim(); + let tvalue = value.toString().replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$env.', 'process.env.') + .replaceAll('$store.', '$store.state.').trim(); + let numsize = 0; + if (tvalue.indexOf('%') != -1) { + tvalue = parseInt(tvalue.replaceAll('%', '').trim()); + numsize = Math.round((tvalue * 12) / 100); + } + // start testing attributes + if (keytest == 'class') { + params.class = tvalue; + } else if (keytest == 'props') { + for (let i of tvalue.split(' ')) { + params[i] = null; + } + } else if ('padding,margen'.split(',').includes(keytest)) { + params['pa-' + tvalue] = null; + } else if (keytest == 'ancho') { + params = {...params, + ...setObjectKeys(`xs-${numsize},sm-${numsize},md-${numsize},lg-${numsize}`, null) + }; + /*} else if (keytest == 'offset') { + params = {...params, + ...setObjectKeys(`offset-xs-${numsize},offset-sm-${numsize},offset-md-${numsize},offset-lg-${numsize}`, null) + };*/ + } else if ('muy chico,movil,small,mobile'.split(',').includes(keytest)) { + params[`xs${numsize}`] = null; + } else if ('chico,tablet,small,tableta'.split(',').includes(keytest)) { + params[`sm${numsize}`] = null; + } else if ('medio,medium,average'.split(',').includes(keytest)) { + params[`md${numsize}`] = null; + } else if ('grande,pc,desktop,escritorio'.split(',').includes(keytest)) { + params[`lg${numsize}`] = null; + } else if ('xfila:grande,xfila:pc,xfila:desktop,pc,escritorio,xfila:escritorio'.split(',').includes(keytest)) { + params[`lg${Math.round(12/tvalue)}`] = null; + } else if ('xfila:medio,xfila:tablet,tablet,xfila'.split(',').includes(keytest)) { + params[`md${Math.round(12/tvalue)}`] = null; + } else if ('xfila:chico,xfila:movil,xfila:mobile'.split(',').includes(keytest)) { + params[`sm${Math.round(12/tvalue)}`] = null; + } else if ('xfila:muy chico,xfila:movil chico,xfila:small mobile'.split(',').includes(keytest)) { + params[`xs${Math.round(12/tvalue)}`] = null; + } else if ('muy chico:offset,movil:offset,small:offset,mobile:offset'.split(',').includes(keytest)) { + params[`offset-xs${Math.round(12/tvalue)}`] = null; + } else if ('chico:offset,tablet:offset,small:offset,tableta:offset'.split(',').includes(keytest)) { + params[`offset-sm${Math.round(12/tvalue)}`] = null; + } else if ('medio:offset,medium:offset,average:offset'.split(',').includes(keytest)) { + params[`offset-md${Math.round(12/tvalue)}`] = null; + } else if ('grande:offset,pc:offset,desktop:offset,escritorio:offset,grande:left'.split(',').includes(keytest)) { + params[`offset-lg${Math.round(12/tvalue)}`] = null; + } else { + if (keytest.charAt(0) != ':' && value != '' && value != tvalue) { + params[':' + key.trim()] = tvalue; + } else { + params[key.trim()] = tvalue; + } + + } + }); + // write tag + resp.open += context.tagParams('v-col', params, false) + '\n'; + resp.close = '\n'; + // return + return resp; + } + }, + + 'def_spacer': { + x_icons: 'idea', + x_text_contains: 'spacer', + x_level: '>2', + hint: 'Spacer es un espaciador flexible', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + resp.open += context.tagParams('v-spacer', {}, true) + '\n'; + return resp; + } + }, + + 'def_progress': { + x_icons: 'idea', + x_text_contains: 'progres', + x_not_text_contains: 'html:', + x_level: '>2', + attributes_aliases: { + 'background-color': 'background-color,background', + 'background-opacity': 'background-opacity,opacity', + 'buffer-value': 'max,max-value', + 'value': 'value,valor', + 'indeterminate': 'loop,infinito', + 'width': 'width,ancho', + 'size': 'size,porte', + 'rotate': 'rotate,rotar' + }, + hint: 'Item de progreso', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { + tipo: 'circular' + }; + if (node.text_note != '') resp.open = ``; + // process our own attributes_aliases to normalize node attributes + let params = aliases2params('def_progress', node); + Object.keys(params).map(function(key) { + // take into account special cases + if (key.toLowerCase() == 'tipo' && 'lineal,linea,linear'.split(',').includes(params[key])) { + tmp.tipo = 'linear'; + delete params[key]; + } else if (key.toLowerCase() == 'indeterminate') { + params[`:${key}`] = params[key]; + delete params[key]; + } + }); + // write tag + resp.open += context.tagParams(`v-progress-${tmp.tipo}`, params, false) + '\n'; + resp.close = `\n`; + // return + return resp; + } + }, + + 'def_dialog': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'dialog', + x_not_text_contains: 'boton:,:', + attributes_aliases: { + 'width': 'width,ancho', + 'max-width': 'max-width,ancho-max,max-ancho', + 'height': 'height,alto', + 'max-height': 'max-height,alto-max,max-alto' + }, + hint: 'Dialogo de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_dialog', node); + if (params[':visible']) { + params['v-model']=params[':visible']; + delete params[':visible']; + } + if (params.visible) { + params['v-model']=params.visible; + delete params.visible; + } + // write tag + resp.open += context.tagParams('v-dialog', params, false) + '\n'; + resp.close += `\n`; + return resp; + } + }, + + 'def_center': { + x_icons: 'idea', + x_text_contains: 'centrar', + hint: 'Centra nodos hijos', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + refx: node.id, + class: 'text-center' + }; + if (node.text_note != '') resp.open = ``; + resp.open = context.tagParams('div', params, false) + '
\n'; + resp.close += '
\n'; + return resp; + } + }, + + 'def_html': { + x_icons: 'idea', + x_text_contains: 'html:', + hint: 'html:x, donde x es cualquier tag', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = aliases2params('def_html', node); + // parse attributes + if (node.text_note != '') resp.open = ``; + let tag = node.text.replace('html:', ''); + if (node.nodes_raw && node.nodes_raw.length > 0) { + let tmp = await node.getNodes({ recurse:false }); + let has_only_events = true; + for (let x of tmp) { + if (x.icons.includes('help')==false) { + has_only_events = false; + break; + } else { + if (x.text.includes('condicion ') || x.text.includes('otra condicion')) { + has_only_events = false; + break; + } + } + await setImmediatePromise(); //@improved + } + if (!has_only_events) { + // this tag has real children + resp.open += context.tagParams(tag, params, false) + '\n'; + resp.close += `\n`; + } else { + // has only ghost childs (self-close) + resp.open += context.tagParams(tag, params, true)+'\n'; + } + } else { + // doesn't have children nodes (self-close) + resp.open += context.tagParams(tag, params, true)+'\n'; + } + resp.state.friendly_name = tag; + return resp; + } + }, + 'def_left': { + x_icons: 'idea', + x_text_contains: 'align:left', + hint: 'Alinea sus nodos hijos a la izquierda', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + refx: node.id, + class: 'text-left' + }; + if (node.text_note != '') resp.open = ``; + resp.open = context.tagParams('div', params, false) + '\n'; + resp.close += '\n'; + return resp; + } + }, + 'def_right': { + x_icons: 'idea', + x_text_contains: 'align:right', + hint: 'Alinea sus nodos hijos a la derecha', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + refx: node.id, + class: 'text-right' + }; + if (node.text_note != '') resp.open = ``; + resp.open = context.tagParams('div', params, false) + '\n'; + resp.close += '\n'; + return resp; + } + }, + 'def_textonly': { + x_level: '>2', + x_empty: 'icons', + x_priority: -5, + x_or_hasparent: 'def_page,def_componente,def_layout', + // @TODO (idea) x_not_hasparent: 'def_toolbar+!def_slot,def_variables,def_page_estilos,def_page_estilos', + hint: 'Texto a mostrar', + func: async function(node, state) { + let resp = context.reply_template({ + state + }), + params = { + refx: node.id, + class: [] + }, + tmp = {}; + let base_text = node.text; + if (node.text_rich!='') { + base_text = node.text_rich; + } + let text = base_text.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store.', '$store.state.'); + if (text == '') text = ' '; + // some extra validation + /* + @todo use this again, after fixing inherited x_states + if (state.from_toolbar && !state.from_slot) { + return {...resp,...{ valid:false }}; + } else if (state.from_datatable_headers && !state.from_slot && !state.from_datatable_fila) { + return {...resp,...{ valid:false }}; + } else if (state.from_variables) { + return {...resp,...{ valid:false }}; + } else if (state.from_estilos) { + return {...resp,...{ valid:false }}; */ + if ((await context.hasParentID(node.id, 'def_toolbar'))==true && (await context.hasParentID(node.id, 'def_slot'))==false) { + return {...resp,...{ valid:false }}; + } else if ((await context.hasParentID(node.id, 'def_datatable_headers'))==true && + (await context.hasParentID(node.id, 'def_slot'))==false && + (await context.hasParentID(node.id, 'def_datatable_fila'))==false) { + return {...resp,...{ valid:false }}; + } else if ((await context.hasParentID(node.id, 'def_variables'))==true) { + return {...resp,...{ valid:false }}; + } else if ((await context.hasParentID(node.id, 'def_page_estilos'))==true || (await context.hasParentID(node.id, 'def_page_css'))==true) { + return {...resp,...{ valid:false }}; + } else { + if (node.text_note != '') resp.open += `\n`; + // + if (node.text.indexOf('..lorem..') != -1 && node.text.indexOf(':') != -1) { + //lorem ipsum text + let lorem = node.text.split(':'); + tmp.lorem = lorem[lorem.length - 1]; + } + if (node.text.indexOf('numeral(') != -1) { + //numeral() filter + context.x_state.plugins['vue-numeral-filter'] = { + global: true, + npm: { + 'vue-numeral-filter': '*' + }, + mode: 'client', + config: `{ locale: 'es-es' }` + }; + } + //node styles + if (node.text_rich=='') { + if (node.font.bold == true) params.class.push('font-weight-bold'); + if (node.font.size <= 10) params.class.push('caption'); + if (node.font.italic == true) params.class.push('font-italic'); + } + // - process attributes + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim(); + let value = node.attributes[key]; + if (keytest == 'class') { + params.class.push(value); + } else if (keytest == ':span') { + tmp.span = true; + } else if (keytest == ':omit') { + tmp.omit = true; + } else if (keytest == ':ntag') { + tmp.ntag = true; + } else if (':length,:largo,len,length,largo'.split(',').includes(key)) { + tmp.lorem = value; + } else if (key == 'small') { + tmp.small = true; + } else if ('ucase,mayusculas,mayuscula'.split(',').includes(key)) { + if (value == 'true' || value == true) params.class.push('text-uppercase'); + } else if ('capitales,capitalize,capital'.split(',').includes(key)) { + if (value == 'true' || value == true) params.class.push('text-capitalize'); + } else if ('lcase,minusculas,minuscula'.split(',').includes(key)) { + if (value == 'true' || value == true) params.class.push('text-lowercase'); + } else if (key == 'truncate') { + if (value == 'true' || value == true) params.class.push('text-truncate'); + } else if (key == 'no-wrap') { + if (value == 'true' || value == true) params.class.push('text-no-wrap'); + } else if ('weight,peso,grosor'.split(',').includes(key)) { + let valuetest = value.toLowerCase(); + if ('thin,fina,100'.split(',').includes(valuetest)) { + params.class.push('font-weight-thin'); + } else if ('light,300'.split(',').includes(valuetest)) { + params.class.push('font-weight-light'); + } else if ('regular,400'.split(',').includes(valuetest)) { + params.class.push('font-weight-light'); + } else if ('medium,500'.split(',').includes(valuetest)) { + params.class.push('font-weight-medium'); + } else if ('bold,700'.split(',').includes(valuetest)) { + params.class.push('font-weight-bold'); + } else if ('black,gruesa,900'.split(',').includes(valuetest)) { + params.class.push('font-weight-black'); + } + + } else if (key == 'color') { + if (value.indexOf(' ') != -1) { + let color_values = value.split(' '); + params.class.push(`${color_values[0]}--text text--${color_values[1]}`); + } else { + params.class.push(`${value}--text`); + } + } else if (key == 'align') { + let valuetest = value.toLowerCase(); + if ('center,centro,centrar'.split(',').includes(valuetest)) { + params.class.push('text-center'); + } else if ('right,derecha'.split(',').includes(valuetest)) { + params.class.push('text-right'); + } else if ('left,izquierda,izquierdo'.split(',').includes(valuetest)) { + params.class.push('text-left'); + } else if ('justify,justificar,justificado'.split(',').includes(valuetest)) { + tmp.jstyle = 'text-align: justify; text-justify: inter-word;'; + if (params.style) { + params.style = params.style.split(';').push(tmp.jstyle).join(';'); + } else { + params.style = tmp.jstyle; + } + } + + } else if (key == 'style') { + if (!params.style) params.styles = []; + params.styles.push(value); + } else { + if (key.charAt(0) != ':' && node.text != '' && text != node.text && key!='v-on') { + params[':' + key] = value; + } else { + params[key] = value; + } + } + }); + // - generate lorem.. ipsum text if within text + if (tmp.lorem) { + let loremIpsum = require('lorem-ipsum').loremIpsum; + text = loremIpsum({ + count: parseInt(tmp.lorem), + units: 'words' + }); + } + // - @TODO i18n here + // - tmp.small + if (tmp.small) { + text = `${text}`; + } + // - normalize class values (depending on vuetify version) + params.class = params.class.map(function(x) { + let resp = x; + resp.replaceAll('text-h1', 'display-4') + .replaceAll('text-h2', 'display-3') + .replaceAll('text-h3', 'display-2') + .replaceAll('text-h4', 'display-1') + .replaceAll('text-h5', 'headline') + .replaceAll('text-subtitle-1', 'subtitle-1') + .replaceAll('text-subtitle-2', 'subtitle-2') + .replaceAll('text-h6', 'title') + .replaceAll('text-body-1', 'body-1') + .replaceAll('text-body-2', 'body-2') + .replaceAll('text-caption', 'caption') + .replaceAll('text-overline', 'overline') + return resp; + }); + //normalize params + if (params.class && params.class.length==0) delete params.class; + if (params.class && params.class.length > 0) params.class = params.class.join(' '); + if (params.style) params.styles = params.styles.join(';'); + //write code + let dad_card_title = await context.isExactParentID(node.id, 'def_card_title'); + let dad_hastextonly = await context.hasParentID(node.id, 'def_textonly'); + if (!tmp.omit) { + if (tmp.ntag && !params.class) { + resp.open += text; + } else { + if (dad_hastextonly==true || (tmp.span && tmp.span==true)) { + resp.open += context.tagParams('span', params) + text + '\n'; + } else if (dad_card_title && dad_card_title==true && !params.class) { + resp.open += text + '\n'; + } else { + resp.open += context.tagParams('div', params) + text + '\n'; + } + } + } + // + } + // return + resp.state.friendly_name=text.replaceAll('@','.'); + resp.state.from_textonly=true; + return resp; + } + }, + + 'def_tag': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'tag:', + attributes_aliases: { + 'option': 'config' + }, + hint: 'Indica que se desea usar un custom tag en el lugar y que se desea instalarlo con la configuración de sus atributos de prefijo :.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { install:{ config:{}, npm_version:'*', extra_imports:[] }, tag:node.text.replaceAll('tag:','').trim(), customcode:'' }; + //params + let attrs = { + mode:'client', + config:{}, + extra_imports: [] + }; + let npms = {}; + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim(); + let value = node.attributes[key].trim(); + if (node.icons.includes('bell') && value.includes('**')) { + value = getTranslatedTextVar(value,true); + } else if (value.includes('assets:')) { + value = context.getAsset(value, 'js'); + } else { + // normalize vue type vars + if (tmp.parent_server==true) { + value = value.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + value = value.replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$params.', '') + .replaceAll('$store.', '$store.state.'); + } + } + if (keytest == 'props') { + value.split(' ').map(x => { + attrs[x] = null + }); + } + // + if (keytest.includes(':option:') || keytest.includes(':config:')) { + let tkey = key.replaceAll(':option:','').replaceAll(':config:','').trim(); + attrs.config[tkey]=value; + } else if (keytest.includes(':use')) { + attrs.use = value; + } else if (keytest.includes(':import')) { + attrs.extra_imports = value.split(','); + } else if (keytest.includes(':mode')) { + attrs.mode = value; + } else if (keytest==':npm') { + let parseNPM = function(keyvalue) { + let original = keyvalue; + let value = { npm:keyvalue, version:'*' }; + if (original.includes(',')) { + value.npm = original.split(',')[0].trim(); + value.version = original.split(',').pop().trim(); + } + if (value.npm.includes('/')) { + if (value.npm.includes('#')) { + let wbranch = value.npm.split('#'); + value.npm = wbranch[0]; + value.version = `https://github.com/${value.npm}.git#${wbranch[1]}`; + value.npm = value.npm.split('/').pop().trim(); + } else { + value.version = `https://github.com/${value.npm}.git`; + value.npm = value.npm.split('/').pop().trim(); + } + } + return value; + } + if (value.includes('|')) { + value.split('|').map(x => { + let tmpn = parseNPM(x); + npms[tmpn.npm] = tmpn.version; + }); + } else { + attrs.npm = parseNPM(value); + npms[attrs.npm.npm] = attrs.npm.version; + } + } else { + attrs[key] = value; + } + }); + //assign child node as custom code + /*let sons = await node.getNodes(); + if (sons.length>0) { + tmp.customcode=trim(sons[0].text); + //context.x_console.outT({ message:`DEBUG child of def_tag says`, color:'cyan', data:sons }); + }*/ + if (Object.keys(npms).length==0) throw `the required attribute :npm is missing! Please specify it.`; + // install plugin + context.x_state.npm = {...context.x_state.npm,...npms}; + /*tmp.xn = npms[Object.keys(npms)[0]]; + attrs.npm = { + [Object.keys(npms)[0]]: tmp.xn + };*/ + let f_npm = Object.keys(npms)[0]; + attrs.npm = npms[f_npm]; + context.x_state.plugins[f_npm] = { + global: true, + npm: npms, + mode: attrs.mode, + extra_imports: attrs.extra_imports, + config: attrs.config, + tag: tmp.tag + }; + if (node.text_note.trim()!='') { + let he = require('he'); + context.x_state.plugins[f_npm].customcode = he.decode(node.text_note.trim()).replaceAll('\n\n',''); + } + //context.x_console.outT({ message:'plugin', data:context.x_state.plugins[f_npm] }); + + if (attrs.use) context.x_state.plugins[f_npm].customvar = attrs.use.replaceAll('-','') + .replaceAll('_','') + .replaceAll('/','') + .replaceAll('.css','') + .replaceAll('.','_') + .toLowerCase().trim(); + if (Object.keys(attrs.config)=='') delete context.x_state.plugins[f_npm].config; + if (resp.state.current_page && resp.state.current_page in context.x_state.pages) { + if (context.x_state.plugins[f_npm].customvar && attrs.use!='') { + context.x_state.pages[resp.state.current_page].imports[f_npm] = context.x_state.plugins[f_npm].customvar; + context.x_state.pages[resp.state.current_page].components[tmp.tag] = context.x_state.plugins[f_npm].customvar; + } else { + /*let assign_ = tmp.tag .replaceAll('-','') + .replaceAll('_','') + .replaceAll('/','') + .replaceAll('.css','') + .replaceAll('.','_') + .toLowerCase().trim();*/ + //context.x_state.pages[resp.state.current_page].imports[f_npm] = assign_; + //context.x_state.pages[resp.state.current_page].components[tmp.tag] = assign_; + } + } + //code + //if (node.text_note != '') resp.open = ``; + delete attrs.npm; delete attrs.mode; delete attrs.use; + delete attrs.extra_imports; delete attrs.config; + attrs.refx = node.id; + resp.open += context.tagParams(tmp.tag, attrs, false) + '\n'; + resp.close += `\n`; + resp.state.friendly_name = tmp.tag.split('-').splice(-1)[0].trim(); + resp.state.from_script = false; + return resp; + } + }, + + //..views.. + //*def_center + //*def_html + //def_tag + //*def_textonly + //*def_margen + //*def_contenedor + //*def_flex + //*def_spacer + //*def_progress + //*def_dialog + + 'def_avatar': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'avatar', + x_not_text_contains: 'fila', + hint: 'Imagen con mascara redondeada', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_avatar', node); + let img_params = {}; + // move :src to img src + if (params.src) { + img_params.src = params.src; + delete params.src; + } + if (params[':src']) { + img_params[':src'] = params[':src']; + delete params[':src']; + } + // write tag + resp.open += context.tagParams('v-avatar', params, false) + '\n'; + resp.open += context.tagParams('v-img', img_params, true) + '\n'; + resp.close += `\n`; + return resp; + } + }, + 'def_boton': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'boton:', + hint: 'Boton de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_boton', node); + // special cases + // targets a scroll position ? + if (params.scrollto) { + context.x_state.plugins['vue-scrollto'] = { + global: true, + npm: { + 'vue-scrollto': '*' + }, + mode: 'client' + }; + if (params.scrollto.includes(',')) { + let element = params.scrollto.split(',')[0]; + let offset = params.scrollto.split(',').pop().trim(); + params['v-scroll-to'] = `{ element:'#${element}', offset:${offset}, cancelable:false }`; + } else { + params['v-scroll-to'] = `{ element:'#${params.scrollto}', cancelable:false }`; + } + delete params.scrollto; + } + // re-map props from older version of vuetify props to ones used here. + if ('flat' in params && params.flat == null) { + params.text = null; + delete params.flat; + } + if ('round' in params && params.round == null) { + params.rounded = null; + delete params.round; + } + // pre-process text + let text = node.text.trim().replaceAll('boton:', ''); + if (context.x_state.central_config.idiomas.indexOf(',') != -1) { + // text uses i18n keys + let def_lang = context.x_state.central_config.idiomas.split(',')[0]; + if (!context.x_state.strings_i18n[def_lang]) { + context.x_state.strings_i18n[def_lang] = {}; + } + let crc32 = 't_' + context.hash(text); + context.x_state.strings_i18n[def_lang][crc32] = text; + text = `{{ $t('${crc32}') }}`; + } else if (text.includes('$') && text.includes('{{') && text.includes('}}')) { + text = text.replaceAll('$params.', '') + .replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$store.', '$store.state.'); + } + // write tag + resp.open += context.tagParams('v-btn', params, false) + text + '\n'; + resp.close += `\n`; + //event friendly name + resp.state.friendly_name = text; + return resp; + } + }, + 'def_chip': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'chip:', + hint: 'Chip de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_chip', node); + // pre-process text + let text = node.text.trim().replaceAll('chip:', ''); + if (context.x_state.central_config.idiomas.indexOf(',') != -1) { + // text uses i18n keys + let def_lang = context.x_state.central_config.idiomas.split(',')[0]; + if (!context.x_state.strings_i18n[def_lang]) { + context.x_state.strings_i18n[def_lang] = {}; + } + let crc32 = 't_' + context.hash(text); + context.x_state.strings_i18n[def_lang][crc32] = text; + text = `{{ $t('${crc32}') }}`; + } else if (text.includes('$') && text.includes('{{') && text.includes('}}')) { + text = text.replaceAll('$params.', '') + .replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$store.', '$store.state.'); + } + // write tag + resp.open += context.tagParams('v-chip', params, false)+'\n'; + resp.close += `${text}\n\n`; + resp.state.friendly_name = text; + if (text.includes('{{')) resp.state.friendly_name = 'chip'; + return resp; + } + }, + + //*def_avatar + //*def_boton + //*def_chip + + 'def_menu': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'menu', + x_not_text_contains: ':', + hint: 'Barra de contenido escondible para menu de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_menu', node); + // special cases + if (params.visible) { + params['v-model'] = params.visible; + delete params.visible; + } + // write tag + resp.open += context.tagParams('v-menu', params, false) + `\n`; + resp.close += `\n`; + return resp; + } + }, + 'def_barralateral': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'lateral', + x_not_text_contains: ':', + hint: 'Barra lateral (normalmente para un menu) escondible de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_barralateral', node); + // special cases + if (params.visible) { + params['value'] = params.visible; + delete params.visible; + } + if (params[':visible']) { + params[':value'] = params[':visible']; + delete params[':visible']; + } + // write tag + resp.open += context.tagParams('v-navigation-drawer', params, false) + `\n`; + resp.close += `\n`; + return resp; + } + }, + 'def_barrainferior': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: 'inferior', + x_not_text_contains: ':', + hint: 'Barra inferior escondible de vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_barrainferior', node); + // special cases + if (params.visible) { + params['v-model'] = params.visible; + delete params.visible; + } + // write tag + resp.open += context.tagParams('v-bottom-sheet', params, false) + `\n`; + resp.close += `\n`; + return resp; + } + }, + + //*def_menu + //*def_barralateral + //*def_barrainferior + + 'def_contenido': { + x_level: '3,4', + x_icons: 'idea', + x_text_exact: 'contenido', + x_or_hasparent: 'def_page,def_componente', + hint: 'Contenido de pagina o componente vuetify', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_contenido',node); + // write tag + resp.open += context.tagParams('v-main', params, false) + `\n`; + resp.close += `\n`; + return resp; + } + }, + 'def_toolbar': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'toolbar', + attributes_aliases: { + 'icon': 'icon,icono' + }, + hint: 'Barra superior o toolbar vuetify que permite auto-alinear un titulo, botones, etc.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = {}; + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_toolbar', node); + // special cases + if (params[':icon']) { + tmp.icon = `{{ ${params[':icon']} }}`; + delete params[':icon']; + } else if (params.icon) { + tmp.icon = params.icon.toLowerCase().trim(); + delete params.icon; + } + // write tag + resp.open += context.tagParams('v-app-bar', params, false) + `\n`; + if (tmp.icon && tmp.icon != '') { + resp.open += `${tmp.icon}\n`; + } else if (tmp.icon && tmp.icon == '') { + resp.open += `\n`; + } + resp.close = `\n`; + resp.state.from_toolbar=true; + return resp; + } + }, + 'def_toolbar_title': { + x_level: '>3', + x_empty: 'icons', + x_all_hasparent: 'def_toolbar', + attributes_aliases:{ + 'grosor': 'weight,peso,grosor' + }, + hint: 'Titulo para nodo toolbar', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_toolbar_title', node); + // special cases + if (params.color) { + if (!params.class) params.class=''; + let tmp = params.class.split(' '); + if (params.color.includes(' ')) { + let name = params.color.split(' ')[0]; + let tint = params.color.split(' ').pop(); + tmp.push(`${name}--text text--${tint}`); + } else { + tmp.push(`${params.color}--text`); + } + params.class = tmp.join(' '); + delete params.color; + } + if (params.grosor) { + if (params.class) params.class=params.class.split(' '); + if (!params.class) params.class=[]; + let valuetest = params.grosor.toLowerCase(); + if ('thin,fina,100'.split(',').includes(valuetest)) { + params.class.push('font-weight-thin'); + } else if ('light,300'.split(',').includes(valuetest)) { + params.class.push('font-weight-light'); + } else if ('regular,400'.split(',').includes(valuetest)) { + params.class.push('font-weight-light'); + } else if ('medium,500'.split(',').includes(valuetest)) { + params.class.push('font-weight-medium'); + } else if ('bold,700'.split(',').includes(valuetest)) { + params.class.push('font-weight-bold'); + } else if ('black,gruesa,900'.split(',').includes(valuetest)) { + params.class.push('font-weight-black'); + } + params.class = params.class.join(' '); + delete params.grosor; + } + // process title (node.text) + let text = node.text.trim(); + if (context.x_state.central_config.idiomas.indexOf(',') != -1) { + // text uses i18n keys + let def_lang = context.x_state.central_config.idiomas.split(',')[0]; + if (!context.x_state.strings_i18n[def_lang]) { + context.x_state.strings_i18n[def_lang] = {}; + } + let crc32 = 't_' + context.hash(text); + context.x_state.strings_i18n[def_lang][crc32] = text; + text = `{{ $t('${crc32}') }}`; + } else if (text.includes('$') && text.includes('{{') && text.includes('}}')) { + text = text.replaceAll('$params.', '') + .replaceAll('$variables.', '') + .replaceAll('$vars.', '') + .replaceAll('$store.', '$store.state.'); + } + // write output + resp.open += context.tagParams('v-toolbar-title',params,false) + text + '\n'; + resp.close = '\n'; + return resp; + } + }, + + 'def_layout_custom': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'layout', + x_not_text_contains: ':', + hint: 'Layout (custom)', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_layout_custom', node); + resp.open += context.tagParams('v-layout',params,true); + return resp; + } + }, + + 'def_divider': { + x_level: '>2', + x_icons: 'idea', + x_text_contains: '---', + hint: 'Divisor, separador visual', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_divider', node); + resp.open += context.tagParams('v-divider',params,true); + return resp; + } + }, + + 'def_slot': { + x_level: '>2', + x_icons: 'list', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Template slot; nombre o nombre=valor', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_slot', node); + if (node.text.includes('=')) { + let extract = require('extractjs')(); + let elements = extract(`{name}={value}`,node.text); + //@todo test this after 'def_datatable' exists + /*if (state.from_datatable) { + if (elements.name=='items') { + elements.name = 'item'; + } else if (elements.name=='headers') { + elements.name = 'header'; + } else if (elements.name=='expand') { + elements.name = 'expanded-item'; + } + }*/ + params[`v-slot:${elements.name}`] = elements.value; + } else { + params[`v-slot:${node.text.trim()}`] = null; + } + resp.open += context.tagParams('template',params,false)+'\n'; + resp.close = '\n'; + resp.state.from_slot=true; + resp.state.from_script=false; + return resp; + } + }, + + 'def_div': { + x_level: '>2', + x_icons: 'idea', + x_not_icons: 'desktop_new', + x_text_exact: 'div', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'HTML div/bloque', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_div', node); + resp.open += context.tagParams('div',params,false)+'\n'; + resp.close = ''; + return resp; + } + }, + + 'def_agrupar': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'agrupar', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Agrupa elementos flex hijos horizontalmente', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_agrupar', node); + if (params.centrar && params.centrar==true) { + params['justify-center'] = null; + params['align-center'] = null; + delete params.centrar; + } + resp.open += context.tagParams('v-row',params,false)+'\n'; + resp.close = ''; + return resp; + } + }, + + 'def_bloque': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'bloque', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Bloque; una fila de algo en bloque completo', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + let params = aliases2params('def_bloque', node); + params.column = null; + if (params.centrar && params.centrar==true) { + params['justify-center'] = null; + params['align-center'] = null; + delete params.centrar; + } + if (node.text_note != '') resp.open = ``; + resp.open += context.tagParams('v-layout',params,false)+'\n'; + resp.close = ''; + return resp; + } + }, + + 'def_hover': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'hover', + hint: 'Crea variable $hover con true si usuario posa mouse sobre su hijo', + func: async function(node, state) { + let resp = context.reply_template({ state }); + //code + if (node.text_note != '') resp.open = ``; + let params = aliases2params('def_hover', node); + resp.open += context.tagParams('v-hover',params,false)+'\n'; + resp.open += context.tagParams('template',{ 'slot-scope':'{ hover }' },false)+'\n'; + resp.close = ''; + return resp; + } + }, + + 'def_tooltip': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'tooltip', + attributes_aliases: { + 'texto': 'texto,text,:text,:texto', + 'class': 'class,:class' + }, + hint: 'Muestra el mensaje definido cuando se detecta mouse sobre sus hijos', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_tooltip', node, false, ''); + let tmp = { text:'', params_span:{} }; + if (params.texto) tmp.text = params.texto; + if (params[':texto']) tmp.text = params[':texto']; + if (tmp.text.includes('this.') && tmp.text.includes('{{')==false) { + tmp.text = `{{ ${tmp.text} }}`; + } + delete params.texto; + delete params[':texto']; + if (params.class) { + tmp.params_span.class = params.class; + delete params.class; + } else if (params[':class']) { + tmp.params_span[':class'] = params.class; + delete params[':class']; + } + //code + if (node.text_note != '') resp.open = ``; + resp.open += context.tagParams('v-tooltip',params,false)+'\n'; + resp.open += context.tagParams('template',{ 'v-slot:activator':'{ on }' },false)+'\n'; + resp.close = ''; + resp.close += context.tagParams('span',tmp.params_span,false) + tmp.text + '\n'; + resp.close += ''; + return resp; + } + }, + + 'def_datatable': { + x_level: '>2', + x_icons: 'idea', + x_text_exact: 'tabla', + attributes_aliases: { + 'drag': 'draggable,:draggable,sort,:sort,drag,:drag,manilla,:manilla', + 'class': 'class,:class', + 'width': 'width,ancho', + 'height': 'height,alto', + 'rows-per-page-text': 'rows-per-page-text' + }, + hint: 'Dibuja una tabla con datos.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_datatable', node); + if (params.drag && params[':items']) { + //install sortablejs plugin + params.ref=node.id; + context.x_state.pages[state.current_page].imports.sortablejs = 'Sortable'; + resp.open += ``; + delete params.drag; + } + //pass header name/id for headers future var + resp.state.datatable_id = node.id + '_headers'; + params[':headers'] = resp.state.datatable_id; + if (params['rows-per-page-text']) { + //@todo add support for multiple footer-props:x attrs to footer-props attr + params[':footer-props'] = { + 'items-per-page-text': params['rows-per-page-text'] + }; + delete params['rows-per-page-text']; + } + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-data-table',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'table'; + resp.state.from_datatable=true; + return resp; + } + }, + + 'def_datatable_headers': { + x_level: '>3', + x_icons: 'edit', + x_text_exact: 'headers', + x_all_hasparent: 'def_datatable', + hint: 'Define los titulos de las columnas de la tabla padre y sus propiedades.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + context.x_state.pages[state.current_page].variables[resp.state.datatable_id] = []; + context.x_state.pages[state.current_page].var_types[resp.state.datatable_id] = 'array'; + resp.state.from_datatable_headers=true; + return resp; + } + }, + + 'def_datatable_headers_title': { + x_level: '>4', + x_empty: 'icons', + x_all_hasparent: 'def_datatable_headers', + attributes_aliases: { + 'value': 'value,campo', + 'sortable': 'orden,ordenable,sortable', + 'ucase': 'ucase,mayusculas,mayuscula', + 'capital': 'capitales,capitalize,capital', + 'lcase': 'lcase,minusculas,minuscula', + 'nowrap': 'no-wrap', + 'weight': 'weight,peso,grosor', + 'fontsize': 'font,size' + }, + hint: 'Define las propiedades del titulo de una columna de la tabla padre.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_datatable_headers_title', node); + let item = { class:[], text:node.text.trim() }; + if (params.class) item.class = params.class.split(' '); + if (node.font.size<=10) item.class.push('caption'); + if (node.font.bold==true) item.class.push('font-weight-bold'); + if (node.font.italic==true) item.class.push('font-italic'); + if (params.value) item.value = params.value; + if (params.sortable) item.sortable = params.sortable; + if (params.ucase && params.ucase==true) item.class.push('text-uppercase'); + if (params.capital && params.capital==true) item.class.push('text-capitalize'); + if (params.lcase && params.lcase==true) item.class.push('text-lowercase'); + if (params.truncate && params.truncate==true) item.class.push('text-truncate'); + if (params.nowrap && params.nowrap==true) item.class.push('text-no-wrap'); + if (params.fontsize) item.class.push(params.fontsize); + if (params.weight) { + if ('thin,fina,100'.includes(params.weight)) item.class.push('font-weight-thin'); + if ('light,300'.includes(params.weight)) item.class.push('font-weight-light'); + if ('regular,400'.includes(params.weight)) item.class.push('font-weight-regular'); + if ('medium,500'.includes(params.weight)) item.class.push('font-weight-medium'); + if ('bold,700'.includes(params.weight)) item.class.push('font-weight-bold'); + if ('black,gruesa,900'.includes(params.weight)) item.class.push('font-weight-black'); + } + // + delete params.class; delete params.refx; + delete params.value; delete params.sortable; delete params.ucase; + delete params.capital; delete params.lcase; delete params.truncate; + delete params.nowrap; delete params.weight; delete params.fontsize; + item = {...item, ...params}; + item.class = item.class.join(' '); + if (item.class.trim()=='') delete item.class; + //assign struct to datatable header var + if (resp.state.datatable_id) { + context.x_state.pages[state.current_page].variables[resp.state.datatable_id].push(item); + context.x_state.pages[state.current_page].var_types[`${resp.state.datatable_id}[${context.x_state.pages[state.current_page].variables[resp.state.datatable_id].length-1}]`] = typeof item; + } + return resp; + } + }, + + 'def_datatable_fila': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'fila', + x_all_hasparent: 'def_datatable', + hint: 'Crea una nueva fila en la tabla padre.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_datatable_fila', node, true); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('tr',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'row'; + resp.state.from_datatable_fila = true; + return resp; + } + }, + + 'def_datatable_col': { + x_level: '>4', + x_icons: 'idea', + x_text_exact: 'columna', + hint: 'Agrupa sus hijos en una columna de una tabla.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_datatable_fila) return {...resp,...{valid:false}}; + let params = aliases2params('def_datatable_col', node, true); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('td',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'column'; + return resp; + } + }, + + //*def_contenido + //*def_toolbar + //*def_toolbar_title + //**def_layout_custom - @todo needs testing + //**def_divider + //**def_slot + //**def_div + //**def_agrupar + //**def_bloque + //**def_hover + //**def_tooltip + //**def_datatable + //**def_datatable_headers + //**def_datatable_headers_title + //**def_datatable_fila + //**def_datatable_col + + 'def_paginador': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'paginador,,', + x_or_hasparent: 'def_page,def_layout,def_componente', + attributes_aliases: { + 'length': 'largo,length,cantidad,paginas,items' + }, + hint: 'Crea un paginador visual en donde asigna el item pagina actual a la variable indicada luego de su coma.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_paginador', node); + if (node.text.includes(',')) { + params['v-model']=node.text.split(',').slice(-1)[0].trim(); + params['v-model'] = params['v-model'].replaceAll('$variables.','') + .replaceAll('$vars.','') + .replaceAll('$params.','') + .replaceAll('$store.','$store.state.'); + } + if (params[':length'] && !params[':total-visible']) { + params[':total-visible'] = params[':length']; + } + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-pagination',params,false)+'\n'; + resp.close = ''; + return resp; + } + }, + + 'def_sparkline': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'sparkline', + x_or_hasparent: 'def_page,def_layout,def_componente', + hint: 'Crea un grafico lineal simple, manipulable con sus parametros.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_sparkline', node, true); + if (params.centrar && params.centrar==true) { + params['justify-center']=null; + params['align-center']=null; + delete params.centrar; + } + if (params.colores) { + params[':gradient'] = JSON.serialize(params.colores.split(',')); + delete params.colores; + } + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-sparkline',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'spark'; + return resp; + } + }, + + 'def_highcharts': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'highcharts', + x_or_hasparent: 'def_page,def_layout,def_componente', + attributes_aliases: { + 'type': 'type,tipo', + 'title': 'title,titulo', + 'data': 'data,series' + }, + hint: 'Crea un grafico Highchart avanzado, manipulable con sus parametros.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let config = {...{ chartOptions:{} },...aliases2params('def_highcharts', node, true)}; + if (config.type) { + config.chartType = config.type; + config.chartOptions.chart = { type:config.type }; + delete config.type; + } + if (config.title) { + config.chartOptions.title = { text:config.title }; + delete config.title; + } + if (config.data) { + config.chartOptions.series = [{ data:config.data }]; + delete config.data; + } + //install plugin + context.x_state.plugins['highcharts-vue'] = { + global:true, + npm: { 'highcharts-vue':'*' }, + tag: 'highcharts' + }; + //create variable for options + let options_var = `options_${node.id}`; + context.x_state.pages[state.current_page].variables[options_var] = config; + context.x_state.pages[state.current_page].var_types[options_var] = typeof config; + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('highcharts',{ ':options':options_var },false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'highchart'; + return resp; + } + }, + + 'def_trend': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'trend', + x_or_hasparent: 'def_page,def_layout,def_componente', + hint: 'Crea un grafico de tendencias simple, manipulable con sus parametros.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_trend', node, true); + if (params.centrar && params.centrar==true) { + params['justify-center']=null; + params['align-center']=null; + delete params.centrar; + } + //install plugin + context.x_state.plugins['pure-vue-chart'] = { + global:true, + npm: { 'pure-vue-chart':'*' }, + mode: 'client', + tag: 'pure-vue-chart' + }; + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('pure-vue-chart',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'trend'; + return resp; + } + }, + + //**def_paginador + + //**def_sparkline + //**def_highcharts -- needs testing (no map available at hand) + //**def_trend + + 'def_listado': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'listado', + x_or_hasparent: 'def_page,def_layout,def_componente', + hint: 'Crea un listado con filas y datos.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado', node); + if (params.lineas) { + if (params.lineas==2) params['two-line']=null; + if (params.lineas==3) params['three-line']=null; + } + //code + if (node.text_note != '') resp.open += ``; + if (params.layout && params.layout=='true') { + params.tag = 'v-list'; delete params.layout; + resp.open += context.tagParams('v-layout',params,false)+'\n'; + if (params.subheader) { + resp.open += context.tagParams('v-subheader',{...params,...{ subheader:null }},false)+params.subheader+'\n'; + } + resp.close = ''; + } else { + resp.open += context.tagParams('v-list',params,false)+'\n'; + if (params.subheader) { + resp.open += context.tagParams('v-subheader',{...params,...{ subheader:null }},false)+params.subheader+'\n'; + } + resp.close = ''; + } + resp.state.friendly_name = 'listado'; + return resp; + } + }, + + 'def_listado_grupo': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'listado:grupo', + x_or_hasparent: 'def_page,def_layout,def_componente', + attributes_aliases: { + 'value': 'value,activo,active,model,v-model' + }, + hint: 'Permite agrupar filas de forma colapsable segun propiedades.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_grupo', node); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-list-group',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'grupo'; + return resp; + } + }, + + 'def_listado_fila': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila|fila)', + x_or_hasparent: 'def_listado,def_listado_dummy', + //x_or_hasparent: 'def_page,def_layout,def_componente', + hint: 'Permite agrupar filas de forma colapsable segun propiedades.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila', node, true); + let tmp = { subheader:null }; + //params + if (params.lineas) { + if (params.lineas==2) params['two-line']=null; + if (params.lineas==3) params['three-line']=null; + } + if (params.subheader) { + tmp.subheader=params.subheader; + params.subheader=null; + } + if (params.scrollto) { + context.x_state.plugins['vue-scrollto'] = { + global:true, + mode: 'client', + npm: { 'vue-scrollto':'*' } + }; + params['v-scroll-to'] = { cancelable:false, element:'#'+params.scrollto }; + if (params.scrollto.includes(',')) { + params['v-scroll-to'].element = '#'+params.scrollto.split(',')[0]; + params['v-scroll-to'].offset = params.scrollto.split(',').splice(-1)[0]; + } + delete params.scrollto; + } + if (node.link!='' && node.link.includes('ID_')) { + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true) { + params.to = `{vuepath:${link_node.text}}`; + } + } + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-list-item',params,false)+'\n'; + if (params.subheader) { + resp.open += context.tagParams('v-subheader',params,false)+tmp.subheader+'\n'; + } + resp.close = ''; + resp.state.friendly_name = 'fila'; + return resp; + } + }, + + 'def_listado_fila_accion': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila:accion|fila:accion|accion)', + x_or_hasparent: 'def_listado_fila,def_listado_dummy', + hint: 'Define la accion de una fila de un listado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila_accion', node); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-list-item-action',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'accion_fila'; + return resp; + } + }, + + 'def_listado_fila_contenido': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila:contenido|fila:contenido|contenido)', + x_or_hasparent: 'def_listado_fila,def_listado_dummy,def_slot', + hint: 'Define el contenido de una fila de un listado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila_contenido', node); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-list-item-content',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'contenido_fila'; + return resp; + } + }, + + 'def_listado_fila_titulo': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila:titulo|fila:titulo|titulo)', + x_or_hasparent: 'def_listado_fila,def_listado_dummy,def_slot', + hint: 'Define el titulo de una fila de un listado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila_titulo', node); + //code + if (node.text_note != '') resp.open += ``; + if (params['v-text'] || params[':v-text']) { + resp.open += context.tagParams('v-list-item-title',params,true)+'\n'; + } else { + resp.open += context.tagParams('v-list-item-title',params,false)+'\n'; + resp.close = ''; + } + resp.state.friendly_name = 'titulo_fila'; + return resp; + } + }, + + 'def_listado_fila_subtitulo': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila:subtitulo|fila:subtitulo|subtitulo)', + x_or_hasparent: 'def_listado_fila,def_listado_dummy,def_slot', + hint: 'Define el subtitulo de una fila de un listado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila_subtitulo', node); + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('v-list-item-subtitle',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'subtitulo_fila'; + return resp; + } + }, + + 'def_listado_fila_avatar': { + x_level: '>3', + x_icons: 'idea', + x_text_pattern: '+(listado:fila:avatar|fila:avatar|fila-avatar|avatar)', + x_or_hasparent: 'def_listado_fila,def_listado_dummy,def_slot', + hint: 'Define el avatar de una fila de un listado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_listado_fila_avatar', node); + //code + if (node.text_note != '') resp.open += ``; + if (state.from_slot) { + resp.open += context.tagParams('v-list-item-avatar',params,false)+'\n'; + resp.close = ''; + } else { + resp.open += context.tagParams('v-list-avatar',params,false)+'\n'; + resp.close = ''; + } + resp.state.friendly_name = 'avatar'; + return resp; + } + }, + //**def_listado + //**def_listado_grupo + //?def_listado_dummy (@todo check what is this for) + //*def_listado_fila + //**def_listado_fila_accion + //**def_listado_fila_contenido + //**def_listado_fila_titulo + //**def_listado_fila_subtitulo + //**def_listado_fila_avatar + + 'def_icono': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'icono', + x_or_hasparent: 'def_page,def_componente,def_layout', + attributes_aliases: { + 'icon': 'icon,icono' + }, + hint: 'Agrega el icono definido en el lugar.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_icono', node); + let tmp={}; + //params + if (params.icon) { + tmp.icon = params.icon; + if (tmp.icon.charAt(0)=='$') { + tmp.icon = tmp.icon.right(tmp.icon.length-1); + tmp.icon = `{{ ${tmp.icon} }}`; + } else { + resp.state.friendly_name = tmp.icon.replaceAll(' ',''); + } + delete params.icon; + } + if (params[':icon']) { + tmp.icon = params[':icon']; + tmp.icon = `{{ ${tmp.icon} }}`; + delete params[':icon']; + } + if (params.class) params.class=params.class.split(' '); + if (params.color) { + if (params.color.includes('#')) { + if (params.style) params.style=params.style.split(';'); + if (!params.style) params.style=[]; + params.style.push(`color:${params.color}`); + } else { + if (!params.class) params.class=[]; + if (params.color.includes(' ')) { + let name = params.color.split(' ')[0]; + let tint = params.color.split(' ').splice(-1)[0]; + params.class.push(`${name}--text text--${tint}`); + } else { + params.class.push(`${params.color.trim()}--text`); + } + } + } + //code + if (params.style) params.style = params.style.join(';'); + if (params.class) params.class = params.class.join(' '); + if (node.text_note != '') resp.open += ``; + let from_toolbar = await context.isExactParentID(node.id, 'def_toolbar'); + if (tmp.icon) { + if (from_toolbar && from_toolbar==true) { + resp.open += context.tagParams('v-btn',{ 'icon':null },false); + resp.open += context.tagParams('v-icon',params,false); + resp.open += tmp.icon; + resp.open += ''; + resp.open += ''; + } else { + resp.open += context.tagParams('v-icon',params,false)+tmp.icon+''; + resp.open += ''; + } + } else { + if (from_toolbar && from_toolbar==true) { + resp.open += context.tagParams('v-app-bar-nav-icon',params,true); + } else { + //icon must be a child node + resp.open += context.tagParams('v-icon',params,false)+'\n'; + resp.close += ''; + } + } + return resp; + } + }, + + 'def_imagen': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'imagen', + //x_not_empty: 'attributes[:src]', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Agrega la imagen indicada en el lugar.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = {...{ alt:'' },...aliases2params('def_imagen', node)}; + //code + if (node.text_note != '') resp.open += ``; + //translate asset if defined + for (let x in params) { + if (params[x] && params[x].includes('assets:')) { + params[x] = context.getAsset(params[x], 'js'); + } + await setImmediatePromise(); //@improved + } + resp.open += context.tagParams('v-img',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'imagen'; + return resp; + } + }, + + 'def_qrcode': { + x_level: '>3', + x_icons: 'idea', + x_text_contains: 'qrcode', + //x_not_empty: 'attributes[:src]', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Agrega un codigo QR en el lugar.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let options = aliases2params('def_qrcode', node); + //code. + if (node.text_note != '') resp.open += ``; + //translate asset if defined + for (let x in options) { + if (options[x] && options[x].includes('assets:')) { + options[x] = context.getAsset(options[x], 'js'); + } + await setImmediatePromise(); //@improved + } + let params = {}; + if (options.value) params.value = options.value; + if (options[':value']) params[':value'] = options[':value']; + if (options.ref) params.ref = options.ref; + delete options.value; delete options[':value']; + delete options.refx; + delete options.ref; + params[':options'] = options; + // install plugin + context.x_state.plugins['@chenfengyuan/vue-qrcode'] = { + global:true, + npm: { '@chenfengyuan/vue-qrcode':'*' }, + tag: 'qrcode', + mode: 'client' + }; + // code + resp.open += context.tagParams('qrcode',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'qrcode'; + return resp; + } + }, + + 'def_mapa': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'mapa', + x_or_hasparent: 'def_page,def_componente,def_layout', + attributes_aliases: { + 'key': 'key,llave', + 'width': 'width,ancho', + 'height': 'height,alto', + 'lat': 'lat,latitude,latitud', + 'lng': 'lon,longitude,longitud,lng' + }, + hint: 'Agrega un mapa en el lugar y permite controlarlo con sus propiedades.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = {...{ width:'100%', height:'300px' },...aliases2params('def_mapa', node, false, 'this.')}; + let to_map = { center:{} }; + let config = { + load: { + key: '', + libraries: 'places,drawing,visualization' + }, + installComponents: true + }; + //params + if (params.pois) { + if (!params[':options']) params[':options']={}; + params[':options'].clickableIcons=params.pois; + } + if (params.style) params.style=params.style.split(';'); + if (!params.style) params.style=[]; + if (params.key) { config.load.key=params.key; delete params.key; } + if (params.lat) { to_map.center.lat=params.lat; delete params.lat; } + if (params.lng) { to_map.center.lng=params.lng; delete params.lng; } + if (params[':lat']) { to_map.center.lat=params[':lat']; delete params[':lat']; } + if (params[':lng']) { to_map.center.lng=params[':lng']; delete params[':lng']; } + if (params.width) { + to_map.width=params.width; + params.style.push(`width: ${to_map.width}`); + delete params.width; + } + if (params.height) { + to_map.height=params.height; + params.style.push(`height: ${to_map.height}`); + delete params.height; + } + params.style = params.style.join(';'); + if (!params[':center'] && to_map.center.lat!='') params[':center']=to_map.center; + //plugin + context.x_state.plugins['vue2-google-maps'] = { + global:true, + mode: 'client', + npm: { 'vue2-google-maps':'*' }, + as_star: true, + tag: 'GmapMap', + config: context.jsDump(config) + }; + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('GmapMap',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'mapa'; + return resp; + } + }, + + 'def_youtube_playlist': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'youtube:playlist', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: 'Agrega un reproductor de playlists de YouTube.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_youtube_playlist', node); + //plugin + context.x_state.plugins['vue-youtube-playlist'] = { + global:true, + npm: { 'vue-youtube-playlist':'*' }, + tag: 'youtube-playlist', + mode: 'client' + }; + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('youtube-playlist',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'youtube'; + return resp; + } + }, + + 'def_youtube': { + x_level: '>3', + x_icons: 'idea', + x_text_exact: 'youtube', + x_or_hasparent: 'def_page,def_componente,def_layout', + attributes_aliases: { + 'player-vars': 'autoplay,player-vars' + }, + hint: 'Agrega un reproductor de videos de YouTube.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + let params = aliases2params('def_youtube', node); + //plugin + context.x_state.plugins['vue-youtube-embed'] = { + global:true, + mode: 'client', + npm: { 'vue-youtube-embed':'*' }, + tag: 'youtube', + config: '{ global:true }' + }; + //code + if (node.text_note != '') resp.open += ``; + resp.open += context.tagParams('youtube',params,false)+'\n'; + resp.close = ''; + resp.state.friendly_name = 'youtube'; + return resp; + } + }, + + //**def_icono + //def_animar -- @todo re-think its usage (not currently in use anywhere) + //**def_imagen + //**def_qrcode + + //**def_mapa + //**def_youtube_playlist + //**def_youtube + + 'def_xcada_registro_view': { + x_icons: 'penguin', + x_text_contains: `por cada registro en`, + x_level: '>2', + attributes_aliases: { + 'use_index': 'index', + 'unique': 'unique,id', + 'target': 'template,target' + }, + hint: `Repite sus hijos por cada elemento entrecomillas, dejando el item en curso en la variable luego de la coma.`, + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let padre = await context.dsl_parser.getParentNode({ id:node.id }); + let hijos = await node.getNodes(); + if (!padre.icons.includes('idea') && !padre.icons.includes('list')) { + if (padre.icons.includes('penguin') && padre.text.indexOf('por cada registro')!=-1) { + // father is another xcada_registro (view type) + } else { + //console.log('state y padre',{state,padre}); + if (hijos.length>0 && !hijos[0].icons.includes('idea')) { + resp.valid=false; + resp.state.from_script=false; + return resp; + } else if (padre.icons.includes("help") && padre.text.indexOf('condicion')==-1) { + resp.valid=false; + resp.state.from_script=true; + return resp; + } + } + } + /* + if (state.from_script && state.from_script==true) { + resp.valid=false; + return resp; + }*/ + let params = (await context.x_commands['def_xcada_registro'].func(node, {...state,...{ get_params:true, from_xcada_view:true } })).state.params; + //code + if (node.text_note != '') resp.open += `\n`; + resp.open += context.tagParams('vue_for', params, false) + '\n'; + resp.close = ''; + return resp; + } + }, + + //**def_xcada_registro_view + + 'def_event_mounted': { + x_icons: 'help', + x_level: '3,4', + x_text_contains: ':mounted', + hint: 'Evento especial :mounted en pagina vue', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (node.nodes_raw.length==0) return resp; + let params = {}; + resp.open = context.tagParams('vue_mounted', {}, false)+''; + resp.state.from_script=true; + return resp; + } + }, + + 'def_event_created': { + x_icons: 'help', + x_level: '3,4', + x_text_contains: ':created', + hint: 'Evento especial :created en pagina vue', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (node.nodes_raw.length==0) return resp; + let params = {}; + resp.open = context.tagParams('vue_created', {}, false)+''; + resp.state.from_script=true; + return resp; + } + }, + + 'def_event_server': { + x_icons: 'help', + x_level: '3,4', + x_text_contains: ':server', + hint: 'Evento especial :server en pagina vue', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (node.nodes_raw.length==0) return resp; + let params = aliases2params('def_event_server',node); + resp.open = context.tagParams('server_asyncdata', {}, false)+''; + resp.state.from_server=true; + resp.state.from_script=true; + return resp; + } + }, + + 'def_event_method': { + x_icons: 'help', + x_level: '3,4', + x_not_text_contains: ':,condicion si,otra condicion', + x_or_isparent: 'def_page,def_componente', + attributes_aliases: { + 'm_params': ':params,params', + 'timer_time': 'timer:time,interval,intervalo,repetir', + 'async': ':async,async' + }, + hint: 'Funcion tipo evento en pagina vue', + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (node.nodes_raw.length==0) return resp; + let params = aliases2params('def_event_method',node); + params.type='async'; + params.name=node.text.trim(); + /*if (params.name.charAt(0)==params.name.toUpperCase()) { + params.friendly_name = params.name; + }*/ + if (params.async && params.async=='false') params.type='sync'; + if (params.async) delete params.async; + //code + resp.open = context.tagParams('vue_event_method', params, false)+''; + resp.state.from_script=true; + return resp; + } + }, + 'def_event_method_call': { + x_text_contains: 'llamar funcion', + x_icons: 'desktop_new', + x_not_empty: 'link', + x_or_hasparent: 'def_page,def_componente', + hint: `Llama la funcion enlazada, traspasando sus atributos como parametros, y asignando opcionalmente su respuesta a la var definida luego de la coma`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let tmp = { link:'x', return:null }; + // create obj from current node as js obj + let obj = await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }}); + let params = obj.state.object; + if (node.text.includes(',')) tmp.return = node.text.split(',').pop().trim(); + //get target function name + if (node.link.includes('ID_')) { + tmp.link_id = node.link; + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true) { + if (link_node.icons.includes('help')) { + tmp.link = link_node.text; + } else if (link_node.icons.includes('idea')) { + let func_name_ = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + tmp.link = "$refs."+link_node.id+'.'+func_name_; + } + } + delete params.refx; + } else { + return {...resp,valid:false}; + } + // write code convertjs(params) + let data = context.jsDump(params).replaceAll("'`","`").replaceAll("`'","`"); + if (tmp.return) resp.open += `let ${tmp.return} = `; + if (Object.keys(params).length==0) data=''; + if (tmp.link.includes('$refs')) { + resp.open += `(this.${tmp.link.split('.').slice(0,-1).join('.')})?(await this.${tmp.link}(${data})):null;`; + } else { + resp.open += `(await this.${tmp.link}(${data}));`; + } + // + return resp; + } + }, + + 'def_event_element': { + x_icons: 'help', + x_level: '>2', + x_not_text_contains: ':server,:mounted,condicion si,otra condicion, ', + hint: `Evento de un elemento visual (ej. imagen->?click). + Se puede enlazar a otro evento de la misma página, en cuyo caso sus atributos se traspasan como parametros.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + //if (node.nodes_raw.length==0) return resp; + //get parent node id + let parent_node = await context.dsl_parser.getParentNode({ id: node.id }); + if (parent_node.icons.includes('idea')==false && parent_node.icons.includes('pencil')==false) { + return {...resp,valid:false }; + } + //get variables etc from node + let attrs = aliases2params('def_event_element',node); + let tmp = { event_test:node.text.trim() }; + let params = { n_params:[], v_params:[], event:node.text.trim(), id:node.id }; + params.type='async'; + if (params.async && params.async=='false') params.type='sync'; + if (params.async) delete params.async; + let isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + //add event name aliases if not son of def_componente_view + if (!state.from_componente) { + if (['post:icon:click','post:icon'].includes(tmp.event_test)==true) params.event = 'click:append'; + if (['pre:icon:click','pre:icon'].includes(tmp.event_test)==true) params.event = 'click:prepend'; + } + params.parent_id = parent_node.id; + params.friendly_name = ""; + //if (!state.from_componente) { + let normal = require('url-record'), ccase = require('fast-case'); + let short_event = params.event.split('.')[0].split(':')[0]; + let tmp_name = ''; + if (parent_node.text.includes('$variables')) { + tmp_name = short_event; + } else { + tmp_name = short_event+'-'+parent_node.text.split('.')[0]; + } + if (state.friendly_name && state.friendly_name!='') { + params.friendly_name = normal(state.friendly_name).split('-')[0]; + tmp_name = short_event+'-'+params.friendly_name.split('.')[0]; + } + params.friendly_name = tmp_name; + //params.friendly_name = normal(tmp_name); //.split('-')[0]; + params.friendly_name = ccase.camelize(params.friendly_name); //`${params.event.split('.')[0]}_`+ + if (params.friendly_name in context.x_state.pages[state.current_page].track_events) { + context.x_state.pages[state.current_page].track_events[params.friendly_name].count += 1; + params.friendly_name = params.friendly_name+context.x_state.pages[state.current_page].track_events[params.friendly_name].count; + } else { + context.x_state.pages[state.current_page].track_events[params.friendly_name] = { count:1 }; + } + //has link? ex. img @event='othermethod' + if (node.link!='' && node.link.includes('ID_')) { + // get event friendly name - @todo check when target is a declared method and not an event - checked and ready! + params.link = 'x'; + params.link_id = node.link; + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true) { + params.link = link_node.text; + } + } + // + delete attrs.refx; + //convert keys to params n_params, and values to v_params + for (let key in attrs) { + if (key.charAt(0)==':') { + params.n_params.push(key.right(key.length-1)); + let val_tmp = attrs[key]; + if (val_tmp.charAt(0)=='$') { + val_tmp = val_tmp.right(val_tmp.length-1); + } + params.v_params.push(val_tmp); + } else if (attrs[key].includes('**') && node.icons.includes('bell')) { + params.n_params.push(key); + let sv = getTranslatedTextVar(attrs[key]); + params.v_params.push(sv); + } else { + params.n_params.push(key); + if (isNumeric(attrs[key])) { + params.v_params.push(attrs[key]); + } else if (attrs[key]=='') { + params.v_params.push('$event'); + } else if (attrs[key].includes('this.') || attrs[key].includes('$event')) { + params.v_params.push(attrs[key]); + } else if (attrs[key].includes('**') && node.icons.includes('bell')) { + let sv = getTranslatedTextVar(attrs[key]); + params.v_params.push(sv); + } else { + params.v_params.push(`'${attrs[key]}'`); + } + } + await setImmediatePromise(); //@improved + } + //add npm packages when needed + if (tmp.event_test=='visibility') { + context.x_state.npm['vue-observe-visibility'] = '*'; + context.x_state.nuxt_config.head_script['polyfill_visibility'] = { src:'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver' }; + context.x_state.pages[state.current_page].imports['vue-observe-visibility'] = `{ ObserveVisibility }`; + context.x_state.pages[state.current_page].directives['observe-visibility'] = 'ObserveVisibility'; + } + //code + params.n_params = params.n_params.join(','); + params.v_params = params.v_params.join(','); + resp.open = context.tagParams('vue_event_element', params, false)+''; + resp.state.from_script=true; + return resp; + } + }, + + 'def_script': { + x_icons: 'desktop_new', + x_level: '>2', + x_text_exact: 'script', + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: `Representa un tag script inyectado en el lugar indicado. Permite escribir y ejecutar código en la posición definida. + Si se define un link, el link se especifica con atributo src y en sus hijos el script se ejecuta luego de cargarlo.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let params = aliases2params('def_script',node); + if (node.link!='') params.src = node.link; + //add packages + context.x_state.npm['vue-script2'] = '*'; + context.x_state.plugins['vue-script2'] = { global:true, mode: 'client', npm: { 'vue-script2':'*' }}; + //code + resp.open = context.tagParams('script2', params, false); + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.close = ''; + resp.state.from_script=true; + return resp; + } + }, + + //*def_script + //*def_event_server + //*def_event_mounted + //*def_event_method + //*def_event_element + + 'def_condicion_view': { + x_icons: 'help', + x_level: '>2', + x_text_contains: 'condicion si', + x_text_pattern: [ + `condicion si "*" +(es|no es|es menor a|es menor o igual a|es mayor a|es mayor o igual a|es menor que|es menor o igual que|es mayor que|es mayor o igual que|esta entre|contiene registro|contiene|contiene item) "*"`, + `condicion si "*" no es "*/*"`, + `condicion si "*" es +(objeto|array|struct|string|texto)`, + `condicion si "*" es +(numero|entero|int|booleano|boleano|boolean|fecha|date|email|rut|nulo|nula)`, + `condicion si "*" no es +(numero|entero|int|booleano|boleano|boolean|fecha|date|email|rut)`, + `condicion si "*" +(esta vacia|esta vacio|is empty|existe|exists|no es indefinido|no es indefinida|esta definida|no esta vacio|existe|esta definida|no es nula|no es nulo|es nula|not empty)`, + `condicion si "*" +(no contiene registros|contiene registros)`, + `condicion si "*" esta entre "*" inclusive` + ], + x_or_hasparent: 'def_page,def_componente,def_layout', + hint: `Declara que la/s vista/s hija/s deben cumplir la condicion indicada para ser visibles.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + let isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + if (resp.state.from_script && resp.state.from_script==true) return {...resp,...{ valid:false }}; + // detect which pattern did the match + let match = require('minimatch'); + let which = -1, did_match=false; + let text_trim = node.text.trim(); + for (let x of context.x_commands['def_condicion_view'].x_text_pattern) { + which+=1; + let test = match(text_trim,x); + if (test==true) { + did_match=true; + break; + } + await setImmediatePromise(); //@improved + }; + if (!did_match) throw `no matching pattern 'condicion' node for case!`; + + // extract the values + let extract = require('extractjs')(); + let defaults = { variable:'', operator:'es', value:'' }; + let patterns = [ + `condicion si "{variable}" {operator} "{value}"`, + `condicion si "{variable}" {operator} "{value}"`, + `condicion si "{variable}" {operator}`, + `condicion si "{variable}" {operator}`, + `condicion si "{variable}" {operator}`, + `condicion si "{variable}" {operator}`, + `condicion si "{variable}" {operator}`, + `condicion si "{variable} esta entre "{value}" inclusive` + ]; + + let elements = {...defaults,...extract(patterns[which],text_trim)}; + // pre-process elements + let original_value = elements.value; + if (typeof elements.variable === 'string' && elements.variable.includes('**') && node.icons.includes('bell')) elements.variable = getTranslatedTextVar(elements.variable); + if (typeof elements.value === 'string' && elements.value.includes('**') && node.icons.includes('bell')) elements.value = getTranslatedTextVar(elements.value); + if (typeof elements.variable === 'string' && (elements.variable.includes('$variables.') || + elements.variable.includes('$vars.') || + elements.variable.includes('$params.') || + elements.variable.includes('$store.') || + elements.variable.includes('$route.')) + ) { + } else if (typeof elements.variable === 'string' && elements.variable.charAt(0)=='$') { + elements.variable = elements.variable.right(elements.variable.length-1); + } + // test for siblings conditions + elements.type = 'v-if'; + let before_me = await context.dsl_parser.getBrotherNodesIDs({ id:node.id, before:true, after:false, array:true }); + if (before_me.length>0) { + if (before_me[0].TEXT && before_me[0].TEXT.includes('condicion si')) { + elements.type = 'v-else-if' + } + } + let escape_value = function(value2) { + let value = value2; + if (typeof value !== 'undefined') { + if ((typeof value === 'string' && isNumeric(value) && value.charAt(0)!='0') || + !isNaN(value) || + (typeof value === 'string' && (value=='true' || value=='false')) || + (typeof value === 'string' && (value.charAt(0)=='$') || value.includes('this.')) + ) { + //value = value; + } else if (original_value.includes('**') && value!=original_value) { + } else { + value = `'${value}'`; + } + } + return value; + }; + // tag params + let params = aliases2params('def_condicion_view',node); + params = {...params, ...{ + target: 'template', + tipo: elements.type, + operador: elements.operator, + valor: elements.value + }}; + let sons = await node.getNodes(); + if (sons.length==1) params.target=sons[0].id; //.id + if (params.individual && (params.individual==true || params.individual=='true')) { + params.tipo = 'v-if'; elements.type = 'v-if'; + delete params.individual; + } + // get full expression, depending on operator + if (elements.operator=='idioma es') { + params.expresion = `this.$i18n && this.$i18n.locale=='${elements.variable}'`; + } else if (['es','=','eq'].includes(elements.operator)) { + if (elements.value==true && elements.value!=1) { + params.expresion = elements.variable; + } else if (elements.value==false && elements.value!=0) { + params.expresion = '!'+elements.variable; + } else if (typeof elements.value === 'string' && ( + elements.value.includes('$variables.') || + elements.value.includes('$vars.') || + elements.value.includes('$params.') || + elements.value.includes('$store.') || + elements.value.includes('this.') + )) { + params.expresion = `${elements.variable} == ${elements.value}`; + } else if (typeof elements.value === 'number') { + params.expresion = `${elements.variable} == ${elements.value}`; + } else if (typeof elements.value === 'string' && + elements.value.charAt(0)=='(' && elements.value.right(1)==')') { + let temp = elements.value.substr(1,elements.value.length-2); + params.expresion = `${elements.variable} == ${temp}`; + } else if (typeof elements.value === 'string' && + elements.value.charAt(0)=='$' && elements.value.includes(`$t('`)==false) { + let temp = elements.value.right(elements.value.length-1); + params.expresion = `${elements.variable} == ${temp}`; + } else if (typeof elements.value === 'string' && (elements.value=='true' || elements.value=='false' || isNumeric(elements.value))) { + params.expresion = `${elements.variable} == ${elements.value}`; + } else if (original_value.includes('**') && elements.value!=original_value) { + //means it had variables + params.expresion = `${elements.variable} == ${elements.value}`; + } else { + params.expresion = `${elements.variable} == ${escape_value(elements.value)}`; + } + + } else if ('es string,es texto,string,texto'.split(',').includes(elements.operator)) { + params.expresion = `_.isString(${elements.variable})`; + + } else if ('es numero,es int,numero,int'.split(',').includes(elements.operator)) { + params.expresion = `_.isNumber(${elements.variable})`; + + } else if ('es boolean,es boleano,es booleano,booleano,boleano,boolean'.split(',').includes(elements.operator)) { + params.expresion = `_.isBoolean(${elements.variable})`; + + } else if ('es fecha,es date,fecha,date'.split(',').includes(elements.operator)) { + params.expresion = `_.isDate(${elements.variable})`; + + } else if ('es entero,es int,entero,int'.split(',').includes(elements.operator)) { + params.expresion = `_.isFinite(${elements.variable})`; + + } else if ('es array,array'.split(',').includes(elements.operator)) { + params.expresion = `_.isArray(${elements.variable})`; + + } else if ('es struct,struct'.split(',').includes(elements.operator)) { + params.expresion = `_.isObject(${elements.variable}) && !_.isArray(${elements.variable}) && !_.isFunction(${elements.variable})`; + + } else if ('es objeto,objeto'.split(',').includes(elements.operator)) { + params.expresion = `_.isObject(${elements.variable})`; + + } else if ('es correo,es email,email,correo'.split(',').includes(elements.operator)) { + params.expresion = `_.isString(${elements.variable}) && /\\S+@\\S+\\.\\S+/.test(${elements.variable})`; + + } else if ('no es correo,no es email'.split(',').includes(elements.operator)) { + params.expresion = `!(_.isString(${elements.variable}) && /\\S+@\\S+\\.\\S+/.test(${elements.variable}))`; + + } else if ('es rut'.split(',').includes(elements.operator)) { + params.expresion = `(validarRUT(${elements.variable})==true)`; + + } else if ('no es rut'.split(',').includes(elements.operator)) { + params.expresion = `(!validarRUT(${elements.variable}))`; + + //numeric testings + } else if ('es menor o igual a,es menor o igual que'.split(',').includes(elements.operator)) { + params.expresion = `_.isNumber(${elements.variable}) && _.isNumber(${elements.value}) && ${elements.variable} <= ${elements.value}`; + + } else if ('es menor a,es menor que'.split(',').includes(elements.operator)) { + params.expresion = `_.isNumber(${elements.variable}) && _.isNumber(${elements.value}) && ${elements.variable} < ${elements.value}`; + + } else if ('es mayor o igual a,es mayor o igual que'.split(',').includes(elements.operator)) { + params.expresion = `_.isNumber(${elements.variable}) && _.isNumber(${elements.value}) && ${elements.variable} >= ${elements.value}`; + + } else if ('es mayor a,es mayor que'.split(',').includes(elements.operator)) { + params.expresion = `_.isNumber(${elements.variable}) && _.isNumber(${elements.value}) && ${elements.variable} > ${elements.value}`; + + } else if ('esta entre'==elements.operator && elements.value.includes(',')) { + let from = elements.value.split(',')[0]; + let until = elements.value.split(',').pop(); + params.expresion = `${elements.variable} >= ${from} && ${elements.variable} <= ${until}`; + + // strings + } else if ('no esta vacio,not empty'.split(',').includes(elements.operator)) { + params.expresion = `(_.isObject(${elements.variable}) || (_.isString(${elements.variable})) && !_.isEmpty(${elements.variable})) || _.isNumber(${elements.variable}) || _.isBoolean(${elements.variable})`; + + } else if ('esta vacio,is empty,esta vacia'.split(',').includes(elements.operator)) { + params.expresion = `(_.isObject(${elements.variable}) ||_.isString(${elements.variable})) && _.isEmpty(${elements.variable})`; + + // other types + } else if ('existe,exists,no es indefinido,no es indefinida,esta definida'.split(',').includes(elements.operator)) { + params.expresion = `!_.isUndefined(${elements.variable})`; + + } else if ('no existe,doesnt exists,es indefinido,es indefinida,no esta definida'.split(',').includes(elements.operator)) { + params.expresion = `_.isUndefined(${elements.variable})`; + + } else if ('no es nula,no es nulo'.split(',').includes(elements.operator)) { + params.expresion = `!_.isNull(${elements.variable})`; + + } else if ('es nula,es nulo'.split(',').includes(elements.operator)) { + params.expresion = `_.isNull(${elements.variable})`; + + } else if ('no es,!=,neq'.split(',').includes(elements.operator)) { + params.expresion = `${elements.variable}!=${escape_value(elements.value)}`; + + // records + } else if ('no contiene registros,contains no records'.split(',').includes(elements.operator)) { + params.expresion = `${elements.variable} && ${elements.variable}.length==0`; + + } else if ('contiene registros,contains records'.split(',').includes(elements.operator)) { + params.expresion = `${elements.variable} && ${elements.variable}.length`; //@todo check if this needs to be .length>0 + + } else if ('contiene registro,contiene item'.split(',').includes(elements.operator)) { + params.expresion = `_.contains(${elements.variable},${escape_value(elements.value)})`; + + } else if ('contiene,contains'.split(',').includes(elements.operator)) { + params.expresion = `${elements.variable}.toLowerCase().indexOf(${escape_value(elements.value)}.toLowerCase())!=-1`; + + } else { + //operator not defined + context.x_console.outT({ message:`Operator (${elements.operator}) not defined in 'condicion si' x_command`, color:'red', data:{elements,params,which} }); + throw `Operator ${elements.operator} not defined in '${node.text}'`; + //params.expresion = `(AQUI VAMOS: ${node.text})`; + } + + //comments? + if (node.text_note != '') resp.open += `\n`; + // prepare expressions + let expresion_js = params.expresion. replaceAll('$variables.','this.') + .replaceAll('$vars.','this.') + .replaceAll('$params.','this.'); + let expresion_view = params.expresion. replaceAll('$variables.','') + .replaceAll('$vars.','') + .replaceAll('$params.',''); + if (state.current_proxy) { + expresion_js = expresion_js.replaceAll('$store.','store.state.'); + expresion_view = expresion_view.replaceAll('$store.','store.state.'); + expresion_js = expresion_js.replaceAll('this.$config.','$config.'); + expresion_view = expresion_view.replaceAll('this.$config.','$config.'); + } else { + expresion_js = expresion_js.replaceAll('$store.','this.$store.state.'); + expresion_view = expresion_view.replaceAll('$store.','$store.state.'); + expresion_js = expresion_js.replaceAll('$config.','this.$config.'); + expresion_view = expresion_view.replaceAll('this.$config.','$config.'); + } + resp.state.meta = { if_js:expresion_js, if_view:expresion_view, params, elements }; + // add support for validar-rut npm library + if (params.expresion && params.expresion.includes('validarRUT')) { + context.x_state.npm['validar-rut']='*'; + //create virtual var 'computed' with underscore + resp.open += context.tagParams('vue_computed', { + name: `validarRUT`, + type: 'computed' + }, false)+'`; + resp.state.meta.script = `let { validarRUT } = require('validar-rut');\n`; + } + // prepare virtual vars for underscore support + if (params.expresion && params.expresion.includes('_.')) { + if (state.current_page) { + context.x_state.pages[state.current_page].imports['underscore'] = '_'; + } else if (state.current_proxy) { + context.x_state.proxies[state.current_proxy].imports['underscore'] = '_'; + } else if (state.current_store) { + context.x_state.stores[state.current_store].imports['underscore'] = '_'; + } + //create virtual var 'computed' with underscore + resp.open += context.tagParams('vue_computed', { + name: `_`, + type: 'computed' + }, false)+'`; + /*resp.open += context.tagParams('vue_computed', { + name: `${node.id}_if`, + type: 'computed' + }, false)+'`;*/ + //@todo seems the expresion should be the new var here... (was not on the cfc) + //params.expresion = `${node.id}_if`; + } + //create vue_if or template tag code (in tags, this. don't go) + if (!(params.expresion.includes('_if'))) params.expresion = expresion_view; + if (params.target=='template') { + // code + resp.open += context.tagParams('template', { + [params.tipo]: params.expresion + }, false); + resp.close = ``; + } else { + // code + resp.open += context.tagParams('vue_if', params, false); + resp.close = ``; + } + return resp; + } + }, + + 'def_otra_condicion_view': { + x_icons: 'help', + x_level: '>2', + x_text_exact: 'otra condicion', + hint: `Visibiliza sus hijos en caso de no cumplirse la condicion anterior.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (resp.state.from_script && resp.state.from_script==true) return {...resp,...{ valid:false }}; + //code + let sons = await node.getNodes(); + if (sons.length>1) { + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += context.tagParams('template', { 'v-else': null }, false); + } else if (sons.length==1) { + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += context.tagParams('vue_if', { + 'expresion':'', + 'tipo':'v-else', + 'target': sons[0].id + }, false); + resp.close = ``; + } else { + // dont write if we dont have children + } + return resp; + } + }, + + 'def_condicion': { + x_icons: 'help', + x_level: '>2', + x_text_contains: 'condicion si', + x_watch: 'def_condicion_view', + hint: `Declara que los hijo/s deben cumplir la condicion indicada para ser ejecutados.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (!resp.state.from_script || (resp.state.from_script && resp.state.from_script==false)) return {...resp,...{ valid:false }}; + let condicion = await context.x_commands['def_condicion_view'].func(node, { ...state, ...{ + from_script:false + }}); + //code. + if (node.text_note != '') resp.open = `/* ${node.text_note.cleanLines()} */\n`; + if (condicion.state.meta.script) { + resp.open += condicion.state.meta.script; + } + if (condicion.state.meta.params.tipo=='v-if') { + resp.open += `if (${condicion.state.meta.if_js}) {\n`; + } else { + resp.open += `else if (${condicion.state.meta.if_js}) {\n`; + } + resp.close = `}\n`; + return resp; + } + }, + + 'def_otra_condicion': { + x_icons: 'help', + x_level: '>2', + x_text_exact: 'otra condicion', + hint: `Ejecuta sus hijos en caso de no cumplirse la condicion anterior.`, + func: async function(node, state) { + let resp = context.reply_template({ + state, + hasChildren: true + }); + if (!resp.state.from_script || (resp.state.from_script && resp.state.from_script==false)) return {...resp,...{ valid:false }}; + //code + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += `else {\n`; + resp.close = `}\n`; + return resp; + } + }, + + //*def_condicion_view + //*def_otra_condicion_view + //*def_condicion (def_script_condicion) + //*def_otra_condicion (def_script_otra_condicion) + + + // ************* + // VARIABLES + // ************* + + 'def_variables': { + x_icons: 'xmag', + x_level: '3,4', + x_or_hasparent: 'def_page,def_componente,def_layout', + x_text_contains: 'variables', + hint: 'Definicion local de variables observadas', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = {}; + // process attributes as variables + // set vars + if (typeof state.current_page !== 'undefined') { + if (typeof context.x_state.pages[state.current_page] === 'undefined') context.x_state.pages[state.current_page] = {}; + if ('variables' in context.x_state.pages[state.current_page] === false) context.x_state.pages[state.current_page].variables = {}; + if ('types' in context.x_state.pages[state.current_page] === false) context.x_state.pages[state.current_page].types = {}; + } + resp.state.from_variables=true; + return resp; + } + }, + + 'def_variables_field': { + x_priority: 1, + x_empty: 'icons', + x_level: '>3', + x_all_hasparent: 'def_variables', + hint: 'Campo con nombre de variable observada y tipo', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.icons.includes('bookmark')==true) return {...resp,...{ valid:false }}; + if (resp.state.vars_path) resp.state.vars_last_level = resp.state.vars_path.length; + //console.log('FIRST CALL var state',resp.state ); + let params = {}, + tmp = { + type: 'string', + field: node.text.trim(), + level: node.level - 3 + }; + let padres = await context.getParentIDs(node.id, false); + if (padres.split(',').includes('def_variables_mock')==true) { + return {...resp,...{ valid:false }}; + } + //console.log('padres test dummy_group',padres); + if (padres.split(',').includes('def_dummy_group')==true) { + tmp.level -= 1; + //console.log('DEBUG this has a dummy parent - def_dummy_group',tmp); + } + // + if ((tmp.field.includes('[') && tmp.field.includes(']')) || + (tmp.field.includes('{') && tmp.field.includes('}'))) { + // this is a script node + tmp.type = 'script'; + tmp.field = `script${node.id}`; + + } else if (tmp.field.includes(':')) { + tmp.type = tmp.field.split(':').pop().toLowerCase().trim(); //listlast + tmp.field = tmp.field.split(':')[0].trim(); + } else if (node.nodes_raw && node.nodes_raw.length > 0) { + // get children nodes, and test that they don't have a help icon. + let subnodes = await node.getNodes(); + let has_event = false; + for (let i of subnodes) { + if (i.icons.includes('help') && i.text=='change') { + has_event = true; + } + await setImmediatePromise(); //@improved + } + if (has_event == false) { + tmp.type = 'object'; + } + } else { + tmp.type = 'string'; + } + // process attributes (and overwrite types if needed) + Object.keys(node.attributes).map(function(keym) { + let keytest = keym.toLowerCase().trim(); + let value = node.attributes[keym]; + //console.log(`${tmp.field} attr key:${keytest}, value:${value}`); + if ('type,tipo,:type,:tipo'.split(',').includes(keytest)) { + tmp.type = value.toLowerCase().trim(); + } else if ('valor,value,:valor,:value'.split(',').includes(keytest)) { + let t_value = value.replaceAll('$variables', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + if (t_value.toLowerCase().trim() == '{now}') t_value = 'new Date()'; + if (t_value.includes('assets:')) { + t_value = context.getAsset(t_value, 'js'); + } + params.value = t_value; + } else { + if (keytest.includes(':')) { + params[keym.trim()] = value.trim(); + } + } + }); + // assign default value for type, if not defined + if ('string,text,texto'.split(',').includes(tmp.type)) { + if ('value' in params === false) { + params.value = ''; + } else { + params.value = params.value.toString(); + } + } else if ('script' == tmp.type) { + params.value = node.text.trim().replaceAll(' ', '') + .replaceAll(''', '"') + .replaceAll('ñ', 'ñ'); + let copy_test = [...resp.state.vars_types]; + if (params.value.charAt(0) != '[' && params.value.charAt(0) != '{') { + params.value = '[' + params.value + ']'; + } else if (copy_test.pop()=='array' && params.value.charAt(0) != '[') { + params.value = '[' + params.value + ']'; + } + let convertjs = require('safe-eval'); + try { + params.value = convertjs(params.value); + } catch (cjerr) { + params.value = [{ + error_in_script_var: cjerr + }]; + } + //params.value = JSON.parse('['+params.value+']'); + + } else if ('date,datetime'.split(',').includes(tmp.type)) { + if ('value' in params === false) { + params.value = new Date(); + } else { + let convertjs = require('safe-eval'); + try { + params.value = convertjs(params.value); + } catch (cjerr) { + } + } + + } else if ('int,numeric,number,numero'.split(',').includes(tmp.type)) { + if ('value' in params === false) { + params.value = 0; + } else { + params.value = parseInt(params.value); + } + } else if ('float,real,decimal'.split(',').includes(tmp.type)) { + if ('value' in params === false) { + params.value = 0.0; + } else { + params.value = parseFloat(params.value); + } + } else if ('boolean,boleano,booleano'.split(',').includes(tmp.type)) { + if ('value' in params === false) { + if (tmp.field == 'true') { + // ex value of an array (true/false) + params.value = true; + } else if (tmp.field == 'false') { + params.value = false; + } else { + params.value = false; + } + } else { + if (params.value == 'true') { + // ex value of an array (true/false) + params.value = true; + } else if (params.value == 'false') { + params.value = false; + } + } + } else if ('array'.split(',').includes(tmp.type)) { + tmp.type = 'array'; + if ('value' in params === false) { + params.value = []; + } else { + params.value = JSON.parse(params.value); + } + + } else if ('struct,object'.split(',').includes(tmp.type)) { + tmp.type = 'object'; + if ('value' in params === false) { + params.value = {}; + } else { + params.value = JSON.parse(params.value); + } + } else if ('null,nulo'.split(',').includes(tmp.type)) { + tmp.type = 'null'; + if ('value' in params === false) { + params.value = null; + } else { + params.value = JSON.parse(params.value); + } + } + // check and prepare global state + if (typeof state.current_page !== 'undefined') { + if (state.current_page in context.x_state.pages === false) context.x_state.pages[state.current_page] = {}; + if ('variables' in context.x_state.pages[state.current_page] === false) context.x_state.pages[state.current_page].variables = {}; + if ('var_types' in context.x_state.pages[state.current_page] === false) context.x_state.pages[state.current_page].var_types = {}; + } + // assign var info to page state + if (tmp.level == 1) { + // this is a single variable (no dad); eq. variables[field] = value/children + context.x_state.pages[state.current_page].var_types[tmp.field] = tmp.type; + context.x_state.pages[state.current_page].variables[tmp.field] = params.value; + resp.state.vars_path = [tmp.field]; + resp.state.vars_types = [tmp.type]; + resp.state.vars_last_level = tmp.level; + } else { + // variables[prev_node_text][current_field] = value + //console.log(`testing ${tmp.level} (current level) with ${resp.state.vars_last_level} (last var level)`); + if (tmp.level>resp.state.vars_last_level) { + //current is son of prev + //console.log(`current var '${tmp.field}' (${tmp.level}) is SON of '${resp.state.vars_path.join('.')}' (${resp.state.vars_last_level})`); + resp.state.vars_path.push(tmp.field); // push new var to paths + resp.state.vars_types.push(tmp.type); + //console.log(`trying to set: ${resp.state.vars_path.join('.')} on context.x_state.pages['${state.current_page}'].variables as ${tmp.type}`); + + } else if (tmp.level==resp.state.vars_last_level) { + //current is brother of prev + //console.log(`current var '${tmp.field}' (${tmp.level}) is BROTHER of '${resp.state.vars_path.join('.')}' (${resp.state.vars_last_level})`); + resp.state.vars_path.pop(); // remove last field from var path + resp.state.vars_types.pop(); // remove last field type from vars_types + //console.log(`vars_path AFTER pop: `,resp.state.vars_path); + resp.state.vars_path.push(tmp.field); // push new var to paths + resp.state.vars_types.push(tmp.type); + //console.log(`trying to set: ${resp.state.vars_path.join('.')} on context.x_state.pages['${state.current_page}'].variables as ${tmp.type}`); + + } else { + //current path is smaller than last + //console.log(`current var '${tmp.field}' (${tmp.level}) is UPPER of '${resp.state.vars_path.join('.')}' (${resp.state.vars_last_level})`); + //console.log(`new var has higher hierarchy than last! ${resp.state.vars_last_level} > ${tmp.level}`); + //console.log('error dump',{ last_level:resp.state, tmp}); + let amount=new Array(resp.state.vars_last_level-tmp.level+1); + for (let t of amount) { + //console.log(`vars_path before pop: `,resp.state.vars_path); + resp.state.vars_path.pop(); // remove last field from var path + resp.state.vars_types.pop(); // remove last field type from vars_types + await setImmediatePromise(); //@improved + } + //console.log(`vars_path AFTER pops: `,resp.state.vars_path); + resp.state.vars_path.push(tmp.field); // push new var to paths + resp.state.vars_types.push(tmp.type); + //console.log(`trying to set: ${resp.state.vars_path.join('.')} on context.x_state.pages['${state.current_page}'].variables as ${tmp.type}`); + } + //console.log('MY DAD TYPE:'+resp.state.vars_types[resp.state.vars_types.length - 2]); + if (resp.state.vars_types[resp.state.vars_types.length - 2] == 'object') { + // dad was an object + let copy_dad = [...resp.state.vars_path]; + if (typeof params.value == 'object' && resp.state.vars_types[resp.state.vars_types.length-1] == 'script') { + copy_dad.pop(); + } + try { + setToValue(context.x_state.pages[state.current_page].variables, params.value, copy_dad.join('.')); + } catch(err_setv) { + console.log('error setting var to parent obj',{value:params.value, copy_dad:copy_dad.join('.') }); + } + } else if (resp.state.vars_types[resp.state.vars_types.length - 2] == 'array') { + //console.log('dad was an array',{ type:resp.state.vars_types[resp.state.vars_types.length-1], path:resp.state.vars_path}); + // dad is an array.. + let copy_dad = [...resp.state.vars_path]; + copy_dad.pop(); + //console.log('my dad path is '+copy_dad.join('.')); + let daddy = getVal(context.x_state.pages[state.current_page].variables, copy_dad.join('.')); + //console.log('daddy says:',daddy); + if (tmp.type == 'script') { + // if we are a script node, just push our values, and not ourselfs. + if (Array.isArray(params.value)) { + params.value.map(i => { + daddy.push(i); + }); + } + + } else if (tmp.field != params.value) { + // push as object (array of objects) + let tmpi = {}; + tmpi[tmp.field] = params.value; + daddy.push(tmpi); + } else { + // push just the value (single value) + daddy.push(params.value); + } + // re-set daddy with new value + setToValue(context.x_state.pages[state.current_page].variables, daddy, copy_dad.join('.')); + } + //*resp.state.vars_types.push(tmp.type); // push new var type to vars_types + context.x_state.pages[state.current_page].var_types[resp.state.vars_path.join('.')] = tmp.type; + resp.state.vars_last_level = resp.state.vars_path.length; + //console.log('BEFORE close: state for next var (cur level: '+tmp.level+', last_level:'+resp.state.vars_last_level+')',resp.state); + //resp.state.vars_last_level = tmp.level; + } + return resp; + } + }, + + 'def_variables_watch': { + x_icons: 'help', + x_level: '>4', + x_text_contains: 'change', + x_all_hasparent: 'def_variables,def_variables_field', + hint: 'Monitorea los cambios realizados a la variable padre', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.nodes_raw.length==0) return resp; + let params = { + name: node.text.trim(), + type: 'watched', + oldvar: 'old', + newvar: 'new' + }; + // process attributes + Object.keys(node.attributes).map(function(keym) { + let keytest = keym.toLowerCase().trim(); + let value = node.attributes[keym]; + if (':old,old'.split(',').includes(keytest)) { + params.oldvar = value; + } else if (':new,new'.split(',').includes(keytest)) { + params.newvar = value; + } else if (':deep,deep'.split(',').includes(keytest)) { + params.deep = value; + } + }); + //get parent node (for deep vars)@todo + if (resp.state.vars_path.length>1) { + //search real parent var tree + let parents = await context.dsl_parser.getParentNodesIDs({ id:node.id, array:true }); + let parents_ = []; + for (let parent_id of parents) { + let node = await context.dsl_parser.getNode({ id:parent_id, recurse:false }); + if (node.icons.length>0) break; + parents_.push(node.text.split(':')[0]); + } + //console.log('parents_: ',parents_.reverse().join('.')); + params.flat = parents_.reverse().join('.'); + } else { + params.flat = resp.state.vars_path.join('.'); // inherit parent var from def_variables_field last state + } + // write tag + resp.open = context.tagParams('vue_watched_var', params, false)+''; + resp.state.from_script=true; + return resp; + } + }, + + 'def_variables_func': { + x_icons: 'help', + x_level: '4,5', + x_not_text_contains: ':server,condicion si,otra condicion', + x_all_hasparent: 'def_variables', + hint: 'Variable tipo funcion', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + name: node.text.trim(), + type: 'computed' + }; + let tmp = { + type: 'async' + }; + // process attributes + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim().replaceAll(':', ''); + let value = node.attributes[key].trim(); + if ('default' == keytest) { + params.valor = value; + } else if ('valor,value'.split(',').includes(keytest)) { + params.valor = value; + } else if ('lazy' == keytest) { + params.lazy = (value == 'true') ? true : false; + } else if ('observar,onchange,cambie,cambien,modifiquen,cuando,monitorear,watch'.split(',').includes(keytest)) { + params.watch = value; + } else if ('async' == keytest) { + tmp.type = (value == 'true') ? 'async' : 'sync'; + } + }); + // built response + if (tmp.type == 'async') { + // add async plugin to app + context.x_state.plugins['vue-async-computed'] = { + global: true, + npm: { + 'vue-async-computed': '*' + } + }; + resp.open = context.tagParams('vue_async_computed', params, false)+'\n'; + } else { + resp.open = context.tagParams('vue_computed', params, false)+'\n'; + } + resp.state.from_script=true; + // return + return resp; + } + }, + + 'def_variables_mock': { + x_icons: 'bookmark', + x_level: '4,5', + x_not_text_contains: ':server,condicion si,otra condicion', + x_all_hasparent: 'def_variables', + hint: 'Variable tipo mockup', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let params = { + name: node.text.split(':')[0].trim(), + type: 'computed' + }; + let tmp = { + type: 'computed', + repeat: 1, + template: '', + _min:null, + _max:null, + seed:null + }; + // process attributes + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim().replaceAll(':', ''); + let value = node.attributes[key].trim(); + if ('default' == keytest) { + params.valor = value; + } else if ('valor,value'.split(',').includes(keytest)) { + params.valor = value; + } else if ('lazy' == keytest) { + params.lazy = (value == 'true') ? true : false; + } else if ('observar,onchange,cambie,cambien,modifiquen,cuando,monitorear,watch'.split(',').includes(keytest)) { + params.watch = value; + } else if ('async' == keytest) { + tmp.type = (value == 'true') ? 'async' : 'sync'; + } else if ('min' == keytest) { + tmp._min = value; + } else if ('max' == keytest) { + tmp._max = value; + } else if ('seed' == keytest) { + tmp.seed = value; + } else if ('cantidad' == keytest) { + tmp.repeat = value; + } + }); + // build transform method + let translate = async function(child) { + let full = child.text.split(':'); + let key = full.shift(); + let cmd = ['random']; //default cmd + let value = ''; + if (full.length>0) { + cmd = full.shift().split(' '); + } + if (cmd[0]=='placeholder') { + value = 'https://via.placeholder.com/'; + if (cmd[1]) value+= cmd[1]+'/'; + if (child.attributes.hexColor) { + if (child.attributes.hexColor=='random') { + value += '{{hexColor websafe=true withHash=false}}'; + } else { + value += ''+child.attributes.hexColor; + } + } + value = `"${value}"`; + } else if (cmd[0]=='picture') { + value = 'https://api.lorem.space/image/face?'; + if (cmd[1]) { + let tmp_w = cmd[1].split('x'); + value+= `w=${tmp_w[0]}&h=${tmp_w[1]}&rnd={{int 0 999999}}`; + } + value = `"${value}"`; + //https://api.lorem.space/image/face?w=150&h=150 + } else if (cmd[0]=='random') { + //use children as posible values + let grandChildren = await child.getNodes(); + if (grandChildren.length==0) { + //use lorem if no children + value = '"{{lorem 20}}"'; + } else { + let gchilds = []; + for (gchild of grandChildren) { + if (gchild.valid==true) { + gchilds.push(`'${gchild.text.replaceAll("'","\'")}'`); + } + } + value = `"{{random ${gchilds.join(' ')}}}"`; + } + } else if (cmd[0]=='lorem') { + if (cmd[1]) { + value+= `"{{lorem ${cmd[1].trim()}}}"`; + } else { + value = '"{{lorem 20}}"'; + } + } else if (cmd[0]=='boolean') { + value = '{{boolean}}'; + } else if (cmd[0]=='id' || cmd[0]=='@index') { + value = '{{@index}}'; + } else if (cmd[0]=='nombre' || cmd[0]=='firstname') { + value = '"{{firstName}}"'; + } else if (cmd[0]=='apellido' || cmd[0]=='lastname') { + value = '"{{lastName}}"'; + } else if (cmd[0]=='empresa' || cmd[0]=='company') { + value = '"{{company}}"'; + } else if (cmd[0]=='email' || cmd[0]=='correo') { + value = '"{{email}}"'; + } else if (cmd[0]=='ciudad' || cmd[0]=='city') { + value = '"{{city}}"'; + } else if (cmd[0]=='calle' || cmd[0]=='street') { + value = '"{{street}}"'; + } else if (cmd[0]=='pais' || cmd[0]=='country') { + value = '"{{country}}"'; + } else if (cmd[0]=='latitud' || cmd[0]=='latitude') { + value = '{{lat}}'; + } else if (cmd[0]=='longitud' || cmd[0]=='longitude') { + value = '{{long}}'; + } else if (cmd[0]=='dominio' || cmd[0]=='domain') { + value = '"{{domain}}"'; + } else if (cmd[0]=='telefono' || cmd[0]=='phone') { + cmd[0] = 'phone'; + if (cmd.length>1) { + value = `{{${cmd.join(' ')}}}`; + } else { + value = `{{phone "+56x xxxx xxxx"}}`; + } + } else if (cmd[0]=='int') { + if (cmd.length>1 && cmd.length<4) { + value = `{{${cmd.join(' ')}}}`; + } else if (cmd.length==4) { + // if includes formatting, declare as string + value = `"{{${cmd.join(' ')}}}"`; + } else { + value = `{{int 0 999999}}`; + } + } else if (cmd[0]=='float') { + if (cmd.length>1) { + value = `{{${cmd.join(' ')}}}`; + } else { + value = `{{float 0 999999 '0.00'}}`; + } + } else if (cmd[0]=='date' || cmd[0]=='fecha') { + if (cmd.length>1) { + cmd[0]='date'; + if (cmd.length==4 && cmd[3].includes('unix')) { + value = `{{${cmd.join(' ')}}}`; + } else { + value = `"{{${cmd.join(' ')}}}"`; + } + } else { + value = `"{{date '1970-1-1' '2022-1-1'}}"`; + } + } else if (cmd[0]=='time' || cmd[0]=='hora') { + if (cmd.length>1) { + cmd[0]='time'; + if (cmd.length==4 && cmd[3].includes('unix')) { + value = `{{${cmd.join(' ')}}}`; + } else { + value = `"{{${cmd.join(' ')}}}"`; + } + } else { + value = `"{{time '00:00' '23:59'}}"`; + } + } else if (cmd[0].includes('$variables.')) { + value = '${JSON.stringify('+cmd[0].replaceAll('$variables.','this.')+')}'; + } else if (cmd[0].includes('{{')) { + //custom type {{int 0 10}} {{ciudad}} + value = `"${cmd.join(' ')}"`; + } + return { + key, + value + }; + }; + // build template + if (node.nodes_raw && node.nodes_raw.length > 0) { + // get children nodes to build template. + let children = await node.getNodes(); + //console.log(children); + let rows = []; + for (child of children) { + let new_ = await translate(child); + //console.log('new_',new_); + rows.push(`\t\t\t"${new_.key}":${new_.value}`); + } + tmp.template = "{ " + rows.join(',').replaceAll(`",\t`,`",\n\t`).replaceAll(`},\t`,`},\n\t`) + " }"; + //console.log('future template',rows); + } else { + // single mock variable + let new_ = await translate(node); + //console.log('single mock var',new_); + tmp.template = new_.value; + } + if (tmp._min && tmp._max) { + tmp.template = `[ + {{#repeat min=${tmp._min} max=${tmp._max}}} +${tmp.template} + {{/repeat}} +]`; + } else { + tmp.template = `[ + {{#repeat ${tmp.repeat}}} +${tmp.template} + {{/repeat}} +]`; + } + // + // build response + let code = ''; + //for each watch, add a virtual code, so vue monitors changes + if (params.watch) { + let watched = params.watch.split(','); + code += `//hack triggering update using watched vars\n`; + for (let value_ of watched) { + value_r = value_.replaceAll('$params.', 'this.') + .replaceAll('$variables.', 'this.') + .replaceAll('$config.', 'this.$config.') + .replaceAll('$store.', 'this.$store.state.'); + code += `if (${value_r}) { let _x_=${value_r}; }\n`; + } + code += `//end hack\n`; + } + // + code += `let dummy_json = require('dummy-json');\n`; + if (tmp.seed) code += `dummyjson.seed = '${tmp.seed}';\n`; + code += `let template = \`${tmp.template}\`;\n`; + code += `return JSON.parse(dummy_json.parse(template));\n`; + // + if (tmp.type == 'async') { + // add async plugin to app + context.x_state.plugins['vue-async-computed'] = { + global: true, + npm: { + 'vue-async-computed': '*', + 'dummy-json': '*' + } + }; + resp.open = context.tagParams('vue_async_computed', params, false)+'\n'; + } else { + context.x_state.npm['dummy-json'] = '*'; + resp.open = context.tagParams('vue_computed', params, false)+'\n'; + } + resp.state.from_script=true; + // return + return resp; + } + }, + // ************************* + // Scriptable definitions + // ************************* + + //..scripts.. + 'def_responder': { + x_icons: 'desktop_new', + //x_text_pattern: `responder "*"`, + x_text_contains: `responder "`, + x_or_hasparent: 'def_variables,def_event_element,def_event_method', + x_level: '>3', + hint: 'Emite una respuesta para la variable de tipo funcion o evento :rules', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + let text = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }); + // tests return types + if (text.includes('$')) { + text = text.replaceAll('$params.', 'this.') + .replaceAll('$variables.', 'this.'); + } + if (text.includes('**') && node.icons.includes('bell')) { + let new_vars = getTranslatedTextVar(text); + resp.open += `return ${new_vars};\n`; + } else if (node.text.includes('$')) { + resp.open += `return ${text};\n`; + } else if (text.includes('assets:')) { + text = context.getAsset(text, 'js'); + resp.open += `return ${text};\n`; + } else if (text == '') { + resp.open += `return '';\n`; + } else if (text.charAt(0) == '(' && text.slice(-1) == ')') { + text = text.slice(1).slice(0, -1); + resp.open += `return ${text};\n`; + } else { + if (context.x_state.central_config.idiomas && context.x_state.central_config.idiomas.includes(',')) { + // @TODO add support for i18m + } else { + resp.open += `return '${text}';\n`; + } + } + return resp; + } + }, + + 'def_struct': { + x_icons: 'desktop_new', + x_text_contains: 'struct,,', + x_not_text_contains: 'traducir', + x_level: '>3', + hint: 'Crea una variable de tipo Objeto, con los campos y valores definidos en sus atributos.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = {}; + // parse output var + tmp.var = node.text.split(',').pop().trim(); //last comma element + if (resp.state.from_server) { // if (context.hasParentID(node.id, 'def_event_server')==true) { + tmp.var = tmp.var.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + tmp.var = (tmp.var == 'resp.') ? 'resp' : tmp.var; + tmp.parent_server = true; + } else { + tmp.var = tmp.var.replaceAll('$variables.', 'this.') + .replaceAll('$store.', 'this.$store.state.') + .replaceAll('$config.', 'this.$config.') + .replaceAll('$params.', 'this.'); + tmp.var = (tmp.var == 'this.') ? 'this' : tmp.var; + } + // process attributes + let attrs = {...node.attributes + }; + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim(); + let value = node.attributes[key].trim(); + if (node.icons.includes('bell') && value.includes('**')) { + value = getTranslatedTextVar(value,true); + } else if (value.includes('assets:')) { + value = context.getAsset(value, 'js'); + } else { + // normalize vue type vars + if (tmp.parent_server==true) { + value = value.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + value = value.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + } + } + attrs[key] = value; //.replaceAll('{now}','new Date()'); + }); + // write output + if (resp.state.as_object) { + resp.state.object = attrs; + resp.open = context.jsDump(attrs).replaceAll("'`","`").replaceAll("`'","`"); + delete resp.state.as_object; + } else { + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += `let ${tmp.var.trim()} = ${context.jsDump(attrs).replaceAll("'`","`").replaceAll("`'","`")};\n`; + } + + return resp; + } + }, + + 'def_extender': { + x_level: '>3', + x_text_contains: `extender "`, + x_icons: 'desktop_new', + hint: 'Extiende los atributos de un objeto con los datos dados en los atributos.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + // create obj from current node as js obj + let obj = await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }}); + // get var name + let tmp = {}; + tmp.var = context.dsl_parser.findVariables({ + text: node.text, + symbol: '"', + symbol_closing: '"' + }).trim(); + // clean given varname $variables, etc. + if ((await context.hasParentID(node.id, 'def_event_server'))==true) { //@todo change after checking (revision) concepto inherited states; if (resp.state.from_server) { + tmp.var = tmp.var.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.').replaceAll('$params.', 'resp.'); + tmp.var = (tmp.var == 'resp.') ? 'resp' : tmp.var; + } else { + tmp.var = tmp.var.replaceAll('$variables.', 'this.').replaceAll('$params.', 'this.').replaceAll('$store.', 'this.$store.state.').replaceAll('$config.', 'this.$config.'); + tmp.var = (tmp.var == 'this.') ? 'this' : tmp.var; + } + // extend given var with 'extend_node' content + // support attr = !attr - 13may21 + for (let x in obj.state.object) { + if (typeof obj.state.object[x] === 'string' && obj.state.object[x].charAt(0)=='!' && + obj.state.object[x].includes('this.')==false) { + obj.state.object[x] = obj.state.object[x].replaceAll('!',`!${tmp.var}.`); + } + } + tmp.nobj = context.jsDump(obj.state.object); + //underscore (seems necesary because vue doesn't detect spreads) + if (state.current_page) { + context.x_state.pages[resp.state.current_page].imports['underscore'] = '_'; + } else if (state.current_proxy) { + context.x_state.proxies[resp.state.current_proxy].imports['underscore'] = '_'; + } else if (state.current_store) { + context.x_state.stores[resp.state.current_store].imports['underscore'] = '_'; + } + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + //resp.open = `${tmp.var} = {...${tmp.var},...${tmp.nobj}};\n`; + resp.open += `${tmp.var} = _.extend(${tmp.var}, ${tmp.nobj});\n`; + return resp; + } + }, + + 'def_literal_js': { + x_icons: 'penguin', + x_not_text_contains: 'por cada registro en', + x_level: '>1', + hint: 'Nodo JS literal; solo traduce $variables y referencias de refrescos a metodos async.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { text:node.text }; + if (node.icons.includes('idea')) { + resp.valid=false; + return resp; + } + if (node.text.includes('$variables.') && node.text.right(2)=='()') { + tmp.text = tmp.text .replaceAll('$variables.','this.$asyncComputed.') + .replaceAll('()','.update();') + .replaceAll(';;',';'); + } else if (node.text.includes('$vars.') && node.text.right(2)=='()') { + tmp.text = tmp.text .replaceAll('$vars.','this.$asyncComputed.') + .replaceAll('()','.update();') + .replaceAll(';;',';'); + } else if (node.text.includes('$params.') && node.text.right(2)=='()') { + //@TODO check this, doesn't look right + tmp.text = tmp.text .replaceAll('$params.','this.$asyncComputed.') + .replaceAll('()','.update();') + .replaceAll(';;',';'); + } else if (node.text.includes('$store.') && node.text.includes('this.$store.state')==false) { + tmp.text = tmp.text .replaceAll('$store.','this.$store.state.') + .replaceAll('this.$nuxt.this.$store.','this.$nuxt.$store.'); + } else if (node.text.includes('assets:')) { + let extract = require('extractjs')(); + let elements = extract(`'assets:{name}'`,node.text); + let value_ = context.getAsset('assets:'+elements.name, 'jsfunc'); + tmp.text = tmp.text.replaceAll(`'assets:${elements.name}'`,value_); + } else { + tmp.text = tmp.text .replaceAll('$variables.','this.') + .replaceAll('$vars.','this.') + .replaceAll('$params.','this.'); + } + //scrollTo plugin? + if (tmp.text.includes('this.$scrollTo')) { + context.x_state.plugins['vue-scrollto'] = { + global:true, + mode: 'client', + npm: { + 'vue-scrollto': '*' + } + }; + } + //vuescript2 + if (tmp.text.includes('vuescript2')) tmp.text = tmp.text.replaceAll('vuescript2.',`require('vue-script2').`); + //underscore + if (tmp.text.includes('_.')) { + context.x_state.pages[resp.state.current_page].imports['underscore'] = '_'; + } + /*if (tmp.text.includes('google.')) { + context.x_state.pages[resp.state.current_page].imports['vue2-google-maps'] = '{ gmapApi }'; + resp.open += 'if (!google) var google = gmapApi;\n'; + }*/ + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += tmp.text; + if (resp.open.right(1)!=';') resp.open += ';'; + resp.open += '\n'; + resp.state.from_script=true; + return resp; + } + }, + + 'def_console': { + x_icons: 'clanbomber', + x_not_icons: 'desktop_new', + x_level: '>1', + hint: 'Emite su texto a la consola. Soporta mostrar los datos/variables de sus atributos.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { text:node.text }; + if (node.icons.includes('bell')) { + tmp.text = getTranslatedTextVar(tmp.text); + } else { + tmp.text = `'${tmp.text}'`; + } + //attr + // process attributes + let attrs = {...node.attributes + }; + Object.keys(node.attributes).map(function(key) { + let keytest = key.toLowerCase().trim(); + let value = node.attributes[key].trim(); + let valuet = getTranslatedTextVar(value); + if (value.includes('assets:')) { + value = context.getAsset(value, 'jsfunc'); + } else { + // normalize vue type vars + value = value.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + } + //bell + if (node.icons.includes('bell') && value.replaceAll('**','')!=valuet) { // && value!=`**${valuet}**`) { + value = getTranslatedTextVar(value); + } else if (!node.icons.includes('bell') && value.includes('**')) { + value = `'${value}'`; + } + // modify values to copy + attrs[key] = value; + }); + //code + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += `console.log(${tmp.text},${context.jsDump(attrs)});\n`; + return resp; + } + }, + + 'def_npm_instalar': { + x_icons: 'desktop_new', + x_text_pattern: [`npm:+(install|instalar) "*"`,`npm:+(install|instalar) "*",*`, + `npm:+(install|instalar) "*/*"`,`npm:+(install|instalar) "*/*",*`], + x_level: '>2', + hint: 'Instala el paquete npm indicado entrecomillas y lo instancia en la página (import:true) o función actual, o lo asigna a la variable indicada luego de la coma.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let defaults = { text:node.text, tipo:'import', tipo_:'', version:'*', git:'', init:'' }; + let attr = aliases2params('def_npm_instalar', node); + attr = {...defaults, ...attr}; + if (attr.import && attr.import!='true') attr.tipo_ = attr.import; + attr.text = context.dsl_parser.findVariables({ + text: node.text, + symbol: '"', + symbol_closing: '"' + }).trim(); + attr.var = attr.tipo_ = node.text.split(',').pop(); + //code + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + if (!attr.require) { + if ('current_func' in resp.state) { + context.x_state.functions[resp.state.current_func].imports[attr.text] = attr.tipo_; + } else { + context.x_state.pages[resp.state.current_page].imports[attr.text] = attr.tipo_; + } + context.x_state.npm[attr.text] = attr.version; + } else { + //add support for user/repo + let pkg_name = attr.text; + if (attr.text.substr(0,1)!='@' && attr.text.includes('/') && !attr.text.includes('http') && !attr.text.includes('github.com')) { + pkg_name = pkg_name.split('/')[1]; + context.x_state.npm[pkg_name] = `https://github.com/${attr.text}.git`; + } else { + context.x_state.npm[attr.text] = attr.version; + } + resp.open += `let ${attr.var} = require('${pkg_name}');\n`; + } + return resp; + } + }, + + 'def_crear_id_unico': { + x_icons: 'desktop_new', + x_text_contains: 'crear id unico,,', //,,=requires comma + x_level: '>2', + hint: 'Obtiene un id unico (en 103 trillones) y lo asigna a la variable luego de la coma.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { var:node.text.split(',').pop() }; + //code + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + context.x_state.npm['nanoid']='2.1.1'; + resp.open += `let ${tmp.var} = require('nanoid')();\n`; + return resp; + } + }, + + 'def_aftertime': { + x_icons: 'desktop_new', + x_text_pattern: `ejecutar en "*" +(segundos|minutos|horas)`, + x_level: '>2', + hint: 'Ejecuta su contenido desfasado en los segundos especificados.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let time = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + //code + let amount = node.text.split(' ').pop(); + if (amount=='minutos') time += `*60`; + if (amount=='horas') time += `*60*60`; + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += `setTimeout(function q() {\n`; + resp.close = `}.bind(this), 1000*${time});\n`; + return resp; + } + }, + + 'def_probar': { + x_icons: 'broken-line', + x_text_exact: 'probar', + x_level: '>2', + hint: 'Encapsula sus hijos en un try/catch.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + //test if there is an error node child + let subnodes = await node.getNodes(); + let has_error = false; + subnodes.map(async function(item) { + if (item.text=='error' && item.icons.includes('help')) has_error=true; + }.bind(this)); + //code + if (node.text_note != '') resp.open = `// ${node.text_note.cleanLines()}\n`; + resp.open += 'try {\n'; + if (has_error==false) { + resp.close += `} catch(e${node.id}) {\n console.log('error en comando probar: recuerda usar evento ?error como hijo para controlarlo.');\n`; + } + resp.close += '}'; + return resp; + } + }, + + 'def_probar_error': { + x_icons: 'help', + x_text_exact: 'error', + x_all_hasparent: 'def_probar', + x_level: '>2', + hint: 'Ejecuta sus hijos si ocurre un error en el nodo padre.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + //code + resp.open += `} catch(e${node.id}) {\n`; + resp.open += `let error = e${node.id};\n`; + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + return resp; + } + }, + + 'def_insertar_modelo': { + x_icons: 'desktop_new', + x_text_pattern: `insertar modelo "*"`, + x_level: '>2', + hint: `Inserta los atributos (campos) y sus valores en el modelo indicado entrecomillas. + Si especifica una variable luego de la coma, asigna el resultado de la nueva insercion en esa variable.`, + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { var:node.id, data:{}, model:'' }; + if (node.text.includes(',')) tmp.var=node.text.split(',').splice(-1)[0].trim(); + tmp.model = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + //get attributes and values as struct + tmp.data = (await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }})).open; + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `this.alasql('INSERT INTO ${tmp.model} VALUES ?', [${tmp.data}]);\n`; + return resp; + } + }, + + 'def_consultar_modelo': { + x_icons: 'desktop_new', + x_text_contains: `consultar modelo "`, + x_level: '>2', + hint: `Realiza una consulta a una base de datos virtual (en memoria). + Sus atributos corresponden a los campos y datos a filtrar. + Se asigna el resultado a la variable luego de la coma.`, + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { var:node.id+'_', data:{}, model:'' }; + if (node.text.includes(',')) tmp.var=node.text.split(',').splice(-1)[0].trim(); + tmp.model = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + //get attributes and values as struct + tmp.data = (await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }})); + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.data.state.object && Object.keys(tmp.data.state.object)!='') { + resp.open += `let ${node.id} = { keys:[], vals:[], where:${tmp.data.open} }; + for (let ${node.id}_k in ${node.id}.where) { + ${node.id}.keys.push(${node.id}_k + '=?'); + ${node.id}.vals.push(${node.id}.where[${node.id}_k]); + } + let ${tmp.var} = this.alasql(\`SELECT * FROM ${tmp.model} WHERE \${${node.id}.keys.join(' AND ')}\`,${node.id}.vals);\n`; + } else { + resp.open += `let ${tmp.var} = this.alasql('SELECT * FROM ${tmp.model}', []);\n`; + resp.open += `let ${node.id} = { where:{} };`; + } + return resp; + } + }, + + 'def_modificar_modelo': { + x_icons: 'desktop_new', + x_text_exact: `modificar modelo`, + x_not_empty: 'link', + x_level: '>2', + hint: `Modifica los datos de la consulta de modelo enlazada, aplicando los datos definidos en sus atributos.`, + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { data:{}, model:'' }; + //if (node.link=='') return {...resp,...{ valid:false }}; + //get target node + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true) { + if (link_node.text.includes('consultar modelo')==false) { + throw 'modificar modelo requires an arrow pointing to a consultar modelo node' + } else { + //get linked info + tmp.model = context.dsl_parser.findVariables({ + text: link_node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + tmp.model_where = link_node.id + '.where'; + //get attributes and new values as struct + tmp.data = (await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }})).open; + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + //write update statement + resp.open += `let ${node.id} = { keys:[], vals:[], from:[], data:${tmp.data} };\n`; + resp.open += `for (let ${node.id}_k in ${node.id}.data) { + ${node.id}.keys.push(${node.id}_k+'=?'); + ${node.id}.vals.push(${node.id}.data[${node.id}_k]); + }\n`; + //write where requirements + resp.open += `for (let ${node.id}_k in ${tmp.model_where}) { + ${node.id}.from.push(${node.id}_k+'=?'); + ${node.id}.vals.push(${tmp.model_where}[${node.id}_k]); + }\n`; + //statement + resp.open += `this.alasql(\`UPDATE ${tmp.model} SET \${${node.id}.keys.join(',')} WHERE \${${node.id}.from.join(' AND ')}\`,${node.id}.vals);\n`; + } + } else { + throw 'modificar modelo requires an arrow pointing to an active consultar modelo node (cannot be cancelled)' + } + // + return resp; + } + }, + + 'def_eliminar_modelo': { + x_icons: 'desktop_new', + x_text_exact: `eliminar modelo`, + x_not_empty: 'link', + x_level: '>2', + hint: `Elimina los datos de la consulta de modelo enlazada.`, + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + let tmp = { model:'' }; + //if (node.link=='') return {...resp,...{ valid:false }}; + //get target node + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true) { + if (link_node.text.includes('consultar modelo')==false) { + throw 'eliminar modelo requires an arrow pointing to a consultar modelo node; link points to node ('+node.link+'): '+link_node.text; + } else { + //get linked info + tmp.model = context.dsl_parser.findVariables({ + text: link_node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + tmp.model_where = link_node.id + '.where'; + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `let ${node.id} = { keys:[], vals:[] };\n`; + resp.open += `for (let ${node.id}_k in ${tmp.model_where}) { + ${node.id}.keys.push(${node.id}_k+'=?'); + ${node.id}.vals.push(${tmp.model_where}[${node.id}_k]); + }\n`; + resp.open += `if (${node.id}.keys.length>0) { + this.alasql(\`DELETE FROM ${tmp.model} WHERE \${${node.id}.keys.join(' AND ')}\`,${node.id}.vals); + } else { + this.alasql(\`DELETE FROM ${tmp.model}\`,[]); + }\n`; + } + } else { + throw 'eliminar modelo requires an arrow pointing to an active consultar modelo node (cannot be cancelled)' + } + // + return resp; + } + }, + + //def_consultar_web + 'def_consultar_web': { + x_icons: 'desktop_new', + x_text_contains: 'consultar web,,', + x_level: '>3', + attributes_aliases: { + 'method': '_method,:metodo,:method,_metodo', + 'response': 'responsetype,response,:responsetype,:response' + }, + hint: 'Realiza una llamada a la url indicada enviando los datos definidos en sus atributos. Entrega resultados en variable definida luego de coma.', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (!state.from_script) return {...resp,...{ valid:false }}; + //prepare + let isProxySon = ('current_proxy' in resp.state)?true:false; + //let isServerSon = ('current_func' in resp.state)?true:false; + let tmp = { + var:node.id, + meta:false, + simple:true, + proxy:isProxySon, + progress:true, + axios_call:(isProxySon==true)?'$axios':'this.$axios', + config: { + method:'get', + url:'', + data:{}, + headers:{}, + auth: {}, + timeout:0, + response:'json', + maxContentLength:5000000 + } + }; + // add axios import in page + if (state.current_page) { + context.x_state.pages[state.current_page].imports['axios'] = 'axios'; + } else if (state.current_proxy) { + context.x_state.proxies[state.current_proxy].imports['axios'] = 'axios'; + } else if (state.current_store) { + context.x_state.stores[state.current_store].imports['axios'] = 'axios'; + } + tmp.axios_call='axios'; + if (node.text.includes(',')) tmp.var=node.text.split(',').splice(-1)[0].trim(); + //attributes + let attrs = aliases2params('def_consultar_web', node, false, 'this.'); + //prepare attrs + for (let x in attrs) { + if (x.charAt(0)==':') { + if (typeof attrs[x] === 'string') { + if (x!=':progress' && x!=':method' && attrs[x].includes('.')==false) { + attrs[x.right(x.length-1)] = '**'+attrs[x]+'**'; + } else if (attrs[x].includes('$config.') || attrs[x].includes('$store.') || attrs[x].includes('this.') || attrs[x].includes('process.env.')) { + if (state.current_proxy) { + attrs[x.right(x.length-1)] = '**'+attrs[x].replaceAll('this.$store.','store.').replaceAll('this.$config.','$config.')+'**'; + } else { + attrs[x.right(x.length-1)] = '**'+attrs[x]+'**'; + } + } else { + attrs[x.right(x.length-1)] = attrs[x]; + } + } else { + attrs[x.right(x.length-1)] = attrs[x]; + } + delete attrs[x]; + } + } + // + delete attrs.refx; + if (node.link!='') tmp.config.url = node.link.trim(); + if (attrs.progress) tmp.progress=attrs.progress; delete attrs.progress; + if (attrs.meta) tmp.meta=true; delete attrs.meta; + if (attrs.url) tmp.config.url = attrs.url; delete attrs.url; + // + // + for (let test of 'method,auth-username,auth-password,encoding,maxlength,redirects,timeout,response'.split(',')) { + if (attrs[test]) { + tmp.simple=false; + if (test=='auth-username' || test=='auth-password') { + tmp.config.auth[test.replaceAll('auth-','')] = attrs[test]; + } else if (test=='encoding') { + tmp.config.responseEncoding = attrs[test]; + } else { + tmp.config[test] = attrs[test]; + } + delete attrs[test]; + } + } + //extract headers from attrs (and keep data) + for (let x in attrs) { + if (x.length>2 && x.substr(0,3)=='x-:') { + tmp.config.headers[x.right(x.length-3)] = attrs[x]; + delete attrs[x]; + } else if (x.length>2 && x.substr(0,2)=='x-') { + tmp.config.headers[x] = attrs[x]; + delete attrs[x]; + } + } + tmp.config.data = {...attrs}; + if (tmp.config.method=='get') { + tmp.config.params = tmp.config.data; + delete tmp.config.data; + } else if (tmp.config.method=='postjson') { + tmp.config.method = 'post'; + tmp.config.data = { params:tmp.config.data }; + } + //simple or advanced? + if (tmp.simple) { + //add comment + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.meta) { + resp.open += `const ${tmp.var} = await ${tmp.axios_call}.${tmp.config.method}(${tmp.config.url}, ${context.jsDump(tmp.config.data)}, { progress:${tmp.progress} });\n`; + } else { + resp.open += `const ${tmp.var} = (await ${tmp.axios_call}.${tmp.config.method}(${tmp.config.url}, ${context.jsDump(tmp.config.data)}, { progress:${tmp.progress} })).data;\n`; + } + } else { + //advanced? + if (tmp.config.response && tmp.config.response!='json') { + tmp.config.responseType = tmp.config.response; + } + delete tmp.config.response; + //write data on close to support download/upload child events to config object + resp.state.from_consultar_web = node.id + '_config'; + //add comment + if (node.text_note != '') resp.close += `// ${node.text_note.cleanLines()}\n`; + // if tmp.config.url doesn't contain a protocol (http/https) then add context.x_state.config_node.axios values as a prefix to it + if (tmp.config.url.includes('://')==false) { + //context.debug('adding prefix (consultar web): '+context.x_state.config_node.axios.local); + //context.debug('tmp.config.url',tmp.config.url); + tmp.config.url = context.x_state.config_node.axios.local + '/' + tmp.config.url; + tmp.config.url = tmp.config.url.replaceAll('://','|=|').replaceAll('//','/').replaceAll('|=|','://'); + } + resp.close += `let ${node.id}_config = ${context.jsDump(tmp.config)};\n`; + // + if (tmp.meta) { + resp.close += `const ${tmp.var} = await ${tmp.axios_call}.request(${node.id}_config, { progress:${tmp.progress} });\n`; + } else { + resp.close += ` + const ${tmp.var}_ = await ${tmp.axios_call}.request(${node.id}_config, { progress:${tmp.progress} }); + const ${tmp.var} = ${tmp.var}_.data;\n`; + } + } + //return + return resp; + } + }, + + 'def_consultar_web_upload': { + x_icons: 'help', + x_text_exact: 'upload', + x_all_hasparent: 'def_consultar_web', + x_level: '>2', + hint: 'Evento para ver el progreso del upload de un consultar web padre (axios).', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (!state.from_consultar_web) return {...resp,...{ valid:false }}; + if (!state.from_script) return {...resp,...{ valid:false }}; + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `${state.from_consultar_web}.onUploadProgress = function(evento) {\n`; + resp.close += `};\n`; + return resp; + } + }, + + 'def_consultar_web_download': { + x_icons: 'help', + x_text_exact: 'download', + x_all_hasparent: 'def_consultar_web', + x_level: '>2', + hint: 'Evento para ver el progreso del download de un consultar web padre (axios).', + func: async function(node, state) { + let resp = context.reply_template({ + state + }); + if (!state.from_consultar_web) return {...resp,...{ valid:false }}; + if (!state.from_script) return {...resp,...{ valid:false }}; + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `${state.from_consultar_web}.onDownloadProgress = function(evento) {\n`; + resp.close += `};\n`; + return resp; + } + }, + + 'def_xcada_registro': { + x_icons: 'penguin', + x_text_contains: `por cada registro en`, + x_level: '>2', + attributes_aliases: { + 'use_index': 'index', + 'unique': 'unique,id', + 'target': 'template,target' + }, + hint: `Repite sus hijos por cada elemento entrecomillas, dejando el item en curso en la variable luego de la coma.`, + func: async function(node, state) { + let resp = context.reply_template({ state }); + let tmp = { key:'', has_await:false, query:node.text, target:'' }; + /*if (!state.from_script && !state.get_params) { + resp.valid=false; + return resp; + }*/ + let padre = await context.dsl_parser.getParentNode({ id:node.id }); + if (padre.icons.includes('idea') && !state.from_xcada_view) { + //console.log('state y padre',{state,padre}); + resp.valid=false; + resp.state.from_script=false; + return resp; + } + if (tmp.query.includes('$store.')) tmp.query = tmp.query.replaceAll('$store.','$store.state.'); + if (tmp.query.includes(',')) tmp.key=tmp.query.split(',').splice(-1)[0].trim(); + tmp.iterator = context.dsl_parser.findVariables({ + text: tmp.query, + symbol: `"`, + symbol_closing: `"` + }).trim(); + if (tmp.iterator.charAt(0)=='$' && + !tmp.iterator.includes('$variables.') && + !tmp.iterator.includes('$vars.') && + !tmp.iterator.includes('$store.') && + !tmp.iterator.includes('$params.') && + !tmp.iterator.includes('$route.')) { + tmp.iterator = tmp.iterator.right(tmp.iterator.length-1); + } + let sons = await node.getNodes(); + if (sons.length==1) { + tmp.target = sons[0].id; + } else if (sons.length>1) { + tmp.target = 'template'; + } + let attrs = aliases2params('def_xcada_registro',node); + let params = { unique:0, key:0, target:tmp.target, tipo:'v-for', iterator:tmp.iterator, item:tmp.key, use_index:`${tmp.key}_index` }; + if (params[':template']) { + params.target = 'template'; + delete params[':template']; delete params['template']; + } + params = {...params,...attrs}; + if (params.unique==0) params.unique = params.use_index; + if (state.get_params) { + resp.state.params = params; + delete resp.state.get_params; + return resp; + } + //code (only from scripting) + if (node.icons.includes('bell') && params.iterator.includes('**')) { + params.iterator = getTranslatedTextVar(params.iterator); + } + params.iterator = params.iterator .replaceAll('$variables.','this.') + .replaceAll('$vars.','this.') + .replaceAll('$params.','this.') + .replaceAll('$store.','this.$store.state.'); + context.x_state.pages[state.current_page].imports['underscore'] = '_'; + //search consultar web nodes + if (!params[':each'] && sons.length>0) { + for (let x of sons) { + if (x.text.includes('consultar web')) { + tmp.has_await = true; + break; + } + await setImmediatePromise(); //@improved + } + } + //write code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.has_await==true) { + resp.open += `_.each(${params.iterator}, async function(${params.item},${params.use_index}) {`; + resp.close = `}, this);`; + } else { + resp.open += `for (let ${params.use_index}=0;${params.use_index}<${params.iterator}.length;${params.use_index}++) {`; + resp.open += `let ${params.item} = ${params.iterator}[${params.use_index}];\n`; + resp.close = `}\n`; + } + // + resp.state.from_script=true; + return resp; + } + }, + + //*def_responder (@todo i18n) + //**def_insertar_modelo (@todo test it after adding support for events) + //**def_consultar_modelo + //**def_modificar_modelo + //**def_eliminar_modelo + //**def_consultar_web + //**def_consultar_web_upload + //**def_consultar_web_download + //*def_aftertime + //*def_struct + //*def_extender + //*def_npm_instalar + //*def_probar + //*def_probar_error (ex.def_event_try) + //*def_literal_js + //*def_console + //**def_xcada_registro + //*def_crear_id_unico + + 'def_guardar_nota': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'guardar nota|capturar nota|note:save|save note', + attributes_aliases: { + 'strip': 'text,strip,limpio', + 'asis': 'asis,as_it_was' + }, + meta_type: 'script', + hint: 'Crea una variable con el contenido HTML indicado en la nota del nodo.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + // attrs + let attrs = {...{ html:true, asis:false },...aliases2params('def_guardar_nota', node, false, 'this.')}; + delete attrs.refx; + if (attrs[':html']) attrs.html=true; + if (attrs[':strip']) attrs.html=false; + //prepare + let tmp = { content:node.text_note }; + tmp.var = node.text.split(',').pop().trim(); + //context.x_console.out({ message:'DEBUG guardar nota!! ', data:node }); + if (attrs.html) { + tmp.content = node.text_note_html; //this has inner of body already + //parse content + if (!attrs[':asis'] && !attrs.asis) { + //transform tags 'p' style:text-align:center to
x
+ //transform

x

to x
+ let cheerio = require('cheerio'); + let sub = cheerio.load(tmp.content, { ignoreWhitespace: false, xmlMode:true, decodeEntities:false }); + let paragraphs = sub('p').toArray(); + paragraphs.map(function(elem) { + let cur = cheerio(elem); + let style = cur.attr('style'); + if (style && style.includes('text-align:center')) { + //transform tags 'p' style:text-align:center to
x
+ cur.replaceWith(`
${cur.html()}
`); + } else { + cur.replaceWith(`${cur.html()}
`); + } + }); + tmp.content = sub.html(); + } + } + //escape variables + if (node.icons.includes('bell')) { + tmp.content = getTranslatedTextVar(tmp.content); + } + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `let ${tmp.var} = ${tmp.content};\n`; + return resp; + } + }, + + 'def_agregar_campos': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'agregar campos a', + meta_type: 'script', + hint: `Agrega los campos definidos en sus atributos (y valores) a cada uno de los registros de la variable de entrada (array de objetos).\n + Si hay una variable definida, se crea una nueva instancia del array con los campos nuevos, en caso contrario se modifican los valores de la variable original.`, + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + //get vars and attrs + let tmp = { var:'' }; + if (node.text.includes(',')) tmp.var = node.text.split(',').pop().trim(); + tmp.original = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }); + if (state.from_server) { + tmp.var = tmp.var.replaceAll('$variables.','resp.') + .replaceAll('$vars.','resp.') + .replaceAll('$params.','resp.'); + tmp.original = tmp.original.replaceAll('$variables.','resp.') + .replaceAll('$vars.','resp.') + .replaceAll('$params.','resp.'); + } else if (tmp.var!='') { + tmp.var = tmp.var.replaceAll('$variables.','this.') + .replaceAll('$vars.','this.') + .replaceAll('$params.','this.') + .replaceAll('$store.','this.$store.state.');pon + tmp.original = tmp.original.replaceAll('$variables.','this.') + .replaceAll('$vars.','this.') + .replaceAll('$params.','this.') + .replaceAll('$store.','this.$store.state.'); + } + if (tmp.original.includes('**') && node.icons.includes('bell')) { + tmp.original = getTranslatedTextVar(tmp.original); + } + // create obj from current node as js obj + tmp.attr = await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }}); + delete tmp.attr.refx; + //change this to resp if parent is server + if (state.from_server) tmp.attr.open = tmp.attr.open.replaceAll('this.','resp.'); + //add underscore + if (state.current_page) { + context.x_state.pages[state.current_page].imports['underscore'] = '_'; + } else if (state.current_proxy) { + context.x_state.proxies[state.current_proxy].imports['underscore'] = '_'; + } else if (state.current_store) { + context.x_state.stores[state.current_store].imports['underscore'] = '_'; + } + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.var.includes('this')) { + resp.open += `${tmp.var} = _.map(${tmp.original}, function(element) { + element = Object.assign(element,${tmp.attr.open}); + return _.extend({},element,${tmp.attr.open}); + });`; + } else if (tmp.var!='') { + resp.open += `let ${tmp.var} = _.map(${tmp.original}, function(element) { + element = Object.assign(element,${tmp.attr.open}); + return _.extend({},element,${tmp.attr.open}); + });`; + } else { + resp.open += `${tmp.original} = _.each(${tmp.original}, function(element) { + element = Object.assign(element,${tmp.attr.open}); + });`; + } + return resp; + } + }, + + 'def_preguntar': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'preguntar|dialogo:confirm', + attributes_aliases: { + 'title': 'titulo,title', + 'message': 'mensaje,contenido,message', + 'buttonTrueText': 'true,aceptar,boton:aceptar', + 'buttonFalseText': 'false,cancel,boton:cancelar', + 'width': 'ancho,width', + 'icon': 'icon,icono', + 'persistent': 'persistent,obligatorio,persistente' + }, + /*x_test_func: function(node) { + //return true if its a valid match + },*/ + hint: `Abre un dialogo preguntando lo indicado en sus atributos, respondiendo true o false en la variable indicada luego de la coma.`, + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + //get vars and attrs + let tmp = { var:'', text:'' }; + if (node.text.includes(',')) tmp.var = node.text.split(',').pop().trim(); + //add plugin + context.x_state.plugins['vuetify-confirm'] = { + global:true, + mode: 'client', + npm: { 'vuetify-confirm':'*' }, + extra_imports: ['vuetify'], + config: '{ vuetify }' + }; + //attrs + let params = aliases2params('def_preguntar', node, false, 'this.'); + delete params.refx; + //process message attribute + if (params.message) { + /* ex.= 'Estas seguro que deseas borrar {{ x }} ?' + 'Estas seguro que deseas borrar '+x+' ?' + */ + tmp.text = params.message; + let new_val = ''; + let vars = context.dsl_parser.findVariables({ + text: params.message, + symbol: `{{`, + symbol_closing: `}}`, + array:true + }); + for (let vr in vars) { + if (vars[vr].includes('|')) { + //add filter support: 'Estas seguro que deseas agregar {{ monto | numeral('0,0') }} ?' + let clean = vars[vr].replaceAll('{{','').replaceAll('}}',''); + let the_var = clean.split('|')[0].trim(); + let the_filter = clean.split('|').pop().trim(); + the_filter = the_filter.replace('(',`(${the_var},`); + tmp.text = tmp.text.replace(vars[vr],`'+this.$nuxt.$options.filters.${the_filter}+'`); + } else { + let n_var = vars[vr].replaceAll('{{',`'+`).replaceAll('}}',`+'`); + tmp.text = tmp.text.replace(vars[vr],n_var); + } + } + // + tmp.text = `'${tmp.text}'`; + delete params.message; + } + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.text && Object.keys(params)==0) { + if (tmp.var.includes('this.')) { + resp.open += `${tmp.var} = await this.$confirm(${tmp.text});\n`; + } else { + resp.open += `let ${tmp.var} = await this.$confirm(${tmp.text});\n`; + } + } else { + if (tmp.var.includes('this.')) { + resp.open += `${tmp.var} = await this.$confirm(${tmp.text},${context.jsDump(params)});\n`; + } else { + resp.open += `let ${tmp.var} = await this.$confirm(${tmp.text},${context.jsDump(params)});\n`; + } + } + return resp; + } + }, + + 'def_var_clonar': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'clonar variable|copiar variable|variable:clonar|variable:copiar', + attributes_aliases: {}, + hint: `Crea una copia de la variable indicada, en la variable luego de la coma.`, + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + //get vars and attrs + let tmp = { var:'', original:'' }; + if (node.text.includes(',')) tmp.var = node.text.split(',').pop().trim(); + //prepare new var + if (tmp.var.includes('$')) { + if (state.from_server) { + tmp.var = tmp.var.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + tmp.var = tmp.var.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + if (tmp.var=='this.') tmp.var='this'; + } + } + //prepare original var + tmp.original = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }); + if (tmp.original.includes('**') && node.icons.includes('bell')) { + tmp.original = getTranslatedTextVar(tmp.original); + } else if (tmp.original.includes('$')) { + if (state.from_server) { + tmp.original = tmp.original.replaceAll('$variables.', 'resp.') + .replaceAll('$vars.', 'resp.') + .replaceAll('$params.', 'resp.'); + } else { + tmp.original = tmp.original.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + if (tmp.original=='this.') tmp.original='this'; + } + } + //code + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.var.includes('this.')) { + resp.open += `${tmp.var} = JSON.parse(JSON.stringify(${tmp.original}));\n`; + } else { + resp.open += `let ${tmp.var} = JSON.parse(JSON.stringify(${tmp.original}));\n`; + } + return resp; + } + }, + + 'def_enviarpantalla': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'enviar a pantalla', + x_not_empty: 'link', + attributes_aliases: { + 'event_label': 'tag,tipo,etiqueta,event_label' + }, + meta_type: 'script', + hint: 'Envia al usuario a la pantalla enlazada.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + if (node.link.includes('ID_')==false) return {...resp,...{ valid:false }}; + if ((await context.hasParentID(node.id, 'def_componente'))==true) { + // components should not have links to other pages, only instances + throw `Invalid 'enviar a pantalla' origin node! Components can't point to other pages; use the instance for that`; + } + // prepare + let tmp = { link:node.link, target:'' }; + let link_node = await context.dsl_parser.getNode({ id:node.link, recurse:false }); + if (link_node && link_node.valid==true && link_node.text.trim()!='') { + tmp.target = `{vuepath:${link_node.text}}`; + } else { + throw `Invalid 'enviar a pantalla' linked node!`; + } + //code + //if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + let isProxySon = ('current_proxy' in resp.state)?true:false; + if (isProxySon==true) { + resp.open += `return redirect('${tmp.target}');\n`; + } else { + // params + let params = aliases2params('def_enviarpantalla', node, false, 'this.'); + delete params.refx; + if (Object.keys(params)!='') { + if (tmp.target.charAt(0)=='/') tmp.target = tmp.target.right(tmp.target.length-1); + if (params[':query']) { + resp.open += `this.$router.push({ path:'${tmp.target}', query:${context.jsDump(params)} });\n`; + } else { + resp.open += `this.$router.push({ name:'${tmp.target}', params:${context.jsDump(params)} });\n`; + } + } else { + resp.open += `this.$router.push('${tmp.target}');\n`; + } + } + return resp; + + } + }, + + 'def_procesar_imagen': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'procesar imagen|transformar imagen|ajustar imagen|imagen:transform', + attributes_aliases: { + 'grey': 'greyscale,gris,grises,grey', + 'maxkb': 'maxkb,compress', + 'format': 'format,format,mimetype' + }, + meta_type: 'script', + hint: 'Aplica las modificaciones indicadas en sus atributos a la imagen (dataurl) indicada como variables. Retorna un dataurl de la imagen modificada.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + // get: cmd 'input', output / prepare params + let tmp = await parseInputOutput(node,state); + let params = (await context.x_commands['def_struct'].func(node, { ...state, ...{ + as_object:true + }})).state.object; + //code + context.x_state.npm['image-js'] = '0.31.4'; + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `let { Image } = require('image-js'); + let ${node.id} = ${tmp.input};\n`; + if (params.maxkb) { + //compress first + context.x_state.npm['browser-image-compression'] = '*'; + context.x_state.pages[resp.state.current_page].imports['browser-image-compression'] = 'imageCompression'; + resp.open += `let ${node.id}_f = await imageCompression.getFilefromDataUrl(${tmp.input}); + let ${node.id}_c = await imageCompression(${node.id}_f, { maxSizeMB: ${params.maxkb}/1000 }); + ${node.id} = await imageCompression.getDataUrlFromFile(${node.id}_c);\n`; + } + //scale and fxs + resp.open += `let ${tmp.output}_ = await Image.load(${node.id});\n`; + if (tmp.output.includes('this.')==false) resp.open += `let `; + resp.open += `${tmp.output} = ${tmp.output}_`; + // params + if (params.anchomax) resp.open += `.resize({ width:(${tmp.output}_.width>${params.anchomax})?${params.anchomax}:${tmp.output}_.width })`; + if (params.altomax) resp.open += `.resize({ height:(${tmp.output}_.height>${params.altomax})?${params.altomax}:${tmp.output}_.height })`; + if (params.resmax) resp.open += `.resize({ width:(${tmp.output}_.width>${params.resmax})?${params.resmax}:${tmp.output}_.width, height:(${tmp.output}_.height>${params.resmax})?${params.resmax}:${tmp.output}_.height })`; + if (params.resize && params.resize.includes('x')) { + resp.open += `.resize({ width:${params.resize.split('x')[0]}, height:${params.resize.split('x').pop().trim()} })`; + } else if (params.resize) { + resp.open += `.resize({ width:${params.resize}, height:${params.resize} })`; + } + if (params.grey || params.greyscale || params.gris || params.grises) resp.open += `.grey()`; + if (params.format || params.formato || params.mimetype) { + if (params.formato) params.format = params.formato; + if (params.mimetype) params.format = params.mimetype; + if (params.format.includes('/')) { + resp.open += `.toDataURL('${params.format.replaceAll("'","")}')`; + } else { + resp.open += `.toDataURL('image/${params.format.replaceAll("'","")}')`; + } + } + resp.open += `;\n`; + // + return resp; + } + }, + + 'def_array_transformar': { + x_icons: 'desktop_new', + x_text_pattern: [`array:+(transformar|manipular)*`], + x_level: '>2', + hint: `Transforma los campos del array de estructuras entregado, restringiendo los campos incluidos, o bien manipulando sus valores.`, + func: async function(node, state) { + let resp = context.reply_template({ state }); + let tmp = {}; + if (node.text.includes(',')) tmp.var=node.text.split(',').splice(-1)[0].trim(); + tmp.text = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }).trim(); + if (node.icons.includes('bell') && tmp.text.includes('**')) { + tmp.text = getTranslatedTextVar(tmp.text); + } + let isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + //code + //context.x_state.functions[resp.state.current_func].imports['underscore'] = '_'; + if (state.current_page) { + context.x_state.pages[state.current_page].imports['underscore'] = '_'; + } else if (state.current_proxy) { + context.x_state.proxies[state.current_proxy].imports['underscore'] = '_'; + } else if (state.current_store) { + context.x_state.stores[state.current_store].imports['underscore'] = '_'; + } + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + if (tmp.var && tmp.var.includes('this.')) { + resp.open += `${tmp.var} = _.map(${tmp.text}, function(o${node.level}) {\n`; //}) + } else { + resp.open += `let ${tmp.var} = _.map(${tmp.text}, function(o${node.level}) {\n`; + } + resp.open += `let ${node.id} = o${node.level};\n`; + Object.keys(node.attributes).map(function(att) { + let name = att.trim();; + let value = node.attributes[att]; + if (name.charAt(0)!=':' && name.charAt(0)!='.') { + if (node.icons.includes('bell')) { + value = getTranslatedTextVar(value); + } + if (isNumeric(value) || value.substr(0,2)=='$.') { + } else if (value.includes(`'`)) { + } else if (value.includes('**') && node.icons.includes('bell')) { + } else if (value!=node.attributes[att]) { + } else if (value!='') { + if (value.charAt(0)=='!') { + value = `!${tmp.text}.${name}`; + } + } + } + // + if (name.toLowerCase()==':campos') { + resp.open += `${node.id} = _.pick(o${node.level}, ${context.jsDump(value.split(',')).replaceAll('[','').replaceAll(']','')});\n`; + } else { + if (value.includes('(') && value.includes(')') && value.includes('?')) { + value = value.replaceAll(`(.`,`(o${node.level}.`); + value = value.replaceAll(`?.`,`?o${node.level}.`); + value = value.replaceAll(`:.`,`:o${node.level}.`); + resp.open += `${node.id}.${name} = ${value};\n`; + } else { + resp.open += `${node.id}.${name} = o${node.level}${value};\n`; + } + } + }); + resp.open += `return ${node.id};\n`; + resp.open += `});\n`; + //return + return resp; + } + }, + + //**def_guardar_nota + //**def_agregar_campos + //**def_preguntar + //def_array_transformar (pending) + //def_procesar_imagen + //def_imagen_exif + //**def_var_clonar + //--def_modificar (invalid node for vue) + //**def_enviarpantalla (todo test) + + 'def_analytics_evento': { + x_level: '>2', + x_icons: 'desktop_new', + x_text_contains: 'analytics:event', + x_or_hasparent: 'def_page,def_componente,def_layout', + attributes_aliases: { + 'event_label': 'tag,tipo,etiqueta,event_label' + }, + meta_type: 'script', + hint: 'Envia el evento indicado al Google Analytics configurado.', + func: async function(node, state) { + let resp = context.reply_template({ state }); + if (!state.from_script) return {...resp,...{ valid:false }}; + //if (!context.x_state.config_node['google:analytics']) return {...resp,...{ valid:false }}; + // params + let params = aliases2params('def_analytics_evento', node, false, 'this.'); + delete params.refx; + let details = {...{ + event_category:state.current_page + },...params}; + //event name + let event = context.dsl_parser.findVariables({ + text: node.text, + symbol: `"`, + symbol_closing: `"` + }); + if (event.includes('**') && node.icons.includes('bell')) { + event = getTranslatedTextVar(event); + } else if (event.includes('$')) { + event = event.replaceAll('$variables.', 'this.') + .replaceAll('$vars.', 'this.') + .replaceAll('$params.', 'this.') + .replaceAll('$store.', 'this.$store.state.'); + event = `'${event}'`; + } else if (event.charAt(0) == '(' && event.slice(-1) == ')') { + event = event.slice(1).slice(0, -1); + } else { + event = `'${event}'`; + } + //code + if ('google:analytics' in context.x_state.config_node) { + if (node.text_note != '') resp.open += `// ${node.text_note.cleanLines()}\n`; + resp.open += `this.$gtag('event', ${event}, ${context.jsDump(details)});\n`; + return resp; + } else { + throw 'analytics:event requires config->google:analytics key!' + } + } + }, + + //**def_analytics_evento - @todo test + //def_medianet_ad - @todo think about the script2 code issue with cheerio + + // OTHER node types + /*'def_imagen': { + x_icons:'idea', + x_not_icons:'button_cancel,desktop_new,help', + x_not_empty:'attributes[:src]', + x_empty:'', + x_level:'>2', + func:async function(node,state) { + return context.reply_template({ otro:'Pablo', state }); + } + },*/ + + // + } +}; + +//private helper methods +function setObjectKeys(obj, value) { + let resp = obj; + if (typeof resp === 'string') { + resp = {}; + let keys = obj.split(','); + for (let i in keys) { + resp[keys[i]] = value; + } + } else { + for (let i in resp) { + resp[i] = value; + } + } + return resp; +} + +function setToValue(obj, value, path) { + var i; + path = path.split('.'); + for (i = 0; i < path.length - 1; i++) + obj = obj[path[i]]; + + obj[path[i]] = value; +} + +function getVal(project, myPath) { + return myPath.split('.').reduce((res, prop) => res[prop], project); +} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..60480b2 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,5805 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.vue_dsl = factory()); +})(this, (function () { 'use strict'; + + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + + if (enumerableOnly) { + symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + }); + } + + keys.push.apply(keys, symbols); + } + + return keys; + } + + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + + if (i % 2) { + ownKeys(Object(source), true).forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } else if (Object.getOwnPropertyDescriptors) { + Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); + } else { + ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + } + + return target; + } + + function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + + function _asyncToGenerator(fn) { + return function () { + var self = this, + args = arguments; + return new Promise(function (resolve, reject) { + var gen = fn.apply(self, args); + + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); + } + + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); + } + + _next(undefined); + }); + }; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + /** + * Base Deploy: A class define deployments for vue_dsl. + * @name base_deploy + * @module base_deploy + **/ + class base_deploy { + constructor() { + var { + context = {}, + name = 'base_deploy' + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + this.context = context; + this.name = name; + } + + logo() { + var _arguments = arguments, + _this = this; + + return _asyncToGenerator(function* () { + var { + name = _this.name, + config = {} + } = _arguments.length > 0 && _arguments[0] !== undefined ? _arguments[0] : {}; + + var cfonts = require('cfonts'); + + cfonts.say(name, _objectSpread2(_objectSpread2({}, { + font: 'block', + gradient: 'red,blue' + }), config)); + })(); + } + + run() { + return _asyncToGenerator(function* () { + return true; + })(); + } + + deploy() { + var _this2 = this; + + return _asyncToGenerator(function* () { + var errors = []; + + _this2.context.x_console.spinner({ + message: "Deploying ".concat(_this2.name, " instance") + }); //spinner.start('Deploying local instance'); + + /*try { + //launch in a new terminal + await this.context.launchTerminal('npm',['run','dev'],this.context.x_state.dirs.app); + //results.git_add = await spawn('npm',['run','dev'],{ cwd:this.x_state.dirs.app }); + spinner.succeed('NuxtJS launched successfully'); + } catch(gi) { + spinner.fail('Project failed to launch'); + errors.push(gi); + }*/ + + + return errors; + })(); + } + + base_build() { + var _this3 = this; + + return _asyncToGenerator(function* () { + // builds the project + var spawn = require('await-spawn'), + path = require('path'), + fs = require('fs').promises; //let ora = require('ora'); + + + var node_modules_final = path.join(_this3.context.x_state.dirs.app, 'node_modules'); + var node_package = path.join(_this3.context.x_state.dirs.app, 'package.json'); + var npm = {}, + errors = []; + + _this3.context.x_console.out({ + message: "Building project", + color: 'cyan' + }); + + var spinner = _this3.context.x_console.spinner({ + message: 'Building project' + }); + + var node_modules_exist = yield _this3.exists(node_modules_final); + var node_package_exist = yield _this3.exists(node_package); + + if (node_modules_exist && node_package_exist) { + //test if every package required is within node_modules + spinner.start("Some npm packages where installed; checking .."); + var pkg = JSON.parse(yield fs.readFile(node_package, 'utf-8')); + var all_ok = true; + + for (var pk in pkg.dependencies) { + var tst_dir = path.join(_this3.context.x_state.dirs.app, 'node_modules', pk); + var tst_exist = yield _this3.exists(tst_dir); + if (!tst_exist) all_ok = false; + } + + node_modules_exist = all_ok; + + if (all_ok) { + spinner.succeed('Using existing npm packages'); + } else { + spinner.warn('Some packages are new, requesting them'); + } + } // issue npm install (400mb) + + + if (!node_modules_exist) { + spinner.start("Installing npm packages"); //this.x_console.outT({ message:`Installing npm packages` }); + + try { + npm.install = yield spawn('npm', ['install'], { + cwd: _this3.context.x_state.dirs.app + }); //, stdio:'inherit' + + spinner.succeed("npm install succesfully"); + } catch (n) { + npm.install = n; + spinner.fail('Error installing npm packages'); + errors.push(n); + } + } // issue npm run build + + + spinner.start("Building VueJS project"); + + var ci = require('ci-info'); + + try { + if (ci.isCI == false) { + npm.build = yield spawn('npm', ['run', 'build'], { + cwd: _this3.context.x_state.dirs.app + }); + } else { + npm.build = yield spawn('npm', ['run', 'build'], { + cwd: _this3.context.x_state.dirs.app, + stdio: 'inherit' + }); + } + + spinner.succeed('Project build successfully'); + } catch (nb) { + npm.build = nb; + spinner.fail('VueJS build failed'); + + if (ci.isCI == false) { + _this3.context.x_console.out({ + message: "Building VueJS again to show error in console", + color: 'red' + }); //build again with output redirected to console, to show it to user + + + try { + console.log('\n'); + npm.build = yield spawn('npm', ['run', 'dev'], { + cwd: _this3.context.x_state.dirs.app, + stdio: 'inherit', + timeout: 15000 + }); + } catch (eg) {} + } else { + _this3.context.x_console.out({ + message: "CI system detected; please double-check your code locally before pushing!", + color: 'red' + }); + } + + errors.push(nb); + } + + return errors; + })(); + } //**************************** + // onPrepare and onEnd steps + //**************************** + + + pre() { + return _asyncToGenerator(function* () {})(); + } + + post() { + return _asyncToGenerator(function* () {})(); + } + + modifyPackageJSON(data) { + return _asyncToGenerator(function* () { + return data; + })(); + } + + modifyVueConfig(config) { + return _asyncToGenerator(function* () { + return config; + })(); + } // HELPER methods + + + exists(dir_or_file) { + return _asyncToGenerator(function* () { + var fs = require('fs').promises; + + try { + yield fs.access(dir_or_file); + return true; + } catch (e) { + return false; + } + })(); + } + + _isLocalServerRunning() { + var _arguments2 = arguments, + _this4 = this; + + return _asyncToGenerator(function* () { + var port = _arguments2.length > 0 && _arguments2[0] !== undefined ? _arguments2[0] : _this4.context.x_state.central_config.port; + + var is_reachable = require('is-port-reachable'); + + var resp = yield is_reachable(port); + return resp; + })(); + } + + launchTerminal(cmd) { + var _arguments3 = arguments; + return _asyncToGenerator(function* () { + var args = _arguments3.length > 1 && _arguments3[1] !== undefined ? _arguments3[1] : []; + var basepath = _arguments3.length > 2 ? _arguments3[2] : undefined; + + var spawn = require('await-spawn'); + + var args_p = ''; + var resp = { + error: false + }; + + if (basepath) { + args_p = "sleep 2; clear; cd ".concat(basepath, " && ").concat(cmd, " ").concat(args.join(' ')); + } else { + args_p = 'sleep 2; clear; ' + cmd + ' ' + args.join(' '); + } + + try { + resp = yield spawn('npx', ['terminal-tab', args_p]); + } catch (e) { + resp = _objectSpread2(_objectSpread2({}, e), { + error: true + }); + } + + return resp; + })(); + } + + } + + class local extends base_deploy { + constructor() { + var { + context = {} + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super({ + context, + name: 'Local' + }); + } + + modifyPackageJSON(config) { + return _asyncToGenerator(function* () { + //little sass errors hack fix 13jun21 + //config.devDependencies['sass-migrator']='*'; + //config.scripts.hackfix = 'sass-migrator division node_modules/vuetify/**/*.sass && sass-migrator division node_modules/vuetify/**/*.scss'; + //config.scripts.dev = 'npm run hackfix && '+config.scripts.dev; + return config; + })(); + } + + modifyVueConfig(config) { + return _asyncToGenerator(function* () { + /*if (this.context.x_state.config_node.axios) { + let ax_config = config.axios; + if (this.context.x_state.config_node.axios.local) { + ax_config.baseURL = this.context.x_state.config_node.axios.local; + ax_config.browserBaseURL = this.context.x_state.config_node.axios.local; + delete ax_config.local; + if (this.context.x_state.config_node.axios.local.includes('127.0.0.1')) + this.context.x_state.config_node.axios.https=false; + } + delete ax_config.deploy; + config.axios = ax_config; + }*/ + // + return config; + })(); + } + + deploy() { + return _asyncToGenerator(function* () { + /* + let build={}; + if ((await this._isLocalServerRunning())==false) { + this.context.x_console.title({ title:'Deploying Local NuxtJS instance', color:'green' }); + await this.logo(); + //only launch nuxt server if its not running already + // builds the app + build.try_build = await this.base_build(); + if (build.try_build.length>0) { + this.x_console.outT({ message:`There was an error building the project.`, color:'red' }); + return false; + } + if (this.context.x_config.nodeploy && this.context.x_config.nodeploy==true) { + this.context.x_console.outT({ message:`Aborting final deployment as requested`, color:'brightRed'}); + return true; + } else { + build.deploy_local = await this.run(); + if (build.deploy_local.length>0) { + this.context.x_console.outT({ message:`There was an error deploying locally.`, color:'red', data:build.deploy_local.toString()}); + return false; + } + } + } else { + this.context.x_console.title({ title:'Updating local running NuxtJS instance', color:'green' }); + await this.logo(); + this.context.x_console.outT({ message:`Project updated.`, color:'green' }); + }*/ + return true; + })(); + } + + run() { + var _this = this; + + return _asyncToGenerator(function* () { + //issue npm run dev + var errors = []; + + require('await-spawn'); + + var spinner = _this.context.x_console.spinner({ + message: 'Deploying local instance' + }); //this.debug('Local deploy'); + + + spinner.start('Deploying local instance'); + + try { + //launch in a new terminal + yield _this.launchTerminal('npm', ['run', 'dev'], _this.context.x_state.dirs.app); //results.git_add = await spawn('npm',['run','dev'],{ cwd:this.x_state.dirs.app }); + + spinner.succeed('NuxtJS launched successfully'); + } catch (gi) { + spinner.fail('Project failed to launch'); + errors.push(gi); + } + + return errors; + })(); + } + + } + + class remote extends base_deploy { + constructor() { + var { + context = {} + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super({ + context, + name: 'Remote' + }); + } + + modifyPackageJSON(config) { + return _asyncToGenerator(function* () { + //little sass errors hack fix 13jun21 + config.devDependencies['sass-migrator'] = '*'; + config.scripts.hackfix = 'sass-migrator division node_modules/vuetify/**/*.sass && sass-migrator division node_modules/vuetify/**/*.scss'; + config.scripts.dev = 'npm run hackfix && ' + config.scripts.dev; + return config; + })(); + } + + modifyPackageJSON(data) { + var _this = this; + + return _asyncToGenerator(function* () { + if (_this.context.x_state.central_config.deploy == 'remote' && !_this.context.x_state.central_config[':hostname']) { + data.scripts.dev += " --hostname '0.0.0.0'"; + } + + return data; + })(); + } + + modifyNuxtConfig(config) { + var _this2 = this; + + return _asyncToGenerator(function* () { + if (_this2.context.x_state.config_node.axios) { + var ax_config = config.axios; + + if (_this2.context.x_state.config_node.axios.local) { + ax_config.baseURL = _this2.context.x_state.config_node.axios.local; + ax_config.browserBaseURL = _this2.context.x_state.config_node.axios.local; + delete ax_config.local; + if (_this2.context.x_state.config_node.axios.local.includes('127.0.0.1')) _this2.context.x_state.config_node.axios.https = false; + } + + delete ax_config.deploy; + config.axios = ax_config; + } //force a static build + + + config.ssr = false; + config.target = 'static'; + config.performance.gzip = false; //return + + return config; + })(); + } + + deploy() { + var _this3 = this; + + return _asyncToGenerator(function* () { + var build = {}; + + if ((yield _this3._isLocalServerRunning()) == false) { + _this3.context.x_console.title({ + title: 'Deploying NuxtJS instance with remote access', + color: 'green' + }); + + yield _this3.logo(); //only launch nuxt server if its not running already + // builds the app + + build.try_build = yield _this3.base_build(); + + if (build.try_build.length > 0) { + _this3.x_console.outT({ + message: "There was an error building the project.", + color: 'red' + }); + + return false; + } + + build.deploy_local = yield _this3.run(); + + if (build.deploy_local.length > 0) { + _this3.context.x_console.outT({ + message: "There was an error deploying locally.", + color: 'red', + data: build.deploy_local.toString() + }); + + return false; + } + } else { + _this3.context.x_console.title({ + title: 'Updating local running NuxtJS instance', + color: 'green' + }); + + yield _this3.logo(); + + _this3.context.x_console.outT({ + message: "Project updated.", + color: 'green' + }); + } + + return true; + })(); + } + + run() { + var _this4 = this; + + return _asyncToGenerator(function* () { + //issue npm run dev + var errors = []; + + require('await-spawn'); + + var sleep = function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + }; + + var spinner = _this4.context.x_console.spinner({ + message: 'Deploying Ngrok local instance' + }); //this.debug('Local deploy'); + + + spinner.start('Deploying local instance'); + + try { + //launch in a new terminal + yield _this4.launchTerminal('npm', ['run', 'dev'], _this4.context.x_state.dirs.app); //results.git_add = await spawn('npm',['run','dev'],{ cwd:this.x_state.dirs.app }); + + spinner.succeed('NuxtJS launched successfully'); + } catch (gi) { + spinner.fail('Project failed to launch'); + errors.push(gi); + } + + spinner.start("Launching remote access for port ".concat(_this4.context.x_state.central_config.port)); + + try { + //launch ngrok in new terminal + yield sleep(1000); + yield _this4.launchTerminal('npx', ['localtunnel', '--port', _this4.context.x_state.central_config.port, '--subdomain', _this4.context.x_state.central_config.apptitle.toLowerCase()], _this4.context.x_state.dirs.app); + spinner.succeed('Remote access requested successfully'); + } catch (ng) { + spinner.fail('Remote access failed to launch'); + errors.push(ng); + } + + return errors; + })(); + } + + } + + class eb extends base_deploy { + constructor() { + var { + context = {} + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super({ + context, + name: 'AWS EB' + }); + } + + logo() { + return _asyncToGenerator(function* () { + var asciify = require('asciify-image'), + path = require('path'); + + var aws = path.join(__dirname, 'assets', 'aws.png'); + var logo_txt = yield asciify(aws, { + fit: 'width', + width: 25 + }); + console.log(logo_txt); + })(); + } + + modifyNuxtConfig(config) { + var _this = this; + + return _asyncToGenerator(function* () { + if (_this.context.x_state.config_node.axios && _this.context.x_state.config_node.axios.deploy) { + var ax_config = config.axios; + ax_config.baseURL = _this.context.x_state.config_node.axios.deploy; + ax_config.browserBaseURL = _this.context.x_state.config_node.axios.deploy; + delete ax_config.deploy; + config.axios = ax_config; + } + + return config; + })(); + } + + deploy() { + var _this2 = this; + + return _asyncToGenerator(function* () { + var build = {}; + + _this2.context.x_console.title({ + title: 'Deploying to Amazon AWS Elastic Bean', + color: 'green' + }); + + yield _this2.logo(); // builds the app + + build.try_build = yield _this2.base_build(); + + if (build.try_build.length > 0) { + _this2.context.x_console.outT({ + message: "There was an error building the project.", + color: 'red' + }); + + return false; + } // deploys to aws + + + build.deploy_aws_eb = yield _this2.run(); //test if results.length>0 (meaning there was an error) + + if (build.deploy_aws_eb.length > 0) { + _this2.context.x_console.outT({ + message: "There was an error deploying to Amazon AWS.", + color: 'red', + data: build.deploy_aws_eb.toString() + }); + + return false; + } + + return true; + })(); + } + + run() { + var _this3 = this; + + return _asyncToGenerator(function* () { + var spawn = require('await-spawn'); + + var errors = []; //AWS EB deploy + + _this3.context.debug('AWS EB deploy'); + + var eb_full = _this3.context.x_state.central_config.deploy.replaceAll('eb:', ''); + + var eb_appname = eb_full; + var eb_instance = "".concat(eb_appname, "-dev"); + + if (_this3.context.x_state.central_config.deploy.includes(',')) { + eb_appname = eb_full.split(',')[0]; + eb_instance = eb_full.split(',').splice(-1)[0]; + } + + if (eb_appname != '') { + var spinner = _this3.context.x_console.spinner({ + message: 'Creating config files' + }); //this.x_console.outT({ message:`Creating EB config yml: ${eb_appname} in ${eb_instance}`, color:'yellow' }); + + + var yaml = require('yaml'); + + var data = { + 'branch-defaults': { + master: { + environment: eb_instance, + group_suffix: null + } + }, + global: { + application_name: eb_appname, + branch: null, + default_ec2_keyname: 'aws-eb', + default_platform: 'Node.js 14 running on 64bit Amazon Linux 2', + default_region: 'us-east-1', + include_git_submodules: true, + instance_profile: null, + platform_name: null, + platform_version: null, + profile: null, + repository: null, + sc: 'git', + workspace_type: 'Application' + } + }; //create .elasticbeanstalk directory + + var path = require('path'), + fs = require('fs').promises; + + var eb_base = _this3.context.x_state.dirs.app; + if (_this3.context.x_state.central_config.static) eb_base = path.join(eb_base, 'dist'); + var eb_dir = path.join(eb_base, '.elasticbeanstalk'); + + try { + yield fs.mkdir(eb_dir, { + recursive: true + }); + } catch (ef) {} //write .elasticbeanstalk/config.yml file with data + + + yield _this3.context.writeFile(path.join(eb_dir, 'config.yml'), yaml.stringify(data)); //write .npmrc file + + yield _this3.context.writeFile(path.join(eb_base, '.npmrc'), 'unsafe-perm=true'); //create .ebignore file + + var eb_ig = "node_modules/\njspm_packages/\n.npm\n.node_repl_history\n*.tgz\n.yarn-integrity\n.editorconfig\n# Mac OSX\n.DS_Store\n# Elastic Beanstalk Files\n.elasticbeanstalk/*\n!.elasticbeanstalk/*.cfg.yml\n!.elasticbeanstalk/*.global.yml"; + yield _this3.context.writeFile(path.join(eb_base, '.ebignore'), eb_ig); //init git if not already + + spinner.succeed('EB config files created successfully'); + var results = {}; + + if (!(yield _this3.exists(path.join(eb_base, '.git')))) { + //git directory doesn't exist + _this3.context.x_console.outT({ + message: 'CREATING .GIT DIRECTORY' + }); + + spinner.start('Initializing project git repository'); + spinner.text('Creating .gitignore file'); + var git_ignore = "# Mac System files\n.DS_Store\n.DS_Store?\n__MACOSX/\nThumbs.db\n# VUE files\nnode_modules/"; + yield _this3.context.writeFile(path.join(eb_base, '.gitignore'), git_ignore); + spinner.succeed('.gitignore created'); + spinner.start('Initializing local git repository ..'); + + try { + results.git_init = yield spawn('git', ['init', '-q'], { + cwd: eb_base + }); + spinner.succeed('GIT initialized'); + } catch (gi) { + results.git_init = gi; + spinner.fail('GIT failed to initialize'); + errors.push(gi); + } + + spinner.start('Adding files to local git ..'); + + try { + results.git_add = yield spawn('git', ['add', '.'], { + cwd: eb_base + }); + spinner.succeed('git added files successfully'); + } catch (gi) { + results.git_add = gi; + spinner.fail('git failed to add local files'); + errors.push(gi); + } + + spinner.start('Creating first git commit ..'); + + try { + results.git_commit = yield spawn('git', ['commit', '-m', 'Inicial'], { + cwd: eb_base + }); + spinner.succeed('git created first commit successfully'); + } catch (gi) { + results.git_commit = gi; + spinner.fail('git failed to create first commit'); + errors.push(gi); + } + } + + if (_this3.context.x_state.central_config.static == true) { + spinner.start('Deploying *static version* to AWS ElasticBean .. please wait'); + } else { + spinner.start('Deploying to AWS ElasticBean .. please wait'); + } // execute eb deploy + + + try { + if (_this3.context.x_config.nodeploy && _this3.context.x_config.nodeploy == true) { + spinner.succeed('EB ready to be deployed (nodeploy as requested)'); + + _this3.context.x_console.outT({ + message: "Aborting final deployment as requested", + color: 'brightRed' + }); + } else { + results.eb_deploy = yield spawn('eb', ['deploy', eb_instance], { + cwd: eb_base + }); //, stdio:'inherit' + + spinner.succeed('EB deployed successfully'); + } + } catch (gi) { + //test if eb failed because instance has not being created yet, if so create it + results.eb_deploy = gi; + spinner.warn('EB failed to deploy'); //this.x_console.outT({ message:gi.toString(), color:'red'}); + + if (gi.code == 4) { + // IAM credentials are invalid or instance hasn't being created (eb create is missing) + spinner.start('Checking if AWS credentials are valid ..'); + + try { + results.eb_create = yield spawn('aws', ['sts', 'get-caller-identity'], { + cwd: eb_base + }); //, stdio:'inherit' + + spinner.succeed('AWS credentials are ok'); + } catch (aws_cred) { + spinner.fail('Current AWS credentials are invalid'); + errors.push(aws_cred); + } + + if (errors.length == 0) { + spinner.start('EB it seems this is a new deployment: issuing eb create'); + + try { + //console.log('\n'); + results.eb_create = yield spawn('eb', ['create', eb_instance], { + cwd: eb_base + }); //, stdio:'inherit' + + spinner.succeed('EB created and deployed successfully'); + } catch (ec) { + _this3.context.x_console.outT({ + message: gi.stdout.toString(), + color: 'red' + }); + + spinner.fail('EB creation failed'); + errors.push(gi); + } + } + } else { + _this3.context.x_console.outT({ + message: 'error: eb create (exitcode:' + gi.code + '):' + gi.stdout.toString(), + color: 'red' + }); + + errors.push(gi); + } + } //if errors.length==0 && this.x_state.central_config.debug=='true' + + + if (errors.length == 0 && _this3.context.x_state.central_config.debug == true && !_this3.context.x_config.nodeploy) { + //open eb logging console + var ci = require('ci-info'); + + if (ci.isCI == false) { + spinner.start('Opening EB debug terminal ..'); + + try { + var abs_cmd = path.resolve(eb_base); + var cmd = "clear; sleep 2; clear; cd ".concat(abs_cmd, " && clear && eb open ").concat(eb_instance); + results.eb_log = yield spawn('npx', ['terminal-tab', cmd], { + cwd: abs_cmd + }); //, detached:true + + spinner.succeed("EB logging opened on new tab successfully"); + } catch (ot) { + results.eb_log = ot; + spinner.fail("I was unable to open a new tab terminal window with the EB debugging console"); + } + } else { + spinner.warn("Omitting EB debug, because a CI env was detected."); + } + } // eb deploy done + + } + + return errors; + })(); + } //**************************** + // onPrepare and onEnd steps + //**************************** + + + post() { + var _this4 = this; + + return _asyncToGenerator(function* () { + var ci = require('ci-info'); //restores aws credentials if modified by onPrepare after deployment + + + if (!_this4.context.x_state.central_config.componente && _this4.context.x_state.central_config.deploy && _this4.context.x_state.central_config.deploy.indexOf('eb:') != -1 && _this4.context.x_state.config_node.aws && ci.isCI == false) { + // @TODO add this block to deploys/eb 'post' method and onPrepare to 'pre' 20-br-21 + // only execute after deploy and if user requested specific aws credentials on map + var path = require('path'), + copy = require('recursive-copy'), + os = require('os'); + + var fs = require('fs'); + + var aws_bak = path.join(_this4.context.x_state.dirs.base, 'aws_backup.ini'); + var aws_file = path.join(os.homedir(), '/.aws/') + 'credentials'; // try to copy aws_bak over aws_ini_file (if bak exists) + + if (yield _this4.context.exists(aws_bak)) { + yield copy(aws_bak, aws_file, { + overwrite: true, + dot: true, + debug: false + }); // remove aws_bak file + + yield fs.promises.unlink(aws_bak); + } + } + })(); + } + + pre() { + var _this5 = this; + + return _asyncToGenerator(function* () { + var ci = require('ci-info'); + + if (!_this5.context.x_state.central_config.componente && _this5.context.x_state.central_config.deploy && _this5.context.x_state.central_config.deploy.indexOf('eb:') != -1 && ci.isCI == false) { + // if deploying to AWS eb:x, then recover/backup AWS credentials from local system + var ini = require('ini'), + path = require('path'), + fs = require('fs').promises; // read existing AWS credentials if they exist + + + var os = require('os'); + + var aws_ini = ''; + var aws_ini_file = path.join(os.homedir(), '/.aws/') + 'credentials'; + + try { + //this.debug('trying to read AWS credentials:',aws_ini_file); + aws_ini = yield fs.readFile(aws_ini_file, 'utf-8'); + + _this5.context.debug('AWS credentials:', aws_ini); + } catch (err_reading) {} // + + + if (_this5.context.x_state.config_node.aws) { + // if DSL defines temporal AWS credentials for this app .. + // create backup of aws credentials, if existing previously + if (aws_ini != '') { + var aws_bak = path.join(_this5.context.x_state.dirs.base, 'aws_backup.ini'); + + _this5.context.x_console.outT({ + message: "config:aws:creating .aws/credentials backup", + color: 'yellow' + }); + + yield fs.writeFile(aws_bak, aws_ini, 'utf-8'); + } // debug + + + _this5.context.x_console.outT({ + message: "config:aws:access ->".concat(_this5.context.x_state.config_node.aws.access) + }); + + _this5.context.x_console.outT({ + message: "config:aws:secret ->".concat(_this5.context.x_state.config_node.aws.secret) + }); // transform config_node.aws keys into ini + + + var to_ini = ini.stringify({ + aws_access_key_id: _this5.context.x_state.config_node.aws.access, + aws_secret_access_key: _this5.context.x_state.config_node.aws.secret + }, { + section: 'default' + }); + + _this5.context.debug('Setting .aws/credentials from config node'); // save as .aws/credentials (ini file) + + + yield fs.writeFile(aws_ini_file, to_ini, 'utf-8'); + } else if (aws_ini != '') { + // if DSL doesnt define AWS credentials, use the ones defined within the local system. + var parsed = ini.parse(aws_ini); + if (parsed.default) _this5.context.debug('Using local system AWS credentials', parsed.default); + _this5.context.x_state.config_node.aws = { + access: '', + secret: '' + }; + if (parsed.default.aws_access_key_id) _this5.context.x_state.config_node.aws.access = parsed.default.aws_access_key_id; + if (parsed.default.aws_secret_access_key) _this5.context.x_state.config_node.aws.secret = parsed.default.aws_secret_access_key; + } + } + })(); + } + + } + + class s3 extends base_deploy { + constructor() { + var { + context = {} + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super({ + context, + name: 'AWS S3' + }); + } + + logo() { + var _this = this; + + return _asyncToGenerator(function* () { + var cfonts = require('cfonts'); + + cfonts.say(_this.name, _objectSpread2({}, { + font: '3d', + colors: ['red', '#333'] + })); + })(); + } + + modifyPackageJSON(config) { + return _asyncToGenerator(function* () { + //little sass errors hack fix 13jun21 + var ci = require('ci-info'); + + if (ci.isCI == false) ; + + return config; + })(); + } + + modifyNuxtConfig(config) { + var _this2 = this; + + return _asyncToGenerator(function* () { + if (_this2.context.x_state.config_node.axios && _this2.context.x_state.config_node.axios.deploy) { + var ax_config = config.axios; + ax_config.baseURL = _this2.context.x_state.config_node.axios.deploy; + ax_config.browserBaseURL = _this2.context.x_state.config_node.axios.deploy; + delete ax_config.deploy; + config.axios = ax_config; + } + + _this2.context.x_state.central_config.static = true; //force static mode + + return config; + })(); + } + + deploy() { + var _this3 = this; + + return _asyncToGenerator(function* () { + var build = {}; + + _this3.context.x_console.title({ + title: 'Deploying to Amazon AWS S3', + color: 'green' + }); + + yield _this3.logo(); // builds the app + + build.try_build = yield _this3.base_build(); + + if (build.try_build.length > 0) { + _this3.context.x_console.outT({ + message: "There was an error building the project.", + color: 'red' + }); + + return false; + } // deploys to aws + + + build.deploy_aws_s3 = yield _this3.run(); //test if results.length>0 (meaning there was an error) + + if (build.deploy_aws_s3.length > 0) { + _this3.context.x_console.outT({ + message: "There was an error deploying to Amazon AWS.", + color: 'red', + data: build.deploy_aws_s3.toString() + }); + + return false; + } + + return true; + })(); + } + + run() { + var _this4 = this; + + return _asyncToGenerator(function* () { + var spawn = require('await-spawn'); + + var path = require('path'); + + var errors = [], + results = {}; + + var bucket = _this4.context.x_state.central_config.deploy.replaceAll('s3:', '').trim(); + + var aliases = []; + + var ci = require('ci-info'); + + var spa_opt = { + cwd: _this4.context.x_state.dirs.base + }; + var profile = ['--profile', 'default']; + + if (ci.isCI == true) { + //spa_opt.stdio = 'inherit'; + profile = []; + } + + if (_this4.context.x_state.central_config.dominio) { + bucket = _this4.context.x_state.central_config.dominio.trim(); + } //support for domain aliases + + + if (bucket.includes('<-') == true) { + require('extractjs'); + + aliases = bucket.split('<-').pop().split(','); + bucket = bucket.split('<-')[0].replaceAll('s3:', '').trim(); + } // + + + var region = 'us-east-1'; + if (_this4.context.x_state.config_node.aws.region) region = _this4.context.x_state.config_node.aws.region; + var dist_folder = path.join(_this4.context.x_state.dirs.compile_folder, 'dist/'); //AWS S3 deploy + + _this4.context.debug('AWS S3 deploy'); //MAIN + //create bucket policy + + + var spinner = _this4.context.x_console.spinner({ + message: "Creating policy for bucket:".concat(bucket) + }); + + var policy = { + Version: '2012-10-17', + Statement: [{ + Sid: 'PublicReadGetObject', + Effect: 'Allow', + Principal: '*', + Action: 's3:GetObject', + Resource: "arn:aws:s3:::".concat(bucket, "/*") + }] + }; + var policyFile = path.join(_this4.context.x_state.dirs.base, 'policy.json'); + + try { + yield _this4.context.writeFile(policyFile, JSON.stringify(policy)); + spinner.succeed('Bucket policy created'); + } catch (x1) { + spinner.fail('Bucket policy creation failed'); + errors.push(x1); + } //create bucket + + + spinner.start('Creating bucket'); + + try { + results.create_bucket = yield spawn('aws', ['s3api', 'create-bucket', '--bucket', bucket, '--region', region, ...profile], spa_opt); //, stdio:'inherit' + + spinner.succeed("Bucket created in ".concat(region)); + } catch (x2) { + spinner.fail('Bucket creation failed'); + errors.push(x2); + } //add bucket policy + //aws s3api put-bucket-policy --bucket www.happy-bunny.xyz --policy file:///tmp/bucket_policy.json --profile equivalent + + + spinner.start('Adding bucket policy'); + + try { + results.adding_policy = yield spawn('aws', ['s3api', 'put-bucket-policy', '--bucket', bucket, '--policy', 'file://' + policyFile, ...profile], spa_opt); //, stdio:'inherit' + + spinner.succeed("Bucket policy added correctly"); + } catch (x3) { + spinner.fail('Adding bucket policy failed'); + errors.push(x3); + } //upload website files to bucket + //aws s3 sync /tmp/SOURCE_FOLDER s3://www.happy-bunny.xyz/ --profile equivalent + + + spinner.start('Uploading website files to bucket'); + + try { + results.website_upload = yield spawn('aws', ['s3', 'sync', dist_folder, 's3://' + bucket + '/', ...profile], spa_opt); //, stdio:'inherit' + + spinner.succeed("Website uploaded successfully"); + } catch (x4) { + spinner.fail('Failed uploading website files'); + errors.push(x4); + } //set s3 bucket as website, set index.html and error page + //aws s3 website s3://www.happy-bunny.xyz/ --index-document index.html --error-document error.html --profile equivalent + + + spinner.start('Setting S3 bucket as type website'); + + try { + results.set_as_website = yield spawn('aws', ['s3', 'website', 's3://' + bucket + '/', '--index-document', 'index.html', '--error-document', '200.html', ...profile], spa_opt); + spinner.succeed("Bucket configured as website successfully"); + } catch (x5) { + spinner.fail('Failed configuring bucket as website'); + errors.push(x5); + } //ALIASES + + + var fs = require('fs').promises; + + if (aliases.length > 0) { + for (var alias of aliases) { + var _spinner = _this4.context.x_console.spinner({ + message: "Creating policy for bucket alias:".concat(alias) + }); + + var _policy = { + RedirectAllRequestsTo: { + HostName: bucket + } + }; + + var _policyFile = path.join(_this4.context.x_state.dirs.base, 'policy_alias.json'); + + try { + yield _this4.context.writeFile(_policyFile, JSON.stringify(_policy)); + + _spinner.succeed("Bucket alias '".concat(alias, "' policy created")); + } catch (x1) { + _spinner.fail("Bucket alias '".concat(alias, "' policy creation failed")); + + errors.push(x1); + } //create bucket + + + _spinner.start("Creating bucket alias '".concat(alias, "'")); + + try { + results.create_bucket = yield spawn('aws', ['s3api', 'create-bucket', '--bucket', alias, '--region', region, ...profile], spa_opt); //, stdio:'inherit' + + _spinner.succeed("Bucket alias '".concat(alias, "' created in ").concat(region)); + } catch (x2) { + _spinner.fail("Bucket alias '".concat(alias, "' creation failed")); + + errors.push(x2); + } //add bucket policy + + + _spinner.start("Adding bucket alias '".concat(alias, "' policy")); + + try { + results.adding_policy = yield spawn('aws', ['s3api', 'put-bucket-website', '--bucket', alias, '--website-configuration', 'file://policy_alias.json', ...profile], spa_opt); //, stdio:'inherit' + + _spinner.succeed("Bucket alias '".concat(alias, "' policy added correctly")); + } catch (x2) { + _spinner.fail("Adding bucket alias '".concat(alias, "' policy failed")); + + errors.push(x2); + } //erase policy_alias.json file + + + try { + yield fs.unlink(_policyFile); + } catch (err_erasepolicy_alias) {} + } + } + + if (errors.length == 0) { + _this4.context.x_console.out({ + message: "Website ready at http://".concat(bucket, ".s3-website-").concat(region, ".amazonaws.com/"), + color: 'brightCyan' + }); + } //erase policy.json file + + + try { + yield fs.unlink(policyFile); + } catch (err_erasepolicy) {} //ready + + + return errors; + })(); + } //**************************** + // onPrepare and onEnd steps + //**************************** + + + post() { + var _this5 = this; + + return _asyncToGenerator(function* () { + var ci = require('ci-info'); //restores aws credentials if modified by onPrepare after deployment + + + if (!_this5.context.x_state.central_config.componente && _this5.context.x_state.central_config.deploy && _this5.context.x_state.central_config.deploy.indexOf('s3:') != -1 && _this5.context.x_state.config_node.aws && ci.isCI == false) { + // @TODO add this block to deploys/s3 'post' method and onPrepare to 'pre' 20-br-21 + // only execute after deploy and if user requested specific aws credentials on map + var path = require('path'), + copy = require('recursive-copy'), + os = require('os'); + + var fs = require('fs'); + + var aws_bak = path.join(_this5.context.x_state.dirs.base, 'aws_backup.ini'); + var aws_file = path.join(os.homedir(), '/.aws/') + 'credentials'; // try to copy aws_bak over aws_ini_file (if bak exists) + + if (yield _this5.context.exists(aws_bak)) { + yield copy(aws_bak, aws_file, { + overwrite: true, + dot: true, + debug: false + }); // remove aws_bak file + + yield fs.promises.unlink(aws_bak); + } + } + })(); + } + + pre() { + var _this6 = this; + + return _asyncToGenerator(function* () { + var ci = require('ci-info'); + + if (!_this6.context.x_state.central_config.componente && _this6.context.x_state.central_config.deploy && _this6.context.x_state.central_config.deploy.indexOf('s3:') != -1 && ci.isCI == false) { + // if deploying to AWS s3:x, then recover/backup AWS credentials from local system + var ini = require('ini'), + path = require('path'), + fs = require('fs').promises; // read existing AWS credentials if they exist + + + var os = require('os'); + + var aws_ini = ''; + var aws_ini_file = path.join(os.homedir(), '/.aws/') + 'credentials'; + + try { + //this.debug('trying to read AWS credentials:',aws_ini_file); + aws_ini = yield fs.readFile(aws_ini_file, 'utf-8'); + + _this6.context.debug('AWS credentials:', aws_ini); + } catch (err_reading) {} // + + + if (_this6.context.x_state.config_node.aws) { + // if DSL defines temporal AWS credentials for this app .. + // create backup of aws credentials, if existing previously + if (aws_ini != '') { + var aws_bak = path.join(_this6.context.x_state.dirs.base, 'aws_backup.ini'); + + _this6.context.x_console.outT({ + message: "config:aws:creating .aws/credentials backup", + color: 'yellow' + }); + + yield fs.writeFile(aws_bak, aws_ini, 'utf-8'); + } // debug + + + _this6.context.x_console.outT({ + message: "config:aws:access ->".concat(_this6.context.x_state.config_node.aws.access) + }); + + _this6.context.x_console.outT({ + message: "config:aws:secret ->".concat(_this6.context.x_state.config_node.aws.secret) + }); + + if (_this6.context.x_state.config_node.aws.region) { + _this6.context.x_console.outT({ + message: "config:aws:region ->".concat(_this6.context.x_state.config_node.aws.region) + }); + } // transform config_node.aws keys into ini + + + var to_aws = { + aws_access_key_id: _this6.context.x_state.config_node.aws.access, + aws_secret_access_key: _this6.context.x_state.config_node.aws.secret + }; + + if (_this6.context.x_state.config_node.aws.region) { + to_aws.region = _this6.context.x_state.config_node.aws.region; + } + + var to_ini = ini.stringify(to_aws, { + section: 'default' + }); + + _this6.context.debug('Setting .aws/credentials from config node'); // save as .aws/credentials (ini file) + + + yield fs.writeFile(aws_ini_file, to_ini, 'utf-8'); + } else if (aws_ini != '') { + // if DSL doesnt define AWS credentials, use the ones defined within the local system. + var parsed = ini.parse(aws_ini); + if (parsed.default) _this6.context.debug('Using local system AWS credentials', parsed.default); + _this6.context.x_state.config_node.aws = { + access: '', + secret: '' + }; + if (parsed.default.aws_access_key_id) _this6.context.x_state.config_node.aws.access = parsed.default.aws_access_key_id; + if (parsed.default.aws_secret_access_key) _this6.context.x_state.config_node.aws.secret = parsed.default.aws_secret_access_key; + if (parsed.default.region) _this6.context.x_state.config_node.aws.region = parsed.default.region; + } + } + })(); + } + + } + + class ghpages extends base_deploy { + constructor() { + var { + context = {} + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + super({ + context, + name: 'GH Pages' + }); + } + + modifyNuxtConfig(config) { + var _this = this; + + return _asyncToGenerator(function* () { + // use axios deploy endpoint + if (_this.context.x_state.config_node.axios && _this.context.x_state.config_node.axios.deploy) { + var ax_config = config.axios; + ax_config.baseURL = _this.context.x_state.config_node.axios.deploy; + ax_config.browserBaseURL = _this.context.x_state.config_node.axios.deploy; + delete ax_config.deploy; + config.axios = ax_config; + } //force a static build, since ghpages only support those + + + config.ssr = false; + config.target = 'static'; + config.performance.gzip = false; + return config; + })(); + } + + deploy() { + var _this2 = this; + + return _asyncToGenerator(function* () { + var build = {}; + + _this2.context.x_console.title({ + title: 'Creating GH Workflow for deploying on ghpages on commit', + color: 'green' + }); + + yield _this2.logo({ + config: { + font: 'chrome', + gradient: false, + space: true, + colors: ['#F2F3F4', '#0C70E0'] + } + }); // builds the app; github can build the app + + /* + build.try_build = await this.base_build(); + if (build.try_build.length>0) { + this.context.x_console.outT({ message:`There was an error building the project.`, color:'red' }); + return false; + }*/ + // creates github actions folder, and workflow + + build.create_ghp = yield _this2.run(); //test if results.length>0 (meaning there was an error) + + if (build.create_ghp.length > 0) { + _this2.context.x_console.outT({ + message: "There was an error creating the github workflow.", + color: 'red', + data: build.create_ghp.toString() + }); + + return false; + } + + return true; + })(); + } + + run() { + var _this3 = this; + + return _asyncToGenerator(function* () { + var yaml = require('yaml'), + errors = []; + + var spinner = _this3.context.x_console.spinner({ + message: 'Creating github workflow for building and publishing' + }); + + var data = { + name: 'DSL Build and Publish', + on: 'push', + jobs: { + build: { + name: 'Build and publish', + 'runs-on': 'ubuntu-latest', + steps: [{ + name: 'Downloads repo code', + uses: 'actions/checkout@2', + with: { + submodules: 'recursive' + } + }, { + name: 'Install packages', + run: 'npm install' + }, { + name: 'Builds static distribution', + run: 'npm run build' + }, { + name: 'Publish dist to GHPages of current repo', + uses: 'peaceiris/actions-gh-pages@v3', + with: { + github_token: '${{ secrets.GITHUB_TOKEN }}', + publish_dir: './dist' + } + }] + } + } + }; + var content = yaml.stringify(data); + + var path = require('path'), + fs = require('fs').promises; + + var target = path.join(_this3.context.x_state.dirs.app, '.github', 'workflows'); // create .github/workflows directory if needed + + try { + yield fs.mkdir(target, { + recursive: true + }); + target = path.join(target, "publish.yml"); + yield _this3.context.writeFile(target, content); + spinner.succeed('Github workflow ready'); + } catch (errdir) { + spinner.fail('Github workflow failed'); + errors.push('Github workflow failed'); + } // create /.gitignore file for built repo + + + spinner.start('Writing repo .gitignore file ..'); + var git = 'dist\n'; + git += 'secrets\n'; + git += 'node_modules'; + target = path.join(_this3.context.x_state.dirs.app, '.gitignore'); + yield _this3.context.writeFile(target, git); + spinner.succeed('Github .gitignore ready'); + return errors; + })(); + } //**************************** + // onPrepare and onEnd steps + //**************************** + + + post() { + return _asyncToGenerator(function* () {})(); + } + + pre() { + return _asyncToGenerator(function* () {})(); + } + + } + + var concepto = require('@concepto/interface'); //import { timingSafeEqual } from 'crypto'; + class vue_dsl extends concepto { + constructor(file) { + var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + // we can get class name, from package.json name key (after its in its own project) + var my_config = { + class: 'vue', + debug: true + }; + + var nuevo_config = _objectSpread2(_objectSpread2({}, my_config), config); + + super(file, nuevo_config); //,...my_config + // custom dsl_git version + + this.x_config.dsl_git = /*#__PURE__*/function () { + var _ref = _asyncToGenerator(function* (content) { + //save git version + var tmp = {}, + fs = require('fs').promises, + path = require('path'); //SECRETS + + + this.x_state.central_config = yield this._readCentralConfig(); + this.x_state.config_node = yield this._readConfig(false); + + if (this.x_flags.dsl.includes('_git.dsl')) { + // if file is x_git.dsl, expand secrets + this.x_console.outT({ + message: 'we are the git!', + color: 'green' + }); + this.x_state.config_node = yield this._restoreSecrets(this.x_state.config_node); + delete this.x_state.config_node[':id']; + delete this.x_state.config_node[':secrets']; + delete this.x_state.config_node['::secrets']; //search and erase config->:secrets node + //this.x_console.out({ message:'config read on git',data:this.x_state.config_node }); + } else { + // if file is x.dsl, + // write x_git.dsl + tmp.dsl_path = path.dirname(path.resolve(this.x_flags.dsl)); + tmp.dsl_git = path.join(tmp.dsl_path, path.basename(this.x_flags.dsl).replace('.dsl', '_git.dsl')); + yield fs.writeFile(tmp.dsl_git, content, 'utf-8'); + this.debug("custom dsl_git file saved as: ".concat(tmp.dsl_git)); // export secret keys as :secrets node to eb_git.dsl + + yield this._secretsToGIT(this.x_state.config_node); + } // + + }); + + return function (_x) { + return _ref.apply(this, arguments); + }; + }().bind(this); // + + } // SECRETS helpers (@todo move this to concepto class) + + + _secretsToGIT(resp) { + var _this = this; + + return _asyncToGenerator(function* () { + var path = require('path'), + fs = require('fs').promises; + + var encrypt = require('encrypt-with-password'); + + var curr_dsl = path.basename(_this.x_flags.dsl); // secret nodes to _git.dsl file + + if (resp['::secrets'] && resp['::secrets'].length > 0 && !curr_dsl.includes('_git.')) { + //encrypt existing secret (password) nodes and save them as config->:secrets within _git.dsl file version + var password = ''; + if (_this.x_config.secrets_pass && _this.x_config.secrets_pass != '') password = _this.x_config.secrets_pass.trim(); + + if (password == '') { + //if a password was not given, invent a memorable one + var gpass = require('password-generator'); + + password = gpass(); + resp[':password'] = password; //inform a pass was created + } //encrypt secrets object + + + var to_secrets = encrypt.encryptJSON(resp['::secrets'], password); //create :secrets node within eb_git.dsl file + + var dsl_parser = require('@concepto/dsl_parser'); + + var dsl = new dsl_parser({ + file: _this.x_flags.dsl.replace('.dsl', '_git.dsl'), + config: { + cancelled: true, + debug: false + } + }); + + try { + yield dsl.process(); + } catch (d_err) { + _this.x_console.out({ + message: "error: file ".concat(_this.x_flags.dsl.replace('.dsl', '_git.dsl'), " does't exist!"), + data: d_err + }); + + return; + } + + var new_content = yield dsl.addNode({ + parent_id: resp[':id'], + node: { + text: ':secrets', + icons: ['password'], + text_note: to_secrets + } + }); + var tmp = {}; + tmp.dsl_git_path = path.dirname(path.resolve(_this.x_flags.dsl)); + var git_target = path.join(tmp.dsl_git_path, path.basename(_this.x_flags.dsl).replace('.dsl', '_git.dsl')); //,path.basename(this.x_flags.dsl) + + yield fs.writeFile(git_target, new_content, 'utf-8'); + + _this.debug("dsl_git file saved as: ".concat(git_target)); + + if (resp[':password']) { + _this.x_console.outT({ + message: "Password generated for DSL GIT secrets ->".concat(password), + color: 'brightGreen' + }); + } // + + } + + return resp; + })(); + } // restore :secrets node info if it exists and a password was given + + + _restoreSecrets(resp) { + var _this2 = this; + + return _asyncToGenerator(function* () { + var path = require('path'), + fs = require('fs').promises; + + var encrypt = require('encrypt-with-password'); + + var curr_dsl = path.basename(_this2.x_flags.dsl); + + if (curr_dsl.includes('_git.') && resp[':secrets']) { + _this2.x_console.outT({ + message: "Secrets node detected!", + color: 'brightCyan' + }); + + if (_this2.x_config.secrets_pass && _this2.x_config.secrets_pass != '') { + _this2.x_console.outT({ + message: 'Decrypting config->secrets', + color: 'brightGreen' + }); + + try { + var from_secrets = encrypt.decryptJSON(resp[':secrets'], _this2.x_config.secrets_pass); // read nodes into resp struct + + for (var xs of from_secrets) { + resp = _objectSpread2(_objectSpread2({}, resp), _this2.configFromNode(resp, xs)); + } + + var tmp = {}; + tmp.dsl_git_path = path.dirname(path.resolve(_this2.x_flags.dsl)); + tmp.non_target = path.join(tmp.dsl_git_path, path.basename(_this2.x_flags.dsl).replace('_git.dsl', '.dsl')); + tmp.exists_non = yield _this2.exists(tmp.non_target); + + if (true) { + //!tmp.exists_non + _this2.x_console.outT({ + message: 'Expanding secrets into ' + curr_dsl.replace('_git.dsl', '.dsl'), + color: 'cyan' + }); // expand secret nodes into non _git.dsl version config key + + + var dsl_parser = require('@concepto/dsl_parser'); + + var dsl = new dsl_parser({ + file: _this2.x_flags.dsl, + config: { + cancelled: true, + debug: false + } + }); + + try { + yield dsl.process(); + } catch (d_err) { + _this2.x_console.out({ + message: "error: file ".concat(_this2.x_flags.dsl, " does't exist!"), + data: d_err + }); + + return; + } // remove config->:secrets node if it exists + + + var $ = dsl.getParser(); + var search = $("node[TEXT=config] node[TEXT=:secrets]").toArray(); + search.map(function (elem) { + $(elem).remove(); + }); // + + var new_content = ''; + + for (var sn of from_secrets) { + new_content = yield dsl.addNode({ + parent_id: resp[':id'], + node: sn + }); + } // save expanded x.dsl file (only if it doesnt exist) + + + yield fs.writeFile(tmp.non_target, new_content, 'utf-8'); + + _this2.debug("recovered dsl file saved as: ".concat(tmp.non_target)); + } // + + } catch (invpass) { + //console.log(invpass); + _this2.x_console.outT({ + message: 'Invalid --secret-pass value for map (check your password)', + color: 'brightRed' + }); + + _this2.x_console.outT({ + message: 'WARNING: The process may fail if keys are needed', + color: 'red' + }); + } + } else { + _this2.x_console.outT({ + message: 'WARNING: file contains secrets, but no --secrets-pass arg was given', + color: 'brightRed' + }); + + _this2.x_console.outT({ + message: 'WARNING: The process may fail if keys are needed', + color: 'red' + }); + } + } + + return resp; + })(); + } // + // ************************** + // methods to be auto-called + // ************************** + //Called after init method finishes + + + onInit() { + var _this3 = this; + + return _asyncToGenerator(function* () { + // define and assign commands + _this3.x_console.outT({ + message: "Vue Compiler", + color: "brightCyan" + }); //await this.addCommands(internal_commands); + + + if (Object.keys(_this3.x_commands).length > 0) _this3.x_console.outT({ + message: "".concat(Object.keys(_this3.x_commands).length, " local x_commands loaded!"), + color: "green" + }); //this.debug('x_commands',this.x_commands); + //this.x_crypto_key = require('crypto').randomBytes(32); // for hash helper method + // init vue + // set x_state defaults + + _this3.x_state = _objectSpread2(_objectSpread2({}, _this3.x_state), { + plugins: {}, + npm: {}, + dev_npm: {}, + envs: {}, + functions: {}, + proxies: {}, + pages: {}, + current_func: '', + current_folder: '', + current_proxy: '', + strings_i18n: {}, + stores: {}, + stores_types: { + versions: {}, + expires: {} + }, + global_head: {}, + // head scripts for index.html + bootloader: { + imports: {} // imports for bootloader.js (ex. vue plugins) + + }, + vue_config: { + // custom vue.config.js + lintOnSave: false, + // disable eslint + mfPlugin: { + name: '', + filename: 'remoteEntry.js', + remotes: {}, + exposes: {}, + shared: { + '{...deps}': '', + vue: { + eager: true, + singleton: true, + requiredVersion: 'deps.vue' + }, + "vue-router": { + eager: true, + singleton: true, + requiredVersion: 'deps["vue-router"]' + }, + vuex: { + eager: true, + singleton: true, + requiredVersion: 'deps["vuex"]' + } + } + } + }, + nuxt_config: { + head_script: {}, + build_modules: {}, + modules: {} + } + }); + if (!_this3.x_state.config_node) _this3.x_state.config_node = yield _this3._readConfig(); + _this3.x_state.central_config = yield _this3._readCentralConfig(); //this.debug('this.x_state',this.x_state); + //if requested silence... + + if (_this3.x_config.silent) { + _this3.x_console.outT({ + message: "silent mode requested", + color: "dim" + }); //this.x_console.setSilent(true); + + + _this3.x_config.debug = false; + } //if requested change deploy target + + + if (_this3.x_config.deploy && _this3.x_config.deploy.trim() != '') { + _this3.x_console.outT({ + message: "(as requested) force changing deploy target to: ".concat(_this3.x_config.deploy.trim()), + color: "brightYellow" + }); + + _this3.x_state.central_config.deploy = _this3.x_config.deploy; + } + + var compile_folder = _this3.x_state.central_config.apptitle; + + if (_this3.x_config.folder && _this3.x_config.folder.trim() != '') { + compile_folder = _this3.x_config.folder.trim(); + } + + if (_this3.x_config.aws_region && _this3.x_config.aws_region.trim() != '') { + if (!_this3.x_state.config_node.aws) _this3.x_state.config_node.aws = {}; + _this3.x_state.config_node.aws.region = _this3.x_config.aws_region.trim(); + } //this.debug('central_config',this.x_state.central_config); + + + _this3.x_state.assets = yield _this3._readAssets(); //this.debug('assets_node',this.x_state.assets); + + var target_folders = {}; + target_folders = { + 'client': 'src/', + 'layouts': 'src/layouts/', + 'components': 'src/components/', + 'pages': 'src/pages/', + 'plugins': 'src/plugins/', + 'static': 'src/static/', + 'public': 'public/', + 'middleware': 'src/middleware/', + 'server': '', + // not supported here 'src/server/', + 'assets': 'src/assets/', + 'css': 'src/assets/css/', + 'store': 'src/store/', + 'lang': 'src/lang/', + 'secrets': 'secrets/' + }; + + if (_this3.x_state.central_config.storybook == true) { + target_folders['storybook'] = '.storybook/'; + target_folders['stories'] = 'stories2/'; + target_folders['stories_assets'] = 'stories2/assets/'; + } + + _this3.x_state.dirs = yield _this3._appFolders(target_folders, compile_folder); // read modelos node (virtual DB) + + _this3.x_state.models = yield _this3._readModelos(); //alias: database tables + //is local server running? if so, don't re-launch it + + _this3.x_state.nuxt_is_running = yield _this3._isLocalServerRunning(); + + _this3.debug('is Server Running: ' + _this3.x_state.nuxt_is_running); // init terminal diagnostics (not needed here) + + + _this3.x_state.es6 = true; // copy sub-directories if defined in node 'config.copiar' key + + if (_this3.x_state.config_node.copiar) { + var _path = require('path'); + + var copy = require('recursive-copy'); + + _this3.x_console.outT({ + message: "copying config:copiar directories to 'static' target folder", + color: "yellow" + }); + + yield Object.keys(_this3.x_state.config_node.copiar).map( /*#__PURE__*/function () { + var _ref2 = _asyncToGenerator(function* (key) { + var abs = _path.join(this.x_state.dirs.base, key); + + try { + yield copy(abs, this.x_state.dirs.static); + } catch (err_copy) { + if (err_copy.code != 'EEXIST') this.x_console.outT({ + message: "error: copying directory ".concat(abs), + data: err_copy + }); + } //console.log('copying ',{ from:abs, to:this.x_state.dirs.static }); + + }); + + return function (_x2) { + return _ref2.apply(this, arguments); + }; + }().bind(_this3)); + + _this3.x_console.outT({ + message: "copying config:copiar directories ... READY", + color: "yellow" + }); + + delete _this3.x_state.config_node.copiar; + } // ********************************************* + // install requested modules within config node + // ********************************************* + // NUXT:ICON + + + if (_this3.x_state.config_node['nuxt:icon']) { + //@TODO refactor this later nuxt:icon -> favicon (as is now for compatibility) + // copy icon to static dir + var _path2 = require('path'); + + var source = _path2.join(_this3.x_state.dirs.base, _this3.x_state.config_node['nuxt:icon']); + + var target = _this3.x_state.dirs.static + 'icon.png'; + + _this3.debug({ + message: "favicon dump (copy icon)", + color: "yellow", + data: source + }); + + var fs = require('fs').promises; + + try { + yield fs.copyFile(source, target); + } catch (err_fs) { + _this3.x_console.outT({ + message: "error: copying favicon icon", + data: err_fs + }); + } + } // GOOGLE:ADSENSE + + + if (_this3.x_state.config_node['google:adsense']) { + _this3.x_state.npm['vue-google-adsense'] = '*'; + _this3.x_state.npm['vue-script2'] = '*'; + } // GOOGLE:ANALYTICS + + + if (_this3.x_state.config_node['google:analytics']) { + _this3.x_state.npm['@nuxtjs/google-gtag'] = '*'; + } // ADD v-mask if latest Nuxt/Vuetify, because vuetify v2+ no longer includes masks support + + + _this3.x_state.plugins['v-mask'] = { + global: true, + mode: 'client', + npm: { + 'v-mask': '*' + }, + customcode: "import Vue from 'vue';\nimport VueMask from 'v-mask';\nVue.directive('mask', VueMask.VueMaskDirective);\nVue.use(VueMask);", + dev_npm: {} + }; // DEFAULT NPM MODULES & PLUGINS + + _this3.x_console.outT({ + message: "vue initialized() ->" + }); + + _this3.x_state.npm['axios'] = '*'; // axios + + _this3.x_state.npm['axios-retry'] = '*'; + _this3.x_state.npm['underscore'] = '*'; // underscore + + _this3.x_state.dev_npm['vue-beautify-loader'] = '*'; // beautify + // Add VueJS + Vuetify + MF support + // dev packages + + _this3.x_state.dev_npm['@babel/core'] = '^7.15.8'; + _this3.x_state.dev_npm['@babel/eslint-parser'] = '^7.12.16'; + _this3.x_state.dev_npm['@babel/plugin-transform-runtime'] = '^7.15.8'; + _this3.x_state.dev_npm['@vue/cli-plugin-babel'] = '~5.0.0'; + _this3.x_state.dev_npm['@vue/cli-plugin-eslint'] = '~5.0.0'; + _this3.x_state.dev_npm['@vue/cli-service'] = '~5.0.0'; + _this3.x_state.dev_npm['eslint'] = '^7.32.0'; + _this3.x_state.dev_npm['eslint-plugin-vue'] = '^8.0.3'; + _this3.x_state.dev_npm['sass'] = '~1.32'; + _this3.x_state.dev_npm['sass-loader'] = '^10.0.0'; + _this3.x_state.dev_npm['vue-cli-plugin-vuetify'] = '~2.5.8'; + _this3.x_state.dev_npm['vue-template-compiler'] = '^2.6.14'; + _this3.x_state.dev_npm['vuetify-loader'] = '^1.7.0'; + _this3.x_state.dev_npm['vue-loader'] = '*'; + _this3.x_state.dev_npm['webpack'] = '^5.57.1'; + _this3.x_state.dev_npm['html-webpack-plugin'] = '^5.5.0'; // dep packages + + _this3.x_state.npm['core-js'] = '^3.8.3'; + _this3.x_state.npm['vue'] = '^2.6.14'; + _this3.x_state.npm['vuex'] = '^3.6.2'; + _this3.x_state.npm['vue-router'] = '^3.6.5'; + _this3.x_state.npm['vuetify'] = '^2.6.13'; // default plugins + + _this3.x_state.plugins['vue-moment'] = { + global: true, + mode: 'client', + npm: { + 'vue-moment': '*' + }, + extra_imports: ['moment'], + requires: ['moment/locale/es'], + config: '{ moment }' + }; // express things + //this.x_state.npm['express'] = '*'; + //this.x_state.npm['serverless-http'] = '*'; + //this.x_state.npm['serverless-apigw-binary'] = '*'; + // dev tools + //this.x_state.dev_npm['serverless-prune-plugin'] = '*'; + //this.x_state.dev_npm['serverless-offline'] = '*'; + // + + /* + if (this.x_state.central_config.dominio) { + this.x_state.dev_npm['serverless-domain-manager'] = '*'; + }*/ + // serialize 'secret' config keys as json files in app secrets sub-directory (if any) + // extract 'secret's from config keys; + + /* */ + + _this3.x_state.secrets = {}; //await _extractSecrets(config_node) + + var path = require('path'); + + for (var key in _this3.x_state.config_node) { + if (typeof key === 'string' && key.includes(':') == false) { + if (_this3.x_state.config_node[key][':secret']) { + var new_obj = _objectSpread2({}, _this3.x_state.config_node[key]); + + delete new_obj[':secret']; + if (new_obj[':link']) delete new_obj[':link']; // set object keys to uppercase + + _this3.x_state.secrets[key] = {}; + var obj_keys = Object.keys(new_obj); + + for (var x in obj_keys) { + _this3.x_state.secrets[key][x.toUpperCase()] = new_obj[x]; + } + + var _target = path.join(_this3.x_state.dirs.secrets, "".concat(key, ".json")); + + yield _this3.writeFile(_target, JSON.stringify(new_obj)); + } + } + } // set config keys as ENV accesible variables (ex. $config.childnode.attributename) + + + var _loop = function _loop(_key) { + // omit special config 'reserved' node keys + if (['aurora', 'vpc', 'aws'].includes(_key) && typeof _this3.x_state.config_node[_key] === 'object') { + Object.keys(_this3.x_state.config_node[_key]).map(function (attr) { + this.x_state.envs["config.".concat(_key, ".").concat(attr)] = "process.env.".concat((_key + '_' + attr).toUpperCase()); + }.bind(_this3)); + } + }; + + for (var _key in _this3.x_state.config_node) { + _loop(_key); + } // show this.x_state contents + //this.debug('x_state says',this.x_state); + + })(); + } //Called after parsing nodes + + + onAfterProcess(processedNode) { + return _asyncToGenerator(function* () { + return processedNode; + })(); + } //Called for defining the title of class/page by testing node. + + + onDefineTitle(node) { + var _this4 = this; + + return _asyncToGenerator(function* () { + var resp = node.text; + Object.keys(node.attributes).map(function (i) { + if (i == 'title' || i == 'titulo') { + resp = node.attributes[i]; + return false; + } + }.bind(_this4)); + /* + for (i in node.attributes) { + if (['title','titulo'].includes(node.attributes[i])) { + resp = node.attributes[i]; + break; + } + }*/ + + return resp; + })(); + } //Called for naming filename of class/page by testing node. + + + onDefineFilename(node) { + return _asyncToGenerator(function* () { + var resp = node.text; // @idea we could use some 'slug' method here + + resp = resp.replace(/\ /g, '_') + '.vue'; + + if (node.icons.includes('gohome')) { + resp = 'index.vue'; + } else if (node.icons.includes('desktop_new')) { + if (node.text.indexOf('assets') != -1) { + resp = 'internal_assets.omit'; + } else if (node.text.indexOf('store') != -1) { + resp = 'internal_stores.omit'; + } else if (node.text.indexOf('proxy') != -1 || node.text.indexOf('proxies') != -1) { + resp = 'internal_middleware.omit'; + } else if (node.text.indexOf('config') != -1) { + resp = 'config.omit'; + } else if (node.text.indexOf('modelos') != -1) { + resp = 'modelos.omit'; + } else if (['servidor', 'server', 'api'].includes(node.text)) { + resp = 'server.omit'; + } + } else if (node.text.indexOf('componente:') != -1) { + resp = node.text.split(':')[node.text.split(':').length - 1] + '.vue'; + } else if (node.text.indexOf('layout:') != -1) { + resp = node.text.split(':')[node.text.split(':').length - 1] + '.vue'; + } else if (node.icons.includes('list')) { + resp = resp.replaceAll('.vue', '.group'); + } + + return resp; + })(); + } //Called for naming the class/page by testing node. + + + onDefineNodeName(node) { + return _asyncToGenerator(function* () { + return node.text.replace(' ', '_'); + })(); + } //Defines template for code given the processedNode of process() - for each level2 node + + + onCompleteCodeTemplate(processedNode) { + return _asyncToGenerator(function* () { + return processedNode; + })(); + } //Defines preparation steps before processing nodes. + + + onPrepare() { + var _this5 = this; + + return _asyncToGenerator(function* () { + if (Object.keys(_this5.x_commands).length > 0) _this5.x_console.outT({ + message: "".concat(Object.keys(_this5.x_commands).length, " x_commands loaded!"), + color: "green" + }); + _this5.deploy_module = { + pre: () => {}, + post: () => {}, + deploy: () => true + }; + var deploy = _this5.x_state.central_config.deploy; + + if (deploy) { + deploy += ''; + + if (deploy.includes('eb:')) { + _this5.deploy_module = new eb({ + context: _this5 + }); + } else if (deploy.includes('s3:')) { + _this5.deploy_module = new s3({ + context: _this5 + }); + } else if (deploy == 'local') { + _this5.deploy_module = new local({ + context: _this5 + }); // + } else if (deploy == 'remote') { + _this5.deploy_module = new remote({ + context: _this5 + }); + } else if (deploy == 'ghpages') { + _this5.deploy_module = new ghpages({ + context: _this5 + }); + } else ; + } + + yield _this5.deploy_module.pre(); + })(); + } //Executed when compiler founds an error processing nodes. + + + onErrors(errors) { + var _this6 = this; + + return _asyncToGenerator(function* () { + _this6.errors_found = true; + })(); + } //configNode helper + + + generalConfigSetup() { + var _this7 = this; + + return _asyncToGenerator(function* () { + //this.x_state.dirs.base + _this7.debug('Setting general configuration steps'); + + _this7.debug('Declaring vue.config.js : initializing'); // default modules + + + _this7.debug('Declaring vue.config.js : default modules'); //google analytics + + + if (_this7.x_state.config_node['google:analytics']) { + _this7.debug('Declaring Google Analytics: NOT SUPPORTED FOR NOW'); + /* + this.x_state.nuxt_config.build_modules['@nuxtjs/google-gtag'] = { + 'id': this.x_state.config_node['google:analytics'].id, + 'debug': true, + 'disableAutoPageTrack': true + }; + if (this.x_state.config_node['google:analytics'].local) this.x_state.nuxt_config.build_modules['@nuxtjs/google-gtag'].debug = this.x_state.config_node['google:analytics'].local; + if (this.x_state.config_node['google:analytics'].auto && this.x_state.config_node['google:analytics'].auto == true) { + delete this.x_state.nuxt_config.build_modules['@nuxtjs/google-gtag']['disableAutoPageTrack']; + }*/ + + } //medianet + + + if (_this7.x_state.config_node['ads:medianet'] && _this7.x_state.config_node['ads:medianet']['cid']) { + _this7.debug('Declaring MediaNet'); + + _this7.x_state.global_head['z_ads_medianet_a'] = { + 'innerHTML': 'window._mNHandle = window._mNHandle || {}; window._mNHandle.queue = window._mNHandle.queue || []; medianet_versionId = "3121199";', + 'type': 'text/javascript' + }; + _this7.x_state.global_head['z_ads_medianet_b'] = { + 'src': "https://contextual.media.net/dmedianet.js?cid=".concat(_this7.x_state.config_node['ads:medianet'][cid]), + 'async': true + }; + _this7.x_state.plugins['vue-script2'] = { + global: true, + npm: { + 'vue-script2': '*' + } + }; + } //google Adsense + + + if (_this7.x_state.config_node['google:adsense']) { + _this7.debug('Declaring Google Adsense'); + + if (_this7.x_state.config_node['google:adsense'].auto && _this7.x_state.config_node['google:adsense'].client) { + _this7.x_state.global_head['google_adsense'] = { + 'src': 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js', + 'data-ad-client': _this7.x_state.config_node['google:adsense'].client, + 'async': true + }; + _this7.x_state.plugins['adsense'] = { + global: true, + npm: { + 'vue-google-adsense': '*', + 'vue-script2': '*' + }, + mode: 'client', + customcode: "\n\t\t\t\t\timport Vue from \"vue\";\n\t\t\t\t\timport Ads from \"vue-google-adsense\";\n\n\t\t\t\t\tVue.use(require('vue-script2'));\n\t\t\t\t\tVue.use(Ads.AutoAdsense, { adClient: '".concat(_this7.x_state.config_node['google:adsense']['client'], "'});") + }; + } else { + _this7.x_state.plugins['adsense'] = { + global: true, + npm: { + 'vue-google-adsense': '*', + 'vue-script2': '*' + }, + mode: 'client', + customcode: "\n\t\t\t\t\timport Vue from \"vue\";\n\t\t\t\t\timport Ads from \"vue-google-adsense\";\n\n\t\t\t\t\tVue.use(require('vue-script2'));\n\t\t\t\t\tVue.use(Ads.Adsense);\n\t\t\t\t\tVue.use(Ads.InArticleAdsense);\n\t\t\t\t\tVue.use(Ads.InFeedAdsense);" + }; + } + } //nuxt:icon + + /* + if (this.x_state.config_node['nuxt:icon']) { + this.debug('Defining nuxt.config.js : module nuxtjs/pwa (nuxt:icon)'); + //this.x_state.nuxt_config.modules['@nuxtjs/pwa'] = {}; + }*/ + //idiomas i18n + + + if (_this7.x_state.central_config['idiomas'].indexOf(',') != -1) { + _this7.debug('Defining nuxt.config.js : module nuxt/i18n (idiomas) - NOT SUPPORTED FOR NOW'); + /* + this.x_state.npm['nuxt-i18n'] = '*'; + this.x_state.npm['fs'] = '*'; + this.x_state.nuxt_config.modules['nuxt-i18n'] = { + 'defaultLocale': this.x_state.central_config['idiomas'].split(',')[0], + 'vueI18n': { 'fallbackLocale': this.x_state.central_config['idiomas'].split(',')[0] }, + 'detectBrowserLanguage': { + 'useCookie': true, + 'alwaysRedirect': true + }, + locales: [], + lazy: true, + langDir: 'lang/' + }; + let self = this; + this.x_state.central_config['idiomas'].split(',').map(function(lang) { + if (lang == 'es') { + self.x_state.nuxt_config.modules['nuxt-i18n'].locales.push({ + code: 'es', + iso: 'es-ES', + file: `${lang}.js` + }); + } else if (lang == 'en') { + self.x_state.nuxt_config.modules['nuxt-i18n'].locales.push({ + code: 'en', + iso: 'en-US', + file: `${lang}.js` + }); + } else { + self.x_state.nuxt_config.modules['nuxt-i18n'].locales.push({ + code: lang, + file: `${lang}.js` + }); + } + }.bind(self));*/ + + } + /* @TODO ADD SUPPORT LATER 15-dic-22 + //local storage + if (this.x_state.stores_types['local'] && Object.keys(this.x_state.stores_types['local']) != '') { + this.debug('Defining nuxt.config.js : module nuxt-vuex-localstorage (store:local)'); + this.x_state.nuxt_config.modules['nuxt-vuex-localstorage'] = { + mode: 'debug', + 'localStorage': Object.keys(this.x_state.stores_types['local']) + }; + } + //session storage + if (this.x_state.stores_types['session'] && Object.keys(this.x_state.stores_types['session']) != '') { + this.debug('Defining nuxt.config.js : module nuxt-vuex-localstorage (store:session)'); + let prev = {}; + // if vuex-localstorage was defined before, recover keys and just replace with news, without deleting previous + if (this.x_state.nuxt_config.modules['nuxt-vuex-localstorage']) prev = this.x_state.nuxt_config.modules['nuxt-vuex-localstorage']; + this.x_state.nuxt_config.modules['nuxt-vuex-localstorage'] = {...prev, + ... { + mode: 'debug', + 'sessionStorage': Object.keys(this.x_state.stores_types['session']) + } + }; + }*/ + //proxies + + /* @TODO: ADD SUPPORT LATER (maybe) 15-dic-22 + let has_proxies = false, + proxies = {}; + let self = this; + Object.keys(this.x_state.central_config).map(function(key) { + if (key.indexOf('proxy:') != -1) { + let just_key = key.split(':')[1]; + proxies[just_key] = self.x_state.central_config[key]; + has_proxies = true; + } + }.bind(self)); + if (has_proxies) { + this.debug('Defining nuxt.config.js : module nuxtjs/proxy (central:proxy)'); + this.x_state.npm['@nuxtjs/proxy'] = '*'; + this.x_state.nuxt_config.modules['@nuxtjs/proxy'] = { 'proxy': proxies }; + }*/ + //end + + })(); + } //.gitignore helper + + + createGitIgnore() { + var _this8 = this; + + return _asyncToGenerator(function* () { + _this8.debug('writing .gitignore files'); + + var fs = require('fs').promises; + require('path'); + + _this8.x_console.out({ + message: 'writing /.gitignore file' + }); + + var git = "# Mac System files\n.DS_Store\n.DS_Store?\n_MACOSX/\nThumbs.db\n# NPM files\npackage.json\npackage-lock.json\nnode_modules/\n# AWS EB files\npolicy.json\n.ebextensions/\n.elasticbeanstalk/*\n!.elasticbeanstalk/*.cfg.yml\n!.elasticbeanstalk/*.global.yml\n# VUE files\n# Concepto files\n.concepto/\naws_backup.ini\nvue.dsl\nvue_diff.dsl\n.secrets-pass\nstore/\n".concat(_this8.x_state.dirs.compile_folder, "/"); + yield fs.writeFile("".concat(_this8.x_state.dirs.base, ".gitignore"), git, 'utf-8'); //.gitignore + })(); + } //process .omit file + + + processOmitFile(thefile) { + var _this9 = this; + + return _asyncToGenerator(function* () { + //@TODO 13-mar-21 check if .toArray() is needed here (ref processInternalTags method) + //internal_stores.omit + var self = _this9; + + if (thefile.file == 'internal_stores.omit') { + _this9.debug('processing internal_stores.omit'); + + var cheerio = require('cheerio'); + + var $ = cheerio.load(thefile.code, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); + var nodes = $("store_mutation").toArray(); + nodes.map(function (elem) { + var cur = $(elem); + var store = cur.attr('store') ? cur.attr('store') : ''; + var mutation = cur.attr('mutation') ? cur.attr('mutation') : ''; + var params = cur.attr('params') ? cur.attr('params') : ''; + var code = cur.text(); + + if (self.x_state.stores[store] && !(':mutations' in self.x_state.stores[store])) { + self.x_state.stores[store][':mutations'] = {}; + } + + self.x_state.stores[store][':mutations'][mutation] = { + code, + params + }; + }); + } //internal_middleware.omit + + + if (thefile.file == 'internal_middleware.omit') { + _this9.debug('processing internal_middleware.omit'); + + var _cheerio = require('cheerio'); + + var _$ = _cheerio.load(thefile.code, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); + + var _nodes = _$("proxy_code").toArray(); + + _nodes.map(function (elem) { + var cur = _$(elem); + + var name = cur.attr('name') ? cur.attr('name') : ''; + self.x_state.proxies[name].code = cur.text().trim(); + }); + } //server.omit - THIS ISNT'T SUPPORTED ON THIS VERSION + + + if (thefile.file == 'server.omit') { + _this9.debug('processing server.omit'); + + var _cheerio2 = require('cheerio'); + + var _$2 = _cheerio2.load(thefile.code, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); + + var _nodes2 = _$2("func_code").toArray(); + + _nodes2.map(function (elem) { + var cur = _$2(elem); + + var name = cur.attr('name') ? cur.attr('name') : ''; + self.x_state.functions[name].code = cur.text().trim(); + }); + } + })(); + } + + getComponentStory(thefile) { + var _this10 = this; + + return _asyncToGenerator(function* () { + // {component}.stories.js file + var js = { + script: '', + style: '', + first: false + }; + var page = _this10.x_state.pages[thefile.title]; + + var camel = require('camelcase'); + + if (page) { + if (page.tipo == 'componente' && page.params != '') { + var argType = {}, + title = thefile.title.split(':')[1].trim(), + evts = ''; //prepare events + + var events = page.stories['_default'].events; + + for (var evt in events) { + var on_name = camel("on_".concat(evt.replaceAll(':', '_'))); + evts += " v-on:".concat(evt, "=\"").concat(on_name, "\""); + argType[on_name] = { + action: 'clicked' + }; + } //prepare component attributes (props) + + + var isNumeric = function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; //let props = []; // story attr control type + + + var default_args = []; + + if (Object.keys(page.defaults) != '') { + page.params.split(',').map(function (key) { + var def_val = ''; + if (page.defaults[key]) def_val = page.defaults[key]; + + if (def_val == 'true' || def_val == 'false') { + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: Boolean, default: ${def_val}}`); + } else if (isNumeric(def_val)) { + //if def_val is number or string with number + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: Number, default: ${def_val}}`); + } else if (def_val.indexOf('[') != -1 && def_val.indexOf(']') != -1) { + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: Array, default: () => ${def_val}}`); + } else if (def_val.indexOf('{') != -1 && def_val.indexOf('}') != -1) { + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: Object, default: () => ${def_val}}`); + } else if (def_val.indexOf("()") != -1) { + //ex. new Date() + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: Object, default: () => ${def_val}}`); + } else if (def_val.toLowerCase().indexOf("null") != -1) { + default_args.push("".concat(key, ": null")); //props.push(`${key}: { default: null }`); + } else if (def_val.indexOf("'") != -1) { + default_args.push("".concat(key, ": ").concat(def_val)); //props.push(`${key}: { type: String, default: ${def_val}}`); + } else { + default_args.push("".concat(key, ": '").concat(def_val, "'")); //props.push(`${key}: { default: '${def_val}' }`); + } + }); + } //write story code + + + var compName = camel(title, { + pascalCase: true + }); + js.script += "import ".concat(compName, " from '../src/components/").concat(title, "/").concat(thefile.file.replace('.vue', '-story.vue'), "';\n\n"); + js.script += "export default {\n title: '".concat(camel(_this10.x_state.central_config.apptitle, { + pascalCase: true + }), "/").concat(title, "',\n component: ").concat(compName, ",\n argTypes: ").concat(JSON.stringify(argType), "\n };\n\n"); + js.script += "const Template = (args, { argTypes }) => ({\n props: Object.keys(argTypes),\n components: { ".concat(compName, " },\n template: '<").concat(compName, " v-bind=\"$props\"").concat(evts, "/>'\n });\n"); //default story + + js.script += "export const Default = Template.bind({});\n"; + js.script += "Default.args = {\n"; + js.script += "".concat(default_args.join(','), "\n};\n"); //additional defined stories + //@todo + } + } + + return js; + })(); + } + + getBasicVue(thefile) { + var _this11 = this; + + return _asyncToGenerator(function* () { + // write .VUE file + var vue = { + template: thefile.code, + script: '', + style: '', + first: false + }; + var page = _this11.x_state.pages[thefile.title]; + + if (page) { + // declare middlewares (proxies) + if (page.proxies.indexOf(',') != -1) { + _this11.debug('- declare middlewares'); + + vue.script += "middleware: [".concat(page.proxies, "]"); + vue.first = true; + } else if (page.proxies.trim() != '') { + _this11.debug('- declare middlewares'); + + vue.script += "middleware: '".concat(page.proxies, "'"); + vue.first = true; + } // layout attr + + + if (page.layout != '') { + _this11.debug('- declare layout'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + vue.script += "layout: '".concat(page.layout.trim(), "'"); + } // declare components + + + if (page.components != '') { + _this11.debug('- declare components'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + vue.script += "components: {"; + var comps = []; + Object.keys(page.components).map(function (key) { + comps.push(" '".concat(key, "': ").concat(page.components[key])); + }); //.bind(page,comps)); + + vue.script += "".concat(comps.join(','), "\n\t}"); + } // declare directives + + + if (page.directives != '') { + _this11.debug('- declare directives'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + vue.script += "directives: {"; + var directs = []; + Object.keys(page.directives).map(function (key) { + if (key == page.directives[key]) { + directs.push(key); + } else { + directs.push("'".concat(key, "': ").concat(page.directives[key])); + } + }); //.bind(page,directs)); + + vue.script += "".concat(directs.join(','), "\n\t}"); + } // declare props (if page tipo componente) + + + if (page.tipo == 'componente' && page.params != '') { + _this11.debug('- declare componente:props'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + + var isNumeric = function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + + var props = []; + + if (Object.keys(page.defaults) != '') { + page.params.split(',').map(function (key) { + var def_val = ''; + if (page.defaults[key]) def_val = page.defaults[key]; + + if (def_val == 'true' || def_val == 'false') { + props.push("".concat(key, ": { type: Boolean, default: ").concat(def_val, "}")); + } else if (isNumeric(def_val)) { + //if def_val is number or string with number + props.push("".concat(key, ": { type: Number, default: ").concat(def_val, "}")); + } else if (def_val.indexOf('[') != -1 && def_val.indexOf(']') != -1) { + props.push("".concat(key, ": { type: Array, default: () => ").concat(def_val, "}")); + } else if (def_val.indexOf('{') != -1 && def_val.indexOf('}') != -1) { + props.push("".concat(key, ": { type: Object, default: () => ").concat(def_val, "}")); + } else if (def_val.indexOf("()") != -1) { + //ex. new Date() + props.push("".concat(key, ": { type: Object, default: () => ").concat(def_val, "}")); + } else if (def_val.toLowerCase().indexOf("null") != -1) { + props.push("".concat(key, ": { default: null }")); + } else if (def_val.indexOf("'") != -1) { + props.push("".concat(key, ": { type: String, default: ").concat(def_val, "}")); + } else { + props.push("".concat(key, ": { default: '").concat(def_val, "' }")); + } + }); + vue.script += "\tprops: {".concat(props.join(','), "}"); + } else { + page.params.split(',').map(function (key) { + props.push("'".concat(key, "'")); + }); + vue.script += "\tprops: [".concat(props.join(','), "]"); + } + } // declare meta data + + + if (page.xtitle || page.meta.length > 0 || page.link.length > 0) { + _this11.debug('- declare head() meta data'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + vue.script += " head() {\n return {\n"; // define title + + if (page.xtitle) { + if (_this11.x_state.central_config.idiomas.indexOf(',') != -1) { + // i18n title + var crc32 = "t_".concat(yield _this11.hash(page.xtitle)); + + var def_lang = _this11.x_state.central_config.idiomas.indexOf(',')[0].trim().toLowerCase(); + + if (!_this11.x_state.strings_i18n[def_lang]) { + _this11.x_state.strings_i18n[def_lang] = {}; + } + + _this11.x_state.strings_i18n[def_lang][crc32] = page.xtitle; + vue.script += "titleTemplate: this.$t('".concat(crc32, "')\n"); + } else { + // normal title + vue.script += "titleTemplate: ".concat(_this11.jsDump(page.xtitle), "\n"); + } + } // define meta SEO + + + if (page.meta.length > 0) { + if (page.xtitle) vue.script += ","; //vue.script += `meta: ${JSON.stringify(page.meta)}\n`; + + vue.script += "meta: ".concat(_this11.jsDump(page.meta), "\n"); + } // define head LINK + + + if (page.link.length > 0) { + if (page.xtitle || page.meta.length > 0) vue.script += ","; + vue.script += "link: ".concat(JSON.stringify(page.link), "\n"); + } + + vue.script += "};\n}"; + } // declare variables (data) + + + if (Object.keys(page.variables) != '') { + _this11.debug('- declare data() variables'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + + require('util'); + + vue.script += "data() {\n"; + vue.script += " return ".concat(_this11.jsDump(page.variables), "\n"); + vue.script += "}\n"; //this.debug('- declare data() variables dump',page.variables); + } + } + + return vue; + })(); + } + + processInternalTags(vue, page) { + var _this12 = this; + + return _asyncToGenerator(function* () { + var cheerio = require('cheerio'); //console.log('PABLO beforeInteralTags:',{ template:vue.template, script:vue.script }); + + + var $ = cheerio.load(vue.template, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); //console.log('PABLO after:',$.html()); + //return vue; + // + + var nodes = $("server_asyncdata").toArray(); + if (nodes.length > 0) _this12.debug('post-processing server_asyncdata tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + nodes.map(function (elem) { + var cur = $(elem); + var name = cur.attr('return') ? cur.attr('return') : ''; + vue.script += "async asyncData({ req, res, params }) {\n"; + vue.script += " if (!process.server) { const req={}, res={}; }\n"; //vue.script += ` ${cur.text()}`; + + vue.script += " ".concat(elem.children[0].data); + vue.script += " return ".concat(name, ";\n"); + vue.script += "}\n"; + cur.remove(); + }); + vue.template = $.html(); + if (nodes.length > 0) vue.script += "}\n"; // process ?mounted event + + nodes = $("vue_mounted").toArray(); + if (nodes.length > 0) _this12.debug('post-processing vue_mounted tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + var uses_await = false, + mounted_content = ''; + nodes.map(function (elem) { + var cur = $(elem); //console.log('valor vue_mounted',elem.children[0].data); + + if (elem.children[0].data.includes('await ')) { + uses_await = true; + } + + mounted_content += elem.children[0].data; //cur.text(); + //vue.script += elem.children[0].data; //cur.text(); + + cur.remove(); + }); + + if (nodes.length > 0) { + if (uses_await) { + vue.script += "async mounted() {\n"; + vue.script += "this.$nextTick(async function() {\n"; + } else { + vue.script += "mounted() {\n"; + } + + vue.script += mounted_content; + } + + vue.template = $.html(); + + if (nodes.length > 0) { + if (uses_await) { + vue.script += "});\n}\n"; + } else { + vue.script += "}\n"; + } + } // process ?created event + + + nodes = $("vue_created").toArray(); + if (nodes.length > 0) _this12.debug('post-processing vue_created tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + uses_await = false, mounted_content = ''; + nodes.map(function (elem) { + var cur = $(elem); //console.log('valor vue_mounted',elem.children[0].data); + + if (elem.children[0].data.includes('await ')) { + uses_await = true; + } + + mounted_content += elem.children[0].data; //cur.text(); + //vue.script += elem.children[0].data; //cur.text(); + + cur.remove(); + }); + + if (nodes.length > 0) { + if (uses_await) { + vue.script += "async created() {\n"; + vue.script += "this.$nextTick(async function() {\n"; + } else { + vue.script += "created() {\n"; + } + + vue.script += mounted_content; + } + + vue.template = $.html(); + + if (nodes.length > 0) { + if (uses_await) { + vue.script += "});\n}\n"; + } else { + vue.script += "}\n"; + } + } // process ?var (vue_computed) + + + nodes = $('vue\_computed').toArray(); //this.debug('nodes',nodes); + + if (nodes.length > 0) _this12.debug('post-processing vue_computed tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + if (nodes.length > 0) vue.script += "computed: {\n"; + var computed = []; + nodes.map(function (elem) { + var cur = $(elem); + var name = cur.attr('name'); + var code = elem.children[0].data; //cur.html(); + //console.log('PABLO debug code computed:',code); + + if (computed.includes("".concat(name, "() {").concat(code, "}")) == false) { + computed.push("".concat(name, "() {").concat(code, "}")); + } + + cur.remove(); //return elem; + }); + vue.template = $.html(); + vue.script += computed.join(','); + if (nodes.length > 0) vue.script += "}\n"; // process ?var (asyncComputed) + + nodes = $('vue_async_computed').toArray(); + if (nodes.length > 0) _this12.debug('post-processing vue_async_computed tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + if (nodes.length > 0) vue.script += "asyncComputed: {\n"; + var async_computed = []; + nodes.map(function (elem) { + var cur = $(elem); + var code = elem.children[0].data; //cur.text(); + + if (cur.attr('valor') || cur.attr('watch')) { + var lazy = ''; + if (cur.attr('lazy')) lazy += ",lazy: ".concat(cur.attr('lazy')); + var valor = ''; + + if (cur.attr('valor')) { + valor += ","; + var test = cur.attr('valor'); + + if (test.indexOf('[') != -1 && test.indexOf(']') != -1 || test.indexOf('{') != -1 && test.indexOf('}') != -1 || test.indexOf('(') != -1 && test.indexOf(')') != -1) { + valor += "default: ".concat(test); + } else { + valor += "default: '".concat(test, "'"); + } + } + + var watch = ''; + + if (cur.attr('watch')) { + watch += ','; + + var _test = cur.attr('watch'); + + var test_n = []; + + _test.split(',').map(function (x) { + var tmp = x.replaceAll('$variables.', '').replaceAll('$vars.', '').replaceAll('$params.', '').replaceAll('$store.', '$store.state.'); + test_n.push("'".concat(tmp, "'")); + }); + + watch += "watch: [".concat(test_n.join(','), "]"); + } + + async_computed.push("\n".concat(cur.attr('name'), ": {\n async get() {\n ").concat(code, "\n }\n ").concat(lazy, "\n ").concat(valor, "\n ").concat(watch, "\n}")); + } else { + async_computed.push("async ".concat(cur.attr('name'), "() {").concat(code, "}")); + } + + cur.remove(); + }); + vue.template = $.html(); + vue.script += async_computed.join(','); + if (nodes.length > 0) vue.script += "}\n"; // process var ?change -> vue_watched_var + + nodes = $('vue_watched_var').toArray(); + if (nodes.length > 0) _this12.debug('post-processing vue_async_computed tag'); + if (nodes.length > 0 && vue.first) vue.script += ',\n'; + vue.first = true; + if (nodes.length > 0) vue.script += "watch: {\n"; + var watched = []; + nodes.map(function (elem) { + var cur = $(elem); + var code = elem.children[0].data; //cur.text(); + + if (cur.attr('deep')) { + watched.push("\n\t\t\t\t'".concat(cur.attr('flat'), "': {\n\t\t\t\t\tasync handler(newVal, oldVal) {\n\t\t\t\t\t\tlet evento = { ").concat(cur.attr('newvar'), ":newVal, ").concat(cur.attr('oldvar'), ":oldVal };\n\t\t\t\t\t\t").concat(code, "\n\t\t\t\t\t},\n\t\t\t\t\tdeep: true\n\t\t\t\t}\n\t\t\t\t")); + } else { + watched.push("\n\t\t\t\t'".concat(cur.attr('flat'), "': async function (newVal, oldVal) {\n\t\t\t\t\tlet evento = { ").concat(cur.attr('newvar'), ":newVal, ").concat(cur.attr('oldvar'), ":oldVal };\n\t\t\t\t\t").concat(code, "\n\t\t\t\t}\n\t\t\t\t")); + } + + cur.remove(); + }); + vue.template = $.html(); + vue.script += watched.join(','); + if (nodes.length > 0) vue.script += "}\n"; // process vue_if tags + // repeat upto 5 times (@todo transform this into a self calling method) + + for (var x of [1, 2, 3, 4, 5]) { + nodes = $('vue_if').toArray(); + + if (nodes.length > 0) { + _this12.debug("post-processing vue_if tag ".concat(x, " (len:").concat(nodes.length, ")")); + + nodes.map(function (elem) { + var cur = $(elem); + var if_type = cur.attr('tipo'); + var if_test = cur.attr('expresion'); + + if (cur.attr('target') != 'template') { + //search refx ID tag + var target = $("*[refx=\"".concat(cur.attr('target'), "\"]")).toArray(); + + if (target.length > 0) { + var target_node = $(target[0]); + + if (if_type == 'v-else') { + target_node.attr(if_type, 'xpropx'); + } else { + target_node.attr(if_type, if_test); + } //erase if tag + + + cur.replaceWith(cur.html()); + } + } + }); + } else { + break; + } + + yield _this12.setImmediatePromise(); //@improved + } // + + + vue.template = $.html(); // process vue_for tags + // repeat upto 5 times (@todo transform this into a self calling method) + + for (var _x3 of [1, 2, 3, 4, 5]) { + nodes = $('vue_for').toArray(); + + if (nodes.length > 0) { + _this12.debug("post-processing vue_for tag ".concat(_x3, " (len:").concat(nodes.length, ")")); + nodes.map(function (elem) { + var cur = $(elem); + var iterator = cur.attr('iterator').replaceAll('$variables.', '').replaceAll('$vars.', '').replaceAll('$params.', '').replaceAll('$store.', '$store.state.'); + + if (cur.attr('use_index') && cur.attr('use_index') == 'false' && cur.attr('key') != 0) { + iterator = "(".concat(cur.attr('item'), ", ").concat(cur.attr('key'), ") in ").concat(iterator); + } else if (cur.attr('use_index') && cur.attr('use_index') == 'false' && cur.attr('key') == 0) { + iterator = "".concat(cur.attr('item'), " in ").concat(iterator); + } else if (cur.attr('key') && cur.attr('key') != 0 && cur.attr('use_index') != 'false') { + iterator = "(".concat(cur.attr('item'), ", ").concat(cur.attr('key'), ", ").concat(cur.attr('use_index'), ") in ").concat(iterator); + } else { + iterator = "(".concat(cur.attr('item'), ", ").concat(cur.attr('use_index'), ") in ").concat(iterator); + } + + if (cur.attr('target') != 'template') { + //search refx ID tag + var target = $("*[refx=\"".concat(cur.attr('target'), "\"]")).toArray(); + + if (target.length > 0) { + var target_node = $(target[0]); + target_node.attr('v-for', iterator); + if (cur.attr('unique') != 0) target_node.attr(':key', cur.attr('unique')); + cur.replaceWith(cur.html()); + } //cur.replaceWith(cur.html()); // remove also if target node is not found + + } else { + // transform x -> + // lookAt x=v_for_selector.html() and selector.replaceWith('') + cur.replaceWith("")); + } + }); + } else { + break; + } + + yield _this12.setImmediatePromise(); //@improved + } // + + + vue.template = $.html(); // process vue_event tags + + var common_methods = $('vue_event_method').toArray(); + var on_events = $('vue_event_element').toArray(); + + if (common_methods.length > 0 || on_events.length > 0) { + _this12.debug('post-processing methods (common, timer, and v-on element events methods)'); + + if (vue.first) vue.script += ',\n'; + vue.first = true; + var methods = [], + _self = _this12; // event_methods + + common_methods.map(function (elem) { + var cur = $(elem); + var code = elem.children[0].data; //cur.text(); + + var tmp = ''; + + if (cur.attr('timer_time')) { + _self.x_state.npm['vue-interval'] = '*'; + page.mixins['vueinterval'] = 'vue-interval/dist/VueInterval.common'; + var timer_prefix = ''; + + if (cur.attr('timer_time') && cur.attr('timer_time') != '') { + //always in ms; tranform into 1e2 notation + var ceros = cur.attr('timer_time').length - 1; + var first = cur.attr('timer_time')[0]; + timer_prefix = "INTERVAL__".concat(first, "e").concat(ceros, "$"); + } + + if (cur.attr('m_params')) { + if (cur.attr('type') == 'async') { + tmp += "".concat(timer_prefix).concat(cur.attr('name'), ": async function(").concat(cur.attr('m_params'), ") {"); + } else { + tmp += "".concat(timer_prefix).concat(cur.attr('name'), ": function(").concat(cur.attr('m_params'), ") {"); + } + } else { + if (cur.attr('type') == 'async') { + tmp += "".concat(timer_prefix).concat(cur.attr('name'), ": async function() {"); + } else { + tmp += "".concat(timer_prefix).concat(cur.attr('name'), ": function() {"); + } + } + } else { + if (cur.attr('m_params')) { + if (cur.attr('type') == 'async') { + tmp += "".concat(cur.attr('name'), ": async function(params) {"); //${cur.attr('m_params')} + } else { + tmp += "".concat(cur.attr('name'), ": function(params) {"); //${cur.attr('m_params')} + } + } else { + if (cur.attr('type') == 'async') { + tmp += "".concat(cur.attr('name'), ": async function() {"); + } else { + tmp += "".concat(cur.attr('name'), ": function() {"); + } + } + } + + methods.push("".concat(tmp, "\n").concat(code, "\n}")); + cur.remove(); + }); // events_methods + + on_events.map(function (elem) { + var evt = $(elem); //search father node of event + + var origin = $($("*[refx=\"".concat(evt.attr('parent_id'), "\"]")).toArray()[0]); + var event = evt.attr('event'); // declare call in origin node + + if (evt.attr('link')) { + // event linked to another node; usually another existing method func + var link = evt.attr('link'); + var method_name = link; + + if (evt.attr('link_id')) { + var target = $("vue_event_element[id=\"".concat(evt.attr('link_id'), "\"]")).toArray(); + + if (target.length > 0) { + var the_node = $(target[0]); + method_name = the_node.attr('friendly_name'); + } + + method_name = method_name.replaceAll(':', '_').replaceAll('.', '_').replaceAll('-', '_'); + } // plugin related events + + + if (event == 'click-outside') { + origin.attr('v-click-outside', method_name); + } else if (event == 'visibility') { + origin.attr('v-observe-visibility', method_name); + } else if (event == ':rules') { + origin.attr(':rules', "[".concat(method_name, "]")); + } else if (event == 'resize') { + origin.attr('v-resize', method_name); + } else { + // custom defined methods + if (evt.attr('v_params')) { + // v-on with params + origin.attr("v-on:".concat(event), "".concat(method_name, "(").concat(evt.attr('v_params'), ")")); + } else { + // without params + if (evt.attr('link_id')) { + origin.attr("v-on:".concat(event), "".concat(method_name, "($event)")); + } else { + origin.attr("v-on:".concat(event), method_name); + } + } // + + } // @TODO check if this is needed/used: was on original CFC code, but it seems it just overwrites previous things + //if (evt.attr('link_id')) { + // origin.attr(`v-on:${event}`,`${link}_${evt.attr('link_id')}($event)`); + //} + // + + } else { + // create method function and script + var tmp = ''; + var _method_name = event; + if (evt.attr('friendly_name') != '') _method_name = "".concat(evt.attr('friendly_name')); //event_suffix + + _method_name = _method_name.replaceAll(':', '_').replaceAll('.', '_').replaceAll('-', '_'); + var method_code = elem.children[0].data; //evt.text(); + + if (event == 'click-outside') { + origin.attr("v-click-outside", _method_name); + tmp = "".concat(_method_name, ": async function() {\n\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t}"); + } else if (event == 'visibility') { + origin.attr("v-observe-visibility", _method_name); + tmp = "".concat(_method_name, ": async function(estado, elemento) {\n\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t}"); + } else if (event == ':rules') { + origin.attr(":rules", "[".concat(_method_name, "]")); + tmp = "".concat(_method_name, ": function() {\n\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t}"); + } else if (event == 'resize') { + origin.attr("v-resize", _method_name); + tmp = "".concat(_method_name, ": async function() {\n\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t}"); + } else { + if (evt.attr('v_params') && evt.attr('v_params') != '') { + origin.attr("v-on:".concat(event), "".concat(_method_name, "(").concat(evt.attr('v_params'), ")")); + } else { + origin.attr("v-on:".concat(event), "".concat(_method_name, "($event)")); + } + + if (evt.attr('n_params')) { + tmp = "".concat(_method_name, ": async function(").concat(evt.attr('n_params'), ") {\n\t\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t\t}"); + } else { + tmp = "".concat(_method_name, ": async function(evento) {\n\t\t\t\t\t\t\t\t").concat(method_code, "\n\t\t\t\t\t\t\t}"); + } + } // push tmp to methods + + + methods.push(tmp); + } // remove original event tag node + // ** evt.remove(); + + }); //remove vue_event_element tags + + on_events.map(function (elem) { + $(elem).remove(); + }); // apply methods and changes + + vue.script += "methods: {\n\t\t\t\t\t\t\t".concat(methods.join(','), "\n\t\t\t\t\t\t }"); + vue.template = $.html(); // apply changes to template + } + /* */ + + + return vue; + })(); + } + + processStyles(vue, page) { + var cheerio = require('cheerio'); + + var $ = cheerio.load(vue.template, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); + var styles = $("page_estilos").toArray(); + + if (styles.length > 0) { + this.debug('post-processing styles'); + var node = $(styles[0]); + + if (node.attr('scoped') && node.attr('scoped') == 'true') { + vue.style += "\n\t\t\t\t"); + } else { + vue.style += "\n\t\t\t\t"); + } + + node.remove(); + } + + vue.template = $.html(); // add page styles (defined in js) to style tag code + + if (Object.keys(page.styles).length > 0) { + var jss = require('jss').default; + + var global_plug = require('jss-plugin-global').default; + + jss.use(global_plug()); + var sheet = jss.createStyleSheet({ + '@global': page.styles + }); + if (!vue.style) vue.style = ''; + vue.style += ""); //this.debug('JSS sheet',sheet.toString()); + } + + return vue; + } + + processMixins(vue, page) { + // call after processInternalTags + if (page.mixins && Object.keys(page.mixins).length > 0) { + this.debug('post-processing mixins'); + var close = ''; + if (vue.first) close += ',\n'; + vue.first = true; + close += "mixins: [".concat(Object.keys(page.mixins).join(','), "]"); + var mixins = []; + + for (var key in page.mixins) { + mixins.push("import ".concat(key, " from '").concat(page.mixins[key], "';")); + } + + vue.script = vue.script.replaceAll('{concepto:mixins:import}', mixins.join(';')); + vue.script = vue.script.replaceAll('{concepto:mixins:array}', close); + } else { + vue.script = vue.script.replaceAll('{concepto:mixins:import}', '').replaceAll('{concepto:mixins:array}', ''); + } + + return vue; + } + + removeRefx(vue) { + var cheerio = require('cheerio'); + + var $ = cheerio.load(vue.template, { + ignoreWhitespace: false, + xmlMode: true, + decodeEntities: false + }); + var refx = $("*[refx]").toArray(); + + if (refx.length > 0) { + this.debug('removing refx attributes (internal)'); + refx.map(function (x) { + $(x).attr('refx', null); + }); + vue.template = $.html(); + } + + return vue; + } + + fixVuePaths(vue, page) { + for (var key in this.x_state.pages) { + if (this.x_state.pages[key].path) { + vue.script = vue.script.replaceAll("{vuepath:".concat(key, "}"), this.x_state.pages[key].path); + } else { + this.x_console.outT({ + message: "WARNING! path key doesn't exist for page ".concat(key), + color: 'yellow' + }); + } + } // remove / when first char inside router push name + + + vue.script = vue.script.replaceAll("this.$router.push({ name:'/", "this.$router.push({ name:'"); + return vue; + } + + processLangPo(vue, page) { + var _this13 = this; + + return _asyncToGenerator(function* () { + // writes default lang.po file and converts alternatives to client/lang/iso.js + if (_this13.x_state.central_config.idiomas.indexOf(',') != -1) { + _this13.debug('process /lang/ po/mo files'); + + var path = require('path'), + fs = require('fs').promises; // .check and create directs if needed + + + var lang_path = path.join(_this13.x_state.dirs.base, '/lang/'); + + try { + yield fs.mkdir(lang_path, { + recursive: true + }); + } catch (errdir) {} // .create default po file from strings_i18n + + + _this13.x_state.central_config.idiomas.split(',')[0]; // .read other po/mo files from lang dir and convert to .js + + + for (var idioma in _this13.x_state.central_config.idiomas.split(',')) { + } // + + } + + return vue; + })(); + } + + createVueXStores() { + var _this14 = this; + + return _asyncToGenerator(function* () { + if (Object.keys(_this14.x_state.stores).length > 0) { + _this14.x_console.outT({ + message: "creating VueX store definitions", + color: 'cyan' + }); + + var path = require('path'); + + require('util'); + + var safe = require('safe-eval'); //console.log('debug stores complete',this.x_state.stores); + + + for (var store_name in _this14.x_state.stores) { + var store = _this14.x_state.stores[store_name]; + var file = path.join(_this14.x_state.dirs.store, "".concat(store_name, ".js")); + var def_types = { + 'integer': 0, + 'int': 0, + 'float': 0.0, + 'boolean': false, + 'array': [] + }; + var obj = {}; + // iterate each store field + //this.debug(`store ${store_name}`,store); + + for (var field_name in store) { + var field = store[field_name]; //this.debug({ message:`checking field ${field_name} within store ${i}` }); + + if (field.default && field.default.trim() == '') { + if (field.type in def_types) { + obj[field_name] = def_types[field.type]; + } else { + obj[field_name] = ''; + } + } else { + if ('integer,int,float,boolean,array'.split(',').includes[field.type]) { + obj[field_name] = safe(field.default); + } else if ('true,false,0,1'.split(',').includes[field.default]) { + obj[field_name] = safe(field.default); + } else { + obj[field_name] = '' + field.default; + } + } + } // expires? + + + if (store_name in _this14.x_state.stores_types['expires']) { + obj['expire'] = parseInt(_this14.x_state.stores_types['expires'][store_name]); + } // versions? + + + if (store_name in _this14.x_state.stores_types['versions']) { + obj['version'] = parseInt(_this14.x_state.stores_types['versions'][store_name]); + } // write content + + + delete obj[':mutations']; + var content = "export const state = () => (".concat(_this14.jsDump(obj), ")\n"); // :mutations? + + if (':mutations' in store) { + var muts = []; + + for (var mut_name in store[':mutations']) { + var mutation = store[':mutations'][mut_name]; //console.log('mutation debug',{mutation, mut_name}); + + var mut = { + params: ['state'] + }; + if (Object.keys(mutation.params).length > 0) mut.params.push('objeto'); + muts.push("".concat(mut_name, "(").concat(mut.params.join(','), ") {\n ").concat(mutation.code, "\n }")); + } + + content += "\nexport const mutations = {".concat(muts.join(','), "}"); + } // write file + + + _this14.writeFile(file, content); + } + } + })(); + } //NOT SUPPORTED ON THIS VERSION + + + createServerMethods() { + var _this15 = this; + + return _asyncToGenerator(function* () { + if (Object.keys(_this15.x_state.functions).length > 0) { + _this15.x_console.outT({ + message: "creating NuxtJS server methods", + color: 'green' + }); + + var path = require('path'); + + var file = path.join(_this15.x_state.dirs.server, "api.js"); + var content = "\n var express = require('express'), _ = require('underscore'), axios = require('axios');\n var server = express();\n var plugins = {\n bodyParser: require('body-parser'),\n cookieParser: require('cookie-parser')\n };\n server.disable('x-powered-by');\n server.use(plugins.bodyParser.urlencoded({ extended: false,limit: '2gb' }));\n server.use(plugins.bodyParser.json({ extended: false,limit: '2gb' }));\n server.use(plugins.cookieParser());\n "; //merge functions import's into a single struct + + var imps = {}; + + for (var x in _this15.x_state.functions) { + for (var imp in _this15.x_state.functions[x]) { + imps[imp] = _this15.x_state.functions[x][imp]; + yield _this15.setImmediatePromise(); //@improved + } + + yield _this15.setImmediatePromise(); //@improved + } //declare imports + + + content += "// app declared functions imports\n"; + + for (var _x4 in imps) { + content += "var ".concat(imps[_x4], " = require('").concat(_x4, "');\n"); + } + + content += "// app declared functions\n"; //declare app methods + + for (var func_name in _this15.x_state.functions) { + var func = _this15.x_state.functions[func_name]; + var func_return = ""; + if (func.return != '') func_return = "res.send(".concat(func.return, ");"); + content += "server.".concat(func.method, "('").concat(func.path, "', async function(req,res) {\n var params = req.").concat(func.method == 'get' ? 'params' : 'body', ";\n ").concat(func.code, "\n ").concat(func_return, "\n });\n"); + } //close + + + content += "module.exports = server;\n"; //write file + + _this15.writeFile(file, content); + + _this15.x_console.outT({ + message: "NuxtJS server methods ready", + color: 'green' + }); + } + })(); + } + + createMiddlewares() { + var _this16 = this; + + return _asyncToGenerator(function* () { + if (Object.keys(_this16.x_state.proxies).length > 0) { + _this16.x_console.outT({ + message: "creating VueJS Middlewares", + color: 'cyan' + }); + + var path = require('path'); + + for (var proxy_name in _this16.x_state.proxies) { + var proxy = _this16.x_state.proxies[proxy_name]; + var file = path.join(_this16.x_state.dirs.middleware, "".concat(proxy_name, ".js")); //add imports + + var content = ""; + + for (var key in proxy.imports) { + content += "import ".concat(proxy.imports[key], " from '").concat(key, "';\n"); + } //add proxy code + + + content += "export default async function ({ route, store, redirect, $axios, $config }) {\n ".concat(proxy.code, "\n\n }\n "); //find and replace instances of strings {vuepath:targetnode} + + for (var page_name in _this16.x_state.pages) { + if (page_name != '') { + var page = _this16.x_state.pages[page_name]; + + if (page.path) { + content = content.replaceAll("{vuepath:".concat(page_name, "}"), page.path); + } else { + _this16.x_console.outT({ + message: "Warning! path key doesn't exist for page ".concat(page_name), + color: 'yellow' + }); + } + } + + yield _this16.setImmediatePromise(); //@improved + } //write file + + + _this16.writeFile(file, content); + + yield _this16.setImmediatePromise(); //@improved + } + + _this16.x_console.outT({ + message: "VueJS Middlewares ready", + color: 'cyan' + }); + } + })(); + } + + createGeneralFiles() { + var _this17 = this; + + return _asyncToGenerator(function* () { + //create general files (babel.config.js, src/bootloader.js, src/main.js, App.vue) + var path = require('path'); //create vuetify plugin - later save vuetify theme here + //add default material design icons support + + + _this17.x_state.dev_npm['material-design-icons-iconfont'] = '*'; + var vuetify_plugin = path.join(_this17.x_state.dirs.plugins, 'vuetify.js'); + var vuetify_plugin_content = "\n import 'material-design-icons-iconfont/dist/material-design-icons.css'\n //import '@fortawesome/fontawesome-free/css/all.css';\n import Vue from 'vue';\n import Vuetify from 'vuetify/lib/framework';\n \n Vue.use(Vuetify);\n \n export default new Vuetify({\n icons: {\n iconfont: 'md',\n },\n }); \n "; + + _this17.writeFile(vuetify_plugin, vuetify_plugin_content); // create src/main.js + + + var main = path.join(_this17.x_state.dirs.client, 'main.js'); + var main_content = "import(\"./bootloader\");"; + + _this17.writeFile(main, main_content); // create src/router.js + // create routes for all pages within project + //this.debug('this.x_state.pages',this.x_state.pages); + + + var pages = { + imports: "", + routes: "" + }; + + for (var page_name in _this17.x_state.pages) { + var page = _this17.x_state.pages[page_name]; + + if (page.tipo == 'page') { + pages.imports += "import ".concat(page_name, " from './pages/").concat(page.file_, "'"); + pages.routes += "{ path:'".concat(page.path, "', component:").concat(page_name, ", name:'").concat(page_name, "' },\n"); + } + } + + var router = path.join(_this17.x_state.dirs.client, 'router.js'); + var router_content = "\n import Vue from 'vue';\n import VueRouter from 'vue-router';\n\n //import pages\n ".concat(pages.imports, "\n\n Vue.use(VueRouter);\n\n //specify routes of project here\n const router = new VueRouter({\n routes: [\n ").concat(pages.routes, "\n ],\n mode: 'history'\n });\n\n export default router;\n "); + + _this17.writeFile(router, router_content); // create src/bootloader.js + + + require('camelcase'); + + var plugins_ = ""; + + for (var plugin_name in _this17.x_state.plugins) { + if (plugin_name != 'vuetify') { + //this.debug('plugin '+plugin_name,this.x_state.plugins[plugin_name]); + var code_ = _this17.x_state.plugins[plugin_name].code; + + if (code_.includes('import Vue from \'vue\';')) { + code_ = code_.replace('import Vue from \'vue\';', ''); + } + + code_ = code_.replaceAll('\n\n', '\n'); + plugins_ += "".concat(code_, "\n"); //plugins_ += `import ${camel(plugin_name)} from './plugins/${plugin_name}.js';\n`; + } + } + + var bootloader = path.join(_this17.x_state.dirs.client, 'bootloader.js'); + var bootloader_content = "\n import Vue from \"vue\";\n import App from \"./App.vue\";\n import vuetify from './plugins/vuetify'\n import router from './router'\n\n //import plugins\n ".concat(plugins_, "\n\n //disable production message\n Vue.config.productionTip = false;\n\n //setup Vue instance\n new Vue({\n vuetify,\n router,\n render: h => h(App)\n }).$mount('#app'); \n "); + + _this17.writeFile(bootloader, bootloader_content); // create src/App.vue + + + var app = path.join(_this17.x_state.dirs.client, 'App.vue'); + var app_content = "\n \n "; + + _this17.writeFile(app, app_content); // create public/index.html & copy favicon there if it exists + + + var index = path.join(_this17.x_state.dirs.public, 'index.html'); + var index_content = "\n \n \n \n \n \n \n \n ".concat(_this17.x_state.central_config.service_name, "\n \n \n \n \n \n
\n \n \n \n "); + + _this17.writeFile(index, index_content); // @todo save default favicon + + + path.join(_this17.x_state.dirs.public, 'favicon.ico'); + })(); + } //NOT SUPPORTED ON THIS VERSION + + + prepareServerFiles() { + var _this18 = this; + + return _asyncToGenerator(function* () { + var path = require('path'); + + var index = "// index.js\n const sls = require('serverless-http');\n const binaryMimeTypes = require('./binaryMimeTypes');\n const express = require('express');\n const app = express();\n const { Nuxt } = require('nuxt');\n const path = require('path');\n const config = require('./nuxt.config.js');\n\n async function nuxtApp() {\n app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist')));\n const nuxt = new Nuxt(config);\n await nuxt.ready();\n app.use(nuxt.render);\n return app;\n }\n\n module.exports.nuxt = async (event, context) => {\n let nuxt_app = await nuxtApp();\n let handler = sls(nuxt_app, { binary: binaryMimeTypes });\n return await handler (event, context);\n }\n "; + var index_file = path.join(_this18.x_state.dirs.app, "index.js"); + + _this18.writeFile(index_file, index); // allowed binary mimetypes + + + require('util'); + + var allowed = ['application/javascript', 'application/json', 'application/octet-stream', 'application/xml', 'font/eot', 'font/opentype', 'font/otf', 'image/jpeg', 'image/png', 'image/svg+xml', 'text/comma-separated-values', 'text/css', 'text/html', 'text/javascript', 'text/plain', 'text/text', 'text/xml']; + + if (_this18.x_state.config_node['nuxt:mimetypes']) { + var user_mimes = []; + + for (var usermime in _this18.x_state.config_node['nuxt:mimetypes']) { + user_mimes.push(usermime); + } + + var sum_mime = [...allowed, ...user_mimes]; + allowed = [...new Set(sum_mime)]; // clean duplicated values from array + } + + var mime = "// binaryMimeTypes.js\n module.exports = ".concat(_this18.jsDump(allowed), ";"); + var mime_file = path.join(_this18.x_state.dirs.app, "binaryMimeTypes.js"); + + _this18.writeFile(mime_file, mime); + })(); + } + + installRequiredPlugins() { + var _this19 = this; + + return _asyncToGenerator(function* () { + _this19.x_state.plugins['vuetify'] = { + global: true, + npm: {}, + dev_npm: { + 'vuetify': '^2.6.13' + }, + vue_config: { + vuetify: { + theme: { + dark: true, + themes: { + dark: { + primary: 'colors.blue.darken2', + accent: 'colors.grey.darken3', + secondary: 'colors.amber.darken3', + info: 'colors.teal.lighten1', + warning: 'colors.amber.base', + error: 'colors.deepOrange.accent4', + success: 'colors.green.accent3' + } + } + } + } + } + }; + _this19.x_state.bootloader.imports['vuetify'] = 'vuetify'; + _this19.x_state.plugins['aos'] = { + //each plugin should automatically create a vue_bootloader.import key + global: true, + npm: { + aos: '*' + }, + mode: 'client', + customcode: "import AOS from \"aos\";\n import \"aos/dist/aos.css\";\n export default ({app}) => {\n app.AOS = new AOS.init({});\n };" + }; //support for tawk.io + + if (_this19.x_state.config_node.tawk && _this19.x_state.config_node.tawk.propertyId && _this19.x_state.config_node.tawk.widgetId) { + _this19.x_state.plugins['tawk'] = { + global: true, + npm: { + '@tawk.to/tawk-messenger-vue': '*' + }, + mode: 'client', + customcode: "import Vue from \"vue\";\n import TawkMessengerVue from '@tawk.to/tawk-messenger-vue';\n\n export default function () {\n Vue.use(TawkMessengerVue, {\n propertyId : '".concat(_this19.x_state.config_node.tawk.propertyId, "',\n widgetId : '").concat(_this19.x_state.config_node.tawk.widgetId, "'\n });\n }") + }; + } + })(); + } + + createVuePlugins() { + var _arguments = arguments, + _this20 = this; + + return _asyncToGenerator(function* () { + var write = _arguments.length > 0 && _arguments[0] !== undefined ? _arguments[0] : true; + + var path = require('path'); + + var resp = { + global_plugins: {}, + css_files: [], + nuxt_config: [], + stories: {} + }; + + for (var plugin_key in _this20.x_state.plugins) { + var plugin = _this20.x_state.plugins[plugin_key]; + + if (typeof plugin === 'object') { + // copy x_state_plugins npm's into npm global imports (for future package.json) + if (plugin.npm) _this20.x_state.npm = _objectSpread2(_objectSpread2({}, _this20.x_state.npm), plugin.npm); + if (plugin.dev_npm) _this20.x_state.dev_npm = _objectSpread2(_objectSpread2({}, _this20.x_state.dev_npm), plugin.dev_npm); + if (plugin.global && plugin.global == true) resp.global_plugins[plugin_key] = '*'; + + if (plugin.styles) { + for (var style_key in plugin.styles) { + var style = plugin.styles[style_key]; + + if (style.file.includes('/') == false) { + var target = path.join(_this20.x_state.dirs.css, style.file); + yield _this20.writeFile(target, style.content); + resp.css_files.push({ + src: "@/assets/css/".concat(style.file), + lang: style.lang + }); + } + } + } // write the plugin code + + + var import_as = '', + _code = ''; + + if (plugin.var) { + import_as = plugin.var; + } else { + import_as = plugin_key.split('/').splice(-1)[0].replaceAll('-', '').replaceAll('_', '').toLowerCase().trim(); + } + + _code = "import Vue from 'vue';\n"; + + if (plugin.as_star) { + if (plugin.as_star == true) { + _code += "import * as ".concat(import_as, " from '").concat(plugin_key, "';\n"); + } else { + _code += "import ".concat(import_as, " from '").concat(plugin_key, "';\n"); + } + } else { + _code += "import ".concat(import_as, " from '").concat(plugin_key, "';\n"); + } + + if (plugin.custom) _code += "".concat(plugin.custom, "\n"); + + if (plugin.extra_imports) { + for (var extra in plugin.extra_imports) { + var new_key = plugin.extra_imports[extra].replaceAll('-', '').replaceAll('_', '').replaceAll('/', '').replaceAll('.css', '').replaceAll('.', '_').toLowerCase().trim(); + _code += "import ".concat(new_key, " from '").concat(plugin.extra_imports[extra], "'\n"); + } + } + + if (plugin.requires) { + for (var req in plugin.requires) { + _code += "require('".concat(plugin.requires[req], "');\n"); + } + } + + if (plugin.styles) { + for (var _style_key in plugin.styles) { + var _style = plugin.styles[_style_key]; + + if (_style.file.includes('/')) { + _code += "import '".concat(_style.file, "';\n"); + } + } + } // add config to plugin code if requested + + + if (plugin.config) { + if (typeof plugin.config === 'object') { + _code += "const config = ".concat(_this20.jsDump(plugin.config), ";\n Vue.use(").concat(import_as, ",config);"); + } else { + _code += "Vue.use(".concat(import_as, ",").concat(plugin.config, ");\n"); + } + } else if (plugin.tag && plugin.customvar == '') { + _code += "Vue.use(".concat(import_as, ",'").concat(plugin.tag, "');\n"); + } else if (plugin.tag) { + _code += "Vue.component('".concat(plugin.tag, "',").concat(import_as, ");\n"); + } else if (plugin.customvar) { + _code += "Vue.use(".concat(plugin.customvar, ");\n"); + } else { + _code += "Vue.use(".concat(import_as, ");\n"); + } // if customcode overwrite 'code' + + + if (plugin.customcode) { + _code = plugin.customcode; + } // write to disk and add to response + + + if (import_as != 'vuetify') { + // vuetify plugin is a little different thant the others so we created separately + // everything is client mode here + _this20.x_state.bootloader.imports[import_as] = "import ".concat(import_as, " from '@plugins/").concat(import_as, ".js';\n"); + + var _target2 = path.join(_this20.x_state.dirs.plugins, "".concat(import_as, ".js")); + + if (write) yield _this20.writeFile(_target2, _code); + } //10-ago-21 assign code to plugin registry (for storybook) + + + resp.stories[plugin_key] = plugin; + resp.stories[plugin_key].code = _code; + } else { + //simple plugin + _this20.x_state.npm[plugin_key] = plugin; + + var _import_as = plugin_key.replaceAll('-', '').replaceAll('_', '').toLowerCase().trim(); + + code += "import Vue from 'vue';\n import ".concat(_import_as, " from '").concat(plugin_key, "';\n Vue.use(").concat(_import_as, ");\n "); // write to disk and add to response + + if (_import_as != 'vuetify') { + _this20.x_state.bootloader.imports[_import_as] = "import ".concat(_import_as, " from '@plugins/").concat(_import_as, ".js';\n"); //resp.nuxt_config.push({ src:`~/plugins/${import_as}.js` }); + + var _target3 = path.join(_this20.x_state.dirs.plugins, "".concat(_import_as, ".js")); + + if (write) yield _this20.writeFile(_target3, code); + } //10-ago-21 assign code to plugin registry (for storybook) + + + resp.stories[plugin_key] = plugin; + resp.stories[plugin_key].code = code; + } + } + + return resp; + })(); + } + + createVueConfig() { + var _this21 = this; + + return _asyncToGenerator(function* () { + //creates the file vue.config.js + //define structure with defaults + var path = require('path'); + + var target = path.join(_this21.x_state.dirs.app, "vue.config.js"); + _this21.x_state.central_config.static == true ? 'static' : 'server'; //let deploy = this.x_state.central_config.deploy+''; + + var config = { + lintOnSave: false, + transpileDependencies: ['vuetify'], + configureWebpack: { + devServer: { + port: _this21.x_state.central_config.port, + historyApiFallback: true, + compress: true, + hot: true, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", + "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization" + } + }, + plugins: ['{mfPlugin}'] + } + }; //nuxt vue config + + if (_this21.x_state.config_node['vue:config']) { + var config_ = _this21.x_state.config_node['vue:config']; + delete config_[':secret']; + delete config_[':link']; + config = _objectSpread2(_objectSpread2({}, config), config_); + } //@TODO env vars now should go on /.env + + /* + config.publicRuntimeConfig={}; + for (let node_key in this.x_state.config_node) { + if (node_key.includes(':')==false) { + if ('aurora,vpc,aws'.split(',').includes(node_key)==false) { + if (this.x_state.secrets[node_key]===undefined && typeof this.x_state.config_node[node_key] === 'object') { + config.publicRuntimeConfig[node_key.toLowerCase()]={...this.x_state.config_node[node_key]}; + } + } + } + }*/ + //23feb22: hack added support for vue2-google-map plugin (@todo make this controlled from the tag command) + + + config.transpileDependencies.push(/^vue2-google-maps($|\/)/); // + //we don't need webpack build rules in this edition:omit from cfc, so we are ready here + //let util = require('util'); + //let content = util.inspect(config,{ depth:Infinity }).replaceAll("'`","`").replaceAll("`'","`"); + + if (_this21.deploy_module.modifyVueConfig) { + config = yield _this21.deploy_module.modifyVueConfig(config); + } + + var dumpJS = content_ => { + var tmp = _this21.jsDump(content_); //self.debug('dumpJS',self.jsDump(content_)); + + + if (tmp) { + tmp = tmp.replaceAll("'`", "`").replaceAll("`'", "`"); + } + + return tmp; + }; + /* + let content = dumpJS(config); + //POST: replace dynamic placeholders with vue_config key/values + //@TODO think a better way of doing this (maybe if value is a string an contains a prefixcode like [eval], we could omit the quotes) + content = content.replaceAll("'{...deps}': ''","...deps"); + for (let key in this.x_state.vue_config) { + if (key=='mfPlugin') { + let newMF = `new ModuleFederationPlugin({`+dumpJS(this.x_state.vue_config[key])+`})\n`; + content = content.replaceAll(`{${key}}`,newMF); + } + }*/ + // generate template vue.config.js with vars + + + var template = "//vue.config.js generated by Concepto DSL\n"; + template += "const ModuleFederationPlugin = require(\"webpack/lib/container/ModuleFederationPlugin\");\n const { defineConfig } = require('@vue/cli-service')\n const path = require(\"path\");\n const deps = require(\"./package.json\").dependencies;\n \n module.exports = defineConfig({\n lintOnSave: ".concat(dumpJS(config.lintOnSave), ",\n transpileDependencies: ").concat(dumpJS(config.transpileDependencies), ",\n configureWebpack: {\n devServer: ").concat(dumpJS(config.configureWebpack.devServer), ",\n resolve: {\n extensions: [\".tsx\", \".ts\", \".vue\", \".jsx\", \".js\", \".json\"],\n alias: {\n \"@\": path.resolve(__dirname,\"./src\"),\n \"@assets\": path.resolve(__dirname,\"./src/assets\")\n },\n },\n plugins: [\n new ModuleFederationPlugin({\n name: \"").concat(_this21.x_state.central_config.service_name, "\",\n filename: \"remoteEntry.js\",\n remotes: ").concat(dumpJS(_this21.x_state.vue_config.mfPlugin.remotes), ",\n exposes: ").concat(dumpJS(_this21.x_state.vue_config.mfPlugin.exposes), ",\n shared: {\n ...deps,\n vue: {\n eager: true,\n singleton: true,\n requiredVersion: deps.vue\n },\n \"vue-router\": {\n eager: true,\n singleton: true,\n requiredVersion: deps[\"vue-router\"]\n },\n vuex: {\n eager: true,\n singleton: true,\n requiredVersion: deps[\"vuex\"]\n },\n }\n })\n ]\n\n }\n })\n "); + yield _this21.writeFile(target, template); //this.x_console.outT({ message:'future nuxt.config.js', data:data}); + })(); + } + + createPackageJSON() { + var _this22 = this; + + return _asyncToGenerator(function* () { + var data = { + name: _this22.x_state.central_config.service_name, + version: '', + description: _this22.x_state.central_config[':description'], + //main: 'index.js', + dependencies: {}, + devDependencies: {}, + scripts: { + dev: 'vue-cli-service serve', + build: 'vue-cli-service build' + }, + keywords: [], + author: '', + license: '', + eslintConfig: { + root: true, + env: { + node: true + }, + extends: ['plugin:vue/essential', 'eslint:recommended'], + parserOptions: { + parser: '@babel/eslint-parser' + }, + rules: {} + } + }; + if (_this22.x_state.central_config[':version']) data.version = _this22.x_state.central_config[':version']; + if (_this22.x_state.central_config[':author']) data.author = _this22.x_state.central_config[':author']; + if (_this22.x_state.central_config[':license']) data.license = _this22.x_state.central_config[':license']; + + if (_this22.x_state.central_config[':git']) { + data.repository = { + type: 'git', + url: "git+".concat(_this22.x_state.central_config[':git'], ".git") + }; + data.bugs = { + url: "".concat(_this22.x_state.central_config[':git'], "/issues") + }; + data.homepage = _this22.x_state.central_config[':git']; + } + + if (_this22.x_state.central_config[':keywords']) data.keywords = _this22.x_state.central_config[':keywords'].split(','); //add dependencies + + for (var pack in _this22.x_state.npm) { + if (_this22.x_state.npm[pack].includes('http') && _this22.x_state.npm[pack].includes('github.com')) { + data.dependencies[pack] = "git+".concat(_this22.x_state.npm[pack]); + } else { + data.dependencies[pack] = _this22.x_state.npm[pack]; + } + } //add devDependencies + + + for (var _pack in _this22.x_state.dev_npm) { + if (_this22.x_state.dev_npm[_pack].includes('http') && _this22.x_state.dev_npm[_pack].includes('github.com')) { + data.devDependencies[_pack] = "git+".concat(_this22.x_state.dev_npm[_pack]); + } else { + data.devDependencies[_pack] = _this22.x_state.dev_npm[_pack]; + } + } //storybook support + + /* */ + + + if (_this22.x_state.central_config.storybook == true) { + data.devDependencies['@socheatsok78/storybook-addon-vuetify'] = '^0.1.8'; + /* + data.devDependencies['@babel/core'] = '^7.15.0'; + data.devDependencies['@storybook/addon-actions'] = '^6.3.6'; + data.devDependencies['@storybook/addon-essentials'] = '^6.3.6'; + data.devDependencies['@storybook/addon-links'] = '^6.3.6'; + data.devDependencies['@storybook/vue'] = '^6.3.6'; + data.devDependencies['babel-loader'] = '^8.2.2'; + data.devDependencies['vue-loader'] = '^15.9.8'; + */ + + data.scripts['storybook2'] = 'start-storybook -s ./stories/assets -p 6006'; + data.scripts['build-storybook2'] = 'build-storybook -s ./stories/assets'; + } //write to disk + + + var path = require('path'); + + var target = path.join(_this22.x_state.dirs.app, "package.json"); + + if (_this22.deploy_module.modifyPackageJSON) { + data = yield _this22.deploy_module.modifyPackageJSON(data); + } + + var content = JSON.stringify(data); + yield _this22.writeFile(target, content); //this.x_console.outT({ message:'future package.json', data:data}); + })(); + } + + createStorybookFiles() { + var _this23 = this; + + return _asyncToGenerator(function* () { + // creates Storybook required files + if (_this23.x_state.central_config.storybook == true) { + var path = require('path'); + + var spawn = require('await-spawn'); + + var spinner = _this23.x_console.spinner({ + message: 'Installing storybook' + }); + + try { + var install = yield spawn('npx', ['sb', 'init', '-f'], { + cwd: _this23.x_state.dirs.app + }); + spinner.succeed("Storybook installed and initialized successfully"); + } catch (n) { + spinner.fail('Storybook failed to initialize'); + } // creates .storybook/main.js file + + + var data = { + 'stories': ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + 'addons': ["@storybook/addon-links", "@storybook/addon-essentials", '@socheatsok78/storybook-addon-vuetify'] + }; //write main.js to disk + //this.x_console.outT({ message:'STORYBOOK dirs', color:'yellow', data:this.x_state.dirs }); + + var target = path.join(_this23.x_state.dirs['storybook'], "main.js"); + var content = 'module.exports = ' + JSON.stringify(data); + yield _this23.writeFile(target, content); // creates .storybook/preview.js + + content = "import { withVuetify } from '@socheatsok78/storybook-addon-vuetify/dist/decorators'\n\nexport const parameters = {\n actions: { argTypesRegex: \"^on[A-Z].*\" },\n controls: {\n matchers: {\n color: /(background|color)$/i,\n date: /Date$/,\n },\n },\n}\n\nexport const decorators = [\n withVuetify\n]"; // write preview.js to disk + + target = path.join(_this23.x_state.dirs['storybook'], "preview.js"); + yield _this23.writeFile(target, content); // creates/writes .storybook/preview-head.html + + content = ""; + target = path.join(_this23.x_state.dirs['storybook'], "preview-head.html"); + yield _this23.writeFile(target, content); // creates custom Theme + // copy po logo + + var po_logo = path.join(__dirname, 'assets', 'po.png'); + var po_target = path.join(_this23.x_state.dirs['stories_assets'], 'po.png'); + + var fs = require('fs-extra'); + + yield fs.copy(po_logo, po_target); // remove original stories + //let fso = require('fs').promises; + + yield fs.rmdir(_this23.x_state.dirs['stories'].replace('stories2', 'stories'), { + recursive: true + }); // copy stories2 to stories folder + + yield fs.copy(_this23.x_state.dirs['stories'], _this23.x_state.dirs['stories'].replace('stories2', 'stories')); + yield fs.rmdir(_this23.x_state.dirs['stories'], { + recursive: true + }); //await fs.remove(path.resolve()); + // creates/writes .storybook/potheme.js + + var config = { + base: 'light', + brandTitle: 'Punto Origen SpA', + brandUrl: 'http://www.puntorigen.com', + brandImage: 'po.png', + colorPrimary: '#E10106', + colorSecondary: '#86CD46', + // UI + appBg: '#FFFFFF', + appContentBg: '#F6F8FC', + appBorderColor: 'grey', + appBorderRadius: 1 + }; + content = "import { create } from '@storybook/theming'\n"; + content += "export default create(".concat(JSON.stringify(config), ");"); + target = path.join(_this23.x_state.dirs['storybook'], "po.js"); + yield _this23.writeFile(target, content); // creates/writes .storybook/manager.js + + content = "import { addons } from '@storybook/addons';\n"; + content += "import poTheme from './po';\n\n"; + content += "addons.setConfig({ theme: poTheme });"; + target = path.join(_this23.x_state.dirs['storybook'], "manager.js"); + yield _this23.writeFile(target, content); + } + })(); + } + + createVSCodeHelpers() { + var _this24 = this; + + return _asyncToGenerator(function* () { + // creates Visual Studio code common helpers + var path = require('path'); // creates /jsconfig.json file for Vetur and IntelliSense + + + var data = { + include: ['./src/**/*'], + compilerOptions: { + baseUrl: './', + module: 'es2015', + moduleResolution: 'node', + target: 'es5', + sourceMap: true, + paths: { + '~/*': ['./src/*'], + '@/*': ['./src/*'], + '~~/*': ['./*'], + '@@/*': ['./*'] + } + }, + exclude: ['node_modules', 'dist', 'secrets'] + }; //write to disk + + var target = path.join(_this24.x_state.dirs.app, "jsconfig.json"); + var content = JSON.stringify(data); + yield _this24.writeFile(target, content); + })(); + } //NOT USED ON THIS VERSION + + + createServerlessYML() { + var _this25 = this; + + return _asyncToGenerator(function* () { + var yaml = require('yaml'), + data = {}; + + var deploy = _this25.x_state.central_config.deploy + ''; + + if (deploy.includes('eb:') == false && deploy.includes('s3:') == false && deploy != false && deploy != 'local') { + data.service = _this25.x_state.central_config.service_name; + data.custom = { + prune: { + automatic: true, + includeLayers: true, + number: 1 + }, + apigwBinary: { + types: ['*/*'] + } + }; //add 'secrets' config json keys - cfc:12895 + //this.x_state.secrets + + for (var secret in _this25.x_state.secrets) { + data.custom[secret] = '${file(secrets/' + secret + '.json)}'; + } //domain info + + + if (_this25.x_state.central_config.dominio) { + data.custom.customDomain = { + domainName: _this25.x_state.central_config.dominio + }; + if (_this25.x_state.central_config.basepath) data.custom.customDomain.basePath = _this25.x_state.central_config.basepath; + if (_this25.x_state.central_config.stage) data.custom.customDomain.stage = _this25.x_state.central_config.stage; + data.custom.customDomain.createRoute53Record = true; + } //nodejs env on aws + + + data.provider = { + name: 'aws', + runtime: 'nodejs8.10', + timeout: _this25.x_state.central_config.timeout + }; + if (_this25.x_state.central_config.stage) data.provider.stage = _this25.x_state.central_config.stage; //env keys + + if (Object.keys(_this25.x_state.config_node) != '') { + data.provider.enviroment = {}; + if (_this25.x_state.central_config.stage) data.provider.enviroment.STAGE = _this25.x_state.central_config.stage; + + if (_this25.x_state.config_node.vpc) { + data.provider.vpc = { + securityGroupIds: [_this25.x_state.config_node.vpc.security_group_id], + subnetIDs: [] + }; + + if (_this25.x_state.secrets.vpc) { + data.provider.vpc.securityGroupIds = ['${self:custom.vpc.SECURITY_GROUP_ID}']; + } + + if (_this25.x_state.config_node.vpc.subnet1_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET1_ID}'); + if (_this25.x_state.config_node.vpc.subnet2_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET2_ID}'); + if (_this25.x_state.config_node.vpc.subnet3_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET3_ID}'); + if (_this25.x_state.config_node.vpc.subnet4_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET4_ID}'); + if (_this25.x_state.config_node.vpc.subnet5_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET5_ID}'); + if (_this25.x_state.config_node.vpc.subnet6_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET6_ID}'); + if (_this25.x_state.config_node.vpc.subnet7_id) data.provider.vpc.subnetIDs.push('${self:custom.vpc.SUBNET7_ID}'); + } + } //aws iam for s3 permissions (x_state.aws_iam) (@TODO later - cfc:12990) + + /* + data.provider.iamRoleStatements = { + Effect: 'Allow' + };*/ + //nuxt handler + + + data.functions = { + nuxt: { + handler: 'index.nuxt', + events: [{ + 'http': 'ANY /' + }, { + 'http': 'ANY /{proxy+}' + }] + } + }; + + if (_this25.x_state.central_config['keep-warm']) { + data.functions.nuxt.events.push({ + schedule: 'rate(20 minutes)' + }); + } //aws resources for s3 (x_state.aws_resources) (@TODO later - no commands use them - cfc:13017) + //serverless plugins + + + data.plugins = ['serverless-apigw-binary', 'serverless-offline', 'serverless-prune-plugin']; + if (_this25.x_state.central_config.dominio) data.plugins.push('serverless-domain-manager'); //write yaml to disk + + var content = yaml.stringify(data); + + var path = require('path'); + + var target = path.join(_this25.x_state.dirs.app, "serverless.yml"); + yield _this25.writeFile(target, content); //debug + //this.debug('future serverless.yml', content); + } + })(); + } + + onEnd() { + var _this26 = this; + + return _asyncToGenerator(function* () { + //execute deploy (npm install, etc) AFTER vue compilation (18-4-21: this is new) + if (!_this26.errors_found) { + //only deploy if no errors were found + if (!(yield _this26.deploy_module.deploy()) && !_this26.x_state.central_config.componente) { + _this26.x_console.outT({ + message: 'Something went wrong deploying, check the console, fix it and run again.', + color: 'red' + }); + + yield _this26.deploy_module.post(); // found errors deploying + + process.exit(100); + } else { + yield _this26.deploy_module.post(); + } + } else { + //found errors compiling + process.exit(50); + } + })(); + } + + exists(dir_or_file) { + return _asyncToGenerator(function* () { + var fs = require('fs').promises; + + try { + yield fs.access(dir_or_file); + return true; + } catch (e) { + return false; + } + })(); + } + + writeFile(file, content) { + var _arguments2 = arguments, + _this27 = this; + + return _asyncToGenerator(function* () { + var encoding = _arguments2.length > 2 && _arguments2[2] !== undefined ? _arguments2[2] : 'utf-8'; + + var fs = require('fs').promises, + prettier = require('prettier'); + + var ext = file.split('.').splice(-1)[0].toLowerCase(); //console.log('writeFile:'+file+' (ext:'+ext+')'); + + /*let beautify = require('js-beautify'); + let beautify_js = beautify.js; + let beautify_vue = beautify.html; + let beautify_css = beautify.css;*/ + + var resp = content; + + if (ext == 'js') { + try { + resp = prettier.format(resp, { + parser: 'babel', + useTabs: true, + singleQuote: true + }); + } catch (ee) { + _this27.debug("error: could not format the JS file; trying js-beautify (".concat(file, ")")); + + var beautify = require('js-beautify'); + + var beautify_js = beautify.js; + resp = beautify_js(resp, {}); + } + } else if (ext == 'json') { + try { + resp = prettier.format(resp, { + parser: 'json' + }); + } catch (ee) { + _this27.debug("error: could not format the JSON file; trying js-beautify"); + + var _beautify = require('js-beautify'); + + var _beautify_js = _beautify.js; + resp = _beautify_js(resp, {}); + } + } else if (ext == 'vue') { + /* + let beautify = require('js-beautify'); + let beautify_vue = beautify.html; + resp = beautify_vue(resp.replaceAll(`="xpropx"`,''),{});*/ + resp = resp.replaceAll("=\"xpropx\"", ''); + + try { + resp = prettier.format(resp, { + parser: 'vue', + htmlWhitespaceSensitivity: 'ignore', + useTabs: true, + printWidth: 2000, + embeddedLanguageFormatting: 'auto', + singleQuote: true, + trailingComma: 'none' + }); + } catch (ee) { + _this27.debug("warning: could not format the vue file; trying vue-beautify", ee); + + var _beautify2 = require('js-beautify'); + + var beautify_vue = _beautify2.html; + resp = beautify_vue(resp, {}); + } + } else if (ext == 'css') { + resp = prettier.format(resp, { + parser: 'css' + }); + } + /* + + let resp = content; + if (ext=='js' || ext=='json') { + resp = beautify_js(resp, { eval_code: false }).replaceAll(`\n\n`,''); + } else if (ext=='vue') { + resp = beautify_vue(resp.replaceAll(`="xpropx"`,''),{}); //{ indent_scripts: 'keep' } + } else if (ext=='css') { + resp = beautify_css(resp, { indent_scripts: 'keep' }); + }*/ + //12-dic-21: only write if target content is different from existing. + + + var target_exists = yield _this27.exists(file); + var same = false; + + if (target_exists) { + var prev = yield fs.readFile(file, encoding); + var prev_hash = yield _this27.hash(prev); + var curr_hash = yield _this27.hash(resp); //this.debug('testing file writing hashes',{prev_hash,curr_hash}); + + if (prev_hash == curr_hash) same = true; + } + + if (!same) yield fs.writeFile(file, resp, encoding); + })(); + } //Transforms the processed nodes into files. + + + onCreateFiles(processedNodes) { + var _this28 = this; + + return _asyncToGenerator(function* () { + //this.x_console.out({ message:'onCreateFiles', data:processedNodes }); + //this.x_console.out({ message:'x_state.plugins', data:this.x_state.plugins }); + yield _this28.generalConfigSetup(); + yield _this28.createGitIgnore(); + var plugins_info4stories = yield _this28.createVuePlugins(false); //this.x_console.out({ message:'plugins_info4stories', data:plugins_info4stories }); + + var add_plugins2story = function add_plugins2story(story_vue) { + var plugins = plugins_info4stories.stories; + var resp = story_vue; + + for (var plugin in plugins) { + if (plugins[plugin].code.includes('vuetify') == false) { + var nscript = "'; + if (!vue.style) vue.style = ''; + vue.full = "".concat(vue.template, "\n").concat(vue.script, "\n").concat(vue.style); // ********************************** // + // write files + + var w_path = path.join(this.x_state.dirs.pages, thefile.file); + + if (page.tipo == 'componente') { + this.x_console.outT({ + message: "writing vue 'component' file ".concat(thefile.file), + color: 'cyan' + }); + w_path = path.join(this.x_state.dirs.components, thefile.file.replace('.vue', '')); //create individual 'component' directory + + var _fs = require('fs').promises; + + try { + yield _fs.mkdir(w_path, { + recursive: true + }); + } catch (errdir) {} + + if (this.x_state.central_config.storybook == true) { + //write {component}-story.vue alongside component file, with paths modified + var vue_story = vue.full; + var svue_path = path.join(w_path, thefile.file.replace('.vue', '-story.vue')); + vue_story = vue_story.replaceAll('@/assets', '../../assets'); + vue_story = vue_story.replaceAll('@/components', '../../components'); + vue_story = vue_story.replaceAll('.vue', '-story.vue'); + vue_story = add_plugins2story(vue_story); // @todo apply sub-tags and plugins directly to .vue + + /*if (vue.script.includes('asyncComputed')) { + let nscript = `'; + if (!vue.style) vue.style = ''; + vue.full = `${vue.template}\n${vue.script}\n${vue.style}`; + // ********************************** // + // write files + let w_path = path.join(this.x_state.dirs.pages, thefile.file); + if (page.tipo == 'componente') { + this.x_console.outT({ message: `writing vue 'component' file ${thefile.file}`, color: 'cyan' }); + w_path = path.join(this.x_state.dirs.components, thefile.file.replace('.vue','')); + //create individual 'component' directory + let fs = require('fs').promises; + try { + await fs.mkdir(w_path, { recursive:true }); + } catch(errdir) { + } + if (this.x_state.central_config.storybook==true) { + //write {component}-story.vue alongside component file, with paths modified + let vue_story = vue.full; + let svue_path = path.join(w_path, thefile.file.replace('.vue','-story.vue')); + vue_story = vue_story.replaceAll('@/assets','../../assets'); + vue_story = vue_story.replaceAll('@/components','../../components'); + vue_story = vue_story.replaceAll('.vue','-story.vue'); + vue_story = add_plugins2story(vue_story); + // @todo apply sub-tags and plugins directly to .vue + /*if (vue.script.includes('asyncComputed')) { + let nscript = `