Template API: Expression evaluation package (#40556)

This commit is contained in:
Matt Sherman 2023-10-09 09:22:17 -04:00 committed by GitHub
commit 8ac66ab2b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2088 additions and 41 deletions

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -0,0 +1 @@
package-lock=false

View File

@ -0,0 +1,3 @@
# Changelog
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

View File

@ -0,0 +1,314 @@
# @woocommerce/expression-evaluation
Evaluation of JavaScript-like expressions in an optional context.
Examples of simple expressions:
```js
1 + 2
```
```js
foo === 'bar'
```
```js
foo ? 'bar' : 'baz'
```
Examples of complex expressions:
```js
foo.bar.baz === 'qux'
```
```js
foo.bar
&& ( foo.bar.baz === 'qux' || foo.baz === 'quux' )
```
```js
foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
```
```js
foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
? "boo"
: "baa"
```
```js
foo
+ 5
/* This is a comment */
* ( bar ? baz : qux )
```
## API
### evaluate
Evaluates an expression in an optional context.
#### Usage
```js
import { evaluate } from '@woocommerce/expression-evaluation';
const result = evaluate( '1 + foo', { foo: 2 } );
console.log( result ); // 3
```
#### Parameters
- _expression_ `string`: The expression to evaluate.
- _context_ `Object`: Optional. The context to evaluate the expression in. Variables in the expression will be looked up in this object.
#### Returns
- `any`: The result of the expression evaluation.
## Expression syntax
### Grammar and types
The expression syntax is based on JavaScript. The formal grammar is defined in [parser.ts](./src/parser.ts).
An expression consists of a single statement.
Features like `if` statements, `for` loops, function calls, and variable assignments, are not supported.
The following types are supported:
- `null`
- Boolean: `true` and `false`
- Number: An integer or floating point number.
- String: A sequence of characters that represent text.
### Literals
Values in an expression can be written as literals.
#### null
```js
null
```
#### Boolean
```js
true
false
```
#### Number
```js
1
5.23
-9
```
#### String
String literals can be written with single or double quotes. This can be helpful if the string contains a single or double quote.
```js
'foo'
"foo"
'foo "bar"'
"foo 'bar'"
```
Quotes can be escaped with a backslash.
```js
'foo \'bar\''
"foo \"bar\""
```
### Context variables
Variables can be used in an expression. The value of a variable is looked up in the context.
```js
const result = evaluate( 'foo', { foo: 1 } );
console.log( result ); // 1
```
Nested properties can be accessed with the dot operator.
```js
const result = evaluate( 'foo.bar', { foo: { bar: 1 } } );
console.log( result ); // 1
```
### Operators
The following operators are supported.
#### Comparison operators
##### Equal (`==`)
Returns `true` if the operands are equal.
```js
1 == 1
```
##### Not equal (`!=`)
Returns `true` if the operands are not equal.
```js
1 != 2
```
##### Strict equal (`===`)
Returns `true` if the operands are equal and of the same type.
```js
1 === 1
```
##### Strict not equal (`!==`)
Returns `true` if the operands are not equal and/or not of the same type.
```js
1 !== "1"
```
##### Greater than (`>`)
Returns `true` if the left operand is greater than the right operand.
```js
2 > 1
```
##### Greater than or equal (`>=`)
Returns `true` if the left operand is greater than or equal to the right operand.
```js
2 >= 2
```
##### Less than (`<`)
Returns `true` if the left operand is less than the right operand.
```js
1 < 2
```
##### Less than or equal (`<=`)
Returns `true` if the left operand is less than or equal to the right operand.
```js
2 <= 2
```
#### Arithmetic operators
##### Addition (`+`)
Returns the sum of two operands.
```js
1 + 2
```
##### Subtraction (`-`)
Returns the difference of two operands.
```js
2 - 1
```
##### Multiplication (`*`)
Returns the product of two operands.
```js
2 * 3
```
##### Division (`/`)
Returns the quotient of two operands.
```js
6 / 2
```
##### Modulus (`%`)
Returns the remainder of two operands.
```js
5 % 2
```
##### Negation (`-`)
Returns the negation of an operand.
```js
-1
```
#### Logical operators
##### Logical AND (`&&`)
Returns `true` if both operands are `true`.
```js
true && true
```
##### Logical OR (`||`)
Returns `true` if either operand is `true`.
```js
true || false
```
##### Logical NOT (`!`)
Returns `true` if the operand is `false`.
```js
!false
```
#### Conditional (ternary) operator
Returns the first value if the condition is `true`, otherwise it returns the second value.
```js
true ? 1 : 2
```
### Comments
Comments can be used to document an expression. Comments are treated as whitespace and are ignored by the parser.
```js
/* This is a comment */
```

View File

@ -0,0 +1,3 @@
module.exports = {
extends: '../internal-js-tests/babel.config.js',
};

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Initial @woocommerce/expression-evaluation package.

View File

@ -0,0 +1,32 @@
{
"name": "woocommerce/expression-evaluation",
"description": "WooCommerce expression evaluation library",
"type": "library",
"license": "GPL-3.0-or-later",
"minimum-stability": "dev",
"require-dev": {
"automattic/jetpack-changelogger": "3.3.0"
},
"config": {
"platform": {
"php": "7.2"
}
},
"extra": {
"changelogger": {
"formatter": {
"filename": "../../../tools/changelogger/class-package-formatter.php"
},
"types": {
"fix": "Fixes an existing bug",
"add": "Adds functionality",
"update": "Update existing functionality",
"dev": "Development related task",
"tweak": "A minor adjustment to the codebase",
"performance": "Address performance issues",
"enhancement": "Improve existing functionality"
},
"changelog": "CHANGELOG.md"
}
}
}

View File

@ -0,0 +1,483 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "76226c5737d8666789d8a162710469da",
"packages": [],
"packages-dev": [
{
"name": "automattic/jetpack-changelogger",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/jetpack-changelogger.git",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Automattic/jetpack-changelogger/zipball/8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"shasum": ""
},
"require": {
"php": ">=5.6",
"symfony/console": "^3.4 || ^5.2 || ^6.0",
"symfony/process": "^3.4 || ^5.2 || ^6.0",
"wikimedia/at-ease": "^1.2 || ^2.0"
},
"require-dev": {
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0",
"yoast/phpunit-polyfills": "1.0.4"
},
"bin": [
"bin/changelogger"
],
"type": "project",
"extra": {
"autotagger": true,
"branch-alias": {
"dev-trunk": "3.3.x-dev"
},
"mirror-repo": "Automattic/jetpack-changelogger",
"version-constants": {
"::VERSION": "src/Application.php"
},
"changelogger": {
"link-template": "https://github.com/Automattic/jetpack-changelogger/compare/${old}...${new}"
}
},
"autoload": {
"psr-4": {
"Automattic\\Jetpack\\Changelog\\": "lib",
"Automattic\\Jetpack\\Changelogger\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.",
"support": {
"source": "https://github.com/Automattic/jetpack-changelogger/tree/v3.3.0"
},
"time": "2022-12-26T13:49:01+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "symfony/console",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/debug": "~2.8|~3.0|~4.0",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "symfony/debug",
"version": "4.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v4.4.44"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"abandoned": "symfony/error-handler",
"time": "2022-07-28T16:29:46+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/process",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "wikimedia/at-ease",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/wikimedia/at-ease.git",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wikimedia/at-ease/zipball/013ac61929797839c80a111a3f1a4710d8248e7a",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a",
"shasum": ""
},
"require": {
"php": ">=5.6.99"
},
"require-dev": {
"jakub-onderka/php-console-highlighter": "0.3.2",
"jakub-onderka/php-parallel-lint": "1.0.0",
"mediawiki/mediawiki-codesniffer": "22.0.0",
"mediawiki/minus-x": "0.3.1",
"ockcyp/covers-validator": "0.5.1 || 0.6.1",
"phpunit/phpunit": "4.8.36 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/Wikimedia/Functions.php"
],
"psr-4": {
"Wikimedia\\AtEase\\": "src/Wikimedia/AtEase/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Tim Starling",
"email": "tstarling@wikimedia.org"
},
{
"name": "MediaWiki developers",
"email": "wikitech-l@lists.wikimedia.org"
}
],
"description": "Safe replacement to @ for suppressing warnings.",
"homepage": "https://www.mediawiki.org/wiki/at-ease",
"support": {
"source": "https://github.com/wikimedia/at-ease/tree/master"
},
"time": "2018-10-10T15:39:06+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"platform-overrides": {
"php": "7.2"
},
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,4 @@
{
"rootDir": "./src",
"preset": "../node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}

View File

@ -0,0 +1,69 @@
{
"name": "@woocommerce/expression-evaluation",
"version": "0.0.1",
"description": "Library for evaluating expressions.",
"author": "Automattic",
"license": "GPL-3.0-or-later",
"keywords": [
"wordpress",
"woocommerce",
"expression",
"evalution"
],
"engines": {
"node": "^16.14.1",
"pnpm": "^8.6.7"
},
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/expression-evaluation/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
"types": "build-types",
"react-native": "src/index",
"dependencies": {
"@wordpress/i18n": "wp-6.0",
"peggy": "^3.0.2"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"turbo:build": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"turbo:test": "jest --config ./jest.config.json",
"prepare": "composer install",
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",
"lint:fix": "eslint src --fix",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@types/jest": "^27.4.1",
"@woocommerce/eslint-plugin": "workspace:*",
"@woocommerce/internal-js-tests": "workspace:*",
"concurrently": "^7.0.0",
"eslint": "^8.32.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^5.1.6"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"pnpm lint:fix",
"pnpm test-staged"
]
}
}

View File

@ -0,0 +1,9 @@
/**
* Internal dependencies
*/
import { parser } from './parser';
export function evaluate( expression: string, context = {} ) {
return parser.parse( expression, { context } );
}

View File

@ -0,0 +1,404 @@
/**
* External dependencies
*/
import * as peggy from 'peggy';
const grammar = `
{{
function evaluateUnaryExpression( operator, operand ) {
switch ( operator ) {
case '!':
return !operand;
break;
case '-':
return -operand;
break;
case '+':
return +operand;
break;
default:
return undefined;
break;
}
}
function evaluateBinaryExpression( head, tail ) {
return tail.reduce( ( leftOperand, tailElement ) => {
const operator = tailElement[ 1 ];
const rightOperand = tailElement[ 3 ];
switch ( operator ) {
case '&&':
return leftOperand && rightOperand;
break;
case '||':
return leftOperand || rightOperand;
break;
case '===':
return leftOperand === rightOperand;
break;
case '!==':
return leftOperand !== rightOperand;
break;
case '==':
return leftOperand == rightOperand;
break;
case '!=':
return leftOperand != rightOperand;
break;
case '<=':
return leftOperand <= rightOperand;
break;
case '<':
return leftOperand < rightOperand;
break;
case '>=':
return leftOperand >= rightOperand;
break;
case '>':
return leftOperand > rightOperand;
break;
case '+':
return leftOperand + rightOperand;
break;
case '-':
return leftOperand - rightOperand;
break;
case '*':
return leftOperand * rightOperand;
break;
case '/':
return leftOperand / rightOperand;
break;
case '%':
return leftOperand % rightOperand;
break;
default:
return undefined;
break;
}
}, head );
}
}}
Start
= Expression
SourceCharacter
= .
WhiteSpace
= " "
/ "\\t"
LineTerminator
= "\\n"
/ "\\r"
/ "\\u2028"
/ "\\u2029"
LineTerminatorSequence
= "\\n"
/ "\\r\\n"
/ "\\r"
/ "\\u2028"
/ "\\u2029"
Comment "comment"
= MultiLineComment
MultiLineComment
= "/*" (!"*/" SourceCharacter)* "*/"
__ "skipped"
= (WhiteSpace / LineTerminatorSequence / Comment)*
IdentifierPath
= variable:Identifier accessor:(__ "." __ Identifier)* {
const path = variable.split( '.' );
let result = path.reduce( ( nextObject, propertyName ) => nextObject[ propertyName ], options.context );
for ( let i = 0; i < accessor.length; i++ ) {
result = result[ accessor[ i ][ 3 ] ];
}
return result;
}
Identifier
= !ReservedWord name:IdentifierName {
return name;
}
IdentifierName
= first:IdentifierStart rest:IdentifierPart* {
return text();
}
IdentifierStart
= [a-zA-Z]
/ "_"
/ "$"
IdentifierPart
= IdentifierStart
ReservedWord
= NullLiteral
/ BooleanLiteral
// Literals
Literal
= NullLiteral
/ BooleanLiteral
/ NumericLiteral
/ StringLiteral
NullLiteral
= NullToken { return null; }
BooleanLiteral
= "true" { return true; }
/ "false" { return false; }
NumericLiteral
= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {
return literal;
}
/ literal:DecimalLiteral !(IdentifierStart / DecimalDigit) {
return literal;
}
HexIntegerLiteral
= "0x"i digits:$HexDigit+ {
return parseInt( digits, 16 );
}
HexDigit
= [0-9a-f]i
DecimalLiteral
= DecimalIntegerLiteral "." DecimalDigit* ExponentPart? {
return parseFloat( text() );
}
/ "." DecimalDigit+ ExponentPart? {
return parseFloat( text() );
}
/ DecimalIntegerLiteral ExponentPart? {
return parseFloat( text() );
}
DecimalIntegerLiteral
= "0"
/ NonZeroDigit DecimalDigit*
DecimalDigit
= [0-9]
NonZeroDigit
= [1-9]
ExponentPart
= ExponentIndicator SignedInteger
ExponentIndicator
= "e"i
SignedInteger
= [+-]? DecimalDigit+
StringLiteral
= '"' chars:DoubleQuotedStringCharacter* '"' {
return chars.join( '' );
}
/ "'" chars:SingleQuotedStringCharacter* "'" {
return chars.join( '' );
}
DoubleQuotedStringCharacter
= !('"' / "\\\\" / LineTerminator) SourceCharacter {
return text();
}
/ "\\\\" escapeSequence:EscapeSequence {
return escapeSequence;
}
/ LineContinuation
SingleQuotedStringCharacter
= !("'" / "\\\\" / LineTerminator) SourceCharacter {
return text();
}
/ "\\\\" escapeSequence:EscapeSequence {
return escapeSequence;
}
/ LineContinuation
LineContinuation
= "\\\\" LineTerminatorSequence {
return '';
}
EscapeSequence
= CharacterEscapeSequence
/ "0" !DecimalDigit {
return "\\0";
}
/ HexEscapeSequence
/ UnicodeEscapeSequence
CharacterEscapeSequence
= SingleEscapeCharacter
/ NonEscapeCharacter
SingleEscapeCharacter
= "'"
/ '"'
/ "\\\\"
/ "b" {
return "\\b";
}
/ "f" {
return "\\f";
}
/ "n" {
return "\\n";
}
/ "r" {
return "\\r";
}
/ "t" {
return "\\t";
}
/ "v" {
return "\\v";
}
NonEscapeCharacter
= (!EscapeCharacter / LineTerminator) SourceCharacter {
return text();
}
EscapeCharacter
= SingleEscapeCharacter
/ DecimalDigit
/ "x"
/ "u"
HexEscapeSequence
= "x" digits:$(HexDigit HexDigit) {
return String.fromCharCode( parseInt( digits, 16 ) );
}
UnicodeEscapeSequence
= "u" digits:$(HexDigit HexDigit HexDigit HexDigit) {
return String.fromCharCode( parseInt( digits, 16 ) );
}
// Tokens
NullToken
= "null" !IdentifierPart
TrueToken
= "true" !IdentifierPart
FalseToken
= "false" !IdentifierPart
// Expressions
PrimaryExpression
= IdentifierPath
/ Literal
/ "(" __ expression:Expression __ ")" {
return expression;
}
UnaryExpression
= PrimaryExpression
/ operator:UnaryOperator __ operand:UnaryExpression {
return evaluateUnaryExpression( operator, operand );
}
UnaryOperator
= "!"
/ "-"
/ "+"
MultiplicativeExpression
= head:UnaryExpression tail:(__ MultiplicativeOperator __ UnaryExpression)* {
return evaluateBinaryExpression( head, tail );
}
MultiplicativeOperator
= "*"
/ "/"
/ "%"
AdditiveExpression
= head:MultiplicativeExpression tail:(__ AdditiveOperator __ MultiplicativeExpression)* {
return evaluateBinaryExpression( head, tail );
}
AdditiveOperator
= "+"
/ "-"
RelationalExpression
= head:AdditiveExpression tail:(__ RelationalOperator __ AdditiveExpression)* {
return evaluateBinaryExpression( head, tail );
}
RelationalOperator
= "<="
/ "<"
/ ">="
/ ">"
EqualityExpression
= head:RelationalExpression tail:(__ EqualityOperator __ RelationalExpression)* {
return evaluateBinaryExpression( head, tail );
}
EqualityOperator
= "==="
/ "!=="
/ "=="
/ "!="
LogicalAndExpression
= head:EqualityExpression tail:(__ LogicalAndOperator __ EqualityExpression)* {
return evaluateBinaryExpression( head, tail );
}
LogicalAndOperator
= "&&"
LogicalOrExpression
= head:LogicalAndExpression tail:(__ LogicalOrOperator __ LogicalAndExpression)* {
return evaluateBinaryExpression( head, tail );
}
LogicalOrOperator
= "||"
ConditionalExpression
= condition:LogicalOrExpression __ ConditionalTrueOperator __ expressionIfTrue:ConditionalExpression __ ConditionalFalseOperator __ expressionIfFalse:ConditionalExpression {
return condition ? expressionIfTrue : expressionIfFalse;
}
/ LogicalOrExpression
ConditionalTrueOperator
= "?"
ConditionalFalseOperator
= ":"
Expression
= __ expression:ConditionalExpression __ {
return expression;
}
`;
export const parser = peggy.generate( grammar );

View File

@ -0,0 +1,482 @@
/**
* Internal dependencies
*/
import { evaluate } from '../';
describe( 'evaluate', () => {
it( 'should evaluate a null literal', () => {
const result = evaluate( 'null' );
expect( result ).toEqual( null );
} );
it( 'should evaluate a boolean true literal', () => {
const result = evaluate( 'true' );
expect( result ).toEqual( true );
} );
it( 'should evaluate a boolean false literal', () => {
const result = evaluate( 'false' );
expect( result ).toEqual( false );
} );
it( 'should evaluate a numeric integer literal', () => {
const result = evaluate( '23' );
expect( result ).toEqual( 23 );
} );
it( 'should evaluate a signed negative integer literal', () => {
const result = evaluate( '-1' );
expect( result ).toEqual( -1 );
} );
it( 'should evaluate a signed positive integer literal', () => {
const result = evaluate( '+1' );
expect( result ).toEqual( 1 );
} );
it( 'should evaluate a numeric floating point literal', () => {
const result = evaluate( '5.23' );
expect( result ).toEqual( 5.23 );
} );
it( 'should evaluate a signed negative floating point literal', () => {
const result = evaluate( '-9.95' );
expect( result ).toEqual( -9.95 );
} );
it( 'should evaluate a signed positive floating point literal', () => {
const result = evaluate( '+9.95' );
expect( result ).toEqual( 9.95 );
} );
it( 'should evaluate a numeric hexadecimal literal', () => {
const result = evaluate( '0x23' );
expect( result ).toEqual( 35 );
} );
it( 'should evaluate a string literal with double quotes', () => {
const result = evaluate( '"foo"' );
expect( result ).toEqual( 'foo' );
} );
it( 'should evaluate a string literal with double quotes and single quotes', () => {
const result = evaluate( '"foo \'bar\'"' );
expect( result ).toEqual( "foo 'bar'" );
} );
it( 'should evaluate a string literal with double quotes and escaped double quotes', () => {
const result = evaluate( '"foo \\"bar\\""' );
expect( result ).toEqual( 'foo "bar"' );
} );
it( 'should evaluate a string literal with double quotes and escaped backslashes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( '"foo \\\\\\"bar\\\\\\""' );
expect( result ).toEqual( 'foo \\"bar\\"' );
} );
it( 'should evaluate a string literal with single quotes', () => {
const result = evaluate( "'foo'" );
expect( result ).toEqual( 'foo' );
} );
it( 'should evaluate a string literal with single quotes and double quotes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( "'foo \"bar\"'" );
expect( result ).toEqual( 'foo "bar"' );
} );
it( 'should evaluate a string literal with single quotes and escaped single quotes', () => {
const result = evaluate( "'foo \\'bar\\''" );
expect( result ).toEqual( "foo 'bar'" );
} );
it( 'should evaluate a string literal with single quotes and escaped backslashes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( "'foo \\\\\\'bar\\\\\\''" );
expect( result ).toEqual( "foo \\'bar\\'" );
} );
it( 'should evaluate a literal with whitespace around it', () => {
const result = evaluate( ' 23 ' );
expect( result ).toEqual( 23 );
} );
it( 'should evaluate a top-level context property', () => {
const result = evaluate( 'foo', {
foo: 'bar',
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a top-level context property with whitespace', () => {
const result = evaluate( ' foo ', {
foo: 'bar',
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a nested context property', () => {
const result = evaluate( 'foo.bar', {
foo: {
bar: 'baz',
},
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with whitespace', () => {
const result = evaluate( 'foo. bar', {
foo: {
bar: 'baz',
},
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with multiple lines', () => {
const result = evaluate(
`foo.
bar`,
{
foo: {
bar: 'baz',
},
}
);
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a NOT expression', () => {
const result = evaluate( '!foo', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a double NOT expression', () => {
const result = evaluate( '!!foo', {
foo: true,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a NOT expression with parentheses', () => {
const result = evaluate( '!( foo )', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a NOT expression with parentheses and spaces', () => {
const result = evaluate( '! ( foo ) ', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a multiplication expression', () => {
const result = evaluate( 'foo * 2', {
foo: 2,
} );
expect( result ).toEqual( 4 );
} );
it( 'should evaluate a division expression', () => {
const result = evaluate( 'foo / 2', {
foo: 4,
} );
expect( result ).toEqual( 2 );
} );
it( 'should evaluate a modulo expression', () => {
const result = evaluate( 'foo % 2', {
foo: 5,
} );
expect( result ).toEqual( 1 );
} );
it( 'should evaluate an addition expression', () => {
const result = evaluate( 'foo + 2', {
foo: 3,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate a subtraction expression', () => {
const result = evaluate( 'foo - 2', {
foo: 5,
} );
expect( result ).toEqual( 3 );
} );
it( 'should evaluate a complex arithmetic expression', () => {
const result = evaluate( 'foo * 2 + 1', {
foo: 3,
} );
expect( result ).toEqual( 7 );
} );
it( 'should evaluate a complex arithmetic expression with parenthesis', () => {
const result = evaluate( 'foo * (2 + 1)', {
foo: 3,
} );
expect( result ).toEqual( 9 );
} );
it( 'should evaluate a less than or equal expression', () => {
const result = evaluate( 'foo <= 1', {
foo: 1,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a less than expression', () => {
const result = evaluate( 'foo < 1', {
foo: 1,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a greater than or equal expression', () => {
const result = evaluate( 'foo >= 1', {
foo: 1,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a greater than expression', () => {
const result = evaluate( 'foo > 1', {
foo: 1,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate an strict equality expression', () => {
const result = evaluate( 'foo === "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an strict inequality expression', () => {
const result = evaluate( 'foo !== "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate an equality expression', () => {
const result = evaluate( 'foo == "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an inequality expression', () => {
const result = evaluate( 'foo != "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a conditional expression that is true', () => {
const result = evaluate( 'foo ? "bar" : "baz"', {
foo: true,
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a conditional expression that is false', () => {
const result = evaluate( 'foo ? "bar" : "baz"', {
foo: false,
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a logical OR expression', () => {
const result = evaluate( 'foo || bar', {
foo: true,
bar: false,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a logical AND expression', () => {
const result = evaluate( 'foo && bar', {
foo: true,
bar: false,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a multiline expression', () => {
const result = evaluate(
`foo
|| bar
|| baz`,
{
foo: false,
bar: false,
baz: true,
}
);
expect( result ).toEqual( true );
} );
it( 'should evaluate a complex expression', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )`,
{
foo: {
bar: true,
baz: 'quux',
},
}
);
expect( result ).toEqual( true );
} );
it( 'should evaluate a complex expression with arithmetic, relational, and logical operators', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )`,
{
foo: {
bar: true,
baz: 'quux',
quux: 10,
},
}
);
expect( result ).toEqual( false );
} );
it( 'should evaluate a complex expression with conditional, arithmetic, relational, and logical operators', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
? "boo"
: "baa"`,
{
foo: {
bar: true,
baz: 'quux',
quux: 10,
},
}
);
expect( result ).toEqual( 'baa' );
} );
it( 'should evaluate an expression with needless parentheses', () => {
const result = evaluate( '(((foo)))', {
foo: true,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an expression with a multiline comment at the end', () => {
const result = evaluate( 'foo /* + 23 */', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment at the beginning', () => {
const result = evaluate( '/* 23 + */ foo', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment in the middle', () => {
const result = evaluate( 'foo + /* 23 */ bar', {
foo: 5,
bar: 3,
} );
expect( result ).toEqual( 8 );
} );
it( 'should evaluate a multiline expression with a multiline comment', () => {
const result = evaluate(
`foo
/*
+ bar
+ boo
*/
+ baz`,
{
foo: 5,
bar: 23,
boo: 6,
baz: 3,
}
);
expect( result ).toEqual( 8 );
} );
it( 'should throw an error if the expression is invalid', () => {
expect( () => evaluate( '= 1' ) ).toThrow();
} );
} );

View File

@ -0,0 +1,11 @@
{
"extends": "../tsconfig-cjs",
"compilerOptions": {
"declaration": true,
"outDir": "build",
"typeRoots": [
"./typings",
"./node_modules/@types"
]
}
}

View File

@ -0,0 +1,14 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"rootDir": "src",
"outDir": "build-module",
"declaration": true,
"declarationMap": true,
"declarationDir": "./build-types",
"typeRoots": [
"./typings",
"./node_modules/@types"
]
}
}

View File

@ -1825,6 +1825,49 @@ importers:
specifier: ^5.1.6
version: 5.1.6
packages/js/expression-evaluation:
dependencies:
'@wordpress/i18n':
specifier: wp-6.0
version: 4.6.1
peggy:
specifier: ^3.0.2
version: 3.0.2
devDependencies:
'@babel/core':
specifier: ^7.17.5
version: 7.21.3
'@types/jest':
specifier: ^27.4.1
version: 27.4.1
'@woocommerce/eslint-plugin':
specifier: workspace:*
version: link:../eslint-plugin
'@woocommerce/internal-js-tests':
specifier: workspace:*
version: link:../internal-js-tests
concurrently:
specifier: ^7.0.0
version: 7.0.0
eslint:
specifier: ^8.32.0
version: 8.32.0
jest:
specifier: ^27.5.1
version: 27.5.1
jest-cli:
specifier: ^27.5.1
version: 27.5.1
rimraf:
specifier: ^3.0.2
version: 3.0.2
ts-jest:
specifier: ^27.1.3
version: 27.1.3(@babel/core@7.21.3)(@types/jest@27.4.1)(jest@27.5.1)(typescript@5.1.6)
typescript:
specifier: ^5.1.6
version: 5.1.6
packages/js/extend-cart-checkout-block: {}
packages/js/integrate-plugin:
@ -4482,7 +4525,7 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.21.3
'@jridgewell/trace-mapping': 0.3.19
'@jridgewell/trace-mapping': 0.3.16
commander: 4.1.1
convert-source-map: 1.8.0
fs-readdir-recursive: 1.1.0
@ -4726,6 +4769,32 @@ packages:
browserslist: 4.19.3
semver: 6.3.0
/@babel/helper-compilation-targets@7.17.7(@babel/core@7.12.9):
resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/compat-data': 7.21.0
'@babel/core': 7.12.9
'@babel/helper-validator-option': 7.21.0
browserslist: 4.19.3
semver: 6.3.0
dev: true
/@babel/helper-compilation-targets@7.17.7(@babel/core@7.17.8):
resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/compat-data': 7.21.0
'@babel/core': 7.17.8
'@babel/helper-validator-option': 7.21.0
browserslist: 4.19.3
semver: 6.3.0
dev: true
/@babel/helper-compilation-targets@7.17.7(@babel/core@7.21.3):
resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==}
engines: {node: '>=6.9.0'}
@ -5011,7 +5080,7 @@ packages:
dependencies:
'@babel/core': 7.17.8
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.21.5
debug: 4.3.4(supports-color@9.2.2)
lodash.debounce: 4.0.8
resolve: 1.22.1
@ -5027,7 +5096,7 @@ packages:
dependencies:
'@babel/core': 7.21.3
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.3)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.21.5
debug: 4.3.4(supports-color@9.2.2)
lodash.debounce: 4.0.8
resolve: 1.22.1
@ -6414,7 +6483,7 @@ packages:
'@babel/compat-data': 7.21.0
'@babel/core': 7.12.9
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.12.9)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9)
'@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.12.9)
dev: true
@ -6428,7 +6497,7 @@ packages:
'@babel/compat-data': 7.21.0
'@babel/core': 7.17.8
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.17.8)
'@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.17.8)
dev: true
@ -6815,7 +6884,7 @@ packages:
dependencies:
'@babel/core': 7.12.9
'@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.12.9)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
dev: true
/@babel/plugin-proposal-unicode-property-regex@7.16.7(@babel/core@7.17.8):
@ -6826,7 +6895,7 @@ packages:
dependencies:
'@babel/core': 7.17.8
'@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
dev: true
/@babel/plugin-proposal-unicode-property-regex@7.16.7(@babel/core@7.21.3):
@ -8271,7 +8340,7 @@ packages:
dependencies:
'@babel/core': 7.17.8
'@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
dev: true
/@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.21.3):
@ -8282,7 +8351,7 @@ packages:
dependencies:
'@babel/core': 7.21.3
'@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-plugin-utils': 7.22.5
/@babel/plugin-transform-flow-strip-types@7.16.7(@babel/core@7.12.9):
resolution: {integrity: sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg==}
@ -8704,12 +8773,10 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.12.9
'@babel/helper-module-transforms': 7.21.2
'@babel/helper-plugin-utils': 7.20.2
'@babel/helper-simple-access': 7.18.6
'@babel/helper-module-transforms': 7.22.15(@babel/core@7.12.9)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-simple-access': 7.22.5
babel-plugin-dynamic-import-node: 2.3.3
transitivePeerDependencies:
- supports-color
dev: true
/@babel/plugin-transform-modules-commonjs@7.17.7(@babel/core@7.17.8):
@ -8719,12 +8786,10 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.17.8
'@babel/helper-module-transforms': 7.21.2
'@babel/helper-plugin-utils': 7.20.2
'@babel/helper-simple-access': 7.18.6
'@babel/helper-module-transforms': 7.22.15(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-simple-access': 7.22.5
babel-plugin-dynamic-import-node: 2.3.3
transitivePeerDependencies:
- supports-color
dev: true
/@babel/plugin-transform-modules-commonjs@7.17.7(@babel/core@7.21.3):
@ -8761,8 +8826,8 @@ packages:
dependencies:
'@babel/core': 7.17.8
'@babel/helper-module-transforms': 7.22.15(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-simple-access': 7.20.2
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-simple-access': 7.22.5
dev: true
/@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.21.3):
@ -8773,8 +8838,8 @@ packages:
dependencies:
'@babel/core': 7.21.3
'@babel/helper-module-transforms': 7.22.15(@babel/core@7.21.3)
'@babel/helper-plugin-utils': 7.21.5
'@babel/helper-simple-access': 7.20.2
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-simple-access': 7.22.5
/@babel/plugin-transform-modules-commonjs@7.22.15(@babel/core@7.12.9):
resolution: {integrity: sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==}
@ -10390,7 +10455,7 @@ packages:
dependencies:
'@babel/compat-data': 7.17.7
'@babel/core': 7.12.9
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.12.9)
'@babel/helper-compilation-targets': 7.17.7(@babel/core@7.12.9)
'@babel/helper-plugin-utils': 7.18.9
'@babel/helper-validator-option': 7.16.7
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.16.7(@babel/core@7.12.9)
@ -10457,12 +10522,12 @@ packages:
'@babel/plugin-transform-unicode-escapes': 7.16.7(@babel/core@7.12.9)
'@babel/plugin-transform-unicode-regex': 7.16.7(@babel/core@7.12.9)
'@babel/preset-modules': 0.1.5(@babel/core@7.12.9)
'@babel/types': 7.22.15
'@babel/types': 7.17.0
babel-plugin-polyfill-corejs2: 0.3.0(@babel/core@7.12.9)
babel-plugin-polyfill-corejs3: 0.5.2(@babel/core@7.12.9)
babel-plugin-polyfill-regenerator: 0.3.0(@babel/core@7.12.9)
core-js-compat: 3.21.1
semver: 6.3.1
semver: 6.3.0
transitivePeerDependencies:
- supports-color
dev: true
@ -10475,7 +10540,7 @@ packages:
dependencies:
'@babel/compat-data': 7.17.7
'@babel/core': 7.17.8
'@babel/helper-compilation-targets': 7.20.7(@babel/core@7.17.8)
'@babel/helper-compilation-targets': 7.17.7(@babel/core@7.17.8)
'@babel/helper-plugin-utils': 7.18.9
'@babel/helper-validator-option': 7.16.7
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.16.7(@babel/core@7.17.8)
@ -10542,12 +10607,12 @@ packages:
'@babel/plugin-transform-unicode-escapes': 7.16.7(@babel/core@7.17.8)
'@babel/plugin-transform-unicode-regex': 7.16.7(@babel/core@7.17.8)
'@babel/preset-modules': 0.1.5(@babel/core@7.17.8)
'@babel/types': 7.22.15
'@babel/types': 7.17.0
babel-plugin-polyfill-corejs2: 0.3.0(@babel/core@7.17.8)
babel-plugin-polyfill-corejs3: 0.5.2(@babel/core@7.17.8)
babel-plugin-polyfill-regenerator: 0.3.0(@babel/core@7.17.8)
core-js-compat: 3.21.1
semver: 6.3.1
semver: 6.3.0
transitivePeerDependencies:
- supports-color
dev: true
@ -12165,6 +12230,49 @@ packages:
- ts-node
dev: true
/@jest/core@29.6.2:
resolution: {integrity: sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/console': 29.6.2
'@jest/reporters': 29.6.2
'@jest/test-result': 29.6.2
'@jest/transform': 29.6.2
'@jest/types': 29.6.1
'@types/node': 16.18.21
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.2.0
exit: 0.1.2
graceful-fs: 4.2.9
jest-changed-files: 29.5.0
jest-config: 29.6.2(@types/node@16.18.21)
jest-haste-map: 29.6.2
jest-message-util: 29.6.2
jest-regex-util: 29.4.3
jest-resolve: 29.6.2
jest-resolve-dependencies: 29.6.2
jest-runner: 29.6.2
jest-runtime: 29.6.2
jest-snapshot: 29.6.2
jest-util: 29.6.2
jest-validate: 29.6.2
jest-watcher: 29.6.2
micromatch: 4.0.5
pretty-format: 29.6.2
slash: 3.0.0
strip-ansi: 6.0.1
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
- ts-node
dev: false
/@jest/core@29.6.2(ts-node@10.9.1):
resolution: {integrity: sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -12206,6 +12314,7 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/@jest/create-cache-key-function@27.5.1:
resolution: {integrity: sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==}
@ -13040,7 +13149,6 @@ packages:
dependencies:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
/@jridgewell/trace-mapping@0.3.17:
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
@ -21428,7 +21536,7 @@ packages:
'@babel/runtime': 7.21.0
'@wordpress/keycodes': 2.19.3
'@wordpress/url': 2.22.2(react-native@0.70.0)
jest: 29.6.2(@types/node@16.18.21)(ts-node@10.9.1)
jest: 29.6.2(@types/node@16.18.21)
lodash: 4.17.21
node-fetch: 2.6.7
puppeteer: 2.1.1
@ -21449,7 +21557,7 @@ packages:
'@wordpress/keycodes': 3.6.1
'@wordpress/url': 3.7.1
form-data: 4.0.0
jest: 29.6.2(@types/node@16.18.21)(ts-node@10.9.1)
jest: 29.6.2(@types/node@16.18.21)
lodash: 4.17.21
node-fetch: 2.6.7
puppeteer-core: 19.7.3(typescript@5.1.6)
@ -28204,12 +28312,8 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
/decimal.js@10.3.1:
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
/decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
dev: true
/decode-uri-component@0.2.0:
resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==}
@ -28268,7 +28372,6 @@ packages:
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dev: true
/deepsignal@1.3.6(@preact/signals@1.2.1)(preact@10.17.1):
resolution: {integrity: sha512-yjd+vtiznL6YaMptOsKnEKkPr60OEApa+LRe+Qe6Ile/RfCOrELKk/YM3qVpXFZiyOI3Ng67GDEyjAlqVc697g==}
@ -34442,6 +34545,35 @@ packages:
- ts-node
dev: true
/jest-cli@29.6.2(@types/node@16.18.21):
resolution: {integrity: sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.6.2
'@jest/test-result': 29.6.2
'@jest/types': 29.6.1
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.9
import-local: 3.0.3
jest-config: 29.6.2(@types/node@16.18.21)
jest-util: 29.6.2
jest-validate: 29.6.2
prompts: 2.4.2
yargs: 17.5.1
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- supports-color
- ts-node
dev: false
/jest-cli@29.6.2(@types/node@16.18.21)(ts-node@10.9.1):
resolution: {integrity: sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -34469,6 +34601,7 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/jest-config@24.9.0:
resolution: {integrity: sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==}
@ -34576,7 +34709,7 @@ packages:
babel-jest: 27.5.1(@babel/core@7.21.3)
chalk: 4.1.2
ci-info: 3.2.0
deepmerge: 4.3.0
deepmerge: 4.3.1
glob: 7.2.3
graceful-fs: 4.2.9
jest-circus: 27.5.1
@ -34639,6 +34772,46 @@ packages:
- supports-color
dev: true
/jest-config@29.6.2(@types/node@16.18.21):
resolution: {integrity: sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
peerDependencies:
'@types/node': '*'
ts-node: '>=9.0.0'
peerDependenciesMeta:
'@types/node':
optional: true
ts-node:
optional: true
dependencies:
'@babel/core': 7.21.3
'@jest/test-sequencer': 29.6.2
'@jest/types': 29.6.1
'@types/node': 16.18.21
babel-jest: 29.6.2(@babel/core@7.21.3)
chalk: 4.1.2
ci-info: 3.2.0
deepmerge: 4.3.1
glob: 7.2.3
graceful-fs: 4.2.9
jest-circus: 29.6.2
jest-environment-node: 29.6.2
jest-get-type: 29.4.3
jest-regex-util: 29.4.3
jest-resolve: 29.6.2
jest-runner: 29.6.2
jest-util: 29.6.2
jest-validate: 29.6.2
micromatch: 4.0.5
parse-json: 5.2.0
pretty-format: 29.6.2
slash: 3.0.0
strip-json-comments: 3.1.1
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
dev: false
/jest-config@29.6.2(@types/node@16.18.21)(ts-node@10.9.1):
resolution: {integrity: sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -34678,6 +34851,7 @@ packages:
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
dev: true
/jest-dev-server@4.4.0:
resolution: {integrity: sha512-STEHJ3iPSC8HbrQ3TME0ozGX2KT28lbT4XopPxUm2WimsX3fcB3YOptRh12YphQisMhfqNSNTZUmWyT3HEXS2A==}
@ -36729,6 +36903,27 @@ packages:
- ts-node
dev: true
/jest@29.6.2(@types/node@16.18.21):
resolution: {integrity: sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.6.2
'@jest/types': 29.6.1
import-local: 3.0.3
jest-cli: 29.6.2(@types/node@16.18.21)
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
- supports-color
- ts-node
dev: false
/jest@29.6.2(@types/node@16.18.21)(ts-node@10.9.1):
resolution: {integrity: sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -36748,6 +36943,7 @@ packages:
- babel-plugin-macros
- supports-color
- ts-node
dev: true
/jmespath@0.16.0:
resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==}
@ -37000,7 +37196,7 @@ packages:
cssom: 0.4.4
cssstyle: 2.3.0
data-urls: 2.0.0
decimal.js: 10.3.1
decimal.js: 10.4.3
domexception: 2.0.1
escodegen: 2.0.0
form-data: 3.0.1
@ -40612,6 +40808,15 @@ packages:
sha.js: 2.4.11
dev: true
/peggy@3.0.2:
resolution: {integrity: sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==}
engines: {node: '>=14'}
hasBin: true
dependencies:
commander: 10.0.1
source-map-generator: 0.8.0
dev: false
/pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
@ -44993,6 +45198,11 @@ packages:
/source-list-map@2.0.1:
resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==}
/source-map-generator@0.8.0:
resolution: {integrity: sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==}
engines: {node: '>= 10'}
dev: false
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
@ -46786,7 +46996,7 @@ packages:
json5: 2.2.3
lodash.memoize: 4.1.2
make-error: 1.3.6
semver: 7.5.0
semver: 7.5.3
typescript: 5.1.6
yargs-parser: 20.2.9
dev: true
@ -46821,7 +47031,7 @@ packages:
json5: 2.2.3
lodash.memoize: 4.1.2
make-error: 1.3.6
semver: 7.5.0
semver: 7.5.3
typescript: 5.1.6
yargs-parser: 20.2.9
dev: true