把html片段编译成选择器嵌套结构
之前写了个vscode插件, 功能是选取一段html片段, 产生对应的css嵌套结构. (描述很有问题, 这2年里我也一直没想明白应该怎么说)
那次写完后写了个总结, 留了几个todo, 现在回头来补一部分.
要解决哪些问题
因为上一版的做法是: 在消费html片段时分析tag, 直接新建了个ret
变量, 在分析的时候直接去拼接字符串了.
上次的博客记录了一些问题:
- 对非法或不完整的html片段没有校验, 所以输出可能也是不完整的.
- 同级别有重复的选择器, 输出的时候没有处理.
- 输出的内容没有格式化.
这些问题只要通过转成ast就都可以解决, 2年前的总结也提到了, 那么现在来简单走一遍ast流程.
因为是场景性的问题, 所以是正常编译流程的超级简化版, 因为输出和输入结构类似, 甚至少了转换ast的步骤.
下面开始, 所有代码都在文章开头的仓库链接中, 文章中不贴代码了.
分析html片段
分析html片段的过程是个有限状态自动机.
我们场景需要的状态很少: 标签开始, 标签结束, 剩下的状态都作为text处理就可以.
从html片段的第一个字符开始消费, 判断状态的类型, 并用正则取出对应的内容, 记录内容和类型, 并将html片段切割掉(消费动作).
构建ast
分析完html片段, 我们会得到一个tokenizer的数组, 元素内容是token类型(如标签开始/标签结束)和元素内容.
(虽然代码中我把这个步骤和构建ast合起来了, 并不重要, 想象已经获得一个tokenizer数组就可以了)
构建ast需要2步: 设计ast, 遍历tokenizer数组, 根据类型和内容生成ast.
ast的设计很简单, 属性有tag, attrs, children.
构建ast我们需要用到一个栈, 在标签开始的时候把当前元素推入栈, 后面的元素就可以挂在栈头元素的children上, 在关闭标签的时候让栈弹出一个就行.
这样, 如果遍历完毕, 栈不为空, 就可以知道html片段不完整.
另外, 在栈弹出的时候, 判断弹出元素的tag是否等于关闭标签的tag也可以判断非法html片段.
transform
构建完ast, 其实就可以利用我们熟悉的js对ast进行任何处理了, 而能解决多少问题或做多少优化, 就看个人算法能力了.
而在transform这步我们要先做的是设计一个函数调用结构, 来方便后续添加功能.
这里想参考babel, 但ast简单所以没这么多生命周期.
就创建一个context传给插件, 让插件可以获取一些状态, 并在遍历ast的合适的时间更新这些状态.
codegen
code generate其实是字符串拼接流程.
有了层级, 代码就可以方便的做缩进了. 这里也维护了个context来让代码调用更舒服, 当然我们的场景只有一种nodetype, 可能过度设计了, 具体代码看文章开头链接.
(本文完)
如果你觉得本文对你有帮助, 你可以请我喝一杯咖啡
本文遵循cc协议
你可以在注明出处和非商用的前提下任意复制及演绎