UNPKG

fruitsconfits

Version:

FruitsConfits - A well typed and sugared parser combinator framework for TypeScript/JavaScript.

321 lines (277 loc) 13.2 kB
# FruitsConfits ### A well typed and _sugared_ parser combinator framework for TypeScript/JavaScript. <img src="https://raw.githubusercontent.com/shellyln/fruitsconfits/master/docs/images/logo.svg?sanitize=true" title="logo" style="width: 200px"> [![npm](https://img.shields.io/npm/v/fruitsconfits.svg)](https://www.npmjs.com/package/fruitsconfits) [![GitHub release](https://img.shields.io/github/release/shellyln/fruitsconfits.svg)](https://github.com/shellyln/fruitsconfits/releases) [![Travis](https://img.shields.io/travis/shellyln/fruitsconfits/master.svg)](https://travis-ci.org/shellyln/fruitsconfits) [![GitHub forks](https://img.shields.io/github/forks/shellyln/fruitsconfits.svg?style=social&label=Fork)](https://github.com/shellyln/fruitsconfits/fork) [![GitHub stars](https://img.shields.io/github/stars/shellyln/fruitsconfits.svg?style=social&label=Star)](https://github.com/shellyln/fruitsconfits) ## Install ```sh npm install fruitsconfits ``` > NOTICE: > Use with `webpack >= 5` > > If you get the error: > > ``` > Module not found: Error: Can't resolve '(importing/path/to/filename)' > in '(path/to/node_modules/path/to/dirname)' > Did you mean '(filename).js'?` > ``` > > Add following setting to your `webpack.config.js`. > > ```js > { > test: /\.m?js/, > resolve: { > fullySpecified: false, > }, > }, > ``` > > On `webpack >= 5`, the extension in the request is mandatory for it to be fully specified > if the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"'. ### Breakikng changes See CHANGELOG.md. ## Features * Build a lexer or parser for a string or object list by parser combinator. * The parser can receive user data context and acts as a reducer. * Sugar sweet API syntaxes. ## High level APIs ### getStringParsers(params) Get the string parser generators. ```ts export function getStringParsers<C, R>( params: { rawToToken: (rawToken: string) => R, concatTokens: (tokens: R[]) => R[], }); ``` #### params * `rawToToken` : function to convert string token to AST element. * `concatTokens` : function to merge two AST elements into one AST element. #### returns returns an object that containing the parsers. * `seq(needle: string)` * parser to match the sequence `needle` * `cls(...needles: string[])` * parser to match the sequence classes `needles` * `notCls(...needles: string[])` * parser to match the negation of sequence classes `needles` * `clsFn(needle: (src: string) => number)` * parser to match the sequence class `needle` * the class is defined by the lambda function * classes * `alpha` * parser to match the sequence of us-ascii alphabetic characters * `upper` * parser to match the sequence of us-ascii upper alphabetic characters * `lower` * parser to match the sequence of us-ascii lower alphabetic characters * `num` * parser to match the sequence of us-ascii decimal numeric characters * `nonzero` * parser to match the sequence of us-ascii decimal numeric characters except `0` * `bin` * parser to match the sequence of us-ascii binary numeric characters * `oct` * parser to match the sequence of us-ascii octal numeric characters * `hex` * parser to match the sequence of us-ascii hexadecimal numeric characters * `alnum` * parser to match the sequence of us-ascii alphabetic and numeric characters * `space` * parser to match the sequence of whitespace characters except newline (CR/LF) characters * the whitespace characters definition conform to javascript regexp * `spaceWithinSingleLine` * parser to match the sequence of whitespace characters * the whitespace characters definition conform to javascript regexp * `ctrl` * parser to match the sequence of control characters * the control characters definition conform to javascript regexp * `newline` * parser to match the sequence of newline (CR/LF) characters * `word` * parser to match the negation of the sequence of whitespaces and control characters * the whitespace and control characters definition conform to javascript regexp * `any` * parser to match the sequence class that matches to any token * numbers * `bin(...prefixes: StringParserFnWithCtx<C, R>[])` * parse a binary number * `oct(...prefixes: StringParserFnWithCtx<C, R>[])` * parse a octal number * `hex(...prefixes: StringParserFnWithCtx<C, R>[])` * parse a hex number * `int` * parse a javascript style integer number * `bigint` * parse a javascript style bigint number * `float` * parse a javascript style floating point number * `isParam(criteria: (o: any) => boolean, conv?: (o: any) => any)` * parser to match a ES6 template strings parameter value * `cat(...parsers: StringParserFnWithCtx<C, R>[])` * parser that combine and concatenate the parsing results of `parsers` * `once(parser: StringParserFnWithCtx<C, R>)` * parser to match once to the parsing results of `parser` * `repeat(parser: StringParserFnWithCtx<C, R>)` * parser to match zero or more times to the parsing results of `parser` * `qty(min?: number, max?: number) => (parser: StringParserFnWithCtx<C, R>)` * parser to match min to max times to the parsing results of `parser` * if min and max are ommitted, it is same as `repeat` parser * if max is ommitted, it matches min or more times * `zeroWidth(helper?: () => R)` * parser to match any zero width and return result that is provided by `helper` * `err(message: string)` * parser to match any zero width and raise the error that has `message` * `beginning(helper?: () => R)` * parser to match zero width beginning of input and return result that is provided by `helper` * `end(helper?: () => R)` * parser to match zero width end of input and return result that is provided by `helper` * `first(...parsers: StringParserFnWithCtx<C, R>[])` * parser to match the first matched parser in the `parsers` * `or(...parsers: StringParserFnWithCtx<C, R>[])` * parser to match the most long matched parser in the `parsers` * `combine(...parsers: StringParserFnWithCtx<C, R>[])` * parser that combine parsers `parsers` * `erase(...parsers: StringParserFnWithCtx<C, R>[])` * parser that combine parsers `parsers` and return empty result `[]` * `trans(fn: (tokens: R[]) => R[]) => (...parsers: StringParserFnWithCtx<C, R>[])` * parser that combine parsers `parsers` and transform the result by `fn` * `ahead(...parsers: StringParserFnWithCtx<C, R>[])` * parser to match zero width by reading ahead and matching with `parsers` * `behind(n: number, helper?: () => R)(...parsers: StringParserFnWithCtx<C, R>[])` * parser to match zero width by reading behind and matching with `parsers` and return result that is provided by `helper` * `rules(args: ApplyProductionRulesArg<string, C, R>) => (lexer: StringParserFnWithCtx<C, R>)` * parser to match the production rules `args` * args.rules : production rules * args.maxApply : maximum number of production rules applied * args.check : end condition of production rules * `makeProgram` * parser to enclose most outer * converts the internal `ParseError` thrown to a return value ### getObjectParsers(params) Get the object list parser generators. ```ts export function getObjectParsers<T extends ArrayLike<T[number]>, C, R>( params: { rawToToken: (rawToken: T[number]) => R, concatTokens: (tokens: R[]) => R[], comparator: (a: T[number], b: T[number]) => boolean, }); ``` #### params * `rawToToken` : function to convert the input object list item to AST element. * `concatTokens` : function to merge two AST elements into one AST element. * `comparator` : function to compare two input object list items. #### returns returns an object that containing the parsers. * `seq(needle: T)` * parser to match the sequence `needle` * `cls(...needles: T[number][])` * parser to match the sequence classes `needles` * `notCls(...needles: T[number][])` * parser to match the negation of sequence classes `needles` * `clsFn(needle: (src: T[number]) => boolean)` * parser to match the sequence class `needle` * the class is defined by the lambda function * classes * `any` * parser to match the sequence class that matches to any token * `cat(...parsers: ParserFnWithCtx<T, C, R>[])` * parser that combine and concatenate the parsing results of `parsers` * `once(parser: ParserFnWithCtx<T, C, R>)` * parser to match once to the parsing results of `parser` * `repeat(parser: ParserFnWithCtx<T, C, R>)` * parser to match zero or more times to the parsing results of `parser` * `qty(min?: number, max?: number) => (parser: ParserFnWithCtx<T, C, R>)` * parser to match min to max times to the parsing results of `parser` * if min and max are ommitted, it is same as `repeat` parser * if max is ommitted, it matches min or more times * `zeroWidth(helper?: () => R)` * parser to match any zero width and return result that is provided by `helper` * `err(message: string)` * parser to match any zero width and raise the error that has `message` * `beginning(helper?: () => R)` * parser to match zero width beginning of input and return result that is provided by `helper` * `end(helper?: () => R)` * parser to match zero width end of input and return result that is provided by `helper` * `first(...parsers: ParserFnWithCtx<T, C, R>[])` * parser to match the first matched parser in the `parsers` * `or(...parsers: ParserFnWithCtx<T, C, R>[])` * parser to match the most long matched parser in the `parsers` * `combine(...parsers: ParserFnWithCtx<T, C, R>[])` * parser that combine parsers `parsers` * `erase(...parsers: ParserFnWithCtx<T, C, R>[])` * parser that combine parsers `parsers` and return empty result `[]` * `trans(fn: (tokens: R[]) => R[]) => (...parsers: ParserFnWithCtx<T, C, R>[])` * parser that combine parsers `parsers` and transform the result by `fn` * `ahead(...parsers: ParserFnWithCtx<T, C, R>[])` * parser to match zero width by reading ahead and matching with `parsers` * `behind(n: number, helper?: () => R)(...parsers: ParserFnWithCtx<T, C, R>[])` * parser to match zero width by reading behind and matching with `parsers` and return result that is provided by `helper` * `rules(args: ApplyProductionRulesArg<T, C, R>) => (lexer: ParserFnWithCtx<T, C, R>)` * parser to match the production rules `args` * args.rules : production rules * args.maxApply : maximum number of production rules applied * args.check : end condition of production rules * `makeProgram` * parser to enclose most outer * converts the internal `ParseError` thrown to a return value ### parserInput(src: T, context?: C) Build a parser input. Example: ```ts ... const program = makeProgram(trans(tokens => tokens)( erase(repeat(commentOrSpace)), first(listValue, objectValue, constExpr(end())), erase(repeat(commentOrSpace)), end(), )); export function parse(s: string) { const z = program(parserInput(s)); if (! z.succeeded) { throw new Error(formatErrorMessage(z)); } return z.tokens[0].value; } ``` ### templateStringsParserInput(strings, values, context?: C) Build a parser input from ES6 template strings. Example: ```ts const program = makeProgram(combine( seq('Hello,'), isParam(o => String(o) === 'world'), seq('!'), end(), )); export function parse(strings: TemplateStringsArray, ...values: any[]) { const z = program(templateStringsParserInput(strings, values)); if (! z.succeeded) { throw new Error(formatErrorMessage(z)); } return z.tokens; } ``` ## Examples * [JSON parser](https://github.com/shellyln/fruitsconfits/blob/master/src/examples/json-parser/index.ts) * [CSV parser](https://github.com/shellyln/fruitsconfits/blob/master/src/examples/csv-parser/index.ts) * [formula parser](https://github.com/shellyln/fruitsconfits/blob/master/src/examples/formula-parser/index.ts) ## Real world examples * [Tynder](https://github.com/shellyln/tynder) * TypeScript friendly Data validator for JavaScript. * [Code](https://github.com/shellyln/tynder/blob/master/src/compiler.ts) * [kanban-board-app](https://github.com/shellyln/kanban-board-app) * Kanban style task management board app * [Code](https://github.com/shellyln/kanban-board-app/blob/master/src/lib/csv.ts) * [Open SOQL](https://github.com/shellyln/open-soql) * Open source implementation of the SOQL. * [Code (1)](https://github.com/shellyln/open-soql/blob/master/src/lib/parser.ts), [(2)](https://github.com/shellyln/open-soql/blob/master/src/lib/csv-parser.ts) ## License [ISC](https://github.com/shellyln/fruitsconfits/blob/master/LICENSE.md) Copyright (c) 2019 Shellyl_N and Authors.