UNPKG

@dooboostore/dom-render

Version:
946 lines (882 loc) 96.4 kB
import { RandomUtils } from '@dooboostore/core'; import { StringUtils } from '@dooboostore/core'; import { EventManager, NormalAttrDataType } from '../events/EventManager'; import type { DomRenderConfig } from '../configs/DomRenderConfig'; import { Range } from '@dooboostore/core'; import { ElementUtils } from '@dooboostore/core-web'; import { ComponentSet } from '../components/ComponentSet'; import { DrPre } from '../operators/DrPre'; import { Dr } from '../operators/Dr'; import { DrIf } from '../operators/DrIf'; import { ExecuteState, OperatorExecuter } from '../operators/OperatorExecuter'; import { DrThis } from '../operators/DrThis'; import { DrForm } from '../operators/DrForm'; import { DrInnerText } from '../operators/DrInnerText'; import { DrInnerHTML } from '../operators/DrInnerHTML'; import { DrFor } from '../operators/DrFor'; import { DrForOf } from '../operators/DrForOf'; import { DrAppender } from '../operators/DrAppender'; import { DrRepeat } from '../operators/DrRepeat'; import { DrTargetElement } from '../operators/DrTargetElement'; import { DrTargetAttr } from '../operators/DrTargetAttr'; import { DrStripElement } from '../operators/DrStripElement'; import { TargetElement } from '../configs/TargetElement'; import { TargetAttr } from '../configs/TargetAttr'; import { DestroyOptionType } from './DestroyOptionType'; import { Attrs } from './Attrs'; import { AttrInitCallBack } from './AttrInitCallBack'; import { ElementInitCallBack } from './ElementInitCallBack'; import { RawSetType } from './RawSetType'; import { Render } from './Render'; import { DrThisProperty } from '../operators/DrThisProperty'; import { RawSetOperatorType } from './RawSetOperatorType'; import { CssParser, CssRule, isStyleRule, isAtRule } from '@dooboostore/core'; import { isOnCreateRenderData, OnCreateRenderDataParams } from '../lifecycle/OnCreateRenderData'; import { isOnCreateRender } from '../lifecycle/OnCreateRender'; import { isOnChangeAttrRender } from '../lifecycle/OnChangeAttrRender'; import { isOnInitRender } from '../lifecycle/OnInitRender'; import { isOnCreatedThisChild } from '../lifecycle/OnCreatedThisChild'; import { isOnDestroyRender, OnDestroyRenderParams } from '../lifecycle/OnDestroyRender'; import { DrTargetElementIsElement } from '../operators/DrTargetElementIsElement'; import { ObjectUtils } from '@dooboostore/core'; import { NodeUtils } from '@dooboostore/core-web'; import { ConvertUtils } from '@dooboostore/core'; import { DomRenderComponentMetaKey } from './index'; export type RenderResult = { raws: RawSet[]; executedOperators: OperatorExecuter[] }; // let renderCnt = 0; export class RawSet { public static readonly DR_NAME = 'dr'; public static readonly DR_IF_NAME = 'dr-if'; public static readonly DR_FOR_NAME = 'dr-for'; public static readonly DR_FOR_OF_NAME = 'dr-for-of'; public static readonly DR_THIS_PROPERTY_NAME = 'dr-this-property'; public static readonly DR_REPEAT_NAME = 'dr-repeat'; public static readonly DR_THIS_NAME = 'dr-this'; public static readonly DR_FORM_NAME = 'dr-form'; public static readonly DR_PRE_NAME = 'dr-pre'; public static readonly DR_APPENDER_NAME = 'dr-appender'; public static readonly DR_INNERHTML_NAME = 'dr-inner-html'; public static readonly DR_INNERTEXT_NAME = 'dr-inner-text'; public static readonly DR_DETECT_NAME = 'dr-detect'; public static readonly DR_STRIP_NAME = 'dr-strip'; public static readonly DR_REPLACE_TARGET_ELEMENT_IS_NAME = 'dr-replace-target-element-is'; // elementName public static readonly DR_TARGET_ELEMENT_ELEMENTNAME = 'dr-target-element'; // 감지처리되는 옵션 public static readonly DR_DETECT_IF_OPTIONNAME = 'dr-detect-option-if'; public static readonly DR_DETECT_FILTER_OPTIONNAME = 'dr-detect-option-filter'; public static readonly DR_DETECT_ATTR_OPTIONNAME = 'dr-detect-option-attr'; /** * @deprecated */ public static readonly DR_THIS_OPTIONNAME = 'dr-option-this'; public static readonly DR_ATTR_OPTIONNAME = 'dr-option-attr'; public static readonly DR_IF_OPTIONNAME = 'dr-option-if'; public static readonly DR_IT_OPTIONNAME = 'dr-option-it'; public static readonly DR_VAR_OPTIONNAME = 'dr-option-var'; public static readonly DR_AFTER_OPTIONNAME = 'dr-option-after'; public static readonly DR_NEXT_OPTIONNAME = 'dr-option-next'; public static readonly DR_BEFORE_OPTIONNAME = 'dr-option-before'; public static readonly DR_COMPLETE_OPTIONNAME = 'dr-option-complete'; public static readonly DR_STRIP_OPTIONNAME = 'dr-option-strip'; public static readonly DR_DESTROY_OPTIONNAME = 'dr-option-destroy'; public static readonly DR_THIS_NAME_OPTIONNAME = 'dr-option-this-name'; public static readonly DR_VARIABLE_NAME_OPTIONNAME = 'dr-option-variable-name'; public static readonly DR_ITEM_VARIABLE_NAME_OPTIONNAME = 'dr-option-item-variable-name'; public static readonly DR_ITEM_VARIABLE_NAME_OPTIONNAME_DEFAULT = 'it'; public static readonly DR_ITEM_INDEX_VARIABLE_NAME_OPTIONNAME = 'dr-option-item-index-variable-name'; public static readonly DR_ITEM_OFFSET_INDEX_VARIABLE_NAME_OPTIONNAME = 'dr-option-item-offset-index-variable-name'; public static readonly DR_ITEM_INDEX_OFFSET_OPTIONNAME = 'dr-option-item-index-offset'; public static readonly DR_ITEM_INDEX_VARIABLE_NAME_OPTIONNAME_DEFAULT = 'index'; public static readonly DR_ITEM_OFFSET_INDEX_VARIABLE_NAME_OPTIONNAME_DEFAULT = 'offsetIndex'; public static readonly DR_INNER_HTML_NAME_OPTIONNAME = 'dr-option-inner-html-name'; public static readonly DR_INNER_TEXT_NAME_OPTIONNAME = 'dr-option-inner-text-name'; public static readonly DR_INNER_HTML_ESCAPED_NAME_OPTIONNAME = 'dr-option-inner-html-escaped-name'; public static readonly DR_KEY_OPTIONNAME = 'dr-option-key'; public static readonly DR_HAS_KEYS_OPTIONNAME = 'dr-option-has-keys'; public static readonly DR_ON_CREATE_ARGUMENTS_OPTIONNAME = 'dr-on-create:arguments'; public static readonly DR_ON_CREATED_CALLBACK_OPTIONNAME = 'dr-on-create:callback'; public static readonly DR_ON_CONSTRUCTOR_ARGUMENTS_OPTIONNAME = 'dr-on-constructor:arguments'; public static readonly drAttrsOriginName: Attrs = { dr: RawSet.DR_NAME, drIf: RawSet.DR_IF_NAME, drFor: RawSet.DR_FOR_NAME, drForOf: RawSet.DR_FOR_OF_NAME, drThisProperty: RawSet.DR_THIS_PROPERTY_NAME, drAppender: RawSet.DR_APPENDER_NAME, drRepeat: RawSet.DR_REPEAT_NAME, drThis: RawSet.DR_THIS_NAME, drForm: RawSet.DR_FORM_NAME, drPre: RawSet.DR_PRE_NAME, drInnerHTML: RawSet.DR_INNERHTML_NAME, drInnerText: RawSet.DR_INNERTEXT_NAME, drItOption: RawSet.DR_IT_OPTIONNAME, drVarOption: RawSet.DR_VAR_OPTIONNAME, drAfterOption: RawSet.DR_AFTER_OPTIONNAME, drNextOption: RawSet.DR_NEXT_OPTIONNAME, drBeforeOption: RawSet.DR_BEFORE_OPTIONNAME, drCompleteOption: RawSet.DR_COMPLETE_OPTIONNAME, drStripElement: RawSet.DR_STRIP_NAME, drReplaceTargetElementIs: RawSet.DR_REPLACE_TARGET_ELEMENT_IS_NAME, drStripOption: RawSet.DR_STRIP_OPTIONNAME, drIfOption: RawSet.DR_IF_OPTIONNAME, drDetectIfOption: RawSet.DR_DETECT_IF_OPTIONNAME, drDestroyOption: RawSet.DR_DESTROY_OPTIONNAME, drHasKeysOption: RawSet.DR_HAS_KEYS_OPTIONNAME, drKeyOption: RawSet.DR_KEY_OPTIONNAME, drItemIndexOffsetOption: RawSet.DR_ITEM_INDEX_OFFSET_OPTIONNAME, drVariableNameOption: RawSet.DR_VARIABLE_NAME_OPTIONNAME, drItemVariableNameOption: RawSet.DR_ITEM_VARIABLE_NAME_OPTIONNAME, drItemIndexVariableNameOption: RawSet.DR_ITEM_INDEX_VARIABLE_NAME_OPTIONNAME, drItemOffsetIndexVariableNameOption: RawSet.DR_ITEM_OFFSET_INDEX_VARIABLE_NAME_OPTIONNAME }; public static readonly DR_TAGS = []; // public static readonly DR_REPLACE_ACTION_ATTRIBUTES = [ // RawSet.DR_REPLACE_TARGET_ELEMENT_IS_NAME // ] public static readonly DR_ELEMENTS = [RawSet.DR_TARGET_ELEMENT_ELEMENTNAME]; public static readonly DR_ATTRIBUTES = [ RawSet.DR_NAME, RawSet.DR_APPENDER_NAME, RawSet.DR_IF_NAME, RawSet.DR_FOR_OF_NAME, RawSet.DR_THIS_PROPERTY_NAME, RawSet.DR_FOR_NAME, RawSet.DR_THIS_NAME, RawSet.DR_FORM_NAME, RawSet.DR_PRE_NAME, RawSet.DR_INNERHTML_NAME, RawSet.DR_INNERTEXT_NAME, RawSet.DR_REPEAT_NAME, // RawSet.DR_DETECT_NAME, // TODO: DrDetect 오퍼레이터 구현 필요 RawSet.DR_STRIP_NAME ] as const; constructor( public uuid: string, public type: RawSetType, public point: { start: Comment | Text | HTMLMetaElement; node: Node; end: Comment | Text | HTMLMetaElement; innerHTML?: string; // thisVariableName?: string | null, parent?: Node | null; parentRawSet?: RawSet; childrenRawSets?: RawSet[]; }, public dataSet: { config: DomRenderConfig; fragment: DocumentFragment; render?: Render; }, public detect?: { action: Function } ) { // point.start.rawSet = this; // console.log('rawset constructor->', (this.point.node as Element).getAttributeNames()); } get isConnected() { // console.log('isConnect???', this, this.point.start.isConnected, this.point.end.isConnected); return this.point && this.point.start && this.point.end && this.point.start.isConnected && this.point.end.isConnected; } // 중요 getUsingTriggerVariables(config?: DomRenderConfig): Set<string> { const usingTriggerVariables = new Set<string>(); // console.log('------data', this.dataSet) this.dataSet.fragment.childNodes.forEach((cNode, key) => { // console.log('-----aaaa-data', cNode, key) let script = ''; if (cNode.nodeType === Node.TEXT_NODE) { script = `\`${(cNode as Text).textContent ?? ''}\``; const expressionGroups = RawSet.expressionGroups(script); // console.log('???????', script, expressionGroups) if (expressionGroups[0].length > 1) { script = expressionGroups[0][1] as string; } // console.log('--', expressionGroups, script) } else if (cNode.nodeType === Node.ELEMENT_NODE) { const element = cNode as Element; const targetAttrNames = (config?.targetAttrs?.map(it => it.name) ?? []).concat(RawSet.DR_ATTRIBUTES, RawSet.DR_DETECT_FILTER_OPTIONNAME, RawSet.DR_DETECT_IF_OPTIONNAME, RawSet.DR_DETECT_ATTR_OPTIONNAME); // .concat(EventManager.normalAttrMapAttrName); const targetScripts = targetAttrNames .map(it => element.getAttribute(it)) .filter(it => it) .map(it => `(${it})`); const targetAttrMap = element.getAttribute(EventManager.normalAttrMapAttrName); // console.log('targetAttrMap-->', targetAttrMap) if (targetAttrMap) { new Map<string, NormalAttrDataType>(JSON.parse(targetAttrMap)).forEach((v, k) => { const variablePaths = v.variablePaths; // let targetScript = v.originalAttrValue; // variablePaths.forEach(it => { // let r = ObjectUtils.Path.toOptionalChainPath(it.inner); // targetScript = targetScript.replaceAll(it.origin,`\${${r}}`); // }) // targetScripts.push(`(${targetScript})`); // 변수 체크만 하는거니깐 이렇게 variablePaths.forEach(it => targetScripts.push(`(${it.inner})`)); // console.log('targetScripts', targetScripts); }); } // console.log('targetScriptstargetScripts', targetScripts) script = targetScripts.join(';'); // script = targetScripts.map(it=>`try{${it}}catch(e){}`).join(';'); // attribute쪽 체크하는거 추가 // console.log('----!!!!!-->', targetAttrNames) // const otherAttrs = element.getAttributeNames() // .filter(it => !targetAttrNames.includes(it.toLowerCase()) && RawSet.isExporesion(element.getAttribute(it))) // .map(it => { // return `\`${element.getAttribute(it) ?? ''}\``; // }).join(';'); // script += ';' + otherAttrs } if (script) { // console.log('------1-',script) script = script.replace(/#[^#]*#/g, '({})'); // console.log('------2-',script) // script = script.replace('}$','}'); // script = script.replace('@this@','this'); // console.log('----------->', script) // TODO: 훔.. 꼭필요한가..? 트리거될때 스크립트변수 까지 감지해야될까? EventManager.VARNAMES.forEach(it => { // script = script.replace(RegExp(it.replace('$', '\\$'), 'g'), `this?.___${it}`); // script = script.replace(RegExp(it.replace('$', '\\$'), 'g'), `this.___${it}`); script = script.replace(RegExp(it.replace('$', '\\$'), 'g'), `this.___${it}`); // console.log('scripts-->', script) }); // console.log('--------1--', script); // script = script.replaceAll('#{','${').replaceAll('}#', '}') // console.log('--------2--', script); // TODO: 훔.. 꼭필요한가..? 트리거될때 스크립트변수 까지 감지해야될까? Array.from(ObjectUtils.Path.detectPathFromScript(script, { excludeThis: true })) .filter(it => !it.startsWith(`___${EventManager.SCRIPTS_VARNAME}`)) .forEach(it => usingTriggerVariables.add(it)); } }); // console.log('usingTriggerVariable----------->', usingTriggerVariables) return usingTriggerVariables; } // 중요 render 처리 부분 // public async render(obj: any, config: DomRenderConfig): Promise<RawSet[]> { // } private lastRenderedValue: string | undefined; public async render(obj: any, config: DomRenderConfig): Promise<RenderResult> { // console.log('render!!!!!!!!!!!!!!') // renderCnt++; // const t0 = performance.now(); // console.group('RawSet render', this); // Dirty Checking Optimization for Text Nodes if (this.dataSet.fragment.childNodes.length === 1 && this.dataSet.fragment.childNodes[0].nodeType === Node.TEXT_NODE) { const textContent = this.dataSet.fragment.childNodes[0].textContent; if (textContent) { const runText = RawSet.expressionGroups(textContent)[0][1]; const __render = { rawSet: this, scripts: EventManager.setBindProperty(config?.scripts, obj), router: config?.router, range: Range.range, element: this.dataSet.fragment.childNodes[0], attribute: {}, rootObject: obj, scriptUtils: ObjectUtils.Script, nearThis: this.findNearThis(obj), parentThis: this.findParentThis(obj), bindScript: ` /** render **/ const ${EventManager.SCRIPTS_VARNAME} = this.__render.scripts; const ${EventManager.RAWSET_VARNAME} = this.__render.rawSet; const ${EventManager.ELEMENT_VARNAME} = this.__render.element; const ${EventManager.ATTRIBUTE_VARNAME} = this.__render.attribute; const ${EventManager.RANGE_VARNAME} = this.__render.range; const ${EventManager.ROUTER_VARNAME} = this.__render.router; const ${EventManager.NEAR_THIS_VARNAME} = this.__render.nearThis; const ${EventManager.PARENT_THIS_VARNAME} = this.__render.parentThis; const ${EventManager.SCRIPT_UTILS_VARNAME} = this.__render.scriptUtils; const ${EventManager.ROOT_OBJECT_VARNAME} = this.__render.rootObject; ` }; try { const newValue = ObjectUtils.Script.evaluateReturn( { bodyScript: __render.bindScript, returnScript: runText }, Object.assign(obj, { __render }) ); const newValueStr = String(newValue); if (this.lastRenderedValue === newValueStr) { // console.log('✓ Skipping render: Value unchanged', newValue); return { raws: [], executedOperators: [] }; } // console.log('✗ Rendering: Value changed', this.lastRenderedValue, '->', newValue); // Update lastRenderedValue BEFORE proceeding with render // This ensures the value is cached even if render fails partway through this.lastRenderedValue = newValueStr; } catch (e) { // Evaluation failed, proceed with normal render // console.log('⚠ Dirty check failed, proceeding with render', e); } } } const genNode = config.window.document.importNode(this.dataSet.fragment, true); const raws: RawSet[] = []; const onAttrInitCallBacks: AttrInitCallBack[] = []; const onElementInitCallBacks: ElementInitCallBack[] = []; const onThisComponentSetCallBacks: ComponentSet[] = []; const drAttrs: Attrs[] = []; // console.log('rawSet render!!', obj, config, this, Array.from(genNode.childNodes.values())); const executedOperators: OperatorExecuter[] = []; for (const cNode of Array.from(genNode.childNodes.values())) { // console.log('cNodecNodecNode', cNode); let attribute = {}; if (cNode.nodeType === Node.ELEMENT_NODE) { attribute = ElementUtils.getAttributeToObject(cNode as Element); } const __render = Object.freeze({ rawSet: this, scripts: EventManager.setBindProperty(config?.scripts, obj), router: config?.router, range: Range.range, element: cNode, attribute: attribute, rootObject: obj, scriptUtils: ObjectUtils.Script, nearThis: this.findNearThis(obj), parentThis: this.findParentThis(obj), bindScript: ` /** render **/ const ${EventManager.SCRIPTS_VARNAME} = this.__render.scripts; const ${EventManager.RAWSET_VARNAME} = this.__render.rawSet; const ${EventManager.ELEMENT_VARNAME} = this.__render.element; const ${EventManager.ATTRIBUTE_VARNAME} = this.__render.attribute; const ${EventManager.RANGE_VARNAME} = this.__render.range; const ${EventManager.ROUTER_VARNAME} = this.__render.router; const ${EventManager.NEAR_THIS_VARNAME} = this.__render.nearThis; const ${EventManager.PARENT_THIS_VARNAME} = this.__render.parentThis; const ${EventManager.SCRIPT_UTILS_VARNAME} = this.__render.scriptUtils; const ${EventManager.ROOT_OBJECT_VARNAME} = this.__render.rootObject; ` }) as unknown as Render; // const normalAttribute = attribute[EventManager.normalAttrMapAttrName]; // if (normalAttribute) { // new Map<string, string>(JSON.parse(normalAttribute)).forEach((v, k) => { // const cval = ScriptUtils.evalReturn({ bodyScript: __render.bindScript, returnScript: v }, Object.assign(obj, { __render: __render })); // console.log('-----------',v,k, cval); // attribute[v] = cval; // }); // } const fag = config.window.document.createDocumentFragment(); if (cNode.nodeType === Node.TEXT_NODE && cNode.textContent) { // console.log('text-->', this, obj, config, cNode.textContent); // console.log('text-->', Array.from(this.fragment.childNodes)) const textContent = cNode.textContent; const runText = RawSet.expressionGroups(textContent)[0][1]; // console.log('--->', RawSet.exporesionGrouops(textContent), textContent,runText, runText[0][1]) let newNode: Node; if (textContent?.startsWith('#')) { const r = ObjectUtils.Script.evaluateReturn({ bodyScript: __render.bindScript, returnScript: runText }, Object.assign(obj, { __render })); const template = config.window.document.createElement('template') as HTMLTemplateElement; template.innerHTML = r; newNode = template.content; } else { const r = ObjectUtils.Script.evaluateReturn({ bodyScript: __render.bindScript, returnScript: runText }, Object.assign(obj, { __render })); newNode = config.window.document.createTextNode(r); } cNode.parentNode?.replaceChild(newNode, cNode); // console.log('-------', this.point.start.parentNode.nodeName) // 중요 style value change 됐을때 다시 처리해야되기떄문에: 마지막에 completed 없는 attr 가지고 판단 하니깐 if (this.type === RawSetType.STYLE_TEXT && this.point.parent) { (this.point.parent as Element).removeAttribute('completed'); } } else if (cNode.nodeType === Node.ELEMENT_NODE) { const element = cNode as Element; // console.log('target-->', element) const drAttr: Attrs = { dr: this.getAttributeAndDelete(element, RawSet.DR_NAME), drIf: this.getAttributeAndDelete(element, RawSet.DR_IF_NAME), drFor: this.getAttributeAndDelete(element, RawSet.DR_FOR_NAME), drForOf: this.getAttributeAndDelete(element, RawSet.DR_FOR_OF_NAME), drThisProperty: this.getAttributeAndDelete(element, RawSet.DR_THIS_PROPERTY_NAME), drAppender: this.getAttributeAndDelete(element, RawSet.DR_APPENDER_NAME), drRepeat: this.getAttributeAndDelete(element, RawSet.DR_REPEAT_NAME), drThis: this.getAttributeAndDelete(element, RawSet.DR_THIS_NAME), drForm: this.getAttributeAndDelete(element, RawSet.DR_FORM_NAME), drPre: this.getAttributeAndDelete(element, RawSet.DR_PRE_NAME), drInnerHTML: this.getAttributeAndDelete(element, RawSet.DR_INNERHTML_NAME), drInnerText: this.getAttributeAndDelete(element, RawSet.DR_INNERTEXT_NAME), drStripElement: this.getAttributeAndDelete(element, RawSet.DR_STRIP_NAME), drReplaceTargetElementIs: this.getAttributeAndDelete(element, RawSet.DR_REPLACE_TARGET_ELEMENT_IS_NAME), drItOption: this.getAttributeAndDelete(element, RawSet.DR_IT_OPTIONNAME), drIfOption: this.getAttributeAndDelete(element, RawSet.DR_IF_OPTIONNAME), drVarOption: this.getAttributeAndDelete(element, RawSet.DR_VAR_OPTIONNAME), drNextOption: this.getAttributeAndDelete(element, RawSet.DR_NEXT_OPTIONNAME), drAfterOption: this.getAttributeAndDelete(element, RawSet.DR_AFTER_OPTIONNAME), drBeforeOption: this.getAttributeAndDelete(element, RawSet.DR_BEFORE_OPTIONNAME), drCompleteOption: this.getAttributeAndDelete(element, RawSet.DR_COMPLETE_OPTIONNAME), drStripOption: this.getAttributeAndDelete(element, RawSet.DR_STRIP_OPTIONNAME), drDestroyOption: this.getAttributeAndDelete(element, RawSet.DR_DESTROY_OPTIONNAME), drKeyOption: this.getAttributeAndDelete(element, RawSet.DR_KEY_OPTIONNAME), drDetectIfOption: this.getAttribute(element, RawSet.DR_DETECT_IF_OPTIONNAME), drHasKeysOption: this.getAttribute(element, RawSet.DR_HAS_KEYS_OPTIONNAME), drItemIndexOffsetOption: this.getAttributeAndDelete(element, RawSet.DR_ITEM_INDEX_OFFSET_OPTIONNAME), drVariableNameOption: this.getAttributeAndDelete(element, RawSet.DR_VARIABLE_NAME_OPTIONNAME), drItemVariableNameOption: this.getAttributeAndDelete(element, RawSet.DR_ITEM_VARIABLE_NAME_OPTIONNAME), drItemIndexVariableNameOption: this.getAttributeAndDelete(element, RawSet.DR_ITEM_INDEX_VARIABLE_NAME_OPTIONNAME), drItemOffsetIndexVariableNameOption: this.getAttributeAndDelete(element, RawSet.DR_ITEM_OFFSET_INDEX_VARIABLE_NAME_OPTIONNAME) }; drAttrs.push(drAttr); // 아래 순서 중요 const operators = [ new DrPre(this, __render, { raws, fag }, { element, attrName: RawSet.DR_PRE_NAME, attr: drAttr.drPre, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drPre }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new Dr(this, __render, { raws, fag }, { element, attrName: RawSet.DR_NAME, attr: drAttr.dr, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.dr }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), // new Dr(this, __render, {raws, fag}, {element, attrName: EventManager.onRenderedInitAttrName, attr: drAttr.dr, attrs: drAttr}, {config, obj, operatorAround: config.operatorAround?.dr}, {onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks}), new DrIf(this, __render, { raws, fag }, { element, attrName: RawSet.DR_IF_NAME, attr: drAttr.drIf, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drIf }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrStripElement(this, __render, { raws, fag }, { element, attrName: RawSet.DR_STRIP_NAME, attr: drAttr.drStripElement, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drThis }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrThis(this, __render, { raws, fag }, { element, attrName: RawSet.DR_THIS_NAME, attr: drAttr.drThis, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drThis }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrForm(this, __render, { raws, fag }, { element, attrName: RawSet.DR_FOR_NAME, attr: drAttr.drForm, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drForm }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrInnerText(this, __render, { raws, fag }, { element, attrName: RawSet.DR_INNERTEXT_NAME, attr: drAttr.drInnerText, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drInnerText }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrInnerHTML(this, __render, { raws, fag }, { element, attrName: RawSet.DR_INNERHTML_NAME, attr: drAttr.drInnerHTML, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drInnerHTML }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrFor(this, __render, { raws, fag }, { element, attrName: RawSet.DR_FOR_NAME, attr: drAttr.drFor, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drFor }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrForOf(this, __render, { raws, fag }, { element, attrName: RawSet.DR_FOR_OF_NAME, attr: drAttr.drForOf, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drForOf }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrThisProperty(this, __render, { raws, fag }, { element, attrName: RawSet.DR_THIS_PROPERTY_NAME, attr: drAttr.drThisProperty, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drThisProperty }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrAppender(this, __render, { raws, fag }, { element, attrName: RawSet.DR_APPENDER_NAME, attr: drAttr.drAppender, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drAppender }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrRepeat(this, __render, { raws, fag }, { element, attrName: RawSet.DR_REPEAT_NAME, attr: drAttr.drRepeat, attrs: drAttr }, { config, obj, operatorAround: config.operatorAround?.drRepeat }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrTargetElementIsElement(this, __render, { raws, fag }, { element, attrName: RawSet.DR_REPLACE_TARGET_ELEMENT_IS_NAME, attr: drAttr.drReplaceTargetElementIs, attrs: drAttr }, { config, obj }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrTargetElement(this, __render, { raws, fag }, { element, attrs: drAttr }, { config, obj }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }), new DrTargetAttr(this, __render, { raws, fag }, { element, attrs: drAttr }, { config, obj }, { onAttrInitCallBacks, onElementInitCallBacks, onThisComponentSetCallBacks }) ]; for (const operator of operators) { const state = await operator.start(); if (state === ExecuteState.EXECUTE) { executedOperators.push(operator); break; } else if (state === ExecuteState.STOP) { return { raws, executedOperators }; } } } } this.point.childrenRawSets = raws; raws.forEach(it => { it.point.parentRawSet = this; }); // console.log('pppppppppppppp', this); // replaceBody와 applyEvent 순서를 바꿨다 20250511 const childrenNodes = Array.from(genNode.childNodes); // console.log(`RawSet aa took ${performance.now() - t0} milliseconds. children`, childrenNodes); this.applyEvent(obj, genNode, config); // console.log(`RawSet xxxxxxxxxx took ${performance.now() - t0} milliseconds.`); this.replaceBody(genNode); // 중요 여기서 마지막에 연션된 값을 그려준다. // console.log(`RawSet replaceBody took ${performance.now() - t0} milliseconds.`); // console.log('rawSEt!!!!!!!', obj, this.near) // console.log('rawSEt!!!!!!!', obj, this.findNearThis(obj),childrenNodes,config) // console.log('rawSEt!!!!!!!', obj, drAttrs) this.onRenderedEvent(obj, childrenNodes, config); // console.log(`RawSet onRenderedEvent took ${performance.now() - t0} milliseconds.`); drAttrs.forEach(it => { if (it.drCompleteOption) { // genNode.childNodes const render = Object.freeze({ rawSet: this, fag: genNode, scripts: EventManager.setBindProperty(config?.scripts, obj) } as Render); ObjectUtils.Script.evaluate( ` const ${EventManager.FAG_VARNAME} = this.__render.fag; const ${EventManager.SCRIPTS_VARNAME} = this.__render.scripts; const ${EventManager.RAWSET_VARNAME} = this.__render.rawSet; ${it.drCompleteOption}`, Object.assign(obj, { __render: render }) ); } }); // console.log(`RawSet drAttrs.forEach took ${performance.now() - t0} milliseconds.`); // 중요 style isolation 나중에 :scope로 대체 가능할듯. // 2023.9.4일 없앰 style 처음들어올때 처리하는걸로 바꿈 // RawSet.generateStyleSheetsLocal(config); for (const it of onThisComponentSetCallBacks) { if (isOnInitRender(it.obj)) { await it.obj?.onInitRender?.({}, this); } } // console.log(`RawSet const it of onThisComponentSetCallBacks took ${performance.now() - t0} milliseconds.`); for (const it of onElementInitCallBacks) { if (isOnInitRender(this.dataSet.render?.currentThis)) { // TODO: 나중에 파라미터 들어가야될듯. 지금은 리팩토링하느라 빠짐 // console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!', it, this.dataSet); // dr-on-init:arguments // if (isOnInitRender()) { // it.targetElement.__render.component.onInitRender?.(...param); // } // if (it.targetElement?.__render?.element && it.targetElement?.__render?.component) { // const oninit = it.targetElement.__render.element.getAttribute(RawSet.DR_ON_INIT_ARGUMENTS_OPTIONNAME); // dr-on-component-init // let param = []; // if (oninit) { // const script = `${it.targetElement.__render.renderScript} return ${oninit} `; // param = ScriptUtils.eval(script, Object.assign(obj, { // __render: it.targetElement.__render // })); // if (!Array.isArray(param)) { // param = [param]; // } // } // // if (isOnInitRender(it.targetElement.__render.component)) { // it.targetElement.__render.component.onInitRender?.(...param); // } // } await this.dataSet.render.currentThis.onInitRender({}, this); } config?.onElementInit?.(it.name, obj, this, it.targetElement); } // console.log(`RawSet for (const it of onElementInitCallBacks) { took ${performance.now() - t0} milliseconds.`); // TODO: 이부분도 위에 targetElement 처럼 해야될까? for (const it of onAttrInitCallBacks) { config?.onAttrInit?.(it.attrName, it.attrValue, obj, this); } // console.log(`RawSet for (const it of onAttrInitCallBacks) { took ${performance.now() - t0} milliseconds.`); // component destroy if (obj[DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY]) { Object.entries(obj[DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY]).forEach(([key, value]) => { const rawSet = (value as any).__rawSet as RawSet; const drAttrs: Attrs | undefined = rawSet?.dataSet.render?.attribute; if (rawSet && !rawSet.isConnected) { const destroyOptions = drAttrs?.drDestroyOption?.split(',') ?? []; RawSet.destroy(obj[DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY][key], { rawSet: rawSet }, config, destroyOptions); delete obj[DomRenderComponentMetaKey.DOMRENDER_COMPONENTS_KEY][key]; } }); } // console.log(`RawSet if (obj.__domrender_components) { took ${performance.now() - t0} milliseconds.`); // console.log('-------raws',raws) // console.log(`RawSet render took ${performance.now() - t0} milliseconds. END!!`, renderCnt); console.groupEnd(); return { raws: raws, executedOperators: executedOperators }; } // 중요 스타일 적용 부분 private static generateRuleSelector(start: string, end: string, sit: string) { const selectorText = `:is(${start} ~ *:not(${start} ~ ${end} ~ *))`; if (sit.startsWith('## ')) { return sit.replace(/^## /, ''); } else if (sit.startsWith('.')) { return `${selectorText}${sit}, ${selectorText} ${sit}`; } else if (sit.includes('::')) { const reg = sit.match(/(.*)::(.*)$/); const first = reg?.[1]; const extracted = reg?.[2]; const divText = `${start} ~ ${first}:not(${start} ~ ${end} ~ *)`; return `${selectorText} ${first}, ${divText}::${extracted}`; } else { const divText = `${start} ~ ${sit}:not(${start} ~ ${end} ~ *)`; return `${selectorText} ${sit}, ${divText}`; } } public static generateStyleTransform(styleBody: string | string[], componentKey: string, styleTagWrap = true) { // console.log('style!!!!!!!!!!!!!!!!1', styleBody, componentKey, styleTagWrap); if (Array.isArray(styleBody)) { styleBody = styleBody.join('\n'); } styleBody = styleBody.replaceAll('#uuid#', componentKey); const { cleanedCss, importRules } = RawSet.extractCssImports(styleBody); styleBody = cleanedCss; const start = `#${componentKey}-start`; const end = `#${componentKey}-end`; // 이거뭐하는지 까먹었네 뭐였지??.. // 동적으로 처리하는것같은데.. css 에서는 동적으로 처리하는걸 지향 해야될것같은데 이기능 deprecated 할지 고민중 // const before = StringUtils.regexExecArrayReplace(styleBody, /(\$\{.*?\}\$)/g, (data) => { // // console.log('동적?', `var(--domrender-${data[0]})`) // return `var(--domrender-${data[0]})`; // }); // const before = styleBody; // console.log('before@@@@@@@@@@@', before) const cssParser = new CssParser(styleBody); const processRule = (rule: CssRule) => { if (isStyleRule(rule)) { const isRoot = rule.selector.includes(':root'); if (!isRoot) { // Handle comma-separated selectors const selectors = rule.selector.split(',').map(s => s.trim()); const transformedSelectors = selectors.map(selector => this.generateRuleSelector(start, end, selector)); rule.selector = transformedSelectors.join(', '); } } else if (isAtRule(rule)) { if (rule.name === 'media') { const hasRoot = rule.children.some(childRule => isStyleRule(childRule) && childRule.selector.includes(':root')); if (!hasRoot) { rule.children.forEach(childRule => { if (isStyleRule(childRule)) { const selectors = childRule.selector.split(',').map(s => s.trim()); const transformedSelectors = selectors.map(selector => this.generateRuleSelector(start, end, selector)); childRule.selector = transformedSelectors.join(', '); } }); } } } }; cssParser.rules.forEach(processRule); let after = cssParser.stringify(); // let after = StringUtils.regexExecArrayReplace(stringify as string, /(var\(--domrender-(\$\{.*?\}\$)?\))/g, (data) => { // return data[2]; // }); // console.log('after@@@@@@@@@@@', after) // 여기서 선언 selector 자체에도 처리가능하도록 한다 20250518 after = after.replaceAll('/*$', '${'); after = after.replaceAll('$*/', '}$'); if (importRules.length) { after = `${importRules.join('\n')}\n${after}`; } if (styleTagWrap) { styleBody = `<style id='${componentKey}-style' domstyle>${after}</style>`; } // console.log('style!!!!!!!!!!!!!!2', styleBody); return styleBody; } private static extractCssImports(styleBody: string) { const importRules: string[] = []; let result = ''; let i = 0; while (i < styleBody.length) { const importIndex = styleBody.indexOf('@import', i); if (importIndex === -1) { result += styleBody.slice(i); break; } result += styleBody.slice(i, importIndex); let j = importIndex + '@import'.length; let inSingleQuote = false; let inDoubleQuote = false; let parenDepth = 0; while (j < styleBody.length) { const ch = styleBody[j]; if (ch === '\\') { j += 2; continue; } if (!inDoubleQuote && ch === "'") { inSingleQuote = !inSingleQuote; } else if (!inSingleQuote && ch === '"') { inDoubleQuote = !inDoubleQuote; } else if (!inSingleQuote && !inDoubleQuote) { if (ch === '(') { parenDepth += 1; } else if (ch === ')' && parenDepth > 0) { parenDepth -= 1; } else if (ch === ';' && parenDepth === 0) { j += 1; break; } } j += 1; } const importRule = styleBody.slice(importIndex, j).trim(); if (importRule) { importRules.push(importRule); } i = j; } return { cleanedCss: result, importRules }; } public applyEvent(obj: any, fragment = this.dataSet.fragment, config?: DomRenderConfig) { // const t0 = performance.now(); this.dataSet.config.eventManager.applyEvent(obj, this.dataSet.config.eventManager.findAttrElements(fragment, config), config); // console.log(`RawSet applyEvent took ${performance.now() - t0} milliseconds.`); } public onRenderedEvent(obj: any, nodes: Node[], config?: DomRenderConfig) { this.dataSet.config.eventManager.onRenderedEvent(obj, nodes, config); } public getAttribute(element: Element, attr: string) { const data = element.getAttribute(attr); return data; } public getAttributeAndDelete(element: Element, attr: string) { const data = element.getAttribute(attr); // if (data) // element.setAttribute(`origin-${attr}`, data); element.removeAttribute(attr); return data; } public getDrAppendAttributeAndDelete(element: Element, obj: any) { let data = element.getAttribute(RawSet.DR_APPENDER_NAME); // if (data && !/\[[0-9]+\]/g.test(data)) { if (data && !/\[.+\]/g.test(data)) { const currentIndex = ObjectUtils.Script.evaluateReturn(`${ObjectUtils.Path.toOptionalChainPath(data)}?.length -1`, obj); // console.log('------?', currentIndex) // if (currentIndex === undefined || isNaN(currentIndex)) { // return undefined; // } // const currentIndex = ScriptUtils.evalReturn(`${data}.length`, obj); data = `${data}[${currentIndex}]`; element.setAttribute(RawSet.DR_APPENDER_NAME, data); // element.setAttribute(RawSet.DR_IF_NAME, data); // element.setAttribute('dr-id', data); // console.log('-->', element) } // if (data && !/\.childs\[[0-9]+\]/g.test(data)) { // const currentIndex = ScriptUtils.evalReturn(`${data}.currentIndex`, obj); // data = `${data}.childs[${currentIndex}]`; // element.setAttribute(RawSet.DR_APPENDER_NAME, data) // } element.removeAttribute(RawSet.DR_APPENDER_NAME); return data; } public replaceBody(genNode: Node) { this.childAllRemove(); this.point.start.parentNode?.insertBefore(genNode, this.point.start.nextSibling); // 중요 start checkpoint 다음인 end checkpoint 앞에 넣는다. 즉 중간 껴넣기 (나중에 meta tag로 변경을 해도될듯하긴한데..) } // 중요 important public static checkPointCreates(element: Node, obj: any, config: DomRenderConfig): RawSet[] { // console.log('!@@@@@@@@@@@@@@@@', obj); // const NodeFilter = (config.window as any).NodeFilter; // const thisVariableName = (element as any).__domrender_this_variable_name; // let html = element instanceof DocumentFragment ? ElementUtils.toInnerHTML(element, {document: config.window.document}) : (element as HTMLElement).outerHTML; // console.log('==============html-->', element, html); const NodeFilter = (config.window as any).NodeFilter; const Node = (config.window as any).Node; const processedNodes = new Set<Node>(); const findNodes = NodeUtils.findNodes(element, node => { // console.log('nodeType', node.nodeType, node, (node as any).tagName, (node as any).data); // for (const processedNode of processedNodes) { // console.log('pre check!!', Array.from(processedNodes),processedNode !== node , processedNode.contains(node)); // // if(processedNode.contains(node)){ // console.log('---prechecker--html', (processedNode as HTMLElement).outerHTML,'------', (node as HTMLElement).outerHTML); // // } // if (processedNode !== node && processedNode.contains(node)) { // console.log('acceptNodeReturn contain', NodeFilter.FILTER_REJECT); // return NodeFilter.FILTER_REJECT; // } // } if (node.nodeType === Node.TEXT_NODE) { // console.log('nodeText--->', node.textContent) // console.log('????????', node.parentElement, node.parentElement?.getAttribute('dr-pre')); // console.log('???????/',node.textContent, node.parentElement?.getAttribute('dr-pre')) // TODO: 나중에 // const between = StringUtils.betweenRegexpStr('[$#]\\{', '\\}', StringUtils.deleteEnter((node as Text).data ?? '')) const between = RawSet.expressionGroups(StringUtils.deleteEnter((node as Text).data ?? '')); // console.log('bbbb', between) const r = between?.length > 0 ? NodeUtils.FindNodesFilterResult.MATCH_AND_SKIP_CHILDREN : NodeUtils.FindNodesFilterResult.NO_MATCH_AND_SKIP_CHILDREN; // console.log('acceptNodeReturn node', r); return r; // return /\$\{.*?\}/g.test(StringUtils.deleteEnter((node as Text).data ?? '')) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; // return /[$#]\{.*?\}/g.test(StringUtils.deleteEnter((node as Text).data ?? '')) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; } else if (node.nodeType === Node.ELEMENT_NODE) { const element = node as Element; // if (typeof Window === 'undefined' && element.getAttribute('ttt') === 'visual') { // return NodeFilter.FILTER_REJECT; // } // console.log('nodeHTML-->', element.outerHTML); if (element.hasAttribute(RawSet.DR_PRE_NAME)) { let r = NodeUtils.FindNodesFilterResult.NO_MATCH_AND_SKIP_CHILDREN; // console.log('acceptNodeReturn', r); return r; } if (element.hasAttribute(EventManager.attrAttrName)) { // console.log('elementAttrAttrName-->', element.outerHTML); const script = element.getAttribute(EventManager.attrAttrName) ?? ''; // console.log('scriptscriptscriptscriptscriptscript,', script) // const keyValuePairs = Array.from(script.matchAll(/['"]?(\w+)['"]?:\s*([^,}]+)/g)) const keyValuePairs = Array.from(script.matchAll(/['"]?([\w-_]+)['"]?:\s*([^,}]+)/g)).map(match => ({ key: match[1], value: match[2] })); (keyValuePairs ?? []).forEach(it => { element.setAttribute(it.key, '${' + it.value + '}$'); }); } // element.setAttribute('dr-event-click', 'console.log(11)'); const targetElementIs = element.getAttribute(RawSet.DR_REPLACE_TARGET_ELEMENT_IS_NAME); const targetElementNames = config.targetElements?.map(it => it.name.toLowerCase()) ?? []; targetElementNames.push(...RawSet.DR_ELEMENTS); const isElement = targetElementNames.includes(element.tagName.toLowerCase()) || targetElementNames.includes(targetElementIs?.toLowerCase() as any); // if (isElement) { // (element as HTMLElement).style.display = 'none'; // (element as HTMLElement).style.width = '100px'; // (element as HTMLElement).style.height = '100px'; // console.log((element as HTMLElement).outerHTML) // } // console.log('------targetElementIstargetElementIs>', targetElementNames, '---', isElement, targetElementIs); // const targetAttrNames = (config.targetAttrs?.map(it => it.name) ?? []).concat([...RawSet.DR_ATTRIBUTES,...EventManager.RAWSET_CHECK_ATTRIBUTE]); const targetAttrNames = (config.targetAttrs?.map(it => it.name) ?? []).concat([...RawSet.DR_ATTRIBUTES]); const normalAttrs = new Map<string, NormalAttrDataType>(); const linkVariables = new Map<string, string>(); const linkNames = EventManager.linkAttrs.map(it => it.name); const isAttr = element .getAttributeNames() .filter(it => !EventManager.noDetectAttr.includes(it)) .filter(it => { const value = element.getAttribute(it)?.trim(); // link일때 if (value && linkNames.includes(it)) { linkVariables.set(it, value); } else if (value && RawSet.isExpression(value)) { // 표현식있을떄 const variablePaths: { origin: string; inner: string }[] = RawSet.expressionGroups(value).map(it => ({ origin: it[0].trim(), inner: it[1].trim() })); const isStringTemplate = variablePaths.length > 1 || (variablePaths[0] && variablePaths[0].origin !== value); // normal Attribute 초반에 셋팅해주기. // TODO: 이거 하긴했는데 사이드 이팩트? // let variablePath: string = RawSet.expressionGroups(value)[0][1]; // const originVariable = variablePath; // variablePath = variablePath.replace(/#[^#]*#/g, '({})'); // const optionalChainPath = ObjectUtils.Path.toOptionalChainPath(variablePath); // const cval = ObjectUtils.Script.evaluateReturn(optionalChainPath, Object.assign(obj)); let targetScript = value; variablePaths.forEach(it => { let r = it.inner.replace(/#[^#]*#/g, '({})'); r = ObjectUtils.Path.toOptionalChainPath(r); targetScript = targetScript.replaceAll(it.origin, `\${${r}}`); }); const cval = ObjectUtils.Script.evaluateReturn('`' + targetScript + '`', Object.assign(obj)); if (cval === null) { element.removeAttribute(it); /* TODO: 여기 더 추가되어야될듯 TODO: 훔..... 없어도될듯? * <select dr-event-change="@this@.onMarketChange($event)" class="market-select"> <option>마켓 선택 (${@this@.markets?.length??0}$개)</option> <option dr-for-of="@this@.markets" dr-option-item-variable-name="market" value="${#market#.uuid}$" dr-attr="{selected: #market#.uuid === @this@.marketUUID ? 'selected' : null}"> ${#market#.name}$ </option> </select> */ // } else if ( // !(element.hasAttribute(RawSet.DR_VARIABLE_NAME_OPTIONNAME) || element.hasAttribute(RawSet.DR_ITEM_VARIABLE_NAME_OPTIONNAME) || element.hasAttribute(RawSet.DR_ITEM_INDEX_VARIABLE_NAME_OPTIONNAME)) // ) { // element.setAttribute(it, cval); } else { element.setAttribute(it, cval); } normalAttrs.set(it, { originalAttrValue: value, variablePaths: variablePaths, isStringTemplate }); // normalAttrs.set(it, originVariable); // console.log('normalAttribute', it, variablePath); } // console.log(element.getAttribute(it), attrExpresion); const isTargetAttr = targetAttrNames.includes(it.toLowerCase()); return isTargetAttr; }).length > 0; if (linkVariables.size) { element.setAttribute(EventManager.linkTargetMapAttrName, JSON.stringify(Array.from(linkVariables.entries()))); } // 기본 attribute를 처리하기위해 if (normalAttrs.size) { element.setAttribute(EventManager.normalAttrMapAttrName, JSON.stringify(Array.from(normalAttrs.entries()))); } // if (isElement) { // element.setAttribute('www', '@this@'); // } const r = isAttr || isElement ? NodeUtils.FindNodesFilterResult.MATCH_AND_SKIP_CHILDREN : NodeUtils.FindNodesFilterResult.NO_MATCH_AND_CONTINUE; // console.log('acceptNodeReturn element', r); return r; } const r = NodeUtils.FindNodesFilterResult.NO_MATCH_AND_CONTINUE; // console.log('acceptNodeReturn nothing', r); return r; }); const pars: RawSet[] = []; let currentNode: Node | null; const name = RandomUtils.uuid(); // console.log('name==', name); // eslint-disable-next-line no-cond-assign // while ((currentNode = nodeIterator?.nextNode())) { // console.log('findNodes~~', findNodes); for (const currentNode of