/
ivanby
/
Compote
Обзор
Документация
Войти
/
ivanby
/
Compote
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
master
yaga/compote.js
966 строк
38 KB
Иван Быков
Обновление compote.js
05 июл 2026, 21:40
05 июл 2026, 21:40
65812a8
Код
Авторство
О чём код?
/* jshint evil: true */ const toolName = 'compote -> '; //*** начало общий код для всех утилит const fs = require('node:fs'); const path = require('node:path'); const process = require('node:process'); const yaml = require('yaml'); let indicatorCurPos = 0; function indicator() { const indicatorChars = ['|', '/', '–', '\\']; if(indicatorCurPos < indicatorChars.length) indicatorCurPos++; if(indicatorCurPos >= indicatorChars.length) indicatorCurPos = 0; return indicatorChars[indicatorCurPos]; } const projectDir = process.cwd(); // доступен ли yaga.config.yaml const yagaConfigYamlPath = path.join( projectDir, 'yaga.config.yaml'); if (!fs.existsSync(yagaConfigYamlPath)) { console.log(toolName + '\x1b[31mПродолжение невозможно: отсутсвует yaga.config.yaml - ' + yagaConfigYamlPath + '\x1b[0m'); process.exit(1); } // читаем yaga.config.yaml let yagaConfigYaml = ''; try { yagaConfigYaml = fs.readFileSync( yagaConfigYamlPath , 'utf8'); } catch (err) { console.log(toolName + '\x1b[31mПродолжение невозможно: не могу прочитать yaga.config.yaml - ' + yagaConfigYamlPath + '\x1b[0m'); process.exit(1); } // парсим yaga.config.yaml let yagaConfig = ''; try { yagaConfig = yaml.parse(yagaConfigYaml); } catch (err) { console.log(toolName + '\x1b[31mПродолжение невозможно: не могу разобрать yaga.config.yaml - ' + yagaConfigYamlPath + '\x1b[0m'); console.log(err); process.exit(1); } // проверяем yagaConfig.target_dir if(!yagaConfig.target_dir || typeof yagaConfig.target_dir != 'string') { console.log(toolName + '\x1b[31mПродолжение невозможно: неверно указана целевая директория yagaConfig.target_dir - ' + yagaConfig.target_dir + '\x1b[0m'); process.exit(1); } const targetDirPath = path.join(projectDir, yagaConfig.target_dir); // проверяем yagaConfig.target_dir if(!fs.existsSync(targetDirPath)) { console.log(toolName + '\x1b[31mПродолжение невозможно: отсутсвует целевая директория yagaConfig.target_dir - ' + targetDirPath + '\x1b[0m'); process.exit(1); } //*** конец общий код для всех утилит // собственно код compote.js // проверяем yagaConfig.compote if( !yagaConfig.compote || !yagaConfig.compote.compote || typeof yagaConfig.compote.compote != 'string' || !/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(yagaConfig.compote.compote) || !yagaConfig.compote.file || typeof yagaConfig.compote.file != 'string' || !yagaConfig.compote.filter || !Array.isArray(yagaConfig.compote.filter) || !yagaConfig.compote.ignore || !Array.isArray(yagaConfig.compote.ignore) ) { console.log(yagaConfig.compote); console.log(toolName + '\x1b[31mПродолжение невозможно: в ' + yagaConfigYamlPath + ' неккоректно настроен ключ compote\x1b[0m'); process.exit(1); } let srcFiles = []; function scanDir(dir) { fs.readdirSync(dir).forEach(file => { const absPath = path.join(dir, file); if (fs.statSync(absPath).isDirectory()) return scanDir(absPath); else { let cndf; for(let ref of yagaConfig.compote.filter) { try { cndf = (new RegExp(ref)).test(absPath); if(cndf) break; } catch (err) { console.log(toolName + '\x1b[31mПродолжение невозможно: в ' + yagaConfigYamlPath + ' неккоректно настроен ключ compote.filter\x1b[0m'); process.exit(1); } } if(cndf) { let cndi; for(let rei of yagaConfig.compote.ignore) { try { cndi = (new RegExp(rei)).test(absPath); if(cndi) break; } catch (err) { console.log(toolName + '\x1b[31mПродолжение невозможно: в ' + yagaConfigYamlPath + ' неккоректно настроен ключ compote.ignore\x1b[0m'); process.exit(1); } } if(!cndi) srcFiles.push(absPath); } } }); } scanDir(targetDirPath); //console.log(srcFiles); // npm install cheerio const cheerio = require('cheerio'); const HTMLM = require("html-minifier"); const htmlMinifier = { minify: (data)=>{ result = HTMLM.minify(data,yagaConfig.compote['minify_html']); return result; } }; const CCSS = new (require('clean-css'))({ inline: ['none'] // disables all inlining }); const cleanCSS = { minify: (data)=>{ if(yagaConfig.compote['minify_style']) result = CCSS.minify(data); else return data; if(result.errors && result.errors.length) throw result.errors; else return result.styles; } }; let $; let compote_path; if( yagaConfig.compote.mount && yagaConfig.compote.mount.element && yagaConfig.compote.root && yagaConfig.compote.name ) { compote_path = `let _prts = this.parents(_co).map(i=>i.compote.forename); _prts[0] = '${yagaConfig.compote.name}'; _co.compote.id = _prts.join('.').replace(/\\.(\\d+)/g, '[$1]');`; } else compote_path = `_co.compote.id = this.parents(_co).map(i=>i.compote.forename).join('.').replace(/\\.(\\d+)/g, '[$1]');`; //compote_path = `_co.getElem().setAttribute('compote-id', _co.compote.id);`; if(typeof yagaConfig.compote.marked == 'string') yagaConfig.compote.marked = yagaConfig.compote.marked.trim(); else yagaConfig.compote.marked = ''; let out_script = ` window.${yagaConfig.compote.compote} = { parents: function (_co) { // цепочка всех предков const _r = []; while(_co) { _r.unshift(_co); _co = _co.parent; } return _r; }, childs: function (_co) { // потомки, плоский массив всех потомков const _r = []; const _tr = (_c)=>{ /* //возможны условия, тут листья: if (!_c.childs || _c.childs.length == 0) { _r.push(_c); return; } */ _r.push(_c); _c.childs.forEach(ch => { _tr(ch); }); }; _tr(_co); return _r; }, setpath_: function (_co) { // назначение compote-id и compote-forename компоненту ${compote_path} const _coElm = _co.getElem(); let a_marked; if(!_co.compote.marked) { a_marked = _coElm.getAttribute('marked'); if(typeof a_marked == 'string') a_marked = a_marked.trim(); else a_marked = ''; a_marked += ' ${yagaConfig.compote.marked}'; a_marked = a_marked.split(' '); _co.compote.marked = a_marked; if(a_marked.includes('compote-id')) { _coElm.setAttribute('compote-id', _co.compote.id); } if(a_marked.includes('compote-forename')) { _coElm.setAttribute('compote-forename', _co.compote.forename); } if(!a_marked.includes('compote')) { _coElm.removeAttribute('compote'); } if(!a_marked.includes('setlist')) { _coElm.removeAttribute('setlist'); } if(!a_marked.includes('marked')) { _coElm.removeAttribute('marked'); } } else { a_marked = _co.compote.marked; if(a_marked.includes('compote-id')) { _coElm.setAttribute('compote-id', _co.compote.id); } if(a_marked.includes('compote-forename')) { _coElm.setAttribute('compote-forename', _co.compote.forename); } } }, props_: function (_co, _prs, _izprs ) { if(_prs && typeof _prs === 'object' && !Array.isArray(_prs)) { for(const pnm of Object.keys(_prs)) if(pnm !== 'root' && pnm !== 'parent' && _co[pnm] && _co[pnm].props instanceof Function) _co[pnm].props(_prs[pnm]); _izprs(_prs); } else { const ret = {}; for(const pnm of Object.keys(_co)) if(pnm !== 'root' && pnm !== 'parent' && _co[pnm] && _co[pnm].props instanceof Function) ret[pnm] = _co[pnm].props(); return {..._izprs(), ...ret}; } }, nested_: function (_co, _prs, _parent, _as) { // _co.childs = []; _co.parent = _parent; const _el = _co.getElem(); _co.compote.name = _el.getAttribute('compote'); _co.compote.forename = typeof _as != 'undefined'? _as : _co.compote.name; if(typeof _co.parent == 'object') { _co.parent[_co.compote.forename] = _co; _co.root = _co.parent.root || _co.parent; } window.${yagaConfig.compote.compote}.setpath_(_co); for(const _cl of _el.querySelectorAll('[nested]')) { let _aprs = _cl.getAttribute('props'); if(typeof _aprs == 'string') { _aprs = this.props_attrs_[parseInt(_aprs)]; } if(_aprs && typeof _aprs == 'object') if(_prs && typeof _prs == 'object') _prs = Object.assign(_aprs, _prs); else _prs = _aprs; let _ca = _cl.getAttribute('nested').split(' as '); if(_ca[0]) _ca = { name: _ca[0], value: _ca[1] }; else _ca = [..._cl.attributes].find(atr=>atr.name != 'nested' && atr.name != 'props'); if(_ca) { if(typeof this[_ca.name] != 'function') throw 'Неизвестный компонент ' + _ca.name + ' в '+_co.compote.name+', продолжение невозможно.'; const _cn = _ca.value || _ca.name; _co[_cn] = this[_ca.name](_prs, _co, _cn); _cl.replaceWith(_co[_cn].getElem()); _co.childs.push(_co[_cn]); } } if(_prs && typeof _prs === 'object' && !Array.isArray(_prs))_co.props(_prs); _el.izba = _co; // в DOM элементе размещается ссылка на его об. izba }, version: "1.0.9" , `; let compoteNoti = toolName + 'Генерирую код в ./' + yagaConfig.target_dir + '/' + yagaConfig.compote.file + ': '; process.stdout.write(compoteNoti); const compotes = {}; let props_attrs = ''; props_attrs_idx = 0; let setlist_flag = false; const handFiles = ()=>{ srcFileOfSrcFiles: for( let srcFile of srcFiles) { let srcText = ''; try { srcText = fs.readFileSync( srcFile , 'utf8'); } catch (err) { console.log(); console.log(toolName + '\x1b[31mПродолжение невозможно: не могу прочитать ' + srcFile + '\x1b[0m'); console.log(err); process.exit(1); } $ = cheerio.load(srcText, { xml: { xmlMode: false, emptyAttrs: false, decodeEntities: false, lowerCaseAttributeNames: true, lowerCaseTags: true } }); let comp_lnk = $('[compote]'); if(!comp_lnk || comp_lnk.length === 0) // это не файл компонента continue; if(comp_lnk.length !== 1) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: допустим только один компонент на файл:\n ' + srcFile + '\x1b[0m'); console.log(); continue; } let comp_name = comp_lnk.attr('compote'); if(!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(comp_name)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: неверное имя компонента (должно быть /^[a-zA-Z_$][a-zA-Z0-9_$]*$/):\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } if(Object.keys(compotes).includes(comp_name)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: дубликат компонента:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } let comp_nesteds = comp_lnk.children('[nested]'); let setlist = comp_lnk.attr('setlist'); if(comp_nesteds && comp_nesteds.length) { for(let cmp_nested of comp_nesteds) { let nested_name, nested_nm, nested_vl; let $cmp_nested = $(cmp_nested); // способ №1 -- имя вкладываемого в значении, включая возможный as nested_name = $cmp_nested.attr('nested'); if(nested_name) { nested_name = nested_name.trim(); let exp_as = nested_name.split(/\s+as\s+/); if(!/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(exp_as[0])) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент имеет некорректное имя (в значении "nested"):\n ' + exp_as[0] + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } if(exp_as[1] && !/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(exp_as[1])) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент имеет некорректное назначаемое имя (в значении "nested" после "as"):\n ' + exp_as[1] + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } nested_name = exp_as[0]; if(exp_as[1]) nested_name += ' as ' + exp_as[1]; $cmp_nested.attr('nested', nested_name); nested_nm = exp_as[0]; nested_vl = exp_as[1]; } // способ №2 -- имя вкладываемого как отдельный атрибут else { nested_name = Object.keys(cmp_nested.attribs).find(nm=>nm != 'nested' && nm != 'props'); if(!nested_name || !/^[a-z_][a-z0-9_]*$/.test(nested_name)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент имеет некорректное имя (как атрибут):\n ' + nested_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } let nested_as = $cmp_nested.attr(nested_name); if(nested_as) nested_as = nested_as.trim(); if(nested_as && !/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(nested_as)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент имеет некорректное назначаемое имя (как значение атрибута):\n ' + nested_as + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } $cmp_nested.attr(nested_name, nested_as); nested_nm = nested_name; nested_vl = nested_as; } if(nested_nm === comp_name) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент не может быть одновременно объявляемым:\n ' + nested_nm + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } if(nested_vl === comp_name) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: вложенный компонент не может быть одновременно объявляемым:\n ' + nested_vl + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } let cmp_props = cmp_nested.attribs['props']; if(typeof setlist != 'string' && cmp_props && typeof cmp_props == 'string') { cmp_props = cmp_props.trim(); try { if(cmp_props[0] !== '{' || cmp_props[cmp_props.length-1] !== '}') throw 0; let test_obj = (new Function('return '+cmp_props+';'))(); if(!test_obj || typeof test_obj != 'object') throw 0; cmp_nested.attribs['props'] = props_attrs_idx+''; props_attrs_idx++; props_attrs += `\n${cmp_props},`; } catch(err) { console.log(cmp_nested); console.log(toolName + '\x1b[31mИгнорирую: props во вложенном компоненте, если указан, должен быть валидным объектом:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } } } } compotes[comp_name] = {}; if(typeof setlist == 'string') { // это компонент-список setlist! if(!setlist.trim()) setlist = 'setlist'; if(!/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(setlist)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: неверное имя setlist (должно быть /^[a-zA-Z$_][a-zA-Z0-9$_]*$/):\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } let tpl_comp = comp_lnk.children('[nested]'); if(!tpl_comp || tpl_comp.length !== 1) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: компонент-список "setlist" должен иметь один и только один вложенный компонент-шаблон:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } tpl_comp = tpl_comp[0]; $tpl_comp = $(tpl_comp); // способ №1 -- имя вкладываемого в значении template_name = $tpl_comp.attr('nested'); if(template_name) { template_name = template_name.trim(); if(!/^[a-zA-Z$_][a-zA-Z0-9$_]*$/.test(template_name)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: компонент-шаблон имеет некорректное имя (в значении "nested"):\n ' + template_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } $tpl_comp.attr('nested', template_name); } // способ №2 -- имя вкладываемого как отдельный атрибут else { template_name = Object.keys(tpl_comp.attribs).find(nm=>nm != 'nested' && nm != 'props'); if(!template_name || !/^[a-z_][a-z0-9_]*$/.test(template_name)) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: компонент-шаблон имеет некорректное имя (как атрибут):\n ' + template_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } } if(template_name === comp_name) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: компонент-шаблон не может быть одновременно объявляемым списком:\n ' + tpl_nm + ' в ' + srcFile + '\x1b[0m'); console.log(); continue srcFileOfSrcFiles; } let template_props = tpl_comp.attribs['props']; if(template_props && typeof template_props == 'string') { template_props = template_props.trim(); try { if(template_props[0] !== '{' || template_props[template_props.length-1] !== '}') throw 0; let test_obj = (new Function('return '+template_props+';'))(); if(!test_obj || typeof test_obj != 'object') throw 0; } catch(err) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: props в компоненте-шаблоне, если указан, должен быть валидным объектом:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } } else template_props = '{}'; compotes[comp_name].setlist = { template_name: template_name, // имя шаблона-компонента template_props: template_props // инициирущий пропс шаблона-компонента }; comp_lnk.html(''); // чистим компонент-список } compotes[comp_name].html = htmlMinifier.minify(comp_lnk.prop('outerHTML').replaceAll('`','\\`')); let scrpt_lnk = $('script'); if(scrpt_lnk && scrpt_lnk.length > 1) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: в компоненте больше одного блока script:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } //compotes[comp_name].script = scrpt_lnk.length? scrpt_lnk.html().replaceAll('`','\\`') : ''; compotes[comp_name].script = scrpt_lnk.length? scrpt_lnk.html() : ''; let stl_lnk = $('style'); if(stl_lnk && stl_lnk.length > 1) { console.log(); console.log(toolName + '\x1b[31mИгнорирую: в компоненте больше одного блока style:\n ' + comp_name + ' в ' + srcFile + '\x1b[0m'); console.log(); continue; } compotes[comp_name].style = stl_lnk.length? cleanCSS.minify(stl_lnk.html()).replaceAll('`','\\`') : ''; let style_code = ''; if(compotes[comp_name].style.length) style_code =` var _dqshd_ = document.querySelector('html>head'); if(!_dqshd_.querySelector('style[compote-style=${comp_name}]')) _dqshd_.appendChild(${comp_name}.newElem(\`<style compote-style="${comp_name}">${compotes[comp_name].style}</style>\`)); _dqshd_ = undefined; `; let props_code = ''; if(compotes[comp_name].setlist) { if(!setlist_flag) { out_script += ` // любой метод если принимает, то это просы или массивы пропсов // любой метод если возвращает, то это просы или массивы пропсов setlist_: { splice: function ($this, idxs, cntrm, ...items) { let len = $this.childs.length; let ret = []; if(typeof idxs != 'number') idxs = 0; if(typeof cntrm != 'number' || cntrm < 0) cntrm = 0; if(idxs > len) idxs = len; if(idxs < 0) idxs = len + idxs; if(idxs < 0) idxs = 0; if(cntrm > 0 && idxs < len) { let toIdx = idxs + cntrm; if(toIdx > len) toIdx = len; for(let idx = idxs; idx < toIdx; idx++) $this.childs[idx].getElem().remove(); for(let idx = idxs; idx < len; idx++){ if($this[idx].destroy instanceof Function) $this[idx].destroy(); delete $this[idx]; } ret = $this.childs.splice(idxs, cntrm).map(itm=>itm.props()); len = $this.childs.length; $this.length = len; for(let idx = idxs; idx < len; idx++) { $this[idx] = $this.childs[idx]; $this[idx].compote.forename = idx; if($this[idx].$index instanceof Function) $this[idx].$index(idx); for(const chld of window.${yagaConfig.compote.compote}.childs($this[idx])) window.${yagaConfig.compote.compote}.setpath_(chld); } } if(Array.isArray(items) && items.length) { const $elem = $this.getElem(); const elems = []; len = $this.childs.length; for(let idx = 0; idx < items.length; idx++) { let citm = {}; const gidx = idxs + idx; const itm = items[idx]; if(itm && typeof itm == 'object' && !Array.isArray(itm)) { citm = Object.assign(itm, $this.${setlist}.template_props); } const nwc = window.${yagaConfig.compote.compote}[$this.${setlist}.template](citm, $this, gidx); $this.childs.splice(gidx, 0, nwc); } for(let idx = idxs; idx < $this.childs.length; idx++) { $this[idx] = $this.childs[idx]; $this[idx].compote.forename = idx; if($this[idx].$index instanceof Function) $this[idx].$index(idx); for(const chld of window.${yagaConfig.compote.compote}.childs($this[idx])) window.${yagaConfig.compote.compote}.setpath_(chld); elems.push($this[idx].getElem()); } if(!len || idxs >= len) $elem.append(...elems); else if(!idxs) $elem.prepend(...elems); else $elem.children[idxs].before(...elems); $this.length = $this.childs.length; } return ret; }, slice: function ($this, idx, idxe) { return $this.childs.slice(idx, idxe).map(itm=>itm.props()); }, push: function ($this, ...items) { this.splice($this, $this.length, 0, ...items); return $this.length; }, pop: function ($this) { const lidx = $this.length-1; if(lidx < 0) return; return this.splice($this, lidx, 1)[0]; }, unshift: function ($this, ...items) { this.splice($this, 0, 0, ...items); return $this.length; }, shift: function ($this) { if(!$this.length) return; return this.splice($this, 0, 1)[0]; }, insert: function ($this, idx, ...items) { this.splice($this, idx, 0, ...items); return $this.length; }, remove: function ($this, idx, cnt) { if(typeof cnt != 'number') cnt = 1; else if(cnt < 0 || cnt > $this.childs.length) cnt = $this.childs.length; return this.splice($this, idx, cnt); }, props: function ($this, prps, setlistnm, $izba_props) { if(prps && typeof prps === 'object' && !Array.isArray(prps)) { if(prps[setlistnm] && Array.isArray(prps[setlistnm]) && prps[setlistnm].length) { if($this.childs.length) $this.clean(); $this.push(...prps[setlistnm]); delete prps[setlistnm]; } $izba_props(prps); } else return {...$izba_props(), [setlistnm]: $this.childs.map(chl=>chl.props())}; }, }, `; setlist_flag = true; } props_code += ` // $this -- псевдомассив $this.${setlist} = { template: '${compotes[comp_name].setlist.template_name}', template_props: ${compotes[comp_name].setlist.template_props} }; $this.length = 0; // эти помощники принимают пропсы, возвращают пропсы // т.е. эти методы для реального удаления и создания элементов списка // array стиль $this.splice = (idxs, cntrm, ...items) => this.setlist_.splice($this, idxs, cntrm, ...items); $this.slice = (idx, idxe) => this.setlist_.slice($this, idx, idxe); $this.push = (...items) => this.setlist_.push($this, ...items); $this.pop = () => this.setlist_.pop($this); $this.unshift = (...items) => this.setlist_.unshift($this, ...items); $this.shift = () => this.setlist_.shift($this); // особые (не array стиль) $this.remove = (idx, cnt) => this.setlist_.remove($this, idx, cnt); $this.clean = () => this.setlist_.remove($this, 0, $this.childs.length); $this.insert = (idx, ...items) => this.setlist_.insert($this, idx, ...items); // особые (не array стиль) // эти методы имеют два режима работы -- с простым обменом пропсами, что быстрее // и с реальными удалением/вставкой из/в DOM элементов с последующим пересчетом // индексов -- за это отвечает последний параметр -- force // сильный режим может понадобится для эффектов анимации, например // обычный -- быстрее для сортирки $this.swap = (idx1, idx2, force) => { if( idx1 !== idx2 && idx1 < $this.length && idx2 < $this.length && idx1 >= 0 && idx2 >= 0 ) { if(force) { if(idx1 < idx2) { const itm1 = $this.remove(idx1); const itm2 = $this.remove(idx2-1); $this.insert(idx1, ...itm2); $this.insert(idx2, ...itm1); } else { const itm2 = $this.remove(idx2); const itm1 = $this.remove(idx1-1); $this.insert(idx2, ...itm1); $this.insert(idx1, ...itm2); } } else { const p1 = $this[idx1].props(); if(p1.$index !== undefined) p1.$index = idx2; const p2 = $this[idx2].props(); if(p2.$index !== undefined) p2.$index = idx1; $this[idx1].props(p2); $this[idx2].props(p1); } return $this.length; } }; $this.up = (idx, force) => $this.swap(idx, idx-1, force); $this.down = (idx, force) => $this.swap(idx, idx+1, force); $this.top = (idx, force) => $this.swap(idx, 0, force); $this.end = (idx, force) => $this.swap(idx, $this.length-1, force); $this.lift = (idx, toIdx, force) => { if(force) return $this.insert(toIdx, ...$this.remove(idx)); if(idx > toIdx) for(let i = idx; i > toIdx; i--) $this.up(i); else if(idx < toIdx) for(let i = idx; i < toIdx; i++) $this.down(i); return $this.length; }; // сортировка -- если условие тру -- делает перестановку $this.swap // слабый и сильный режим, модифицирует также $this.childs через $this.swap // не повторяет интерфейс родного метода массивов sort! тут нет -1, 0, 1, только тру и фолс // но сработает, если cmpFn вернет -1, 1, и не сработает, если 0 $this.sort = (cmpFn, force) => { const length = $this.length; if (typeof cmpFn !== 'function') { throw new TypeError('setlist component sort() method requires a compare function'); } for (let i = 0; i < length - 1; i++) { let mIdx = i; for (let j = i + 1; j < length; j++) { if ( cmpFn($this[j], $this[mIdx]) ) mIdx = j; } if (mIdx !== i) $this.swap(i, mIdx, force); } return $this; }; const $izba_props = $this.props; $this.props = prps => this.setlist_.props($this, prps, '${setlist}', $izba_props); `; } else { props_code += ` const $izba_props = $this.props; $this.props = prps => this.props_($this, prps, $izba_props); `; } if( yagaConfig.compote.mount && yagaConfig.compote.mount.element === 'body' && yagaConfig.compote.mount.method === 'replaceWith' && yagaConfig.compote.root === comp_name ) out_script += // body и replaceWith const $index = $forename; `${comp_name}: function ($props, $parent, $forename) { const ${comp_name} = $izba('body'${yagaConfig.compote.izba? ','+yagaConfig.compote.izba : ''}); const $this = ${comp_name}; ${style_code} ${props_code} $this.compote = {}; this.nested_($this, $props, $parent, $forename); ${compotes[comp_name].script.includes('$elem')? 'const $elem = $this.getElem();' : ''} ${compotes[comp_name].script.includes('$root')? 'const $root = $this.root;' : ''} ${compotes[comp_name].script} return $this; }, `; else out_script += `${comp_name}: function ($props, $parent, $forename) { const ${comp_name} = $izba(\`${compotes[comp_name].html}\`${yagaConfig.compote.izba? ','+yagaConfig.compote.izba : ''}); const $this = ${comp_name}; ${style_code} ${props_code} $this.compote = {}; this.nested_($this, $props, $parent, $forename); ${compotes[comp_name].script.includes('$elem')? 'const $elem = $this.getElem();' : ''} ${compotes[comp_name].script.includes('$root')? 'const $root = $this.root;' : ''} ${compotes[comp_name].script.includes('$index')? 'const $index = $forename;' : ''} ${compotes[comp_name].script} return $this; }, `; try { fs.unlinkSync(srcFile); } catch (err) { console.log(toolName + '\x1b[31mПродолжение невозможно: не могу удалить ' + srcFile + '\x1b[0m'); console.log(err); process.exit(1); } } out_script += `props_attrs_: [${props_attrs} ], `; if( yagaConfig.compote.mount && typeof yagaConfig.compote.mount.element == 'string' && yagaConfig.compote.root && yagaConfig.compote.name ) { let on_ready = typeof yagaConfig.compote.mount.on_ready == 'string'; out_script += `mount: function () {`; if(on_ready) out_script += `document.addEventListener("${yagaConfig.compote.mount.on_ready}", () => {`; if( !(yagaConfig.compote.mount.element === 'body' && yagaConfig.compote.mount.method === 'replaceWith') ) out_script += ` window.${yagaConfig.compote.name} = window.${yagaConfig.compote.compote}.${yagaConfig.compote.root}(); document.querySelector('${yagaConfig.compote.mount.element}') .${['prepend', 'append', 'replaceWith'].includes(yagaConfig.compote.mount.method)? yagaConfig.compote.mount.method : 'append'}(window.${yagaConfig.compote.name}.getElem()); window.${yagaConfig.compote.compote}.root = window.${yagaConfig.compote.name};`; else // body и replaceWith out_script += ` const srcEl = $izba.newElem(\`${compotes[yagaConfig.compote.root].html}\`); const dstEl = document.querySelector('body'); [...srcEl.attributes].forEach( attr => dstEl.setAttribute(attr.nodeName, attr.nodeValue) ); while (srcEl.firstChild) dstEl.appendChild(srcEl.firstChild); window.${yagaConfig.compote.name} = window.${yagaConfig.compote.compote}.${yagaConfig.compote.root}(); window.${yagaConfig.compote.compote}.root = window.${yagaConfig.compote.name};`; if(on_ready) out_script += `});`; out_script += ` }};`; if(yagaConfig.compote.mount.auto) out_script += ` window.${yagaConfig.compote.compote}.mount();`; } else out_script += ` }};`; }; handFiles(); //console.log(out_script); try { fs.writeFileSync( targetDirPath + '/' + yagaConfig.compote.file , out_script, 'utf8'); } catch (err) { console.log(); console.log(toolName + '\x1b[31mПродолжение невозможно: не могу записать ' + srcFile + '\x1b[0m'); console.log(err); process.exit(1); } process.stdout.write('\b'); process.stdout.write('\x1b[32mготово\x1b[0m'); console.log(); /* // два промиса // после подключения компонента в DOM // если назначен этот промис afterConnect // до удаления из DOM если назначен этот промис beforeRemove */