JSPM

  • Created
  • Published
  • Downloads 28740
  • Score
    100M100P100Q141709F
  • License MIT

Parser for edge template engine

Package Exports

  • edge-parser

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (edge-parser) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Edge Parser

Parser to convert edge template to invokable functions

circleci-image npm-image license-image

Table of contents

This repo is the parser to convert edge templates to a self invoked Javascript function. Later you can invoke this function by providing a context.

Usage

Install the package from npm registry as follows:

npm i edge-parser

# yarn
yarn add edge-parser

and then use it as follows

import { Parser } from 'edge-parser'

const tagsIfAny = {}
const parser = new Parser(tagsIfAny, { filename: 'foo.edge' })

parser.parseTemplate(`Hello {{ username }}`)

Output

(function (template, ctx) {
  let out = ''
  out += 'Hello '
  out += `${ctx.escape(ctx.resolve('username'))}`
  return out
})(template, ctx)

Notice of use of ctx in the function body. Parser doesn't provide the implementation of ctx, the runtime of template engine should provide it.

Parser API

Along with parsing the main template, the parser also exposes the API, that tags can use to selectively parse the content of a tag.

generateEdgeExpression(template, lexerLoc)

Parses a string as a Javascript expression. The output is a valid Estree expression.

The following example returns a BinaryExpression

parser.generateEdgeExpression('2 + 2', {
  start: { line: 1, col: 1 },
  end: { line: 1, col: 1 },
})

generateAcornExpression(template, lexerLoc)

The method is same as generateEdgeExpression, instead it will not transform the expression to be compatible with the Edge runtime environment.

This method is helpful, when you want to parse a string to generate it's AST and then cherry pick nested expressions and then process them further.

The following example returns a BinaryExpression

parser.generateAcornExpression('2 + 2', {
  start: { line: 1, col: 1 },
  end: { line: 1, col: 1 },
})

generateLexerTokens (template)

Returns an array of lexer tokens for the given template. The method is a shortcut to self import the lexer module and then generating tokens.

const tokens = parser.generateLexerTokens('Hello {{ username }}')

Output

[
  {
    "type": "raw",
    "line": 1,
    "value": "Hello "
  },
  {
    "type": "mustache",
    "loc": {
      "start": {
        "line": 1,
        "col": 8
      },
      "end": {
        "line": 1,
        "col": 20
      }
    },
    "properties": {
      "jsArg": " username "
    }
  }
]

acornToEdgeExpression(expression)

Convert an acorn expression to be compatible with the Edge runtime.

const expression = parser.generateAcornExpression('2 + 2', {
  start: { line: 1, col: 1 },
  end: { line: 1, col: 1 },
})

parser.acornToEdgeExpression(expression)

stringifyExpression(expression)

Convert edge or acorn expression back to a string. This is helpful, when you mutate some nodes inside the expression and now want a valid Javascript string out of it.

const expression = parser.generateEdgeExpression('2 + 2', {
  start: { line: 1, col: 1 },
  end: { line: 1, col: 1 },
})

expression.left.value = 3

parser.stringifyExpression(expression) // returns 3 + 2

parseTemplate(template)

Parse a template to an invokable function. This is what you will use most of the time.

parser.parseTemplate('Hello {{ username }}')

Output

(function (template, ctx) {
  let out = ''
  out += 'Hello '
  out += `${ctx.escape(ctx.resolve('username'))}`
  return out
})(template, ctx)

processLexerToken(token, buffer)

You will often find yourself using this method as a tag author, when you want to recursively process all children of your tag

const byPass = {
  block: true,
  seekable: false,
  name: 'bypass',

  compile (parser, buffer, token) {
    token.children.forEach((child) => parser.processLexerToken(child, buffer))
  }
}

and then use it as

@bypass
  Hello {{ username }}
@endbypass

Supported Expressions

The following expressions are supported by the parser. Can you also access the list of supported expressions as

import { expressions } from 'edge-parser'

Identifier

The identifier is wrapped inside ctx.resolve. The resolve method job is to resolve the value.

In following statement username is the identifier

Hello {{ username }}

Literal

A string literal

Hello {{ 'Guest' }}

ArrayExpression

The [1, 2, 3, 4] is an array expression.

Evens are {{
  [1, 2, 3, 4].filter((num) => num % 2 === 0)
}}

ObjectExpression

The { username: 'virk' } is an Object expression

{{ toJSON({ username: 'virk' })  }}

UnaryExpression

Following are examples of UnaryExpression.

{{ typeof(username) }}

{{ !!username }}

BinaryExpression

Here {{ 2 + 2 }} is the binary expression

{{ 2 + 2 }} = 4

LogicalExpression

Following is the example of LogicalExpression.

{{ username || admin.username }}

MemberExpression

{{ username.toUpperCase() }}

ConditionalExpression

{{ username ? username : 'Guest' }}

CallExpression

{{ upper(username) }}

SequenceExpression

Sequence is not supported in mustache blocks and instead used inside tags. For example:

Everything inside () is a sequence expression.

@component('button', text = 'Submit', type = 'Primary')

TemplateLiteral

{{ Hello `${username}` }}

ArrowFunctionExpression

{{
  users.map((user) => {
    return user.username
  })
}}

Context expectations

Context must have following methods to work with the core parser.

class Context {
  // Resolve value for a key
  resolve(key: string): any

  // make input HTML safe
  escape (input: string): string
}

API Docs

Following are the autogenerated files via Typedoc