UNPKG

@tbela99/css-parser

Version:

CSS parser, minifier and validator for node and the browser

119 lines (116 loc) 4.64 kB
import { EnumToken } from '../../ast/types.js'; import { tokensfuncDefMap, LOC } from '../../syntax/constants.js'; import { equalsIgnoreCase } from './text.js'; function matchGenericSyntax(stream) { const stack = []; let i = 0; let success = true; let expectAndOr = false; let expectComma = false; const errors = []; const scopes = [new Set()]; for (; i < stream.length; i++) { const token = stream[i]; if (token.typ === EnumToken.WhitespaceTokenType || token.typ === EnumToken.CommentTokenType) { continue; } if (token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(token.typ)) { stack.push(token); scopes.push(new Set()); expectAndOr = false; continue; } if (token.typ === EnumToken.EndParensTokenType) { if (stack.length === 0 || (stack.at(-1)?.typ !== EnumToken.StartParensTokenType && !tokensfuncDefMap.has(stack.at(-1)?.typ))) { errors.push({ action: "drop", message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].src}:${token[LOC].sta.lin}:${token[LOC].sta.col}`, node: token, location: token[LOC], }); success = false; break; } stack.pop(); scopes.pop(); // if (scopes.length === 0) { // return { // success: false, // errors: [ // { // action: "drop", // node: token, // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${token[LOC]!.sta.col}`, // location: token[LOC]!, // }, // ], // }; // } continue; } if (token.typ === EnumToken.IdenTokenType && equalsIgnoreCase("and", token.val)) { if (!expectAndOr || scopes.at(-1)?.has(EnumToken.OrTokenType)) { errors.push({ action: "drop", message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].src}:${token[LOC].sta.lin}:${token[LOC].sta.col}`, node: token, location: token[LOC], }); success = false; break; } Object.assign(token, { typ: EnumToken.AndTokenType }); scopes.at(-1).add(EnumToken.AndTokenType); expectComma = false; continue; } if (token.typ === EnumToken.IdenTokenType && equalsIgnoreCase("or", token.val)) { if (!expectAndOr || scopes.at(-1)?.has(EnumToken.AndTokenType)) { errors.push({ action: "drop", message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].src}:${token[LOC].sta.lin}:${token[LOC].sta.col}`, node: token, location: token[LOC], }); success = false; break; } expectComma = false; Object.assign(token, { typ: EnumToken.OrTokenType }); scopes.at(-1).add(EnumToken.OrTokenType); continue; } if (token.typ === EnumToken.CommaTokenType) { if (!expectComma) { errors.push({ action: "drop", message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].src}:${token[LOC].sta.lin}:${token[LOC].sta.col}`, node: token, location: token[LOC], }); success = false; break; } stack.push(token); expectComma = false; continue; } expectAndOr = true; expectComma = true; if (stack.length > 0 && stack.at(-1)?.typ === EnumToken.CommaTokenType) { stack.pop(); } } if (stack.length > 0) { errors.push({ action: "drop", message: `unexpected token ${EnumToken[stack.at(-1)?.typ]} at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, node: stack.at(-1), location: stack.at(-1)?.[LOC], }); success = false; } return { success, errors }; } export { matchGenericSyntax };