ecmarkdown
Advanced tools
Comparing version 5.1.2 to 6.0.0
@@ -6,10 +6,7 @@ export type { OpaqueTagNode, TagNode, CommentNode, AlgorithmNode, TextNode, StarNode, UnderscoreNode, TickNode, TildeNode, PipeNode, FormatNode, UnorderedListNode, OrderedListNode, ListNode, UnorderedListItemNode, OrderedListItemNode, Node, } from './node-types'; | ||
import { Emitter } from './emitter'; | ||
export declare type Options = { | ||
trackPositions?: boolean; | ||
}; | ||
declare let parseFragment: typeof Parser.parseFragment; | ||
declare let parseAlgorithm: typeof Parser.parseAlgorithm; | ||
declare let emit: typeof Emitter.emit; | ||
declare let fragment: (str: string, options?: Options | undefined) => string; | ||
declare let algorithm: (str: string, options?: Options | undefined) => string; | ||
declare let fragment: (str: string) => string; | ||
declare let algorithm: (str: string) => string; | ||
export { parseFragment, parseAlgorithm, visit, emit, fragment, algorithm }; |
@@ -13,5 +13,5 @@ "use strict"; | ||
exports.emit = emit; | ||
let fragment = (str, options) => emitter_1.Emitter.emit(parser_1.Parser.parseFragment(str, options)); | ||
let fragment = (str) => emitter_1.Emitter.emit(parser_1.Parser.parseFragment(str)); | ||
exports.fragment = fragment; | ||
let algorithm = (str, options) => emitter_1.Emitter.emit(parser_1.Parser.parseAlgorithm(str, options)); | ||
let algorithm = (str) => emitter_1.Emitter.emit(parser_1.Parser.parseAlgorithm(str)); | ||
exports.algorithm = algorithm; |
@@ -0,1 +1,5 @@ | ||
declare type ActualOmit<T, K extends string> = T extends unknown ? Omit<T, K> : never; | ||
export declare type Unlocated<T extends { | ||
location: LocationRange; | ||
}> = ActualOmit<T, 'location'>; | ||
export declare type Position = { | ||
@@ -13,3 +17,3 @@ line: number; | ||
done: true; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -20,3 +24,3 @@ export declare type Format = 'star' | 'underscore' | 'tick' | 'pipe' | 'tilde'; | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -26,3 +30,3 @@ export declare type ParabreakToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -32,3 +36,3 @@ export declare type LinebreakToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -38,3 +42,3 @@ export declare type WhitespaceToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -44,3 +48,3 @@ export declare type TextToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -50,3 +54,3 @@ export declare type CommentToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -56,3 +60,3 @@ export declare type OpaqueTagToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -62,3 +66,3 @@ export declare type TagToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -68,3 +72,3 @@ export declare type UnorderedListToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -74,3 +78,3 @@ export declare type OrderedListToken = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -80,3 +84,3 @@ export declare type IdToken = { | ||
value: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -88,3 +92,3 @@ export declare type Token = EOFToken | FormatToken | ParabreakToken | LinebreakToken | WhitespaceToken | TextToken | CommentToken | TagToken | UnorderedListToken | OrderedListToken | OpaqueTagToken; | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -94,3 +98,3 @@ export declare type TagNode = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -100,3 +104,3 @@ export declare type CommentNode = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -106,3 +110,3 @@ export declare type AlgorithmNode = { | ||
contents: OrderedListNode; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -112,3 +116,3 @@ export declare type TextNode = { | ||
contents: string; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -118,3 +122,3 @@ export declare type StarNode = { | ||
contents: FragmentNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -124,3 +128,3 @@ export declare type UnderscoreNode = { | ||
contents: FragmentNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -130,3 +134,3 @@ export declare type TickNode = { | ||
contents: FragmentNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -136,3 +140,3 @@ export declare type TildeNode = { | ||
contents: FragmentNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -145,3 +149,3 @@ export declare type PipeNode = { | ||
contents: null; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -153,3 +157,3 @@ export declare type FormatNode = StarNode | UnderscoreNode | TickNode | TildeNode | PipeNode; | ||
contents: UnorderedListItemNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -161,3 +165,3 @@ export declare type OrderedListNode = { | ||
contents: OrderedListItemNode[]; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -169,3 +173,3 @@ export declare type UnorderedListItemNode = { | ||
id: string | null; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -177,3 +181,3 @@ export declare type OrderedListItemNode = { | ||
id: string | null; | ||
location?: LocationRange; | ||
location: LocationRange; | ||
}; | ||
@@ -183,1 +187,2 @@ export declare type FragmentNode = TextNode | FormatNode | CommentNode | TagNode | OpaqueTagNode; | ||
export declare type Node = OpaqueTagNode | TagNode | CommentNode | AlgorithmNode | TextNode | StarNode | UnderscoreNode | TickNode | TildeNode | PipeNode | UnorderedListNode | OrderedListNode | UnorderedListItemNode | OrderedListItemNode; | ||
export {}; |
@@ -1,3 +0,2 @@ | ||
import type { Position, Token, Format, Node, TextNode, CommentNode, TagNode, FragmentNode, ListNode, OrderedListNode, OrderedListItemNode, UnorderedListItemNode } from './node-types'; | ||
import type { Options } from './ecmarkdown'; | ||
import type { Unlocated, LocationRange, Position, Token, Format, Node, PipeNode, TextNode, CommentNode, TagNode, FragmentNode, OrderedListNode, OrderedListItemNode, UnorderedListItemNode } from './node-types'; | ||
import { Tokenizer } from './tokenizer'; | ||
@@ -9,14 +8,22 @@ declare type ParseFragmentOpts = { | ||
_t: Tokenizer; | ||
_posStack: Position[] | undefined; | ||
constructor(tokenizer: Tokenizer, options?: Options); | ||
static parseAlgorithm(str: string, options?: Options): { | ||
_posStack: Position[]; | ||
constructor(tokenizer: Tokenizer); | ||
static parseAlgorithm(str: string): { | ||
name: "algorithm"; | ||
contents: OrderedListNode; | ||
} & { | ||
location: LocationRange; | ||
}; | ||
static parseFragment(str: string, options?: Options): FragmentNode[]; | ||
static parseFragment(str: string): FragmentNode[]; | ||
parseAlgorithm(): { | ||
name: "algorithm"; | ||
contents: OrderedListNode; | ||
} & { | ||
location: LocationRange; | ||
}; | ||
parseList(): ListNode; | ||
parseList(): (Pick<OrderedListNode, "start" | "contents" | "name" | "indent"> & { | ||
location: LocationRange; | ||
}) | (Pick<import("./node-types").UnorderedListNode, "contents" | "name" | "indent"> & { | ||
location: LocationRange; | ||
}); | ||
parseListItem(kind: 'ol', indent: number): OrderedListItemNode; | ||
@@ -26,10 +33,24 @@ parseListItem(kind: 'ul', indent: number): UnorderedListItemNode; | ||
parseFragment(opts: ParseFragmentOpts, closingFormatKind: Format): (TextNode | CommentNode | TagNode)[]; | ||
parseText(opts: ParseFragmentOpts, closingFormatKind: Format | undefined): TextNode | null; | ||
parseFormat(format: Format, opts: ParseFragmentOpts): FragmentNode[]; | ||
parseText(opts: ParseFragmentOpts, closingFormatKind: Format | undefined): ({ | ||
name: "text"; | ||
contents: string; | ||
} & { | ||
location: LocationRange; | ||
}) | null; | ||
parseFormat(format: Format, opts: ParseFragmentOpts): (TagNode | CommentNode | TextNode)[] | (Pick<PipeNode, "optional" | "contents" | "name" | "nonTerminal" | "params"> & { | ||
location: LocationRange; | ||
})[] | ({ | ||
name: "star" | "underscore" | "tick" | "tilde"; | ||
contents: (TagNode | CommentNode | TextNode)[]; | ||
} & { | ||
location: LocationRange; | ||
})[]; | ||
pushPos(): void; | ||
popPos(): Position | undefined; | ||
getPos(node?: Node | Token): Position | undefined; | ||
getEnd(node: Node | Token): Position | undefined; | ||
finish<T extends Node>(node: T, start?: Position, end?: Position): T; | ||
getPos(node?: Node | Token): Position; | ||
getEnd(node: Node | Token): Position; | ||
finish<T extends Unlocated<Node>>(node: T, start?: Position, end?: Position): T & { | ||
location: LocationRange; | ||
}; | ||
} | ||
export {}; |
@@ -11,16 +11,14 @@ "use strict"; | ||
class Parser { | ||
constructor(tokenizer, options) { | ||
constructor(tokenizer) { | ||
this._t = tokenizer; | ||
this._posStack = options && options.trackPositions ? [] : undefined; | ||
this._posStack = []; | ||
} | ||
static parseAlgorithm(str, options) { | ||
let tokenizer = new tokenizer_1.Tokenizer(str, options); | ||
return new Parser(tokenizer, options).parseAlgorithm(); | ||
static parseAlgorithm(str) { | ||
let tokenizer = new tokenizer_1.Tokenizer(str); | ||
return new Parser(tokenizer).parseAlgorithm(); | ||
} | ||
static parseFragment(str, options) { | ||
let tokenizer = new tokenizer_1.Tokenizer(str, options); | ||
let out = new Parser(tokenizer, options).parseFragment({}); | ||
if (tokenizer.peek().name !== 'EOF') { | ||
throw new Error('expecting EOF, got ' + tokenizer.peek().name); | ||
} | ||
static parseFragment(str) { | ||
let tokenizer = new tokenizer_1.Tokenizer(str); | ||
let out = new Parser(tokenizer).parseFragment({}); | ||
tokenizer.expect('EOF'); | ||
return out; | ||
@@ -41,10 +39,6 @@ } | ||
} | ||
if (this._t.peek().name !== 'ol') { | ||
throw new Error('expecting ordered list, got ' + this._t.peek().name); | ||
} | ||
this._t.expect('ol'); | ||
this.pushPos(); | ||
let ret = this.finish({ name: 'algorithm', contents: this.parseList() }); | ||
if (this._t.peek().name !== 'EOF') { | ||
throw new Error('expecting EOF, got ' + this._t.peek().name); | ||
} | ||
this._t.expect('EOF'); | ||
return ret; | ||
@@ -136,3 +130,3 @@ } | ||
else if (tok.name === 'comment' || tok.name === 'tag' || tok.name === 'opaqueTag') { | ||
frag.push(tok); // Why can't TS infer this type? | ||
frag.push(tok); | ||
this._t.next(); | ||
@@ -151,4 +145,5 @@ } | ||
else { | ||
throw new Error( | ||
// @ts-ignore | ||
throw new Error('Unexpected token ' + tok.name); | ||
`Unknown token type ${tok.name}. This is a bug in ecmarkdown; please report it.`); | ||
} | ||
@@ -221,5 +216,3 @@ } | ||
} | ||
// @ts-ignore this should be `location!.end`, but we need to wait for TS to release a bugfix before we can do that | ||
// see https://github.com/microsoft/TypeScript/pull/36539 | ||
let endLoc = this._posStack && (lastRealTok === null || lastRealTok === void 0 ? void 0 : lastRealTok.location.end); | ||
let endLoc = lastRealTok === null || lastRealTok === void 0 ? void 0 : lastRealTok.location.end; | ||
return this.finish({ name: 'text', contents }, undefined, endLoc); | ||
@@ -277,27 +270,22 @@ } | ||
pushPos() { | ||
if (this._posStack) { | ||
this._posStack.push(this.getPos()); | ||
} | ||
this._posStack.push(this.getPos()); | ||
} | ||
popPos() { | ||
var _a; | ||
return (_a = this._posStack) === null || _a === void 0 ? void 0 : _a.pop(); | ||
return this._posStack.pop(); | ||
} | ||
// TODO rename to getStart ? | ||
getPos(node = this._t.peek()) { | ||
var _a; | ||
return this._posStack && ((_a = node.location) === null || _a === void 0 ? void 0 : _a.start); | ||
return node.location.start; | ||
} | ||
getEnd(node) { | ||
var _a; | ||
return this._posStack && ((_a = node.location) === null || _a === void 0 ? void 0 : _a.end); | ||
return node.location.end; | ||
} | ||
finish(node, start, end) { | ||
if (this._posStack) { | ||
let actualStart = start !== null && start !== void 0 ? start : this.popPos(); | ||
let actualEnd = end !== null && end !== void 0 ? end : (this._t.previous === undefined | ||
? { line: 1, column: 0, offset: 0 } | ||
: { ...this._t.previous.location.end }); | ||
node.location = { start: actualStart, end: actualEnd }; | ||
} | ||
let actualStart = start !== null && start !== void 0 ? start : this.popPos(); | ||
let actualEnd = end !== null && end !== void 0 ? end : (this._t.previous === undefined | ||
? { line: 1, column: 1, offset: 0 } | ||
: { ...this._t.previous.location.end }); | ||
// @ts-ignore | ||
node.location = { start: actualStart, end: actualEnd }; | ||
// @ts-ignore | ||
return node; | ||
@@ -304,0 +292,0 @@ } |
@@ -1,6 +0,4 @@ | ||
import type { Token, IdToken, Position } from './node-types'; | ||
import type { Options } from './ecmarkdown'; | ||
import type { Unlocated, Token, IdToken, Position } from './node-types'; | ||
export declare class Tokenizer { | ||
str: string; | ||
_trackPositions: boolean; | ||
_eof: boolean; | ||
@@ -14,3 +12,3 @@ pos: number; | ||
column: number; | ||
constructor(str: string, options?: Options); | ||
constructor(str: string); | ||
scanDigits(): string; | ||
@@ -27,8 +25,11 @@ scanWhitespace(): string; | ||
getLocation(): Position; | ||
enqueueLookahead(tok: Token, pos: Position): void; | ||
enqueue(tok: Token, pos: Position): void; | ||
enqueueLookahead(tok: Unlocated<Token>, pos: Position): void; | ||
enqueue(tok: Unlocated<Token>, pos: Position): void; | ||
dequeue(): import("./node-types").EOFToken | import("./node-types").FormatToken | import("./node-types").ParabreakToken | import("./node-types").LinebreakToken | import("./node-types").WhitespaceToken | import("./node-types").TextToken | import("./node-types").CommentToken | import("./node-types").OpaqueTagToken | import("./node-types").TagToken | import("./node-types").UnorderedListToken | import("./node-types").OrderedListToken | undefined; | ||
peek(dist?: number): Token; | ||
next(): Token; | ||
locate(tok: Token | IdToken, startPos: Position): void; | ||
locate(tok: Unlocated<Token>, startPos: Position): asserts tok is Token; | ||
locate(tok: Unlocated<IdToken>, startPos: Position): asserts tok is IdToken; | ||
expect(name: Token['name']): void; | ||
raise(message: string, pos: Position): void; | ||
} |
@@ -9,9 +9,8 @@ "use strict"; | ||
class Tokenizer { | ||
constructor(str, options) { | ||
constructor(str) { | ||
this.str = str; | ||
this._trackPositions = !!(options && options.trackPositions); | ||
this._eof = false; | ||
this.pos = 0; | ||
this.line = 1; | ||
this.column = 0; | ||
this.column = 1; | ||
this.queue = []; // stores tokens when we peek so we don't have to rematch | ||
@@ -299,3 +298,3 @@ this._newline = true; | ||
// Don't think it's possible to reach here. | ||
throw new Error('Unexpected token ' + chr + ' at offset ' + this.pos); | ||
this.raise(`Unexpected token ${chr}`, start); | ||
} | ||
@@ -349,22 +348,38 @@ } | ||
locate(tok, startPos) { | ||
if (this._trackPositions) { | ||
if (tok.name === 'linebreak') { | ||
this.column = 0; | ||
++this.line; | ||
} | ||
else if (tok.name === 'parabreak') { | ||
let size = tok.contents.length; | ||
this.column = 0; | ||
this.line += size; | ||
} | ||
else { | ||
let width = this.pos - startPos.offset; | ||
this.column += width; | ||
} | ||
tok.location = { | ||
start: startPos, | ||
end: this.getLocation(), | ||
}; | ||
if (tok.name === 'linebreak') { | ||
this.column = 1; | ||
++this.line; | ||
} | ||
else if (tok.name === 'parabreak') { | ||
let size = tok.contents.length; | ||
this.column = 1; | ||
this.line += size; | ||
} | ||
else { | ||
let width = this.pos - startPos.offset; | ||
this.column += width; | ||
} | ||
// @ts-ignore | ||
tok.location = { | ||
start: startPos, | ||
end: this.getLocation(), | ||
}; | ||
} | ||
expect(name) { | ||
let lookahead = this.peek(); | ||
if (lookahead.name === name) { | ||
return; | ||
} | ||
this.raise(`Unexpected token ${lookahead.name}; expected ${name}`, lookahead.location.start); | ||
} | ||
raise(message, pos) { | ||
let e = new SyntaxError(message); | ||
// @ts-ignore | ||
e.offset = pos.offset; | ||
// @ts-ignore | ||
e.line = pos.line; | ||
// @ts-ignore | ||
e.column = pos.column; | ||
throw e; | ||
} | ||
} | ||
@@ -371,0 +386,0 @@ exports.Tokenizer = Tokenizer; |
{ | ||
"name": "ecmarkdown", | ||
"version": "5.1.2", | ||
"version": "6.0.0", | ||
"description": "A compiler for \"Ecmarkdown\" algorithm shorthand into HTML.", | ||
@@ -9,3 +9,4 @@ "main": "dist/ecmarkdown.js", | ||
"prepublish": "npm run build", | ||
"test": "mocha --reporter dot test/tokenizer.js test/parser.js && node test/run-cases.js", | ||
"test": "mocha test/", | ||
"rebaseline": "UPDATE_SNAPSHOTS=true npm run test", | ||
"lint": "eslint --ext .js,.ts src test", | ||
@@ -12,0 +13,0 @@ "format": "prettier --write src test" |
50538
1223