- Notifications
You must be signed in to change notification settings - Fork2
Parse using JavaScript generator functions — it’s like components but for parsing!
License
JavaScriptRegenerated/yieldparser
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
npm add yieldparserYieldparser parses a source chunk-by-chunk. You define a generator function thatyields each chunk to be found. This chunk can be astring, aRexExp, oranother generator function. Your generator function receives replies fromparsing that chunk, for example a regular expression would receive a reply withthe matches that were found. You then use this information to build a result:the value that your generator function returns. This could be a simple value, orit could be an entire AST (abstract syntax tree).
If you yield an array of choices, then each choice is tested and the first onethat matches is used.
If your chunks don’t match the input string, then an error result is returnedwith the remaining string and the chunk that it failed on. If it succeeds, thena success result is returned with the return value of the generator function,and the remaining string (if there is anything remaining).
Runparse(input, yourGeneratorIterable) to take an input string and parse intoa result.
Runinvert(output, yourGeneratorIterable) to take an expected result and mapit back to a source string.
- Routes
- IP Address
- Maths expressions:
5 * 6 + 3 - Basic CSS
- Semver parser
- Emoticons to Emoji
- CSV
- JSON
- Cron
- Markdown subset
Define a generator function for each route you have, and then define a top levelRoutes generator function. Then parse your path usingparse().
You can also map from a route object back to a path string usinginvert().
import{invert,mustEnd,parse}from"yieldparser";typeRoute=|{type:"home"}|{type:"about"}|{type:"terms"}|{type:"blog"}|{type:"blogArticle";slug:string};function*Home(){yield"/";yieldmustEnd;return{type:"home"}asRoute;}function*About(){yield"/about";yieldmustEnd;return{type:"about"}asRoute;}function*Terms(){yield"/legal";yield"/terms";yieldmustEnd;return{type:"terms"}asRoute;}function*blogPrefix(){yield"/blog";}function*BlogHome(){yieldblogPrefix;yieldmustEnd;return{type:"blog"};}function*BlogArticle(){yieldblogPrefix;yield"/";const[slug]:[string]=yield/^.+/;return{type:"blogArticle", slug};}function*BlogRoutes(){returnyield[BlogHome,BlogArticle];}function*Routes(){returnyield[Home,About,Terms,BlogRoutes];}parse("/",Routes());// result: { type: "home" }, success: true, remaining: ""}parse("/about",Routes());// result: { type: "about" }, success: true, remaining: ""}parse("/legal/terms",Routes());// result: { type: "terms" }, success: true, remaining: ""}parse("/blog",Routes());// result: { type: "blog" }, success: true, remaining: ""}parse("/blog/happy-new-year",Routes());// result: { type: "blogArticle", slug: "happy-new-year" }, success: true, remaining: ""}invert({type:"home"},Routes());// "/"invert({type:"about"},Routes());// "/about"invert({type:"terms"},Routes());// "/legal/terms"invert({type:"blog"},Routes());// "/blog"invert({type:"blogArticle",slug:"happy-new-year"},Routes());// "/blog/happy-new-year"
import{mustEnd,parse}from"yieldparser";function*Digit(){const[digit]:[string]=yield/^\d+/;constvalue=parseInt(digit,10);if(value<0||value>255){returnnewError(`Digit must be between 0 and 255, was${value}`);}returnvalue;}function*IPAddress(){constfirst=yieldDigit;yield".";constsecond=yieldDigit;yield".";constthird=yieldDigit;yield".";constfourth=yieldDigit;yieldmustEnd;return[first,second,third,fourth];}parse("1.2.3.4",IPAddress());/*{ success: true, result: [1, 2, 3, 4], remaining: '',}*/parse("1.2.3.256",IPAddress());/*{ success: false, failedOn: { nested: [ { yielded: new Error('Digit must be between 0 and 255, was 256'), }, ], }, remaining: '256',}*/
import{has,hasMore,parse}from"yieldparser";typeSelector=string;interfaceDeclaraction{property:string;value:string;}interfaceRule{selectors:Array<Selector>;declarations:Array<Declaraction>;}constwhitespaceMay=/^\s*/;function*PropertyParser(){const[name]:[string]=yield/[-a-z]+/;returnname;}function*ValueParser(){const[rawValue]:[string]=yield/(-?\d+(rem|em|%|px|)|[-a-z]+)/;returnrawValue;}function*DeclarationParser(){constname=yieldPropertyParser;yieldwhitespaceMay;yield":";yieldwhitespaceMay;constrawValue=yieldValueParser;yieldwhitespaceMay;yield";";return{ name, rawValue};}function*RuleParser(){constdeclarations:Array<Declaraction>=[];const[selector]:[string]=yield/(:root|[*]|[a-z][\w]*)/;yieldwhitespaceMay;yield"{";yieldwhitespaceMay;while((yieldhas("}"))===false){yieldwhitespaceMay;declarations.push(yieldDeclarationParser);yieldwhitespaceMay;}return{ selector, declarations};}function*RulesParser(){construles=[];yieldwhitespaceMay;while(yieldhasMore){rules.push(yieldRuleParser);yieldwhitespaceMay;}returnrules;}constcode=`:root { --first-var: 42rem; --second-var: 15%;}* { font: inherit; box-sizing: border-box;}h1 { margin-bottom: 1em;}`;parse(code,RulesParser());/*{ success: true, result: [ { selector: ':root', declarations: [ { name: '--first-var', rawValue: '42rem', }, { name: '--second-var', rawValue: '15%', }, ], }, { selector: '*', declarations: [ { name: 'font', rawValue: 'inherit', }, { name: 'box-sizing', rawValue: 'border-box', }, ], }, { selector: 'h1', declarations: [ { name: 'margin-bottom', rawValue: '1em', }, ], }, ], remaining: '',}*/
About
Parse using JavaScript generator functions — it’s like components but for parsing!
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.