npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@datadayrepos/js-lexer

v0.0.1-beta.14

Published

lexer for safe eval of js expressions

Downloads

2

Readme

js-lexer

JS Lexer is a bespoke, security-conscious JavaScript expression parser designed for specific contexts.

🚀 Features

  • Security first: It allows only execution of safe expressions.
  • CSP Compliant: Fully compatible with the most stringent Content Security Policy (CSP) settings enforced by web servers.
  • Lightweight: A minimal footprint of just 3kb.
  • Its fast and optimized: Offers speed and optimization comparable to native JavaScript solutions.

Purpose and context

The primary goal of JS Lexer is to provide a secure parsing mechanism for JavaScript expressions. This necessity stems from the requirement to execute dynamically generated code within our editors, particularly focusing on logical operators and value comparisons within objects.

Traditional approaches in native JavaScript often clash with stringent CSP directives. The scarcity of secure parsers capable of replacing eval or new Function() constructors was notably surprising. These traditional methods are alarmingly prone to injection attacks and hijacking vulnerabilities. Although there is a debate among experts about the relative safety of modern new Function() constructs compared to the notoriously unsafe eval function, browser standard authorities deem them risky enough to warrant caution.

In our quest to deliver high-security applications, we recognized the need for a parser that not only supports dynamic services but also adheres to strict security standards. JS Lexer is our solution to this challenge, striking a balance between dynamic code execution and robust security measures.

Technically, the expression parser is based on the principles of the Shunting yard algorithm.

🛠 Usage

import { safeFunction } from '@datadayrepos/js-lexer'

// execute the function here and pass in necesarry arguments
const result = safeFunction(
  expression, // js like expression as string
  context, // main object
  subcontext, // sub object of parent
  langObject // special case for i18n translation parser
)

1. The objects

The objects in this context refer to any valid JavaScript object structure, with the exception of functions. This primarily includes object structures and arrays.

The term "subobject" is used to describe a subset of the main object, although it can, in principle, be an independent entity.

The expressions

Expressions within this framework are subject to certain restrictions:

Scope Limitation: Expressions can only reference the two objects passed into the function. They do not have access to global variables or any other external data. This limitation is central to the security model.

Syntax and Policies: First Context Object: The mandatory context object can be referred to in one of two ways:

  • Using the notation '$.path.to.something', with "$." as the initial path marker.
  • Alternatively, as "rootFormData."

Second Context Object: This object can be referenced as:

  • '$$$.path.to.something', with "$$$." as the initial path marker.
  • Or, as "parentFormData."

Expressions Involvement: It is feasible to construct expressions that reference either one or both of these objects.

Language Context Object: This is a special case. It will traverse the path of an i18n-style language object passed in: Using the expression marker 't()'.

Examples:

Here are some examples of expressions that conform to the specified syntax and policies:

Accessing an Array Element and Checking for a Value:

'rootFormData.array_1[0].multicheckbox_1.includes(\'value2\')'

This expression accesses the first element of array_1 in rootFormData and checks if multicheckbox_1 includes the value 'value2'.

Negating a Property Value:

'!rootFormData.c.bb'

Here, the expression negates the boolean value of property bb within the c object of rootFormData.

Comparing a Property Value to a Number:

'rootFormData.ll[3].tt < 5'

In this case, the expression checks if the tt property in the third index of the ll array in rootFormData is less than 5.

Ternary Expression:

rootFormData.status === 'active' ? 'Status is active' : 'Status is inactive'

The expression checks if rootFormData.status is equal to 'active'. If true, it evaluates to 'Status is active'. If false, it evaluates to 'Status is inactive'.

Language Parser Usage:

't(myNameSpace.c)'

This expression uses the language context object to retrieve a translated string, accessing the c property within the myNameSpace namespace.

Each of these examples demonstrates how to construct expressions within the defined syntax rules, enabling the manipulation and evaluation of JavaScript object properties in a secure manner.

Supported operations

These are the currently supported operations:

Comparison Operations These operations are used for comparing values:

!: Not, for negation or inequality checks.

: Greater than. <: Less than.

JavaScript Specific Operations Operations that are specific to JavaScript functionality:

.: Dot operator, currently supports .includes() method for array and string inclusion checks. t: Internationalization function, supports t() syntax for language translations.

Logical Operations These are used for logical reasoning and flow control:

&: Logical AND. :: Used in conditional (ternary) expressions. =: Assignment or equality. ?: Used in conditional (ternary) expressions. |: Logical OR.

Mathematical Operations Operations for performing mathematical calculations:

%: Modulus, for finding the remainder. (: Opening parenthesis for grouping expressions. ): Closing parenthesis for grouping expressions. *: Multiplication. +: Addition. -: Subtraction. /: Division.

String Operations Operations specifically for handling strings:

': Single quotes for defining string literals. `: Backticks for defining string literals. ": Double quotes for defining string literals.

Each of these operations plays a specific role in manipulating and evaluating expressions within your system, ensuring a structured and secure way to handle JavaScript expressions.

2. Install

npm install @datadayrepos/js-lexer

3. Develop

Your src directory is where your TypeScript source files reside. Transpiled files are output to the dist directory. The dist-test dir holds a larger output with test functions and objects.

💻 DEV Commands

Build: Transpile TypeScript to JavaScript

pnpm run build

Linting: Check and fix code style

pnpm run lint
pnpm run lint:fix

Release: Bump version and publish

pnpm run release

Testing: Run tests (tbd)

pnpm run test

Type Checking: Validate TypeScript

pnpm run typecheck

Publish: Publish package publicly

pnpm run pub

Test e2e: Builds tests-build and runs the tests of the parser and compiler

pnpm run test:e2e

Test e2e: Builds tests-build and runs the tests of the getvalue parser

pnpm run test:getPathVal

4. Todo

This is Beta 1. We expect some issues.

  • The reverser is nearly developed but not accessible in this api. This constructs expressions from AST trees. It is usefull for integration with UIX based expression builders.

  • We expect some issues with using expressions that uses js "includes"

📦 Template Structure

{
  "name": "__PACKAGE_NAME__",
  "type": "module",
  "version": "0.0.1",
  "private": true,
  "description": "__PACKAGE_DESCRIPTION__",
  "scripts": {
    "lint": "eslint --cache .",
    "lint:fix": "eslint . --fix",
    "release": "bumpp -r && pnpm -r publish",
    "test": "echo \"Error: no test specified\" && exit 1",
    "typecheck": "tsc --noEmit",
    "build": "tsc",
    "pub": "npm publish --access public"
  }
}

🗂️ File Structure

  • src/: Source files written in TypeScript.
  • dist/: Transpiled source files in JavaScript.
  • dist-test/: Transpiled source files in JavaScript in test mode.

🔗 Links

📄 License

Proprietary License © 2023 Ivar Strand