2
0
mirror of https://github.com/tenrok/BBob.git synced 2026-06-14 18:42:24 +03:00

fix(#206): TagNode.create now with null content argument by default (#233)

* fix: TagNode.create with null content by default

* Create five-meals-sing.md

* fix: tests

* fix(preset): types inference

* fix: preset types

* fix: preset types

* fix: lock file, parser and utils

* refactor: move types to separate package

* fix(preset): add @bbob/core to dev deps

* fix(preset): lock file

* test(preset-vue): create tags

* test(preset-vue): tests

* chore(nx): fix nx cover deps

* chore: changesets
This commit is contained in:
Nikolay Kost
2024-06-24 01:32:15 +03:00
committed by GitHub
parent 95d9b8a2ba
commit 270f5645f8
58 changed files with 657 additions and 428 deletions
+6 -5
View File
@@ -3,6 +3,7 @@ import {
CLOSE_BRAKET,
SLASH,
} from '@bbob/plugin-helper';
import type { Token as TokenInterface } from "@bbob/types";
// type, value, line, row,
@@ -87,11 +88,11 @@ const tokenToText = (token: Token) => {
* @export
* @class Token
*/
class Token<TokenValue = string> {
private t: number // type
private v: string // value
private l: number // line
private r: number // row
class Token<TokenValue = string> implements TokenInterface {
readonly t: number // type
readonly v: string // value
readonly l: number // line
readonly r: number // row
constructor(type?: number, value?: TokenValue, row: number = 0, col: number = 0) {
this[TOKEN_LINE_ID] = row;
-1
View File
@@ -2,4 +2,3 @@ export { TagNode } from '@bbob/plugin-helper';
export { default } from './parse';
export * from './parse';
export * from './lexer'
export * from './types'
+29 -19
View File
@@ -10,12 +10,12 @@ import {
EQ,
N,
} from '@bbob/plugin-helper';
import type { LexerOptions, LexerTokenizer } from "@bbob/types";
import {
Token, TYPE_ATTR_NAME, TYPE_ATTR_VALUE, TYPE_NEW_LINE, TYPE_SPACE, TYPE_TAG, TYPE_WORD,
} from './Token';
import { CharGrabber, createCharGrabber, trimChar, unquote } from './utils';
import type { LexerOptions, LexerTokenizer } from "./types";
// for cases <!-- -->
const EM = '!';
@@ -24,15 +24,24 @@ export function createTokenOfType(type: number, value: string, r = 0, cl = 0) {
return new Token(type, value, r, cl)
}
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
const WHITESPACES = [SPACE, TAB];
const SPECIAL_CHARS = [EQ, SPACE, TAB];
const isWhiteSpace = (char: string) => (WHITESPACES.indexOf(char) >= 0);
const isEscapeChar = (char: string) => char === BACKSLASH;
const isSpecialChar = (char: string) => (SPECIAL_CHARS.indexOf(char) >= 0);
const isNewLine = (char: string) => char === N;
const unq = (val: string) => unquote(trimChar(val, QUOTEMARK));
export function createLexer(buffer: string, options: LexerOptions = {}): LexerTokenizer {
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
let row = 0;
let col = 0;
@@ -47,6 +56,7 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
const contextFreeTags = (options.contextFreeTags || [])
.filter(Boolean)
.map((tag) => tag.toLowerCase());
const nestedMap = new Map<string, boolean>();
const onToken = options.onToken || (() => {
});
@@ -54,22 +64,14 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
const NOT_CHAR_TOKENS = [
openTag, SPACE, TAB, N,
];
const WHITESPACES = [SPACE, TAB];
const SPECIAL_CHARS = [EQ, SPACE, TAB];
const isCharReserved = (char: string) => (RESERVED_CHARS.indexOf(char) >= 0);
const isNewLine = (char: string) => char === N;
const isWhiteSpace = (char: string) => (WHITESPACES.indexOf(char) >= 0);
const isCharToken = (char: string) => (NOT_CHAR_TOKENS.indexOf(char) === -1);
const isSpecialChar = (char: string) => (SPECIAL_CHARS.indexOf(char) >= 0);
const isEscapableChar = (char: string) => (char === openTag || char === closeTag || char === BACKSLASH);
const isEscapeChar = (char: string) => char === BACKSLASH;
const onSkip = () => {
col++;
};
const unq = (val: string) => unquote(trimChar(val, QUOTEMARK));
const checkContextFreeMode = (name: string, isClosingTag?: boolean) => {
if (contextFreeTag !== '' && isClosingTag) {
contextFreeTag = '';
@@ -339,8 +341,16 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
function isTokenNested(token: Token) {
const value = openTag + SLASH + token.getValue();
// potential bottleneck
return buffer.indexOf(value) > -1;
if (nestedMap.has(value)) {
return !!nestedMap.get(value);
} else {
const status = (buffer.indexOf(value) > -1)
nestedMap.set(value, status);
return status;
}
}
return {
+3 -19
View File
@@ -1,3 +1,5 @@
import type { NodeContent, TagNodeTree, LexerTokenizer, ParseOptions } from "@bbob/types";
import {
CLOSE_BRAKET,
OPEN_BRAKET,
@@ -7,26 +9,8 @@ import {
import { createLexer } from "./lexer";
import type { NodeContent, TagNodeTree } from "@bbob/plugin-helper";
import type { LexerTokenizer, LexerOptions } from "./types";
import type { Token } from "./Token";
type ParseError = {
tagName: string;
lineNumber: number;
columnNumber: number;
};
export interface ParseOptions {
createTokenizer?: (input: string, options?: LexerOptions) => LexerTokenizer;
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
contextFreeTags?: string[];
enableEscapeTags?: boolean;
onError?: (error: ParseError) => void;
}
class NodeList<Value> {
private n: Value[];
@@ -201,7 +185,7 @@ function parse(input: string, opts: ParseOptions = {}) {
function handleTagStart(token: Token) {
flushTagNodes();
const tagNode = TagNode.create(token.getValue());
const tagNode = TagNode.create(token.getValue(), {}, []);
const isNested = isTokenNested(token);
tagNodes.push(tagNode);
-15
View File
@@ -1,15 +0,0 @@
import type Token from "./Token";
export interface LexerTokenizer {
tokenize: () => Token<string>[];
isTokenNested?: (token: Token<string>) => boolean;
}
export type LexerOptions = {
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
enableEscapeTags?: boolean;
contextFreeTags?: string[];
onToken?: (token?: Token<string>) => void;
};
+9 -1
View File
@@ -35,6 +35,10 @@ export class CharGrabber {
}
getCurr() {
if (typeof this.s[this.c.pos] === 'undefined') {
return ''
}
return this.s[this.c.pos]
}
@@ -51,7 +55,11 @@ export class CharGrabber {
getPrev() {
const prevPos = this.c.pos - 1;
return typeof this.s[prevPos] !== 'undefined' ? this.s[prevPos] : null;
if (typeof this.s[prevPos] === 'undefined') {
return null
}
return this.s[prevPos];
}
isLast() {