37-mini-vue 解析插值

实现解析插值功能

  1. 我们创建目录并写好测试文件
js 复制代码
import {
    baseParse
} from '../src/parse'
describe("Parse", () => {
    describe("interpolation", () => {
        test('simple interpolation', () => {
            const ast = baseParse("{{message}}")
            // root ast 是整棵树的根节点
            expect(ast.children[0]).toStrictEqual({ // 希望的结构
                type: "interpolation",
                content: {
                    type: "simple_expression",
                    content: "message"
                }
            })
        })
    })
})
  1. 我们简单写一个 baseParse 函数,直接返回我们希望的解构,先让测试不报错
js 复制代码
// compiler-core/src/parse.ts
export function baseParse() {
    return [{ // 希望的结构
        type: "interpolation",
        content: {
            type: "simple_expression",
            content: "message"
        }
    }]
}
  1. 测试已经通过,我们对 baseParse 函数进一步处理
js 复制代码
// 1. 我们对传入的参数进行处理 ✅
export function baseParse(content: string) {
  const context = createParseContext(content) // 将数据放在对象中,方便处理

  // 2. 这里对返回值进行处理 ✅
  return createRoot([
    {
      type: "interpolation",
      content: {
        type: "simple_expression",
        content: "message"
      }
    }
  ])
}

/**
 * 本来直接返回,这里返回一个函数,函数内返回原来的值,方便对返回值,进行一些处理
 * @param content 
 * @returns 
 */
function createParseContext(content) {
  return {
    source: content
  }
}

function createRoot(children) {
  return {
    children
  }
}
  1. 我们已经对现有的函数和数据进行了抽离,我们想要对单条返回对象进行一些操作,于是我们对这里的
    返回值做进一步的处理
js 复制代码
export function baseParse(content: string) {
  const context = createParseContext(content) 
  // 我们将这里传入的参数,再次传入一个函数
  return createRoot(parseChildren(context))
}
// 这里将每条对象数据放入数组中
function parseChildren(context) {
  const nodes: any[] = []
  let node:any
  if(context.source.startsWith('{{')) {
     node = parseInterpolation(context)
  }
  nodes.push(node)
  return nodes
}
// 这里将每条对象数据进行处理
function parseInterpolation(context) {
  return {
    type: "interpolation",
      content: {
      type: "simple_expression",
        content: "message"
    }
  }
}
  1. 我们现在对每条对象数据进行处理
js 复制代码
function parseInterpolation(context) {
  // 插值语法的分隔符
  const openDelimiter = "{{"
  const closeDelimiter = "}}"
  // }} 的下标
  const closeIndex = context.source.indexOf(closeDelimiter, openDelimiter.length)
  /* 将内容向后推, 取 {{ 后面的数据  */
  advanceBy(context, openDelimiter.length)
  // 内容的长度
  const rawContentLength = closeIndex - openDelimiter.length
  // 截取内容 
  const rawContent = context.source.slice(0, rawContentLength)
  // 去掉空格
  const content = rawContent.trim()
  // 插值语法后面拼接的字符串
  advanceBy(context, rawContentLength + closeDelimiter.length)

  return {
    type: NodeTypes.INTERPOLATION, // 这里对一些类型抽离
    content: {
      type: NodeTypes.SIMPLE_EXPRESSION,
      content
    }
  }
}

function advanceBy(context: any, length: number) {
  context.source = context.source.slice(length)
}
// compiler-core/src/ast.ts 类型抽离
export const enum NodeTypes {
  INTERPOLATION,
  SIMPLE_EXPRESSION
}
相关推荐
碳基修炼15 分钟前
排查记:本地 devServer 是 http,浏览器却把 302 重定向升级成了 https
前端·http
步行cgn17 分钟前
Spring p 命名空间注入详解
java·前端·spring
何何____24 分钟前
Vue 生命周期详解
前端·javascript
江米小枣tonylua44 分钟前
TypeScript 全面の拥抱 !Prisma 8 + Electron 升级实战
前端
闪耀之光M781 小时前
npm命令解析
前端
咸鱼老弟1 小时前
AI Agent 的"自主性悖论"——为什么给它的自由度越大,越要配一套更硬的护栏
前端·人工智能
默_笙2 小时前
💫 闭包是个背包:拆解小米前端面试题里的三道"闭包陷阱"
前端·javascript·面试
天若有情6732 小时前
粒子星空背景单页HTML模板|炫酷动态星空特效网页(纯前端)
前端·html·css动画·网页特效·粒子星空·静态网页模版
工业涂料百问2 小时前
【趋势前沿】系列(三)工业涂料国产替代的三个台阶:航空、海工、电子的突破路径与认证壁垒
前端
前端snow2 小时前
ai agent --- agentic RAG
前端