Skip to content

Commit 62c92cc

Browse files
Fixed Event Bubbling & innerHTML Rendering
1 parent 2d954e9 commit 62c92cc

5 files changed

Lines changed: 53 additions & 33 deletions

File tree

MyNeoApp/compiler/NeoParser.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export class NeoParser {
55
if (scriptMatch) scriptContent = scriptMatch[1].trim();
66

77
// 태그 블록만 추출하기 위해 스크립트 제외
8-
const cleanSource = source.replace(/@Script\s*\{[\s\S]*?\}/, "").trim();
8+
const cleanSource = source.replace(/@Script\s*\{[\s\S]*?\}/, "").trim();
99

1010
const root = this.parseRecursive(cleanSource);
1111
return { root, scriptContent };
@@ -39,21 +39,23 @@ export class NeoParser {
3939

4040
const blockContent = text.substring(startIndex, endIndex - 1);
4141

42+
const contentWithoutChildren = blockContent.replace(/@\w+:\w+\s*\{[\s\S]*?\}/g, "");
43+
4244
// 1. 블록 내부에서 속성 추출 (Innerhtml, Style, Event)
4345
// 줄바꿈과 대소문자를 무시하고 " " 사이의 값을 정확히 가져옴
44-
const htmlMatch = blockContent.match(/Innerhtml:\s*"([\s\S]*?)"/i);
46+
const htmlMatch = blockContent.match(/innerHTML:\s*"([\s\S]*?)"/i);
4547
if (htmlMatch) node.innerHtml = htmlMatch[1].trim();
4648

4749
const styleMatch = blockContent.match(/Style\(([\s\S]*?)\)/i);
4850
if (styleMatch) node.styles = this.parseKV(styleMatch[1]);
4951

50-
const eventMatch = blockContent.match(/Event\(([\s\S]*?)\)/i);
52+
const eventMatch = contentWithoutChildren.match(/Event\(([\s\S]*?)\)/i);
5153
if (eventMatch) node.events = this.parseKV(eventMatch[1]);
5254

5355
// 2. 자식 노드 재귀적 탐색
5456
// 본인의 속성 정의 부분을 제외한 나머지 텍스트에서 자식 탐색
5557
const remainingText = blockContent
56-
.replace(/Innerhtml:\s*"[\s\S]*?"/i, "")
58+
.replace(/innerHTML:\s*"[\s\S]*?"/i, "")
5759
.replace(/Style\(.*?\)/si, "")
5860
.replace(/Event\(.*?\)/si, "");
5961

@@ -64,8 +66,19 @@ export class NeoParser {
6466
const childNode = this.parseRecursive(remainingText.substring(childMatch.index));
6567
if (childNode) {
6668
node.children.push(childNode);
67-
// 중복 탐색 방지를 위해 인덱스 건너뛰기 로직 생략 (현재 구조 최적화)
68-
break; // 예시용 단일 자식 우선 처리, 실제론 루프 최적화 필요
69+
70+
// 자식 노드의 끝 지점을 찾아서 다음 검색 위치를 조정
71+
let braceCount = 1;
72+
let i = remainingText.indexOf('{', childMatch.index) + 1;
73+
74+
while (braceCount > 0 && i < remainingText.length) {
75+
if (remainingText[i] === '{') braceCount++;
76+
else if (remainingText[i] === '}') braceCount--;
77+
i++;
78+
}
79+
80+
// 정규식의 다음 검색 시작 위치를 자식 노드가 끝난 지점(i)으로 옮겨줘
81+
childRegex.lastIndex = i;
6982
}
7083
}
7184

MyNeoApp/compiler/index.js

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,30 @@ try {
2222

2323
// 3. 코드 생성 함수 (재귀 구조)
2424
function generateCode(node, indent = " ") {
25-
const childrenCode = node.children
26-
.map(child => generateCode(child, indent + " "))
27-
.join(',\n');
28-
29-
// 이벤트들을 객체 문자열로 변환
30-
const eventProps = Object.entries(node.events).map(([evt, action]) => {
31-
const propName = `on${evt.charAt(0).toUpperCase() + evt.slice(1)}`;
32-
// $count -> state.count로 치환
33-
let processedAction = action.replace(/\$(\w+)/g, 'state.$1');
34-
return `${propName}: () => { ${processedAction} }`;
35-
}).join(`,\n${indent} `);
36-
37-
return `${indent}h('${node.tag}', {
38-
${indent} id: '${node.id}',
39-
${indent} style: ${JSON.stringify(node.styles)},
40-
${indent} innerHTML: \`${node.innerHtml.replace(/\$(\w+)/g, '${state.$1}')}\`${eventProps ? ',\n' + indent + ' ' + eventProps : ''}
41-
${indent}}, [${childrenCode ? '\n' + childrenCode + '\n' + indent : ''}])`;
42-
}
25+
26+
const textNode = node.innerHtml
27+
? `\`${node.innerHtml.replace(/\$(\w+)/g, '${state.$1}')}\``
28+
: null;
29+
30+
const childrenCode = node.children
31+
.map(child => generateCode(child, indent + " "))
32+
.join(',\n');
33+
34+
const allChildren = [textNode, childrenCode].filter(Boolean).join(',\n');
35+
36+
// 이벤트들을 객체 문자열로 변환
37+
const eventProps = Object.entries(node.events).map(([evt, action]) => {
38+
const propName = `on${evt.charAt(0).toUpperCase() + evt.slice(1)}`;
39+
// $count -> state.count로 치환
40+
let processedAction = action.replace(/\$(\w+)/g, 'state.$1');
41+
return `${propName}: () => { ${processedAction} }`;
42+
}).join(`,\n${indent} `);
43+
44+
return `${indent}h('${node.tag}', {
45+
${indent} id: '${node.id}',
46+
${indent} style: ${JSON.stringify(node.styles)}${eventProps ? ',\n' + indent + ' ' + eventProps : ''}
47+
${indent}}, [${allChildren ? '\n' + allChildren + '\n' + indent : ''}])`;
48+
}
4349

4450
// render 함수 생성 부분
4551
const finalJS = `

MyNeoApp/core/NeoCore.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export function h(tag, props, children = []) {
2727
if (props.style) Object.assign(el.style, props.style);
2828

2929
// 컴파일러가 주는 innerHTML과 파서가 주는 innerHtml 모두 대응
30-
const content = props.innerHTML || props.innerHtml;
31-
if (content !== undefined) {
32-
el.innerHTML = content;
33-
}
30+
// const content = props.innerHTML || props.innerHtml;
31+
// if (content !== undefined) {
32+
// el.innerHTML = content;
33+
// }
3434

3535
Object.keys(props).forEach(key => {
3636
if (key.startsWith('on') && typeof props[key] === 'function') {

MyNeoApp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@junnyontop-pixel/neo-app",
3-
"version": "1.1.13",
3+
"version": "1.1.17",
44
"description": "나만의 커스텀 프레임워크 Neo",
55
"main": "core/NeoCore.js",
66
"type": "module",

MyNeoApp/src/App.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ export default function render(state) {
66
if (state.title === undefined) state.title = "hello, neo";
77

88
return h('button', {
9-
id: 'Btn',
10-
style: {},
11-
innerHTML: `인사하기`,
9+
id: 'Btn',
10+
style: {},
1211
onClick: () => { sayHello( }
13-
}, []);
12+
}, [
13+
`인사하기`
14+
]);
1415
}

0 commit comments

Comments
 (0)