Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

edge-parser

Package Overview
Dependencies
Maintainers
1
Versions
92
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

edge-parser - npm Package Compare versions

Comparing version 6.0.2 to 7.0.0

build/src/Expressions/SpreadElement.d.ts

1

build/index.d.ts

@@ -31,2 +31,3 @@ export { Stack } from './src/Stack';

ChainExpression: "ChainExpression";
SpreadElement: "SpreadElement";
};

@@ -26,2 +26,3 @@ import { TagToken, LexerTagDefinitionContract, MustacheToken } from 'edge-lexer';

export declare type ClaimTagFn = (name: string) => LexerTagDefinitionContract | null;
export declare type OnLineFn = (line: string) => string;
/**

@@ -31,6 +32,37 @@ * Parser options

export declare type ParserOptions = {
/**
* Is parsing in async mode
*/
async?: boolean;
/**
* Modify the line before it is being processed by the lexer
*/
onLine?: OnLineFn;
/**
* Modify the tag before it is being processed by the parser
*/
onTag?: TagTransformer;
/**
* Modify the mustache block before it is being processed by the parser
*/
onMustache?: MustacheTransformer;
/**
* Claim un-registered tags
*/
claimTag?: ClaimTagFn;
/**
* Nested or flat path to the escape method for escaping values.
*/
escapeCallPath: string | [string, string];
/**
* Name of the property to be used for accessing the values from
* the template. Leave it to an empty string, if properties
* are available directly (meaning without a subpath).
*/
statePropertyName: string;
/**
* An array of local variables to be accessible directly. Define these
* so that the parser doesn't access them from the state property.
*/
localVariables?: string[];
};

5

build/src/EdgeBuffer/index.d.ts

@@ -31,4 +31,5 @@ /**

private compiledOutput;
constructor(filename: string, options?: {
outputVar?: string;
constructor(filename: string, options: {
outputVar: string;
rethrowCallPath: string | [string, string];
});

@@ -35,0 +36,0 @@ /**

@@ -26,3 +26,4 @@ "use strict";

this.options = {
outputVar: 'out',
outputVar: '',
rethrowCallPath: '',
fileNameVar: '$filename',

@@ -48,3 +49,6 @@ lineVar: '$lineNumber',

this.currentFileName = this.filename;
Object.assign(this.options, options);
this.options.outputVar = options.outputVar;
this.options.rethrowCallPath = Array.isArray(options.rethrowCallPath)
? options.rethrowCallPath.join('.')
: options.rethrowCallPath;
}

@@ -90,3 +94,3 @@ /**

*/
buffer.push(`ctx.reThrow(error, ${this.options.fileNameVar}, ${this.options.lineVar});`);
buffer.push(`${this.options.rethrowCallPath}(error, ${this.options.fileNameVar}, ${this.options.lineVar});`);
/**

@@ -93,0 +97,0 @@ * End catch block

@@ -12,2 +12,3 @@ "use strict";

const transformAst_1 = require("../Parser/transformAst");
const edge_error_1 = require("edge-error");
exports.default = {

@@ -26,3 +27,8 @@ toStatement(statement, filename, parser) {

else {
throw new Error(`Report this error to the maintainers: Expected Arrow function params to be an identifier. Instead received ${param.type}`);
const { line, col } = parser.utils.getExpressionLoc(param);
throw new edge_error_1.EdgeError(`Report this error to the maintainers: Unexpected arrow function property type ${param.type}`, 'E_PARSER_ERROR', {
line,
col,
filename,
});
}

@@ -29,0 +35,0 @@ });

@@ -12,6 +12,5 @@ "use strict";

const makeStatePropertyAccessor_1 = require("../Parser/makeStatePropertyAccessor");
const WHITE_LISTED = ['state', '$filename'];
exports.default = {
toStatement(statement, _, parser) {
if (WHITE_LISTED.indexOf(statement.name) > -1 ||
if ((parser.options.localVariables || []).indexOf(statement.name) > -1 ||
parser.stack.has(statement.name) ||

@@ -21,4 +20,4 @@ global[statement.name] !== undefined) {

}
return makeStatePropertyAccessor_1.makeStatePropertyAccessor(statement);
return makeStatePropertyAccessor_1.makeStatePropertyAccessor(parser.options.statePropertyName, statement);
},
};

@@ -23,1 +23,2 @@ export { default as Identifier } from './Identifier';

export { default as ChainExpression } from './ChainExpression';
export { default as SpreadElement } from './SpreadElement';

@@ -14,3 +14,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainExpression = exports.ThisExpression = exports.ReturnStatement = exports.BlockStatement = exports.NewExpression = exports.AwaitExpression = exports.AssignmentExpression = exports.SequenceExpression = exports.LogicalExpression = exports.ConditionalExpression = exports.FunctionDeclaration = exports.UnaryExpression = exports.ObjectExpression = exports.ArrayExpression = exports.BinaryExpression = exports.TemplateLiteral = exports.Literal = exports.ArrowFunctionExpression = exports.CallExpression = exports.ExpressionStatement = exports.MemberExpression = exports.Identifier = void 0;
exports.SpreadElement = exports.ChainExpression = exports.ThisExpression = exports.ReturnStatement = exports.BlockStatement = exports.NewExpression = exports.AwaitExpression = exports.AssignmentExpression = exports.SequenceExpression = exports.LogicalExpression = exports.ConditionalExpression = exports.FunctionDeclaration = exports.UnaryExpression = exports.ObjectExpression = exports.ArrayExpression = exports.BinaryExpression = exports.TemplateLiteral = exports.Literal = exports.ArrowFunctionExpression = exports.CallExpression = exports.ExpressionStatement = exports.MemberExpression = exports.Identifier = void 0;
var Identifier_1 = require("./Identifier");

@@ -60,1 +60,3 @@ Object.defineProperty(exports, "Identifier", { enumerable: true, get: function () { return __importDefault(Identifier_1).default; } });

Object.defineProperty(exports, "ChainExpression", { enumerable: true, get: function () { return __importDefault(ChainExpression_1).default; } });
var SpreadElement_1 = require("./SpreadElement");
Object.defineProperty(exports, "SpreadElement", { enumerable: true, get: function () { return __importDefault(SpreadElement_1).default; } });

@@ -12,16 +12,28 @@ "use strict";

const transformAst_1 = require("../Parser/transformAst");
const edge_error_1 = require("edge-error");
exports.default = {
toStatement(statement, filename, parser) {
statement.properties = statement.properties.map((node) => {
/**
* Since we change the structure of node.value, we have to
* turnoff shorthand objects, so that the astring outputs
* the key name explicitly
*/
node.shorthand = false;
if (node.computed === true) {
node.key = transformAst_1.transformAst(node.key, filename, parser);
if (node.type === 'Property') {
/**
* Since we change the structure of node.value, we have to
* turnoff shorthand objects, so that the astring outputs
* the key name explicitly
*/
node.shorthand = false;
if (node.computed === true) {
node.key = transformAst_1.transformAst(node.key, filename, parser);
}
node.value = transformAst_1.transformAst(node.value, filename, parser);
return node;
}
node.value = transformAst_1.transformAst(node.value, filename, parser);
return node;
if (node.type === 'SpreadElement') {
return transformAst_1.transformAst(node, filename, parser);
}
const { line, col } = parser.utils.getExpressionLoc(node);
throw new edge_error_1.EdgeError(`Report this error to the maintainers: Unexpected object property type "${node.type}"`, 'E_PARSER_ERROR', {
line,
col,
filename,
});
});

@@ -28,0 +40,0 @@ return statement;

@@ -7,3 +7,3 @@ import { Token } from 'edge-lexer';

import { transformAst } from './transformAst';
import { makeCtxCallable } from './makeCtxCallable';
import { makeEscapeCallable } from './makeEscapeCallable';
import { makeStatePropertyAccessor } from './makeStatePropertyAccessor';

@@ -46,3 +46,3 @@ import { ParserTagDefinitionContract, ParserOptions } from '../Contracts';

[key: string]: ParserTagDefinitionContract;
}, stack?: Stack, options?: ParserOptions);
}, stack: Stack, options: ParserOptions);
/**

@@ -55,3 +55,3 @@ * Parser utilities work with the AST

stringify: typeof stringify;
makeCtxCallable: typeof makeCtxCallable;
makeEscapeCallable: typeof makeEscapeCallable;
makeStatePropertyAccessor: typeof makeStatePropertyAccessor;

@@ -65,2 +65,6 @@ collectObjectExpressionProperties: typeof collectObjectExpressionProperties;

/**
* Returns the options to be passed to the tokenizer
*/
private getTokenizerOptions;
/**
* Process escaped tag token by writing it as it is. However, the children

@@ -71,4 +75,3 @@ * inside a tag are still processed.

/**
* Process escaped tag token by writing it as it is. However, the children
* inside a tag are still processed.
* Process escaped muscahe block by writing it as it is.
*/

@@ -75,0 +78,0 @@ private processEscapedMustache;

@@ -18,3 +18,3 @@ "use strict";

const transformAst_1 = require("./transformAst");
const makeCtxCallable_1 = require("./makeCtxCallable");
const makeEscapeCallable_1 = require("./makeEscapeCallable");
const makeStatePropertyAccessor_1 = require("./makeStatePropertyAccessor");

@@ -45,3 +45,3 @@ const collectObjectExpressionProperties_1 = require("./collectObjectExpressionProperties");

class Parser {
constructor(tags, stack = new Stack_1.Stack(), options = {}) {
constructor(tags, stack = new Stack_1.Stack(), options) {
this.tags = tags;

@@ -61,3 +61,3 @@ this.stack = stack;

stringify: stringify_1.stringify,
makeCtxCallable: makeCtxCallable_1.makeCtxCallable,
makeEscapeCallable: makeEscapeCallable_1.makeEscapeCallable,
makeStatePropertyAccessor: makeStatePropertyAccessor_1.makeStatePropertyAccessor,

@@ -76,2 +76,15 @@ collectObjectExpressionProperties: collectObjectExpressionProperties_1.collectObjectExpressionProperties,

/**
* Returns the options to be passed to the tokenizer
*/
getTokenizerOptions(options) {
if (!this.options) {
return options;
}
return {
claimTag: this.options.claimTag,
onLine: this.options.onLine,
filename: options.filename,
};
}
/**
* Process escaped tag token by writing it as it is. However, the children

@@ -97,4 +110,3 @@ * inside a tag are still processed.

/**
* Process escaped tag token by writing it as it is. However, the children
* inside a tag are still processed.
* Process escaped muscahe block by writing it as it is.
*/

@@ -115,3 +127,5 @@ processEscapedMustache(token, buffer) {

*/
const expression = type === edge_lexer_1.MustacheTypes.MUSTACHE ? makeCtxCallable_1.makeCtxCallable('escape', [node]) : node;
const expression = type === edge_lexer_1.MustacheTypes.MUSTACHE
? makeEscapeCallable_1.makeEscapeCallable(this.options.escapeCallPath, [node])
: node;
/**

@@ -135,8 +149,3 @@ * Template literal, so there is no need to wrap it inside another

tokenize(template, options) {
const tokenizer = new edge_lexer_1.Tokenizer(template, this.tags, this.options.claimTag
? {
claimTag: this.options.claimTag,
filename: options.filename,
}
: options);
const tokenizer = new edge_lexer_1.Tokenizer(template, this.tags, this.getTokenizerOptions(options));
tokenizer.parse();

@@ -143,0 +152,0 @@ return tokenizer.tokens;

/**
* Returns Acorn complaint AST for a collable expression
*/
export declare function makeStatePropertyAccessor(args: object): any;
export declare function makeStatePropertyAccessor(propertyName: string, args: object): any;

@@ -15,3 +15,3 @@ "use strict";

*/
function makeStatePropertyAccessor(args) {
function makeStatePropertyAccessor(propertyName, args) {
return {

@@ -21,3 +21,3 @@ type: 'MemberExpression',

type: 'Identifier',
name: 'state',
name: propertyName,
},

@@ -24,0 +24,0 @@ computed: false,

{
"name": "edge-parser",
"version": "6.0.2",
"version": "7.0.0",
"description": "Parser for edge template engine",

@@ -62,6 +62,3 @@ "main": "build/index.js",

"np": "^7.2.0",
"npm-audit-html": "^1.5.0",
"prettier": "^2.2.1",
"typedoc": "^0.20.14",
"typedoc-plugin-markdown": "^3.4.0",
"typescript": "^4.1.3",

@@ -88,3 +85,3 @@ "youch": "^2.1.1"

"hooks": {
"pre-commit": "doctoc README.md --title='## Table of contents' && git add README.md && npm audit --production --json | ./node_modules/.bin/npm-audit-html && git add npm-audit.html",
"pre-commit": "doctoc README.md --title='## Table of contents' && git add README.md",
"commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js"

@@ -91,0 +88,0 @@ }

@@ -17,5 +17,4 @@ <div align="center"><img src="https://res.cloudinary.com/adonis-js/image/upload/q_100/v1600679850/edge-banner_wao6ex.png" width="600px"></div>

- [transformAst(acornAst, filename)](#transformastacornast-filename)
- [tokenize (template)](#tokenize-template)
- [tokenize (template, options: { filename })](#tokenize-template-options--filename-)
- [stringify(expression)](#stringifyexpression)
- [parse(template)](#parsetemplate)
- [processToken(token, buffer)](#processtokentoken-buffer)

@@ -38,8 +37,8 @@ - [Supported Expressions](#supported-expressions)

- [FunctionDeclaration](#functiondeclaration)
- [Template expectations](#template-expectations)
- [API Docs](#api-docs)
- [BlockStatement](#blockstatement)
- [ChainExpression](#chainexpression)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
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](#context-expectations).
This repo is the **parser to convert edge templates** to a self invoked Javascript function.

@@ -60,12 +59,31 @@ ## Usage

```js
import { Parser } from 'edge-parser'
import { Parser, EdgeBuffer, Stack } from 'edge-parser'
const tagsIfAny = {}
const parser = new Parser(tagsIfAny, { filename: 'foo.edge' })
const filename = 'eval.edge'
const statePropertyName = 'state'
const escapeCallPath = 'escape'
const outputVar = 'out'
const rethrowCallPath = 'reThrow'
parser.parse(`Hello {{ username }}`)
const parser = new Parser({}, new Stack(), {
statePropertyName,
escapeCallPath,
})
const buffer = new EdgeBuffer(filename, { outputVar, rethrowCallPath })
parser
.tokenize('Hello {{ username }}', { filename })
.forEach((token) => parser.processToken(token, buffer))
```
**Output**
- All the first set of `const` declarations are the config values that impacts the compiled output.
- `filename` is required to ensure that exceptions stack traces point back to the correct filename.
- `statePropertyName` is the variable name from which the values should be accessed. For example: `{{ username }}` will be compiled as `state.username`. Leave it to empty, if state is not nested inside an object.
- `escapeCallPath` Reference to the `escape` method for escaping interpolation values. For example: `{{ username }}` will be compiled as `escape(state.username)`. The `escape` method should escape only strings and return the other data types as it is.
- `outputVar` is the variable name that holds the output of the compiled template.
- `rethrowCallPath` Reference to the `reThrow` method to raise the template exceptions with the current `$filename` and `$lineNumber`. Check the following compiled output to see how this function is called.
**Compiled output**
```js

@@ -77,5 +95,5 @@ let out = ''

out += 'Hello '
out += `${ctx.escape(state.username)}`
out += `${escape(state.username)}`
} catch (error) {
ctx.reThrow(error, $filename, $lineNumber)
reThrow(error, $filename, $lineNumber)
}

@@ -85,4 +103,32 @@ return out

> 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.
You can wrap the compiled output inside a function and invoke it as follows
```ts
/**
* Convert string to a function
*/
const fn = new Function('', `return function template (state, escape, reThrow) { ${output} }`)()
/**
* Template state
*/
const state = { username: 'virk' }
/**
* Escape function
*/
function escape(value: any) {
return value
}
/**
* Rethrow function
*/
function reThrow(error: Error) {
throw error
}
console.log(fn(state, escape, reThrow))
```
## Parser API

@@ -122,3 +168,3 @@

#### tokenize (template)
#### tokenize (template, options: { filename })

@@ -128,3 +174,5 @@ Returns an array of [lexer tokens](https://github.com/edge-js/lexer) for the given template. The method is a shortcut to self import the lexer module and then generating tokens.

```ts
const tokens = parser.tokenize('Hello {{ username }}')
const tokens = parser.tokenize('Hello {{ username }}', {
filename: 'eval.edge',
})
```

@@ -179,25 +227,2 @@

#### parse(template)
Parse a template to an `IIFE`. This is what you will use most of the time.
```ts
parser.parse('Hello {{ username }}')
```
**Output**
```js
let out = ''
let $lineNumber = 1
let $filename = 'eval.edge'
try {
out += 'Hello '
out += `${ctx.escape(state.username)}`
} catch (error) {
ctx.reThrow(error, $filename, $lineNumber)
}
return out
```
#### processToken(token, buffer)

@@ -351,25 +376,19 @@

## Template expectations
#### BlockStatement
You must define a context object with `escape` and `reThrow` methods when executing the parser compiled function
Here the `map` callback is the block statement
```ts
const ctx = {
escape(value) {
if (typeof value === 'string') {
return escapedValue
}
return value
},
reThrow(error, fileName, lineNumber) {},
}
```
{{
users.map(() => {})
}}
```
## API Docs
#### ChainExpression
Following are the auto generated files via Type doc
Support for optional chaining
- [API](docs/README.md)
```
{{ user?.username }}
```

@@ -376,0 +395,0 @@ [circleci-image]: https://img.shields.io/circleci/project/github/edge-js/parser/master.svg?style=for-the-badge&logo=circleci

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc