123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- const blank = {
- ' ': true,
- '\n': true,
- '\t': true,
- '\r': true,
- '\f': true
- }
- function Parser () {
- this.styles = []
- this.selectors = []
- }
- /**
- * @description 解析 css 字符串
- * @param {string} content css 内容
- */
- Parser.prototype.parse = function (content) {
- new Lexer(this).parse(content)
- return this.styles
- }
- /**
- * @description 解析到一个选择器
- * @param {string} name 名称
- */
- Parser.prototype.onSelector = function (name) {
- // 不支持的选择器
- if (name.includes('[') || name.includes('*') || name.includes('@')) return
- const selector = {}
- // 伪类
- if (name.includes(':')) {
- const info = name.split(':')
- const pseudo = info.pop()
- if (pseudo === 'before' || pseudo === 'after') {
- selector.pseudo = pseudo
- name = info[0]
- } else return
- }
- // 分割交集选择器
- function splitItem (str) {
- const arr = []
- let i, start
- for (i = 1, start = 0; i < str.length; i++) {
- if (str[i] === '.' || str[i] === '#') {
- arr.push(str.substring(start, i))
- start = i
- }
- }
- if (!arr.length) {
- return str
- } else {
- arr.push(str.substring(start, i))
- return arr
- }
- }
- // 后代选择器
- if (name.includes(' ')) {
- selector.list = []
- const list = name.split(' ')
- for (let i = 0; i < list.length; i++) {
- if (list[i].length) {
- // 拆分子选择器
- const arr = list[i].split('>')
- for (let j = 0; j < arr.length; j++) {
- selector.list.push(splitItem(arr[j]))
- if (j < arr.length - 1) {
- selector.list.push('>')
- }
- }
- }
- }
- } else {
- selector.key = splitItem(name)
- }
- this.selectors.push(selector)
- }
- /**
- * @description 解析到选择器内容
- * @param {string} content 内容
- */
- Parser.prototype.onContent = function (content) {
- // 并集选择器
- for (let i = 0; i < this.selectors.length; i++) {
- this.selectors[i].style = content
- }
- this.styles = this.styles.concat(this.selectors)
- this.selectors = []
- }
- /**
- * @description css 词法分析器
- * @param {object} handler 高层处理器
- */
- function Lexer (handler) {
- this.selector = ''
- this.style = ''
- this.handler = handler
- }
- Lexer.prototype.parse = function (content) {
- this.i = 0
- this.content = content
- this.state = this.blank
- for (let len = content.length; this.i < len; this.i++) {
- this.state(content[this.i])
- }
- }
- Lexer.prototype.comment = function () {
- this.i = this.content.indexOf('*/', this.i) + 1
- if (!this.i) {
- this.i = this.content.length
- }
- }
- Lexer.prototype.blank = function (c) {
- if (!blank[c]) {
- if (c === '/' && this.content[this.i + 1] === '*') {
- this.comment()
- return
- }
- this.selector += c
- this.state = this.name
- }
- }
- Lexer.prototype.name = function (c) {
- if (c === '/' && this.content[this.i + 1] === '*') {
- this.comment()
- return
- }
- if (c === '{' || c === ',' || c === ';') {
- this.handler.onSelector(this.selector.trimEnd())
- this.selector = ''
- if (c !== '{') {
- while (blank[this.content[++this.i]]);
- }
- if (this.content[this.i] === '{') {
- this.floor = 1
- this.state = this.val
- } else {
- this.selector += this.content[this.i]
- }
- } else if (blank[c]) {
- this.selector += ' '
- } else {
- this.selector += c
- }
- }
- Lexer.prototype.val = function (c) {
- if (c === '/' && this.content[this.i + 1] === '*') {
- this.comment()
- return
- }
- if (c === '{') {
- this.floor++
- } else if (c === '}') {
- this.floor--
- if (!this.floor) {
- this.handler.onContent(this.style)
- this.style = ''
- this.state = this.blank
- return
- }
- }
- this.style += c
- }
- module.exports = Parser
|