์ฐธ๊ณ :
์ํคํผ๋์
https://yceffort.kr/2021/05/ast-for-javascript
Abstract Syntax Tree, ํ๊ตญ์ด๋ก '์ถ์ ๊ตฌ๋ฌธ ํธ๋ฆฌ'๋ผ๊ณ ํ๋ค.
ํ๋ก๊ทธ๋จ ์ฝ๋๋ฅผ ํธ๋ฆฌ๊ตฌ์กฐ๋ก ๋ง๋ค์ด ๊ตฌ์กฐํํ ๊ฒฐ๊ณผ๋ฌผ์ด๋ค.
const x = 10;
//์์ ๋ณ์ ์ ์ธ & ์ด๊ธฐํ๋ฌธ์ AST๋ก ๋ค์๊ณผ ๊ฐ์ด ๋ณํ๋ค.
{
"type": "VariableDeclaration", // "์ด๊ฑด ๋ณ์ ์ ์ธ๋ฌธ์ด์ผ"
"kind": "const", // "const ์ข
๋ฅ์ ๋ณ์์ผ"
"declarations": [ // "์ ์ธ๋ ๋ณ์ ๋ชฉ๋ก์ ๋ค์๊ณผ ๊ฐ์"
{
"id": { "name": "x" }, // "๋ณ์ ์ด๋ฆ์ 'x'์ด๊ณ "
"init": { "value": 10 } // "์ด๊ธฐ๊ฐ์ 10์ด์ผ"
}
]
}
function square(n) {
return n * n
}
//์์ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ด ๋ณํ๋๋ค.
//babel ์ปดํ์ผ๋ฌ
{
"type": "Program",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"range": [0, 36],
"errors": [],
"comments": [],
"sourceType": "module",
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"range": [0, 36],
"id": {
"type": "Identifier",
"start": 9,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "square"
},
"range": [9, 15],
"name": "square",
"_babelType": "Identifier"
},
"generator": false,
"async": false,
"expression": false,
"params": [
{
"type": "Identifier",
"start": 16,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 17
},
"identifierName": "n"
},
"range": [16, 17],
"name": "n",
"_babelType": "Identifier"
}
],
"body": {
"type": "BlockStatement",
"start": 18,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 3,
"column": 1
}
},
"range": [18, 36],
"body": [
{
"type": "ReturnStatement",
"start": 22,
"end": 34,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 14
}
},
"range": [22, 34],
"argument": {
"type": "BinaryExpression",
"start": 29,
"end": 34,
"loc": {
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 14
}
},
"range": [29, 34],
"left": {
"type": "Identifier",
"start": 29,
"end": 30,
"loc": {
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 10
},
"identifierName": "n"
},
"range": [29, 30],
"name": "n",
"_babelType": "Identifier"
},
"operator": "*",
"right": {
"type": "Identifier",
"start": 33,
"end": 34,
"loc": {
"start": {
"line": 2,
"column": 13
},
"end": {
"line": 2,
"column": 14
},
"identifierName": "n"
},
"range": [33, 34],
"name": "n",
"_babelType": "Identifier"
},
"_babelType": "BinaryExpression"
},
"_babelType": "ReturnStatement"
}
],
"_babelType": "BlockStatement"
},
"_babelType": "FunctionDeclaration"
}
]
}
์์ฑ ๊ณผ์
- ํ ํฐํ Tokenization
- ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ฌธ๋ฒ ๊ท์น์ ๋ฐ๋ผ ์ฝ๋๋ฅผ ํ ํฐ ๋จ์๋ก ๋ถํด
- ์:ย
const x = 10;
const
: ๋ณ์ ์ ์ธ ํค์๋x
: ๋ณ์๋ช=
: ํ ๋น ์ฐ์ฐ์10
: ๋ฆฌํฐ๋ด ๊ฐ
- ํ์ฑ Parsing
- ํ ํฐ๋ค์ ๋ฌธ๋ฒ ๊ท์น์ ๋ฐ๋ผ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ์กฐํฉ
- ๊ฐ ๋ ธ๋๋ ์ฝ๋์ ์๋ฏธ์ ์์๋ฅผ ๋ํ๋
์ฝ๋๋ฅผ ์ด๋ ๊ฒ ์ชผ๊ฐ์ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ง๋ค์ด์ผ ์ปดํจํฐ๊ฐ ์ฝ๋๋ฅผ ์ดํดํ ์ ์๋ค๊ณ ํ๋ค.
๊ทธ๋์ IDE๋ฅผ ์ฌ์ฉํ ๋ IDE๊ฐ ๋ฏธ๋ฆฌ ๋ฌธ๋ฒ ์ค๋ฅ๋ฅผ ์์์ฐจ๋ฆด ์ ์๊ฒ ๋๋๊ฒ.
๊ทธ๋ฆฌ๊ณ ๊ถ๊ทน์ ์ผ๋ก ์ปดํ์ผ๋ฌ๊ฐ ๊ณ ๊ธ์ด ์ฝ๋๋ฅผ ๊ธฐ๊ณ์ด๋ก ๋ฒ์ญํ๊ณ ํ๋ก๊ทธ๋จ์ด ์ปดํจํฐ์์ ์คํ๋ ์ ์๊ฒ ๋๋ค.
unifiedjs ์์
unified ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ HTML๊ณผ Markdown ์ฝ๋๋ฅผ AST๋ก ๋ณํํ๊ณ , AST๋ฅผ ๋ค์ HTML์ด๋ Markdown ์ฝ๋๋ก ๋ณํํ๋ ๊ณผ์ ์์ ๋ค์ํ ์ฒ๋ฆฌ๋ฅผ ์ํํ ์ ์๋ 500๊ฐ๊ฐ ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ํ๊ณ๋ค.
remark๋ mdํ์ผ์ AST๋ก ๋ค๋ฃฐ ์ ์๊ฒ ํ๊ณ , rehype๋ htmlํ์ผ์ AST๋ก ๋ค๋ฃฐ ์ ์๊ฒ ํ๋ค.
๋ ์ฌ์ด์ ์๋ ๊ณตํต๋ AST์ ๋ํ ๊ท๊ฒฉ์ ํต์ผ(ํธํ)์ ๋ชจ๋ unified๋ผ๋ ์ ์ฒด์ ์ธ ๊ณผ์ ์์์ ์ด๋ฃจ์ด์ง๋ฉด์ ๊ฐ๋ฅํ๊ฒ ๋๋ค.
const processedContent = await remark()
.use(breaks)
.use(remarkMath)
.use(remarkRehype)
.use(rehypeKatex)
.use(rehypeStringify)
.process(matterResult.content);
const contentHTML = processedContent.toString();
์ด๋ ๊ฒ use()
๋ฅผ ํตํด ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๊ธฐ๋ฅ์ ํ๋์ฉ ์ถ๊ฐํด ๊ฐํธํ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.