Save current BZZZ config-ui state before CHORUS branding update

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-08-19 00:19:00 +10:00
parent 6a6a49b7b1
commit c177363a19
16410 changed files with 1789161 additions and 230 deletions

View File

@@ -0,0 +1,8 @@
{
"presets": ["env"],
"plugins": [
["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }],
"transform-object-rest-spread",
// "@babel/plugin-proposal-nullish-coalescing-operator", // TODO: update to babel 7
],
}

View File

@@ -0,0 +1,4 @@
node_modules/
reports/
lib/
coverage/

20
install/config-ui/node_modules/jsx-ast-utils/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,20 @@
{
"root": true,
"extends": "airbnb-base",
"parser": "@babel/eslint-parser",
"rules": {
"no-use-before-define": ["error", { "functions": false }],
},
"overrides": [
{
"files": "src/index.js",
"rules": {
"import/no-import-module-exports": 0,
},
},
],
}

View File

@@ -0,0 +1,5 @@
# These are supported funding model platforms
github: [jsx-eslint, ljharb]
open_collective: eslint-plugin-jsx-a11y
tidelift: "npm/jsx-ast-utils"

View File

@@ -0,0 +1,231 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v3.3.5](https://github.com/jsx-eslint/jsx-ast-utils/compare/v3.3.4...v3.3.5) - 2023-07-28
### Fixed
- [Fix] `extractProp`: support `JSXFragment` [`#132`](https://github.com/jsx-eslint/jsx-ast-utils/issues/132)
### Commits
- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/parser`, `eslint` [`e5555d1`](https://github.com/jsx-eslint/jsx-ast-utils/commit/e5555d152dbe1e85324139756f637e65fe047976)
- [Tests] fix a test [`bde3ba9`](https://github.com/jsx-eslint/jsx-ast-utils/commit/bde3ba9c9dc294d5472eefa0b3f31ab0e1aed739)
## [v3.3.4](https://github.com/jsx-eslint/jsx-ast-utils/compare/v3.3.3...v3.3.4) - 2023-06-28
### Commits
- [Refactor] use `array.prototype.flat` `object.values` over `.reduce` [`bad51d0`](https://github.com/jsx-eslint/jsx-ast-utils/commit/bad51d062000ffdc19d925723a6515458318cf92)
- [meta] add `auto-changelog` [`af1de69`](https://github.com/jsx-eslint/jsx-ast-utils/commit/af1de693d1005144c13a75573631a670fa44547e)
- [Tests] add test for `import.meta` [`1d39f58`](https://github.com/jsx-eslint/jsx-ast-utils/commit/1d39f58c7bc6a89aa936e666b76e355c9436e854)
- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/parser`, `aud`, `eslint`, `eslint-plugin-import` [`3baaf76`](https://github.com/jsx-eslint/jsx-ast-utils/commit/3baaf76c9c48ae85687ed23a3b9894c45927e081)
- [Fix] `TSNonNullExpression`: Handle function calls [`26cc3c4`](https://github.com/jsx-eslint/jsx-ast-utils/commit/26cc3c48165518b9fcdc9c625d918accc3e00107)
- [Dev Deps] update `eslint`, `@babel/core`, `@babel/parser`, `object.entries`, `object.fromentries` [`0e4f80c`](https://github.com/jsx-eslint/jsx-ast-utils/commit/0e4f80c2129c5b5ee50e4df2f25c5fb6728cbe8e)
- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/parser`, `aud` [`b5427a6`](https://github.com/jsx-eslint/jsx-ast-utils/commit/b5427a65fac33e2264461b072b3edb078242dc85)
- [meta] run build in prepack, not prepublish [`a0f4f38`](https://github.com/jsx-eslint/jsx-ast-utils/commit/a0f4f383ddf82cd2914c7e594f356d9a78c80570)
- [Deps] update `array-includes` [`c479841`](https://github.com/jsx-eslint/jsx-ast-utils/commit/c479841d0b65188a3223541e885fa6286756a2c6)
- [Deps] update `object.assign` [`9685dce`](https://github.com/jsx-eslint/jsx-ast-utils/commit/9685dce823d71ac06fccd61d8aa8e13ba3d42f38)
<!-- auto-changelog-above -->
3.3.3 / 2022-08-08
==================
- [Fix] Mark ChainExpression as a noop (#109)
- [Deps] update `object.assign`
- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/parser`, `eslint`
3.3.2 / 2022-07-06
==================
- [Fix] Handle `as` casts in TSNonNullExpression
3.3.1 / 2022-06-22
==================
- [Fix] `ArrayExpression`: handle sparse array (#117)
- [Deps] update `array-includes`
- [meta] move jest config to separate file
- [meta] use `npmignore` to autogenerate an npmignore file
- [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/parser`, `eslint`
3.3.0 / 2022-04-30
==================
- [New] add `JSXFragment`, `JSXText`; fix `JSXElement` to handle children
- [Dev Deps] update `@babel/core`, `@babel/parser`, `eslint`, `eslint-plugin-import`
3.2.2 / 2022-03-31
==================
- [Fix] `TSNonNullExpression`: handle computed MemberExpressions (#109)
- [Fix] avoid a crash in ChainExpressions in a TSAsExpression
3.2.1 / 2021-09-16
==================
- [patch] include project name in error logging (#113)
- [readme] update badges, URLs
- [Deps] update `array-includes`
- [meta] dont lint coverage results
- [meta] add GitHub org to FUNDING.yml
- [meta] add OpenCollective to FUNDING.yml
- [meta] run `aud` in `posttest`
- [meta] add Automatic Rebase and Require Allow Edits workflows
- [actions] use `node/install` instead of `node/run`; use `codecov` action
- [Tests] unpin `caniuse-lite`, since breaking change is fixed
- [Tests] pin `caniuse-lite`, due to breaking change in patch version
- [Tests] fix linting errors
- [Tests] migrate tests to Github Actions
- [Tests] stop using coveralls
- [Tests] skip failing fragment test in node 4
- [Dev Deps] update `@babel/core`, `@babel/parser`, `aud`, `eslint`, `eslint-plugin-import`, `object.entries`, `object.fromentries`
3.2.0 / 2020-12-16
==================
- [New] add support for fragment syntax (`<>`) (#108)
- [Fix] `TSNonNullExpression`: handle `ThisExpression`s (#108)
- [Deps] update `array-includes`, `object.assign`
- [Dev Deps] update `@babel/core`, `@babel/parser`, `eslint`, `eslint-config-airbnb-base`, `object.entries`, `object.fromentries`
3.1.0 / 2020-10-13
==================
- [New] add `TSNonNullExpression` (#105)
- [New] add `AssignmentExpression` (#106)
- [Dev Deps] update `eslint`
3.0.0 / 2020-10-06
==================
- [Breaking] Don't return node.start & node.end (#100)
- [Breaking] add `ChainExpression`; `CallExpression` now includes arguments (#102)
- [New] add `SequenceExpression` (#101)
- [Deps] update `object.assign`
- [Dev Deps] update `eslint`, `eslint-plugin-import`
- [Dev Deps] update `@babel/core`, `@babel/parser`, `eslint`, `eslint-plugin-import`
- [Tests] use proper `actual, expected` ordering for non-confusing failure messages
2.4.1 / 2020-06-11
==================
- [Fix] `expressions/TemplateLiteral`: use `.range[0]` instead of `.start`
2.4.0 / 2020-06-11
==================
- [New] Provide both range and start & end property on Node, support eslint v7 (#97)
- [Dev Deps] update `@babel/core`, `@babel/parser`, `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-import`, `flow-parser`
- [meta] remove yarn registry from npmrc, so `npm publish` works
2.3.0 / 2020-05-24
==================
- [New] add nullish coalescing (#99)
- [New] add OptionalCallExpression (#99)
- [Deps] update `array-includes`
- [meta] add `safe-publish-latest`
- [Dev Deps] update `@babel/parser`, `babel-eslint`, `coveralls`, `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-import`, `in-publish`, `object.entries`, `object.fromentries`, `rimraf`
- [Tests] on `node` `v14`; test all branches
2.2.3 / 2019-10-24
==================
- (fix) Fix crash on spread (#94)
2.2.2 / 2019-10-24
==================
- (improvement) Add support for retrieving props from a spread with object expression (#93)
2.2.1 / 2019-06-30
==================
- (improvement) Account for TypeCastExpression in the utils
2.2.0 / 2019-06-25
==================
- (fix) Fix getLiteralPropValue for TS-specific node types.
- (chore) upgrade dependencies.
- (improvement) Stop throwing errors when unknown AST nodes are encountered.
- (dev) CI changes.
2.1.0 / 2018-04-19
==================
- Fix undefined bug for template strings. #45
- Adding support for `objectRestSpread` within props #60
- Accommodate ExperimentalSpreadProperty in prop values #75
- Account for SpreadElement AST Nodes #76
- Support OptionalMemberExpression AST nodes #77
- Add support to Typescript's node types #72
2.0.1 / 2017-08-31
==================
- [fix] Add support for BindExpression
2.0.0 / 2017-07-07
==================
- [breaking] Remove undefined return from `propName` so it always returns a value.
1.4.1 / 2017-04-19
==================
- [fix] - Fixing fatal throw in `getPropValue` for `ArrowFunctionExpression`
1.4.0 / 2017-02-02
==================
- [new] Add eventHandlers and eventHandlersByType to API. These are the event names for DOM elements on JSX-using libraries such as React, inferno, and preact.
1.3.5 / 2016-12-14
==================
- [fix] Normalize literals "true" and "false" before converting to boolean in Literal prop value extractor.
1.3.4 / 2016-11-15
==================
- [fix] Recursively resolve JSXMemberExpression names for elementType. (i.e. `<Component.Render.Me />`). Fixes [#9](https://github.com/evcohen/jsx-ast-utils/issues/9)
1.3.3 / 2016-10-28
==================
- [fix] Add support for `ArrayExpression`.
1.3.2 / 2016-10-11
==================
- [fix] Add support for `UpdateExpression`.
1.3.1 / 2016-07-13
==================
- [fix] Add `JSXElement` to expression types to handle recursively extracting prop value.
1.3.0 / 2016-07-12
==================
- [new] Add support for `TaggedTemplateExpression`.
1.2.1 / 2016-06-15
==================
- [fix] Point to `lib` instead of `src` for root exports.
1.2.0 / 2016-06-15
==================
- [new] Export functions from root so they can be imported like the following: `require('jsx-ast-utils/{function}')`.
1.1.1 / 2016-06-12
==================
- [fix] Better support for expressions in `TemplateLiteral` extraction.
1.1.0 / 2016-06-10
==================
- [new] Support for namespaced element names.
- [new] Add `propName` to API to get correct name for prop.
1.0.1 / 2016-06-10
==================
- [fix] Return actual reserved words instead of string representations of them.
1.0.0 / 2016-06-09
==================
- Initial stable release

View File

@@ -0,0 +1,8 @@
The MIT License (MIT)
Copyright (c) 2016 Ethan Cohen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

298
install/config-ui/node_modules/jsx-ast-utils/README.md generated vendored Normal file
View File

@@ -0,0 +1,298 @@
# jsx-ast-utils <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
[![github actions][actions-image]][actions-url]
[![coverage][codecov-image]][codecov-url]
[![dependency status][deps-svg]][deps-url]
[![dev dependency status][dev-deps-svg]][dev-deps-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![npm badge][npm-badge-png]][package-url]
AST utility module for statically analyzing JSX.
## Installation
```sh
$ npm i jsx-ast-utils --save
```
## Usage
This is a utility module to evaluate AST objects for JSX syntax. This can be super useful when writing linting rules for JSX code. It was originally in the code for [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y), however I thought it could be useful to be extracted and maintained separately so **you** could write new interesting rules to statically analyze JSX.
### ESLint example
```js
import { hasProp } from 'jsx-ast-utils';
// OR: var hasProp = require('jsx-ast-utils').hasProp;
// OR: const hasProp = require('jsx-ast-utils/hasProp');
// OR: import hasProp from 'jsx-ast-utils/hasProp';
module.exports = context => ({
JSXOpeningElement: node => {
const onChange = hasProp(node.attributes, 'onChange');
if (onChange) {
context.report({
node,
message: `No onChange!`
});
}
}
});
```
## API
### AST Resources
1. [JSX spec](https://github.com/facebook/jsx/blob/master/AST.md)
2. [JS spec](https://github.com/estree/estree/blob/master/spec.md)
### hasProp
```js
hasProp(props, prop, options);
```
Returns boolean indicating whether an prop exists as an attribute on a JSX element node.
#### Props
Object - The attributes on the visited node. (Usually `node.attributes`).
#### Prop
String - A string representation of the prop you want to check for existence.
#### Options
Object - An object representing options for existence checking
1. `ignoreCase` - automatically set to `true`.
2. `spreadStrict` - automatically set to `true`. This means if spread operator exists in
props, it will assume the prop you are looking for is not in the spread.
Example: `<div {...props} />` looking for specific prop here will return false if `spreadStrict` is `true`.
<hr />
### hasAnyProp
```js
hasAnyProp(props, prop, options);
```
Returns a boolean indicating if **any** of props in `prop` argument exist on the node.
#### Props
Object - The attributes on the visited node. (Usually `node.attributes`).
#### Prop
Array<String> - An array of strings representing the props you want to check for existence.
#### Options
Object - An object representing options for existence checking
1. `ignoreCase` - automatically set to `true`.
2. `spreadStrict` - automatically set to `true`. This means if spread operator exists in
props, it will assume the prop you are looking for is not in the spread.
Example: `<div {...props} />` looking for specific prop here will return false if `spreadStrict` is `true`.
<hr />
### hasEveryProp
```js
hasEveryProp(props, prop, options);
```
Returns a boolean indicating if **all** of props in `prop` argument exist on the node.
#### Props
Object - The attributes on the visited node. (Usually `node.attributes`).
#### Prop
Array<String> - An array of strings representing the props you want to check for existence.
#### Options
Object - An object representing options for existence checking
1. `ignoreCase` - automatically set to `true`.
2. `spreadStrict` - automatically set to `true`. This means if spread operator exists in
props, it will assume the prop you are looking for is not in the spread.
Example: `<div {...props} />` looking for specific prop here will return false if `spreadStrict` is `true`.
<hr />
### getProp
```js
getProp(props, prop, options);
```
Returns the JSXAttribute itself or undefined, indicating the prop is not present on the JSXOpeningElement.
#### Props
Object - The attributes on the visited node. (Usually `node.attributes`).
#### Prop
String - A string representation of the prop you want to check for existence.
#### Options
Object - An object representing options for existence checking
1. `ignoreCase` - automatically set to `true`.
<hr />
### elementType
```js
elementType(node)
```
Returns the tagName associated with a JSXElement.
#### Node
Object - The visited JSXElement node object.
<hr />
### getPropValue
```js
getPropValue(prop);
```
Returns the value of a given attribute. Different types of attributes have their associated values in different properties on the object.
This function should return the most *closely* associated value with the intention of the JSX.
#### Prop
Object - The JSXAttribute collected by AST parser.
<hr />
### getLiteralPropValue
```js
getLiteralPropValue(prop);
```
Returns the value of a given attribute. Different types of attributes have their associated values in different properties on the object.
This function should return a value only if we can extract a literal value from its attribute (i.e. values that have generic types in JavaScript - strings, numbers, booleans, etc.)
#### Prop
Object - The JSXAttribute collected by AST parser.
<hr />
### propName
```js
propName(prop);
```
Returns the name associated with a JSXAttribute. For example, given `<div foo="bar" />` and the JSXAttribute for `foo`, this will return the string `"foo"`.
#### Prop
Object - The JSXAttribute collected by AST parser.
<hr />
### eventHandlers
```js
console.log(eventHandlers);
/*
[
'onCopy',
'onCut',
'onPaste',
'onCompositionEnd',
'onCompositionStart',
'onCompositionUpdate',
'onKeyDown',
'onKeyPress',
'onKeyUp',
'onFocus',
'onBlur',
'onChange',
'onInput',
'onSubmit',
'onClick',
'onContextMenu',
'onDblClick',
'onDoubleClick',
'onDrag',
'onDragEnd',
'onDragEnter',
'onDragExit',
'onDragLeave',
'onDragOver',
'onDragStart',
'onDrop',
'onMouseDown',
'onMouseEnter',
'onMouseLeave',
'onMouseMove',
'onMouseOut',
'onMouseOver',
'onMouseUp',
'onSelect',
'onTouchCancel',
'onTouchEnd',
'onTouchMove',
'onTouchStart',
'onScroll',
'onWheel',
'onAbort',
'onCanPlay',
'onCanPlayThrough',
'onDurationChange',
'onEmptied',
'onEncrypted',
'onEnded',
'onError',
'onLoadedData',
'onLoadedMetadata',
'onLoadStart',
'onPause',
'onPlay',
'onPlaying',
'onProgress',
'onRateChange',
'onSeeked',
'onSeeking',
'onStalled',
'onSuspend',
'onTimeUpdate',
'onVolumeChange',
'onWaiting',
'onLoad',
'onError',
'onAnimationStart',
'onAnimationEnd',
'onAnimationIteration',
'onTransitionEnd',
]
*/
```
Contains a flat list of common event handler props used in JSX to attach behaviors
to DOM events.
#### eventHandlersByType
The same list as `eventHandlers`, grouped into types.
```js
console.log(eventHandlersByType);
/*
{
clipboard: [ 'onCopy', 'onCut', 'onPaste' ],
composition: [ 'onCompositionEnd', 'onCompositionStart', 'onCompositionUpdate' ],
keyboard: [ 'onKeyDown', 'onKeyPress', 'onKeyUp' ],
focus: [ 'onFocus', 'onBlur' ],
form: [ 'onChange', 'onInput', 'onSubmit' ],
mouse: [ 'onClick', 'onContextMenu', 'onDblClick', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp' ],
selection: [ 'onSelect' ],
touch: [ 'onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart' ],
ui: [ 'onScroll' ],
wheel: [ 'onWheel' ],
media: [ 'onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', 'onError', 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting' ],
image: [ 'onLoad', 'onError' ],
animation: [ 'onAnimationStart', 'onAnimationEnd', 'onAnimationIteration' ],
transition: [ 'onTransitionEnd' ],
}
*/
```
[1]: https://npmjs.org/package/jsx-ast-utils
[2]: https://versionbadg.es/jsx-eslint/jsx-ast-utils.svg
[5]: https://david-dm.org/jsx-eslint/jsx-ast-utils.svg
[6]: https://david-dm.org/jsx-eslint/jsx-ast-utils
[7]: https://david-dm.org/jsx-eslint/jsx-ast-utils/dev-status.svg
[8]: https://david-dm.org/jsx-eslint/jsx-ast-utils#info=devDependencies
[11]: https://nodei.co/npm/jsx-ast-utils.png?downloads=true&stars=true
[license-image]: https://img.shields.io/npm/l/jsx-ast-utils.svg
[license-url]: LICENSE
[downloads-image]: https://img.shields.io/npm/dm/jsx-ast-utils.svg
[downloads-url]: https://npm-stat.com/charts.html?package=jsx-ast-utils
[codecov-image]: https://codecov.io/gh/jsx-eslint/jsx-ast-utils/branch/main/graphs/badge.svg
[codecov-url]: https://app.codecov.io/gh/jsx-eslint/jsx-ast-utils/
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/jsx-eslint/jsx-ast-utils
[actions-url]: https://github.com/jsx-eslint/jsx-ast-utils/actions

View File

@@ -0,0 +1,93 @@
/* eslint-env jest */
import getProp from '../src/getProp';
const nodeVersion = parseInt(process.version.match(/^v(\d+)\./)[1], 10);
export const fallbackToBabylon = nodeVersion < 6;
let parserName;
const babelParser = fallbackToBabylon ? require('babylon') : require('@babel/parser');
const flowParser = require('flow-parser');
const defaultPlugins = [
'jsx',
'functionBind',
'estree',
'objectRestSpread',
'optionalChaining',
// 'nullishCoalescing', // TODO: update to babel 7
];
let plugins = [...defaultPlugins];
let isESM = false;
export function setParserName(name) {
parserName = name;
}
export function changePlugins(pluginOrFn) {
if (Array.isArray(pluginOrFn)) {
plugins = pluginOrFn;
} else if (typeof pluginOrFn === 'function') {
plugins = pluginOrFn(plugins);
} else {
throw new Error('changePlugins argument should be either an array or a function');
}
}
export function setIsESM() {
isESM = true;
}
beforeEach(() => {
plugins = [...defaultPlugins];
isESM = false;
});
function parse(code) {
if (parserName === undefined) {
throw new Error('No parser specified');
}
if (parserName === 'babel') {
try {
return babelParser.parse(code, { plugins, sourceFilename: 'test.js', ...(isESM && { sourceType: 'module' }) });
} catch (_) {
// eslint-disable-next-line no-console
console.warn(`Failed to parse with ${fallbackToBabylon ? 'babylon' : 'Babel'} parser.`);
}
}
if (parserName === 'flow') {
try {
return flowParser.parse(code, { plugins });
} catch (_) {
// eslint-disable-next-line no-console
console.warn('Failed to parse with the Flow parser');
}
}
throw new Error(`The parser ${parserName} is not yet supported for testing.`);
}
export function getOpeningElement(code) {
const parsedCode = parse(code);
let body;
if (parsedCode.program) {
// eslint-disable-next-line prefer-destructuring
body = parsedCode.program.body;
} else {
// eslint-disable-next-line prefer-destructuring
body = parsedCode.body;
}
if (Array.isArray(body) && body[0] != null) {
const [{ expression }] = body;
return expression.type === 'JSXFragment' ? expression.openingFragment : expression.openingElement;
}
return null;
}
export function extractProp(code, prop = 'foo') {
const node = getOpeningElement(code);
const { attributes: props } = node;
return getProp(props, prop);
}
export const describeIfNotBabylon = fallbackToBabylon ? describe.skip : describe;

View File

@@ -0,0 +1,118 @@
/* eslint-env mocha */
import assert from 'assert';
import { getOpeningElement, setParserName, describeIfNotBabylon } from '../helper';
import elementType from '../../src/elementType';
describe('elementType tests', () => {
beforeEach(() => {
setParserName('babel');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof elementType;
assert.equal(actual, expected);
});
it('should throw an error if the argument is missing', () => {
assert.throws(() => { elementType(); }, Error);
});
it('should throw an error if the argument not a JSX node', () => {
assert.throws(() => { elementType({ a: 'foo' }); }, Error);
});
it('should return the correct type of the DOM element given its node object', () => {
const code = '<div />';
const node = getOpeningElement(code);
const expected = 'div';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('should return the correct type of the custom element given its node object', () => {
const code = '<Slider />';
const node = getOpeningElement(code);
const expected = 'Slider';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('should return the correct type of the custom object element given its node object', () => {
const code = '<UX.Slider />';
const node = getOpeningElement(code);
const expected = 'UX.Slider';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('should return the correct type of the namespaced element given its node object', () => {
const code = '<UX:Slider />';
const node = getOpeningElement(code);
const expected = 'UX:Slider';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('should return the correct type of the multiple custom object element given its node object', () => {
const code = '<UX.Slider.Blue.Light />';
const node = getOpeningElement(code);
const expected = 'UX.Slider.Blue.Light';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('should return this.Component when given its node object', () => {
const code = '<this.Component />';
const node = getOpeningElement(code);
const expected = 'this.Component';
const actual = elementType(node);
assert.equal(actual, expected);
});
describeIfNotBabylon('fragments', () => {
it('should work with fragments', () => {
const code = '<>foo</>';
const node = getOpeningElement(code);
const expected = '<>';
const actual = elementType(node);
assert.equal(actual, expected);
});
it('works with nested fragments', () => {
const code = `
<Hello
role="checkbox"
frag={
<>
<div>Hello</div>
<>
<div>There</div>
</>
</>
}
/>
`;
const node = getOpeningElement(code);
const expected = 'Hello';
const actual = elementType(node);
assert.equal(actual, expected);
});
});
});

View File

@@ -0,0 +1,101 @@
/* eslint-env mocha */
import assert from 'assert';
import includes from 'array-includes';
import eventHandlers, { eventHandlersByType } from '../../src/eventHandlers';
describe('eventHandlers', () => {
it('should contain a list of common JSX event handlers', () => {
assert([
'onCopy',
'onCut',
'onPaste',
'onCompositionEnd',
'onCompositionStart',
'onCompositionUpdate',
'onKeyDown',
'onKeyPress',
'onKeyUp',
'onFocus',
'onBlur',
'onChange',
'onInput',
'onSubmit',
'onClick',
'onContextMenu',
'onDblClick',
'onDoubleClick',
'onDrag',
'onDragEnd',
'onDragEnter',
'onDragExit',
'onDragLeave',
'onDragOver',
'onDragStart',
'onDrop',
'onMouseDown',
'onMouseEnter',
'onMouseLeave',
'onMouseMove',
'onMouseOut',
'onMouseOver',
'onMouseUp',
'onSelect',
'onTouchCancel',
'onTouchEnd',
'onTouchMove',
'onTouchStart',
'onScroll',
'onWheel',
'onAbort',
'onCanPlay',
'onCanPlayThrough',
'onDurationChange',
'onEmptied',
'onEncrypted',
'onEnded',
'onError',
'onLoadedData',
'onLoadedMetadata',
'onLoadStart',
'onPause',
'onPlay',
'onPlaying',
'onProgress',
'onRateChange',
'onSeeked',
'onSeeking',
'onStalled',
'onSuspend',
'onTimeUpdate',
'onVolumeChange',
'onWaiting',
'onLoad',
'onError',
'onAnimationStart',
'onAnimationEnd',
'onAnimationIteration',
'onTransitionEnd',
].every((handlerName) => includes(eventHandlers, handlerName)));
});
});
describe('eventHandlersByType', () => {
it('should be keyed by type', () => {
assert([
'clipboard',
'composition',
'keyboard',
'focus',
'form',
'mouse',
'selection',
'touch',
'ui',
'wheel',
'media',
'image',
'animation',
'transition',
].every((type) => !!eventHandlersByType[type]));
});
});

View File

@@ -0,0 +1,176 @@
/* eslint-env mocha */
import assert from 'assert';
import entries from 'object.entries';
import fromEntries from 'object.fromentries';
import { getOpeningElement, setParserName, fallbackToBabylon } from '../helper';
import getProp from '../../src/getProp';
const literal = {
source: '<div {...{ id: "foo" }} />',
target: '<div id="foo" />',
offset: { keyOffset: -6, valueOffset: -7 },
};
const expression1 = {
source: '<div {...{ id }} />',
target: '<div id={id} />',
offset: { keyOffset: -6, valueOffset: -2 },
};
const expression2 = {
source: '<div {...{ id: `foo${bar}baz` }} />', // eslint-disable-line no-template-curly-in-string
target: '<div id={`foo${bar}baz`} />', // eslint-disable-line no-template-curly-in-string
offset: { keyOffset: -6, valueOffset: -6 },
};
describe('getProp', () => {
it('should create the correct AST for literal with flow parser', () => {
actualTest('flow', literal);
});
it('should create the correct AST for literal with babel parser', () => {
actualTest('babel', literal);
});
it('should create the correct AST for expression with flow parser (1)', () => {
actualTest('flow', expression1);
});
it('should create the correct AST for expression with babel parser (1)', () => {
actualTest('babel', expression1);
});
it('should create the correct AST for expression with flow parser (2)', () => {
actualTest('flow', expression2);
});
it('should create the correct AST for expression with babel parser (2)', () => {
actualTest('babel', expression2);
});
});
function actualTest(parserName, test) {
setParserName(parserName);
const { source, target, offset } = test;
const sourceProps = stripConstructors(getOpeningElement(source).attributes);
const targetProps = stripConstructors(getOpeningElement(target).attributes);
const prop = 'id';
const sourceResult = getProp(sourceProps, prop);
const targetResult = getProp(targetProps, prop);
if (fallbackToBabylon && parserName === 'babel' && test === literal) {
// Babylon (node < 6) adds an `extra: null` prop to a literal if it is parsed from a
// JSXAttribute, other literals don't get this.
sourceResult.value.extra = null;
}
assert.deepStrictEqual(
adjustLocations(sourceResult, offset),
adjustRange(targetResult),
);
}
function adjustRange({ name, value: { expression, ...value }, ...node }) {
return {
...adjustNodeRange(node),
name: adjustNodeRange(name),
value: {
...adjustNodeRange(value),
...(expression ? { expression: adjustNodeRangeRecursively(expression) } : {}),
},
};
}
function adjustNodeRange(node) {
if (!node.loc) {
return node;
}
const [start, end] = node.range || [node.start, node.end];
return {
...node,
end: undefined,
range: [start, end],
start: undefined,
};
}
function adjustNodeRangeRecursively(node) {
if (Array.isArray(node)) {
return node.map(adjustNodeRangeRecursively);
}
if (node && typeof node === 'object') {
return adjustNodeRange(mapValues(node, adjustNodeRangeRecursively));
}
return node;
}
function stripConstructors(value) {
return JSON.parse(JSON.stringify(value));
}
function adjustLocations(node, { keyOffset, valueOffset }) {
const hasExpression = !!node.value.expression;
return {
...adjustNodeLocations(node, {
startOffset: keyOffset,
endOffset: valueOffset + (hasExpression ? 1 : 0),
}),
name: adjustNodeLocations(node.name, { startOffset: keyOffset, endOffset: keyOffset }),
value: {
...adjustNodeLocations(node.value, {
startOffset: valueOffset - (hasExpression ? 1 : 0),
endOffset: valueOffset + (hasExpression ? 1 : 0),
}),
...(hasExpression
? {
expression: adjustLocationsRecursively(
node.value.expression,
{ startOffset: valueOffset, endOffset: valueOffset },
),
}
: {}
),
},
};
}
function adjustNodeLocations(node, { startOffset, endOffset }) {
if (!node.loc) {
return node;
}
const [start, end] = node.range || [];
return {
...node,
end: undefined,
loc: {
...node.loc,
start: {
...node.loc.start,
column: node.loc.start.column + startOffset,
},
end: {
...node.loc.end,
column: node.loc.end.column + endOffset,
},
},
range: [start + startOffset, end + endOffset],
start: undefined,
};
}
function adjustLocationsRecursively(node, { startOffset, endOffset }) {
if (Array.isArray(node)) {
return node.map((x) => adjustLocationsRecursively(x, { startOffset, endOffset }));
}
if (node && typeof node === 'object') {
return adjustNodeLocations(
mapValues(node, (x) => adjustLocationsRecursively(x, { startOffset, endOffset })),
{ startOffset, endOffset },
);
}
return node;
}
function mapValues(o, f) {
return fromEntries(entries(o).map(([k, v]) => [k, f(v)]));
}

View File

@@ -0,0 +1,149 @@
/* eslint-env mocha */
import assert from 'assert';
import { getOpeningElement, setParserName } from '../helper';
import getProp from '../../src/getProp';
describe('getProp', () => {
beforeEach(() => {
setParserName('babel');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof getProp;
assert.equal(actual, expected);
});
it('should return undefined if no arguments are provided', () => {
const expected = undefined;
const actual = getProp();
assert.equal(actual, expected);
});
it('should return undefined if the attribute is absent', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = undefined;
const actual = getProp(props, prop);
assert.equal(actual, expected);
});
it('should return the correct attribute if the attribute exists', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = 'id';
const actual = getProp(props, prop).name.name;
assert.equal(actual, expected);
});
it('should return the correct attribute if the attribute exists in spread', () => {
const code = '<div {...{ id: "foo" }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'ID';
const expected = 'id';
const actual = getProp(props, prop).name.name;
assert.equal(actual, expected);
});
it('should return the correct attribute if the attribute exists in spread as an expression', () => {
const code = '<div {...{ id }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = 'id';
const actual = getProp(props, prop);
const actualName = actual.name.name;
const actualValue = actual.value.expression.name;
assert.equal(actualName, expected);
assert.equal(actualValue, expected);
});
it('should return the correct attribute if the attribute exists in spread (case sensitive)', () => {
const code = '<div {...{ id: "foo" }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = { ignoreCase: false };
const expected = 'id';
const actual = getProp(props, prop, options).name.name;
assert.equal(actual, expected);
});
it('should return undefined if the attribute does not exist in spread (case sensitive)', () => {
const code = '<div {...{ id: "foo" }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'ID';
const options = { ignoreCase: false };
const expected = undefined;
const actual = getProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return undefined for key in spread', () => {
// https://github.com/reactjs/rfcs/pull/107
const code = '<div {...{ key }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'key';
const expected = undefined;
const actual = getProp(props, prop);
assert.equal(actual, expected);
});
it('should return undefined if the attribute may exist in spread', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = undefined;
const actual = getProp(props, prop);
assert.equal(actual, expected);
});
it('should not crash if the spread contains a spread', () => {
const code = '<div {...{ ...props }} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
getProp(props, prop);
});
it('should return undefined if the attribute is considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
ignoreCase: false,
};
const expected = undefined;
const actual = getProp(props, prop, options);
assert.equal(actual, expected);
});
});

View File

@@ -0,0 +1,556 @@
/* eslint-env mocha */
/* eslint no-template-curly-in-string: 0 */
import assert from 'assert';
import {
extractProp,
describeIfNotBabylon,
changePlugins,
setParserName,
setIsESM,
} from '../helper';
import { getLiteralPropValue } from '../../src/getPropValue';
describe('getLiteralPropValue', () => {
beforeEach(() => {
setParserName('babel');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof getLiteralPropValue;
assert.equal(actual, expected);
});
it('should return undefined when not provided with a JSXAttribute', () => {
const expected = undefined;
const actual = getLiteralPropValue(1);
assert.equal(actual, expected);
});
it('should not throw error when trying to get value from unknown node type', () => {
const prop = {
type: 'JSXAttribute',
value: {
type: 'JSXExpressionContainer',
},
};
let counter = 0;
// eslint-disable-next-line no-console
const errorOrig = console.error;
// eslint-disable-next-line no-console
console.error = () => {
counter += 1;
};
let value;
assert.doesNotThrow(() => {
value = getLiteralPropValue(prop);
}, Error);
assert.equal(null, value);
assert.equal(counter, 1);
// eslint-disable-next-line no-console
console.error = errorOrig;
});
describe('Null', () => {
it('should return true when no value is given', () => {
const prop = extractProp('<div foo />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Literal', () => {
it('should return correct string if value is a string', () => {
const prop = extractProp('<div foo="bar" />');
const expected = 'bar';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct string if value is a string expression', () => {
const prop = extractProp('<div foo={"bar"} />');
const expected = 'bar';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct integer if value is a integer expression', () => {
const prop = extractProp('<div foo={1} />');
const expected = 1;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "true" to boolean type', () => {
const prop = extractProp('<div foo="true" />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "TrUE" to boolean type', () => {
const prop = extractProp('<div foo="TrUE" />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "false" to boolean type', () => {
const prop = extractProp('<div foo="false" />');
const expected = false;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "FaLsE" to boolean type', () => {
const prop = extractProp('<div foo="FaLsE" />');
const expected = false;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return String null when value is null', () => {
const prop = extractProp('<div foo={null} />');
const expected = 'null';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('JSXElement', () => {
it('should return null', () => {
const prop = extractProp('<div foo={<bar />} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Identifier', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when identifier is literally `undefined`', () => {
const prop = extractProp('<div foo={undefined} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describeIfNotBabylon('Chain Expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={abc?.def} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Tagged Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={noop`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={noop`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Arrow function expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ () => { return "bar"; }} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Function expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ function() { return "bar"; } } />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Logical expression', () => {
it('should return null for && operator', () => {
const prop = extractProp('<div foo={bar && baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return null for || operator', () => {
const prop = extractProp('<div foo={bar || baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Member expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar.baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Call expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar()} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Unary expression', () => {
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-bar} />');
// -"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-42} />');
const expected = -42;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+bar} />');
// +"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+42} />');
const expected = 42;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with !', () => {
const prop = extractProp('<div foo={!bar} />');
const expected = false; // !"bar" === false
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with ~', () => {
const prop = extractProp('<div foo={~bar} />');
const expected = -1; // ~"bar" === -1
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return true when evaluating `delete foo`', () => {
const prop = extractProp('<div foo={delete x} />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when evaluating `void foo`', () => {
const prop = extractProp('<div foo={void x} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
// TODO: We should fix this to check to see if we can evaluate it.
it('should return undefined when evaluating `typeof foo`', () => {
const prop = extractProp('<div foo={typeof x} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Update expression', () => {
it('should correctly evaluate an expression that prefixes with ++', () => {
const prop = extractProp('<div foo={++bar} />');
// ++"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with --', () => {
const prop = extractProp('<div foo={--bar} />');
// --"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with ++', () => {
const prop = extractProp('<div foo={bar++} />');
// "bar"++ => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with --', () => {
const prop = extractProp('<div foo={bar--} />');
// "bar"-- => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
});
describe('This expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={this} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Conditional expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar ? baz : bam} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Binary expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={1 == "1"} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Object expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ { bar: "baz" } } />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('New expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={new Bar()} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('Array expression', () => {
it('should evaluate to correct representation of the the array in props', () => {
const prop = extractProp('<div foo={["bar", 42, null]} />');
const expected = ['bar', 42];
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
it('should return an empty array provided an empty array in props', () => {
const prop = extractProp('<div foo={[]} />');
const expected = [];
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
describe('Bind expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={::this.handleClick} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describeIfNotBabylon('import.meta', () => {
beforeEach(() => {
setIsESM();
});
it('should return null', () => {
const prop = extractProp('<div foo={import.meta.env.whyIsThisNotOnProcess} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describeIfNotBabylon('Typescript', () => {
beforeEach(() => {
changePlugins((pls) => [...pls, 'typescript']);
});
it('should return string representation of variable identifier wrapped in a Typescript non-null assertion', () => {
const prop = extractProp('<div foo={bar!} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a deep Typescript non-null assertion', () => {
const prop = extractProp('<div foo={(bar!)!} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a Typescript type coercion', () => {
changePlugins((pls) => [...pls, 'typescript']);
const prop = extractProp('<div foo={bar as any} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should work with a this.props value', () => {
const prop = extractProp('<a href={this.props.href!}>Download</a>', 'href');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
});

View File

@@ -0,0 +1,522 @@
/* eslint-env mocha */
/* eslint no-template-curly-in-string: 0 */
import assert from 'assert';
import {
extractProp,
describeIfNotBabylon,
changePlugins,
setParserName,
} from '../helper';
import { getLiteralPropValue } from '../../src/getPropValue';
describe('getLiteralPropValue', () => {
beforeEach(() => {
setParserName('flow');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof getLiteralPropValue;
assert.equal(actual, expected);
});
it('should return undefined when not provided with a JSXAttribute', () => {
const expected = undefined;
const actual = getLiteralPropValue(1);
assert.equal(actual, expected);
});
it('should not throw error when trying to get value from unknown node type', () => {
const prop = {
type: 'JSXAttribute',
value: {
type: 'JSXExpressionContainer',
},
};
let counter = 0;
// eslint-disable-next-line no-console
const errorOrig = console.error;
// eslint-disable-next-line no-console
console.error = () => {
counter += 1;
};
let value;
assert.doesNotThrow(() => {
value = getLiteralPropValue(prop);
}, Error);
assert.equal(null, value);
assert.equal(counter, 1);
// eslint-disable-next-line no-console
console.error = errorOrig;
});
describe('Null', () => {
it('should return true when no value is given', () => {
const prop = extractProp('<div foo />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Literal', () => {
it('should return correct string if value is a string', () => {
const prop = extractProp('<div foo="bar" />');
const expected = 'bar';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct string if value is a string expression', () => {
const prop = extractProp('<div foo={"bar"} />');
const expected = 'bar';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct integer if value is a integer expression', () => {
const prop = extractProp('<div foo={1} />');
const expected = 1;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "true" to boolean type', () => {
const prop = extractProp('<div foo="true" />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "TrUE" to boolean type', () => {
const prop = extractProp('<div foo="TrUE" />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "false" to boolean type', () => {
const prop = extractProp('<div foo="false" />');
const expected = false;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "FaLsE" to boolean type', () => {
const prop = extractProp('<div foo="FaLsE" />');
const expected = false;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return String null when value is null', () => {
const prop = extractProp('<div foo={null} />');
const expected = 'null';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('JSXElement', () => {
it('should return null', () => {
const prop = extractProp('<div foo={<bar />} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Identifier', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when identifier is literally `undefined`', () => {
const prop = extractProp('<div foo={undefined} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Tagged Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={noop`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={noop`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Arrow function expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ () => { return "bar"; }} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Function expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ function() { return "bar"; } } />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Logical expression', () => {
it('should return null for && operator', () => {
const prop = extractProp('<div foo={bar && baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return null for || operator', () => {
const prop = extractProp('<div foo={bar || baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Member expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar.baz} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Call expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar()} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Unary expression', () => {
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-bar} />');
// -"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-42} />');
const expected = -42;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+bar} />');
// +"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+42} />');
const expected = 42;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with !', () => {
const prop = extractProp('<div foo={!bar} />');
const expected = false; // !"bar" === false
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with ~', () => {
const prop = extractProp('<div foo={~bar} />');
const expected = -1; // ~"bar" === -1
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return true when evaluating `delete foo`', () => {
const prop = extractProp('<div foo={delete x} />');
const expected = true;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when evaluating `void foo`', () => {
const prop = extractProp('<div foo={void x} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
// TODO: We should fix this to check to see if we can evaluate it.
it('should return undefined when evaluating `typeof foo`', () => {
const prop = extractProp('<div foo={typeof x} />');
const expected = undefined;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Update expression', () => {
it('should correctly evaluate an expression that prefixes with ++', () => {
const prop = extractProp('<div foo={++bar} />');
// ++"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with --', () => {
const prop = extractProp('<div foo={--bar} />');
// --"bar" => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with ++', () => {
const prop = extractProp('<div foo={bar++} />');
// "bar"++ => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with --', () => {
const prop = extractProp('<div foo={bar--} />');
// "bar"-- => NaN
const expected = true;
const actual = Number.isNaN(getLiteralPropValue(prop));
assert.equal(actual, expected);
});
});
describe('This expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={this} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Conditional expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={bar ? baz : bam} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Binary expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={1 == "1"} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Object expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={ { bar: "baz" } } />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('New expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={new Bar()} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('Array expression', () => {
it('should evaluate to correct representation of the the array in props', () => {
const prop = extractProp('<div foo={["bar", 42, null]} />');
const expected = ['bar', 42];
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
it('should return an empty array provided an empty array in props', () => {
const prop = extractProp('<div foo={[]} />');
const expected = [];
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
describe('Bind expression', () => {
it('should return null', () => {
const prop = extractProp('<div foo={::this.handleClick} />');
const expected = 'null';
const actual = getLiteralPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describeIfNotBabylon('Typescript', () => {
beforeEach(() => {
changePlugins((pls) => [...pls, 'typescript']);
});
it('should return string representation of variable identifier wrapped in a Typescript non-null assertion', () => {
const prop = extractProp('<div foo={bar!} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a deep Typescript non-null assertion', () => {
const prop = extractProp('<div foo={(bar!)!} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a Typescript type coercion', () => {
changePlugins((pls) => [...pls, 'typescript']);
const prop = extractProp('<div foo={bar as any} />');
const expected = null;
const actual = getLiteralPropValue(prop);
assert.equal(actual, expected);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,963 @@
/* eslint-env mocha */
/* eslint no-template-curly-in-string: 0 */
import assert from 'assert';
import {
extractProp,
changePlugins,
describeIfNotBabylon,
setParserName,
} from '../helper';
import getPropValue from '../../src/getPropValue';
describe('getPropValue', () => {
beforeEach(() => {
setParserName('flow');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof getPropValue;
assert.equal(actual, expected);
});
it('should return undefined when not provided with a JSXAttribute', () => {
const expected = undefined;
const actual = getPropValue(1);
assert.equal(actual, expected);
});
it('should throw not error when trying to get value from unknown node type', () => {
const prop = {
type: 'JSXAttribute',
value: {
type: 'JSXExpressionContainer',
},
};
let counter = 0;
// eslint-disable-next-line no-console
const errorOrig = console.error;
// eslint-disable-next-line no-console
console.error = () => {
counter += 1;
};
let value;
assert.doesNotThrow(() => {
value = getPropValue(prop);
}, Error);
assert.equal(null, value);
assert.equal(counter, 1);
// eslint-disable-next-line no-console
console.error = errorOrig;
});
describe('Null', () => {
it('should return true when no value is given', () => {
const prop = extractProp('<div foo />');
const expected = true;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Literal', () => {
it('should return correct string if value is a string', () => {
const prop = extractProp('<div foo="bar" />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct string if value is a string expression', () => {
const prop = extractProp('<div foo={"bar"} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return correct integer if value is a integer expression', () => {
const prop = extractProp('<div foo={1} />');
const expected = 1;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "true" to boolean type', () => {
const prop = extractProp('<div foo="true" />');
const expected = true;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should convert "false" to boolean type', () => {
const prop = extractProp('<div foo="false" />');
const expected = false;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('JSXElement', () => {
it('should return correct representation of JSX element as a string', () => {
const prop = extractProp('<div foo={<bar />} />');
const expected = '<bar />';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Identifier', () => {
it('should return string representation of variable identifier', () => {
const prop = extractProp('<div foo={bar} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when identifier is literally `undefined`', () => {
const prop = extractProp('<div foo={undefined} />');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return String object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={String} />');
const expected = String;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Array object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Array} />');
const expected = Array;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Date object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Date} />');
const expected = Date;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Infinity object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Infinity} />');
const expected = Infinity;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Math object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Math} />');
const expected = Math;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Number object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Number} />');
const expected = Number;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return Object object when using a reserved JavaScript object', () => {
const prop = extractProp('<div foo={Object} />');
const expected = Object;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return template literal with expression type wrapped in curly braces', () => {
const prop = extractProp('<div foo={`bar ${baz()}`} />');
const expected = 'bar {CallExpression}';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should ignore non-expressions in the template literal', () => {
const prop = extractProp('<div foo={`bar ${<baz />}`} />');
const expected = 'bar ';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Tagged Template literal', () => {
it('should return template literal with vars wrapped in curly braces', () => {
const prop = extractProp('<div foo={noop`bar ${baz}`} />');
const expected = 'bar {baz}';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return string "undefined" for expressions that evaluate to undefined', () => {
const prop = extractProp('<div foo={noop`bar ${undefined}`} />');
const expected = 'bar undefined';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return template literal with expression type wrapped in curly braces', () => {
const prop = extractProp('<div foo={noop`bar ${baz()}`} />');
const expected = 'bar {CallExpression}';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should ignore non-expressions in the template literal', () => {
const prop = extractProp('<div foo={noop`bar ${<baz />}`} />');
const expected = 'bar ';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Arrow function expression', () => {
it('should return a function', () => {
const prop = extractProp('<div foo={ () => { return "bar"; }} />');
const expected = 'function';
const actual = getPropValue(prop);
assert.equal(expected, typeof actual);
// For code coverage ¯\_(ツ)_/¯
actual();
});
it('should handle ArrowFunctionExpression as conditional consequent', () => {
const prop = extractProp('<div foo={ (true) ? () => null : () => ({})} />');
const expected = 'function';
const actual = getPropValue(prop);
assert.equal(expected, typeof actual);
// For code coverage ¯\_(ツ)_/¯
actual();
});
});
describe('Function expression', () => {
it('should return a function', () => {
const prop = extractProp('<div foo={ function() { return "bar"; } } />');
const expected = 'function';
const actual = getPropValue(prop);
assert.equal(expected, typeof actual);
// For code coverage ¯\_(ツ)_/¯
actual();
});
});
describe('Logical expression', () => {
it('should correctly infer result of && logical expression based on derived values', () => {
const prop = extractProp('<div foo={bar && baz} />');
const expected = 'baz';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when evaluating `undefined && undefined` ', () => {
const prop = extractProp('<div foo={undefined && undefined} />');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly infer result of || logical expression based on derived values', () => {
const prop = extractProp('<div foo={bar || baz} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly infer result of || logical expression based on derived values', () => {
const prop = extractProp('<div foo={undefined || baz} />');
const expected = 'baz';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when evaluating `undefined || undefined` ', () => {
const prop = extractProp('<div foo={undefined || undefined} />');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Member expression', () => {
it('should return string representation of form `object.property`', () => {
const prop = extractProp('<div foo={bar.baz} />');
const expected = 'bar.baz';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate to a correct representation of member expression with a nullable member', () => {
const prop = extractProp('<div foo={bar?.baz} />');
const expected = 'bar?.baz';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Call expression', () => {
it('should return string representation of callee', () => {
const prop = extractProp('<div foo={bar()} />');
const expected = 'bar()';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of callee', () => {
const prop = extractProp('<div foo={bar.call()} />');
const expected = 'bar.call()';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Unary expression', () => {
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-bar} />');
// -"bar" => NaN
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with -', () => {
const prop = extractProp('<div foo={-42} />');
const expected = -42;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+bar} />');
// +"bar" => NaN
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with +', () => {
const prop = extractProp('<div foo={+42} />');
const expected = 42;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with !', () => {
const prop = extractProp('<div foo={!bar} />');
const expected = false; // !"bar" === false
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with ~', () => {
const prop = extractProp('<div foo={~bar} />');
const expected = -1; // ~"bar" === -1
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return true when evaluating `delete foo`', () => {
const prop = extractProp('<div foo={delete x} />');
const expected = true;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return undefined when evaluating `void foo`', () => {
const prop = extractProp('<div foo={void x} />');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
// TODO: We should fix this to check to see if we can evaluate it.
it('should return undefined when evaluating `typeof foo`', () => {
const prop = extractProp('<div foo={typeof x} />');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Update expression', () => {
it('should correctly evaluate an expression that prefixes with ++', () => {
const prop = extractProp('<div foo={++bar} />');
// ++"bar" => NaN
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that prefixes with --', () => {
const prop = extractProp('<div foo={--bar} />');
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with ++', () => {
const prop = extractProp('<div foo={bar++} />');
// "bar"++ => NaN
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
it('should correctly evaluate an expression that suffixes with --', () => {
const prop = extractProp('<div foo={bar--} />');
const expected = true;
const actual = Number.isNaN(getPropValue(prop));
assert.equal(actual, expected);
});
});
describe('This expression', () => {
it('should return string value `this`', () => {
const prop = extractProp('<div foo={this} />');
const expected = 'this';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Conditional expression', () => {
it('should evaluate the conditional based on the derived values correctly', () => {
const prop = extractProp('<div foo={bar ? baz : bam} />');
const expected = 'baz';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the conditional based on the derived values correctly', () => {
const prop = extractProp('<div foo={undefined ? baz : bam} />');
const expected = 'bam';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the conditional based on the derived values correctly', () => {
const prop = extractProp('<div foo={(1 > 2) ? baz : bam} />');
const expected = 'bam';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Binary expression', () => {
it('should evaluate the `==` operator correctly', () => {
const trueProp = extractProp('<div foo={1 == "1"} />');
const falseProp = extractProp('<div foo={1 == bar} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `!=` operator correctly', () => {
const trueProp = extractProp('<div foo={1 != "2"} />');
const falseProp = extractProp('<div foo={1 != "1"} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `===` operator correctly', () => {
const trueProp = extractProp('<div foo={1 === 1} />');
const falseProp = extractProp('<div foo={1 === "1"} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `!==` operator correctly', () => {
const trueProp = extractProp('<div foo={1 !== "1"} />');
const falseProp = extractProp('<div foo={1 !== 1} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `<` operator correctly', () => {
const trueProp = extractProp('<div foo={1 < 2} />');
const falseProp = extractProp('<div foo={1 < 0} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `>` operator correctly', () => {
const trueProp = extractProp('<div foo={1 > 0} />');
const falseProp = extractProp('<div foo={1 > 2} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `<=` operator correctly', () => {
const trueProp = extractProp('<div foo={1 <= 1} />');
const falseProp = extractProp('<div foo={1 <= 0} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `>=` operator correctly', () => {
const trueProp = extractProp('<div foo={1 >= 1} />');
const falseProp = extractProp('<div foo={1 >= 2} />');
const trueVal = getPropValue(trueProp);
const falseVal = getPropValue(falseProp);
assert.equal(true, trueVal);
assert.equal(false, falseVal);
});
it('should evaluate the `<<` operator correctly', () => {
const prop = extractProp('<div foo={1 << 2} />');
const expected = 4;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `>>` operator correctly', () => {
const prop = extractProp('<div foo={1 >> 2} />');
const expected = 0;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `>>>` operator correctly', () => {
const prop = extractProp('<div foo={2 >>> 1} />');
const expected = 1;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `+` operator correctly', () => {
const prop = extractProp('<div foo={1 + 1} />');
const expected = 2;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `-` operator correctly', () => {
const prop = extractProp('<div foo={1 - 1} />');
const expected = 0;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `*` operator correctly', () => {
const prop = extractProp('<div foo={10 * 10} />');
const expected = 100;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `/` operator correctly', () => {
const prop = extractProp('<div foo={10 / 2} />');
const expected = 5;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `%` operator correctly', () => {
const prop = extractProp('<div foo={10 % 3} />');
const expected = 1;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `|` operator correctly', () => {
const prop = extractProp('<div foo={10 | 1} />');
const expected = 11;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `^` operator correctly', () => {
const prop = extractProp('<div foo={10 ^ 1} />');
const expected = 11;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `&` operator correctly', () => {
const prop = extractProp('<div foo={10 & 1} />');
const expected = 0;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `in` operator correctly', () => {
const prop = extractProp('<div foo={foo in bar} />');
const expected = false;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `instanceof` operator correctly', () => {
const prop = extractProp('<div foo={{} instanceof Object} />');
const expected = true;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should evaluate the `instanceof` operator when right side is not a function', () => {
const prop = extractProp('<div foo={"bar" instanceof Baz} />');
const expected = false;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('Object expression', () => {
it('should evaluate to a correct representation of the object in props', () => {
const prop = extractProp('<div foo={ { bar: "baz" } } />');
const expected = { bar: 'baz' };
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
it('should evaluate to a correct representation of the object, ignore spread properties', () => {
const prop = extractProp('<div foo={{bar: "baz", ...{baz: "bar", foo: {...{bar: "meh"}}}}} />');
const expected = { bar: 'baz', baz: 'bar', foo: { bar: 'meh' } };
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
it('should evaluate to a correct representation of the object, ignore spread properties', () => {
const prop = extractProp('<div foo={{ pathname: manageRoute, state: {...data}}} />');
const expected = { pathname: 'manageRoute', state: {} };
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('New expression', () => {
it('should return a new empty object', () => {
const prop = extractProp('<div foo={new Bar()} />');
const expected = {};
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('Sequence array expression', () => {
it('should evaluate to correct representation of the the array in props', () => {
const prop = extractProp('<div foo={[{"type":"Literal","start":821,"end":827}]} />');
const expected = [{
type: 'Literal',
start: 821,
end: 827,
}];
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describe('Array expression', () => {
it('should evaluate to correct representation of the the array in props', () => {
const prop = extractProp('<div foo={["bar", 42, null]} />');
const expected = ['bar', 42, null];
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
it('should evaluate to a correct representation of an array with spread elements', () => {
const prop = extractProp('<div foo={[...this.props.params, bar]} />');
const expected = [undefined, 'bar'];
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
});
it('should return an empty array provided an empty array in props', () => {
const prop = extractProp('<div foo={[]} />');
const expected = [];
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
describe('Bind expression', () => {
it('should return string representation of bind function call when object is null', () => {
const prop = extractProp('<div foo={::this.handleClick} />');
const expected = null;
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
it('should return string representation of bind function call when object is not null', () => {
const prop = extractProp('<div foo={foo::bar} />');
const expected = 'foo';
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
it('should return string representation of bind function call when binding to object properties', () => {
const prop = extractProp('<div foo={a.b::c} />');
const otherProp = extractProp('<div foo={::a.b.c} />');
const expected = 'a.b';
const actual = getPropValue(prop);
const otherExpected = null;
const otherActual = getPropValue(otherProp);
assert.deepEqual(actual, expected);
assert.deepEqual(otherActual, otherExpected);
});
});
describe('Type Cast Expression', () => {
it('should return the expression from a type cast', () => {
const prop = extractProp('<div foo={(this.handleClick: (event: MouseEvent) => void))} />');
const expected = 'this.handleClick';
const actual = getPropValue(prop);
assert.deepEqual(actual, expected);
});
});
describeIfNotBabylon('Typescript', () => {
beforeEach(() => {
changePlugins((pls) => [...pls, 'typescript']);
});
it('should return string representation of variable identifier wrapped in a Typescript non-null assertion', () => {
const prop = extractProp('<div foo={bar!} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a deep Typescript non-null assertion', () => {
const prop = extractProp('<div foo={(bar!)!} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
it('should return string representation of variable identifier wrapped in a Typescript type coercion', () => {
changePlugins((pls) => [...pls, 'typescript']);
const prop = extractProp('<div foo={bar as any} />');
const expected = 'bar';
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
describe('JSX empty expression', () => {
it('should work with an empty expression', () => {
const prop = extractProp('<div>\n{/* Hello there */}\n</div>', 'children');
const expected = undefined;
const actual = getPropValue(prop);
assert.equal(actual, expected);
});
});
});

View File

@@ -0,0 +1,412 @@
/* eslint-env mocha */
import assert from 'assert';
import { getOpeningElement, setParserName } from '../helper';
import hasProp, { hasAnyProp, hasEveryProp } from '../../src/hasProp';
describe('hasProp', () => {
beforeEach(() => {
setParserName('babel');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof hasProp;
assert.equal(actual, expected);
});
it('should return false if no arguments are provided', () => {
const expected = false;
const actual = hasProp();
assert.equal(actual, expected);
});
it('should return false if the prop is absent', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = false;
const actual = hasProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if the prop exists', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = true;
const actual = hasProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if the prop may exist in spread loose mode', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
spreadStrict: false,
};
const expected = true;
const actual = hasProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return false if the prop is considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
ignoreCase: false,
};
const expected = false;
const actual = hasProp(props, prop, options);
assert.equal(actual, expected);
});
});
describe('hasAnyProp tests', () => {
it('should export a function', () => {
const expected = 'function';
const actual = typeof hasAnyProp;
assert.equal(actual, expected);
});
it('should return false if no arguments are provided', () => {
const expected = false;
const actual = hasAnyProp();
assert.equal(actual, expected);
});
it('should return false if the prop is absent', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = false;
const actual = hasAnyProp(props, prop);
assert.equal(actual, expected);
});
it('should return false if all props are absent in array', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = ['id', 'className'];
const expected = false;
const actual = hasAnyProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return false if all props are absent in space delimited string', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = 'id className';
const expected = false;
const actual = hasAnyProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return true if the prop exists', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = true;
const actual = hasAnyProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if any prop exists in array', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['className', 'id'];
const expected = true;
const actual = hasAnyProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if any prop exists in space delimited string', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'className id';
const expected = true;
const actual = hasAnyProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if the prop may exist in spread loose mode', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
spreadStrict: false,
};
const expected = true;
const actual = hasAnyProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return true if any prop may exist in spread loose mode', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['id', 'className'];
const options = {
spreadStrict: false,
};
const expected = true;
const actual = hasAnyProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return false if the prop is considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
ignoreCase: false,
};
const expected = false;
const actual = hasAnyProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return false if all props are considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['id', 'iD', 'className'];
const options = {
ignoreCase: false,
};
const expected = false;
const actual = hasAnyProp(props, prop, options);
assert.equal(actual, expected);
});
});
describe('hasEveryProp tests', () => {
it('should export a function', () => {
const expected = 'function';
const actual = typeof hasEveryProp;
assert.equal(actual, expected);
});
it('should return true if no arguments are provided', () => {
const expected = true;
const actual = hasEveryProp();
assert.equal(actual, expected);
});
it('should return false if the prop is absent', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = false;
const actual = hasEveryProp(props, prop);
assert.equal(actual, expected);
});
it('should return false if any props are absent in array', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = ['id', 'className'];
const expected = false;
const actual = hasEveryProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return false if all props are absent in array', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = ['id', 'className'];
const expected = false;
const actual = hasEveryProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return false if any props are absent in space delimited string', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = 'id className';
const expected = false;
const actual = hasEveryProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return false if all props are absent in space delimited string', () => {
const code = '<div />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const propsToCheck = 'id className';
const expected = false;
const actual = hasEveryProp(props, propsToCheck);
assert.equal(actual, expected);
});
it('should return true if the prop exists', () => {
const code = '<div id="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const expected = true;
const actual = hasEveryProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if all props exist in array', () => {
const code = '<div id="foo" className="box" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['className', 'id'];
const expected = true;
const actual = hasEveryProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if all props exist in space delimited string', () => {
const code = '<div id="foo" className="box" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'className id';
const expected = true;
const actual = hasEveryProp(props, prop);
assert.equal(actual, expected);
});
it('should return true if the props may exist in spread loose mode', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
spreadStrict: false,
};
const expected = true;
const actual = hasEveryProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return true if all props may exist in spread loose mode', () => {
const code = '<div {...props} />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['id', 'className'];
const options = {
spreadStrict: false,
};
const expected = true;
const actual = hasEveryProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return false if the prop is considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = 'id';
const options = {
ignoreCase: false,
};
const expected = false;
const actual = hasEveryProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return false if all props are considered absent in case-sensitive mode', () => {
const code = '<div ID="foo" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['id', 'iD', 'className'];
const options = {
ignoreCase: false,
};
const expected = false;
const actual = hasEveryProp(props, prop, options);
assert.equal(actual, expected);
});
it('should return true if all props are considered present in case-sensitive mode', () => {
const code = '<div ID="foo" className="box" />';
const node = getOpeningElement(code);
const { attributes: props } = node;
const prop = ['ID', 'className'];
const options = {
ignoreCase: false,
};
const expected = true;
const actual = hasEveryProp(props, prop, options);
assert.equal(actual, expected);
});
});

View File

@@ -0,0 +1,35 @@
/* eslint-env mocha */
import fs from 'fs';
import path from 'path';
import assert from 'assert';
import core from '../../src/index';
const src = fs.readdirSync(path.resolve(__dirname, '../../src'))
.filter((f) => f.indexOf('.js') >= 0)
.map((f) => path.basename(f, '.js'));
describe('main export', () => {
it('should export an object', () => {
const expected = 'object';
const actual = typeof core;
assert.equal(actual, expected);
});
src.filter((f) => f !== 'index').forEach((f) => {
it(`should export ${f}`, () => {
assert.equal(
core[f],
require(path.join('../../src/', f)).default // eslint-disable-line
);
});
it(`should export ${f} from root`, () => {
const file = `${f}.js`;
const expected = true;
const actual = fs.statSync(path.join(path.resolve('.'), file)).isFile();
assert.equal(actual, expected);
});
});
});

View File

@@ -0,0 +1,42 @@
/* eslint-env mocha */
import assert from 'assert';
import { extractProp, setParserName } from '../helper';
import propName from '../../src/propName';
describe('propName', () => {
beforeEach(() => {
setParserName('babel');
});
it('should export a function', () => {
const expected = 'function';
const actual = typeof propName;
assert.equal(actual, expected);
});
it('should throw an error if the argument is missing', () => {
assert.throws(() => { propName(); }, Error);
});
it('should throw an error if the argument not a JSX node', () => {
assert.throws(() => { propName({ a: 'foo' }); }, Error);
});
it('should return correct name for normal prop', () => {
const prop = extractProp('<div foo="bar" />');
const expected = 'foo';
const actual = propName(prop);
assert.equal(actual, expected);
});
it('should return correct name for namespaced prop', () => {
const prop = extractProp('<div foo:bar="baz" />', 'foo:bar');
const expected = 'foo:bar';
const actual = propName(prop);
assert.equal(actual, expected);
});
});

View File

@@ -0,0 +1 @@
module.exports = require('./lib').elementType; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').eventHandlers; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').eventHandlersByType; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').getLiteralPropValue; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').getProp; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').getPropValue; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').hasAnyProp; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').hasEveryProp; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1 @@
module.exports = require('./lib').hasProp; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1,48 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = elementType;
function resolveMemberExpressions() {
var object = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var property = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (object.type === 'JSXMemberExpression') {
return resolveMemberExpressions(object.object, object.property) + '.' + property.name;
}
return object.name + '.' + property.name;
}
/**
* Returns the tagName associated with a JSXElement.
*/
function elementType() {
var node = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var name = node.name;
if (node.type === 'JSXOpeningFragment') {
return '<>';
}
if (!name) {
throw new Error('The argument provided is not a JSXElement node.');
}
if (name.type === 'JSXMemberExpression') {
var _name$object = name.object,
object = _name$object === undefined ? {} : _name$object,
_name$property = name.property,
property = _name$property === undefined ? {} : _name$property;
return resolveMemberExpressions(object, property);
}
if (name.type === 'JSXNamespacedName') {
return name.namespace.name + ':' + name.name.name;
}
return node.name.name;
}

View File

@@ -0,0 +1,40 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.eventHandlersByType = undefined;
var _arrayPrototype = require('array.prototype.flat');
var _arrayPrototype2 = _interopRequireDefault(_arrayPrototype);
var _object = require('object.values');
var _object2 = _interopRequireDefault(_object);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Common event handlers for JSX element event binding.
*/
var eventHandlersByType = {
clipboard: ['onCopy', 'onCut', 'onPaste'],
composition: ['onCompositionEnd', 'onCompositionStart', 'onCompositionUpdate'],
keyboard: ['onKeyDown', 'onKeyPress', 'onKeyUp'],
focus: ['onFocus', 'onBlur'],
form: ['onChange', 'onInput', 'onSubmit'],
mouse: ['onClick', 'onContextMenu', 'onDblClick', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp'],
selection: ['onSelect'],
touch: ['onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart'],
ui: ['onScroll'],
wheel: ['onWheel'],
media: ['onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', 'onError', 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting'],
image: ['onLoad', 'onError'],
animation: ['onAnimationStart', 'onAnimationEnd', 'onAnimationIteration'],
transition: ['onTransitionEnd']
};
exports.default = (0, _arrayPrototype2.default)((0, _object2.default)(eventHandlersByType));
exports.eventHandlersByType = eventHandlersByType;

View File

@@ -0,0 +1,115 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.default = getProp;
var _propName = require('./propName');
var _propName2 = _interopRequireDefault(_propName);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var DEFAULT_OPTIONS = {
ignoreCase: true
};
/**
* Returns the JSXAttribute itself or undefined, indicating the prop
* is not present on the JSXOpeningElement.
*
*/
function getProp() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var prop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;
function getName(name) {
return options.ignoreCase ? name.toUpperCase() : name;
}
var propToFind = getName(prop);
function isPropToFind(property) {
return property.type === 'Property' && property.key.type === 'Identifier' && propToFind === getName(property.key.name);
}
var foundAttribute = props.find(function (attribute) {
// If the props contain a spread prop, try to find the property in the object expression.
if (attribute.type === 'JSXSpreadAttribute') {
return attribute.argument.type === 'ObjectExpression' && propToFind !== getName('key') // https://github.com/reactjs/rfcs/pull/107
&& attribute.argument.properties.some(isPropToFind);
}
return propToFind === getName((0, _propName2.default)(attribute));
});
if (foundAttribute && foundAttribute.type === 'JSXSpreadAttribute') {
return propertyToJSXAttribute(foundAttribute.argument.properties.find(isPropToFind));
}
return foundAttribute;
}
function propertyToJSXAttribute(node) {
var key = node.key,
value = node.value;
return _extends({
type: 'JSXAttribute',
name: _extends({ type: 'JSXIdentifier', name: key.name }, getBaseProps(key)),
value: value.type === 'Literal' ? adjustRangeOfNode(value) : _extends({ type: 'JSXExpressionContainer', expression: adjustExpressionRange(value) }, getBaseProps(value))
}, getBaseProps(node));
}
function adjustRangeOfNode(node) {
var _ref = node.range || [node.start, node.end],
_ref2 = _slicedToArray(_ref, 2),
start = _ref2[0],
end = _ref2[1];
return _extends({}, node, {
end: undefined,
range: [start, end],
start: undefined
});
}
function adjustExpressionRange(_ref3) {
var expressions = _ref3.expressions,
quasis = _ref3.quasis,
expression = _objectWithoutProperties(_ref3, ['expressions', 'quasis']);
return _extends({}, adjustRangeOfNode(expression), expressions ? { expressions: expressions.map(adjustRangeOfNode) } : {}, quasis ? { quasis: quasis.map(adjustRangeOfNode) } : {});
}
function getBaseProps(_ref4) {
var loc = _ref4.loc,
node = _objectWithoutProperties(_ref4, ['loc']);
var _adjustRangeOfNode = adjustRangeOfNode(node),
range = _adjustRangeOfNode.range;
return {
loc: getBaseLocation(loc),
range: range
};
}
function getBaseLocation(_ref5) {
var start = _ref5.start,
end = _ref5.end,
source = _ref5.source,
filename = _ref5.filename;
return _extends({
start: start,
end: end
}, source !== undefined ? { source: source } : {}, filename !== undefined ? { filename: filename } : {});
}

View File

@@ -0,0 +1,57 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getPropValue;
exports.getLiteralPropValue = getLiteralPropValue;
var _values = require('./values');
var _values2 = _interopRequireDefault(_values);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var extractValue = function extractValue(attribute, extractor) {
if (attribute && attribute.type === 'JSXAttribute') {
if (attribute.value === null) {
// Null valued attributes imply truthiness.
// For example: <div aria-hidden />
// See: https://facebook.github.io/react/docs/jsx-in-depth.html#boolean-attributes
return true;
}
return extractor(attribute.value);
}
return undefined;
};
/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return the most *closely* associated
* value with the intention of the JSX.
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
function getPropValue(attribute) {
return extractValue(attribute, _values2.default);
}
/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return a value only if we can extract
* a literal value from its attribute (i.e. values that have generic
* types in JavaScript - strings, numbers, booleans, etc.)
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
function getLiteralPropValue(attribute) {
return extractValue(attribute, _values.getLiteralValue);
}

View File

@@ -0,0 +1,74 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = hasProp;
exports.hasAnyProp = hasAnyProp;
exports.hasEveryProp = hasEveryProp;
var _propName = require('./propName');
var _propName2 = _interopRequireDefault(_propName);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var DEFAULT_OPTIONS = {
spreadStrict: true,
ignoreCase: true
};
/**
* Returns boolean indicating whether an prop exists on the props
* property of a JSX element node.
*/
function hasProp() {
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var prop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;
var propToCheck = options.ignoreCase ? prop.toUpperCase() : prop;
return props.some(function (attribute) {
// If the props contain a spread prop, then refer to strict param.
if (attribute.type === 'JSXSpreadAttribute') {
return !options.spreadStrict;
}
var currentProp = options.ignoreCase ? (0, _propName2.default)(attribute).toUpperCase() : (0, _propName2.default)(attribute);
return propToCheck === currentProp;
});
}
/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if any of them exist on the node.
*/
function hasAnyProp() {
var nodeProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;
var propsToCheck = typeof props === 'string' ? props.split(' ') : props;
return propsToCheck.some(function (prop) {
return hasProp(nodeProps, prop, options);
});
}
/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if all of them exist on the node
*/
function hasEveryProp() {
var nodeProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_OPTIONS;
var propsToCheck = typeof props === 'string' ? props.split(' ') : props;
return propsToCheck.every(function (prop) {
return hasProp(nodeProps, prop, options);
});
}

View File

@@ -0,0 +1,40 @@
'use strict';
var _hasProp = require('./hasProp');
var _hasProp2 = _interopRequireDefault(_hasProp);
var _elementType = require('./elementType');
var _elementType2 = _interopRequireDefault(_elementType);
var _eventHandlers = require('./eventHandlers');
var _eventHandlers2 = _interopRequireDefault(_eventHandlers);
var _getProp = require('./getProp');
var _getProp2 = _interopRequireDefault(_getProp);
var _getPropValue = require('./getPropValue');
var _getPropValue2 = _interopRequireDefault(_getPropValue);
var _propName = require('./propName');
var _propName2 = _interopRequireDefault(_propName);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = {
hasProp: _hasProp2.default,
hasAnyProp: _hasProp.hasAnyProp,
hasEveryProp: _hasProp.hasEveryProp,
elementType: _elementType2.default,
eventHandlers: _eventHandlers2.default,
eventHandlersByType: _eventHandlers.eventHandlersByType,
getProp: _getProp2.default,
getPropValue: _getPropValue2.default,
getLiteralPropValue: _getPropValue.getLiteralPropValue,
propName: _propName2.default
};

View File

@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = propName;
/**
* Returns the name of the prop given the JSXAttribute object.
*/
function propName() {
var prop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (!prop.type || prop.type !== 'JSXAttribute') {
throw new Error('The prop must be a JSXAttribute collected by the AST parser.');
}
if (prop.name.type === 'JSXNamespacedName') {
return prop.name.namespace.name + ':' + prop.name.name.name;
}
return prop.name.name;
}

View File

@@ -0,0 +1,23 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromJSXElement;
/**
* Extractor function for a JSXElement type value node.
*
* Returns self-closing element with correct name.
*/
function extractValueFromJSXElement(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var Tag = value.openingElement.name.name;
if (value.openingElement.selfClosing) {
return '<' + Tag + ' />';
}
return '<' + Tag + '>' + [].concat(value.children).map(function (x) {
return getValue(x);
}).join('') + '</' + Tag + '>';
}

View File

@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromJSXFragment;
/**
* Extractor function for a JSXFragment type value node.
*
* Returns self-closing element with correct name.
*/
function extractValueFromJSXFragment(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
if (value.children.length === 0) {
return '<></>';
}
return '<>' + [].concat(value.children).map(function (x) {
return getValue(x);
}).join('') + '</>';
}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromJSXText;
/**
* Extractor function for a JSXText type value node.
*
* Returns self-closing element with correct name.
*/
function extractValueFromJSXText(value) {
return value.raw;
}

View File

@@ -0,0 +1,27 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromLiteral;
/**
* Extractor function for a Literal type value node.
*
* @param - value - AST Value object with type `Literal`
* @returns { String|Boolean } - The extracted value converted to correct type.
*/
function extractValueFromLiteral(value) {
var extractedValue = value.value;
var normalizedStringValue = typeof extractedValue === 'string' && extractedValue.toLowerCase();
if (normalizedStringValue === 'true') {
return true;
}
if (normalizedStringValue === 'false') {
return false;
}
return extractedValue;
}

View File

@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromArrayExpression;
/**
* Extractor function for an ArrayExpression type value node.
* An array expression is an expression with [] syntax.
*
* @returns - An array of the extracted elements.
*/
function extractValueFromArrayExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return value.elements.map(function (element) {
if (element === null) return undefined;
return getValue(element);
});
}

View File

@@ -0,0 +1,19 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromAssignmentExpression;
/**
* Extractor function for a AssignmentExpression type value node.
* An assignment expression looks like `x = y` or `x += y` in expression position.
* This will return the assignment as the value.
*
* @param - value - AST Value object with type `AssignmentExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromAssignmentExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return getValue(value.left) + ' ' + value.operator + ' ' + getValue(value.right);
}

View File

@@ -0,0 +1,78 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromBinaryExpression;
/**
* Extractor function for a BinaryExpression type value node.
* A binary expression has a left and right side separated by an operator
* such as `a + b`.
*
* @param - value - AST Value object with type `BinaryExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromBinaryExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var operator = value.operator,
left = value.left,
right = value.right;
var leftVal = getValue(left);
var rightVal = getValue(right);
switch (operator) {
case '==':
return leftVal == rightVal; // eslint-disable-line
case '!=':
return leftVal != rightVal; // eslint-disable-line
case '===':
return leftVal === rightVal;
case '!==':
return leftVal !== rightVal;
case '<':
return leftVal < rightVal;
case '<=':
return leftVal <= rightVal;
case '>':
return leftVal > rightVal;
case '>=':
return leftVal >= rightVal;
case '<<':
return leftVal << rightVal; // eslint-disable-line no-bitwise
case '>>':
return leftVal >> rightVal; // eslint-disable-line no-bitwise
case '>>>':
return leftVal >>> rightVal; // eslint-disable-line no-bitwise
case '+':
return leftVal + rightVal;
case '-':
return leftVal - rightVal;
case '*':
return leftVal * rightVal;
case '/':
return leftVal / rightVal;
case '%':
return leftVal % rightVal;
case '|':
return leftVal | rightVal; // eslint-disable-line no-bitwise
case '^':
return leftVal ^ rightVal; // eslint-disable-line no-bitwise
case '&':
return leftVal & rightVal; // eslint-disable-line no-bitwise
case 'in':
try {
return leftVal in rightVal;
} catch (err) {
return false;
}
case 'instanceof':
if (typeof rightVal !== 'function') {
return false;
}
return leftVal instanceof rightVal;
default:
return undefined;
}
}

View File

@@ -0,0 +1,30 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromBindExpression;
/**
* Extractor function for a BindExpression type value node.
* A bind expression looks like `::this.foo`
* This will return `this.foo.bind(this)` as the value to indicate its existence,
* since we can not execute the function this.foo.bind(this) in a static environment.
*
* @param - value - AST Value object with type `BindExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromBindExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var callee = getValue(value.callee);
// If value.object === null, the callee must be a MemberExpression.
// https://github.com/babel/babylon/blob/master/ast/spec.md#bindexpression
var object = value.object === null ? getValue(value.callee.object) : getValue(value.object);
if (value.object && value.object.property) {
return object + '.' + callee + '.bind(' + object + ')';
}
return callee + '.bind(' + object + ')';
}

View File

@@ -0,0 +1,23 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromCallExpression;
/**
* Extractor function for a CallExpression type value node.
* A call expression looks like `bar()`
* This will return `bar` as the value to indicate its existence,
* since we can not execute the function bar in a static environment.
*
* @param - value - AST Value object with type `CallExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromCallExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var args = Array.isArray(value.arguments) ? value.arguments.map(function (x) {
return getValue(x);
}).join(', ') : '';
return '' + getValue(value.callee) + (value.optional ? '?.' : '') + '(' + args + ')';
}

View File

@@ -0,0 +1,19 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromChainExpression;
/**
* Extractor function for a ChainExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `ChainExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj?.property` convention.
*/
function extractValueFromChainExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return getValue(value.expression || value);
}

View File

@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromConditionalExpression;
/**
* Extractor function for a ConditionalExpression type value node.
*
* @param - value - AST Value object with type `ConditionalExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromConditionalExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var test = value.test,
alternate = value.alternate,
consequent = value.consequent;
return getValue(test) ? getValue(consequent) : getValue(alternate);
}

View File

@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromFunctionExpression;
/**
* Extractor function for a FunctionExpression type value node.
* Statically, we can't execute the given function, so just return a function
* to indicate that the value is present.
*
* @param - value - AST Value object with type `FunctionExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromFunctionExpression(value) {
return function () {
return value;
};
}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromIdentifier;
var JS_RESERVED = {
Array: Array,
Date: Date,
Infinity: Infinity,
Math: Math,
Number: Number,
Object: Object,
String: String,
undefined: undefined
};
/**
* Extractor function for a Identifier type value node.
* An Identifier is usually a reference to a variable.
* Just return variable name to determine its existence.
*
* @param - value - AST Value object with type `Identifier`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromIdentifier(value) {
var name = value.name;
if (Object.hasOwnProperty.call(JS_RESERVED, name)) {
return JS_RESERVED[name];
}
return name;
}

View File

@@ -0,0 +1,33 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromLogicalExpression;
/**
* Extractor function for a LogicalExpression type value node.
* A logical expression is `a && b` or `a || b`, so we evaluate both sides
* and return the extracted value of the expression.
*
* @param - value - AST Value object with type `LogicalExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromLogicalExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var operator = value.operator,
left = value.left,
right = value.right;
var leftVal = getValue(left);
var rightVal = getValue(right);
if (operator === '&&') {
return leftVal && rightVal;
}
if (operator === '??') {
// return leftVal ?? rightVal; // TODO: update to babel 7
return leftVal === null || typeof leftVal === 'undefined' ? rightVal : leftVal;
}
return leftVal || rightVal;
}

View File

@@ -0,0 +1,19 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromMemberExpression;
/**
* Extractor function for a MemberExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `MemberExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property` convention.
*/
function extractValueFromMemberExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return '' + getValue(value.object) + (value.optional ? '?.' : '.') + getValue(value.property);
}

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromNewExpression;
/**
* Extractor function for a NewExpression type value node.
* A new expression instantiates an object with `new` keyword.
*
* @returns - an empty object.
*/
function extractValueFromNewExpression() {
return new Object(); // eslint-disable-line
}

View File

@@ -0,0 +1,36 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromObjectExpression;
var _object = require('object.assign');
var _object2 = _interopRequireDefault(_object);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Extractor function for an ObjectExpression type value node.
* An object expression is using {}.
*
* @returns - a representation of the object
*/
function extractValueFromObjectExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return value.properties.reduce(function (obj, property) {
// Support types: SpreadProperty and ExperimentalSpreadProperty
if (/^(?:Experimental)?Spread(?:Property|Element)$/.test(property.type)) {
if (property.argument.type === 'ObjectExpression') {
return (0, _object2.default)({}, obj, extractValueFromObjectExpression(property.argument));
}
} else {
return (0, _object2.default)({}, obj, _defineProperty({}, getValue(property.key), getValue(property.value)));
}
return obj;
}, {});
}

View File

@@ -0,0 +1,21 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromOptionalCallExpression;
/**
* Extractor function for a OptionalCallExpression type value node.
* A member expression is accessing a property on an object `obj.property` and invoking it.
*
* @param - value - AST Value object with type `OptionalCallExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property?.()` convention.
*/
function extractValueFromOptionalCallExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return getValue(value.callee) + '?.(' + value.arguments.map(function (x) {
return getValue(x);
}).join(', ') + ')';
}

View File

@@ -0,0 +1,19 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromOptionalMemberExpression;
/**
* Extractor function for a OptionalMemberExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `OptionalMemberExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj?.property` convention.
*/
function extractValueFromOptionalMemberExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return getValue(value.object) + '?.' + getValue(value.property);
}

View File

@@ -0,0 +1,21 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromSequenceExpression;
/**
* Extractor function for a SequenceExpression type value node.
* A Sequence expression is an object with an attribute named
* expressions which contains an array of different types
* of expression objects.
*
* @returns - An array of the extracted elements.
*/
function extractValueFromSequenceExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return value.expressions.map(function (element) {
return getValue(element);
});
}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromSpreadElement;
/**
* Extractor function for a SpreadElement type value node.
* We can't statically evaluate an array spread, so just return
* undefined.
*
* @param - value - AST Value object with type `SpreadElement`
* @returns - An prototypeless object.
*/
function extractValueFromSpreadElement() {
return undefined;
}

View File

@@ -0,0 +1,100 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromTSNonNullExpression;
var extractValueFromThisExpression = require('./ThisExpression').default;
var extractValueFromCallExpression = require('./CallExpression').default;
function navigate(obj, prop, value) {
if (value.computed) {
return value.optional ? obj + '?.[' + prop + ']' : obj + '[' + prop + ']';
}
return value.optional ? obj + '?.' + prop : obj + '.' + prop;
}
/**
* Extractor function for a TSNonNullExpression type value node.
* A TSNonNullExpression is accessing a TypeScript Non-Null Assertion
* Operator !
*
* @param - value - AST Value object with type `TSNonNullExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property` convention.
*/
function extractValueFromTSNonNullExpression(value) {
// eslint-disable-next-line global-require
// const getValue = require('.').default;
var errorMessage = 'The prop value with an expression type of TSNonNullExpression could not be resolved. Please file an issue ( https://github.com/jsx-eslint/jsx-ast-utils/issues/new ) to get this fixed immediately.';
// it's just the name
if (value.type === 'Identifier') {
var name = value.name;
return name;
}
if (value.type === 'Literal') {
return value.value;
}
if (value.type === 'TSAsExpression') {
return extractValueFromTSNonNullExpression(value.expression);
}
if (value.type === 'CallExpression') {
return extractValueFromCallExpression(value);
}
if (value.type === 'ThisExpression') {
return extractValueFromThisExpression();
}
// does not contains properties & is not parenthesized
if (value.type === 'TSNonNullExpression' && (!value.extra || value.extra.parenthesized === false)) {
var expression = value.expression;
return extractValueFromTSNonNullExpression(expression) + '!';
}
// does not contains properties & is parenthesized
if (value.type === 'TSNonNullExpression' && value.extra && value.extra.parenthesized === true) {
var _expression = value.expression;
return '(' + extractValueFromTSNonNullExpression(_expression) + '!' + ')';
}
if (value.type === 'MemberExpression') {
// contains a property & is not parenthesized
if (!value.extra || value.extra.parenthesized === false) {
return navigate(extractValueFromTSNonNullExpression(value.object), extractValueFromTSNonNullExpression(value.property), value);
}
// contains a property & is parenthesized
if (value.extra && value.extra.parenthesized === true) {
var result = navigate(extractValueFromTSNonNullExpression(value.object), extractValueFromTSNonNullExpression(value.property), value);
return '(' + result + ')';
}
}
// try to fail silently, if specs for TSNonNullExpression change
// not throw, only log error. Similar to how it was done previously
if (value.expression) {
var _expression2 = value.expression;
while (_expression2) {
if (_expression2.type === 'Identifier') {
// eslint-disable-next-line no-console
console.error(errorMessage);
return _expression2.name;
}
var _expression3 = _expression2;
_expression2 = _expression3.expression;
}
}
// eslint-disable-next-line no-console
console.error(errorMessage);
return '';
}

View File

@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromTaggedTemplateExpression;
var _TemplateLiteral = require('./TemplateLiteral');
var _TemplateLiteral2 = _interopRequireDefault(_TemplateLiteral);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Returns the string value of a tagged template literal object.
* Redirects the bulk of the work to `TemplateLiteral`.
*/
function extractValueFromTaggedTemplateExpression(value) {
return (0, _TemplateLiteral2.default)(value.quasi);
}

View File

@@ -0,0 +1,46 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromTemplateLiteral;
function sortStarts(a, b) {
return (a.range ? a.range[0] : a.start) - (b.range ? b.range[0] : b.start);
}
/**
* Returns the string value of a template literal object.
* Tries to build it as best as it can based on the passed
* prop. For instance `This is a ${prop}` will return 'This is a {prop}'.
*
* If the template literal builds to undefined (`${undefined}`), then
* this should return "undefined".
*/
function extractValueFromTemplateLiteral(value) {
var quasis = value.quasis,
expressions = value.expressions;
var partitions = quasis.concat(expressions);
return partitions.sort(sortStarts).map(function (_ref) {
var type = _ref.type,
_ref$value = _ref.value;
_ref$value = _ref$value === undefined ? {} : _ref$value;
var raw = _ref$value.raw,
name = _ref.name;
if (type === 'TemplateElement') {
return raw;
}
if (type === 'Identifier') {
return name === 'undefined' ? name : '{' + name + '}';
}
if (type.indexOf('Expression') > -1) {
return '{' + type + '}';
}
return '';
}).join('');
}

View File

@@ -0,0 +1,15 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromThisExpression;
/**
* Extractor function for a ThisExpression type value node.
* A this expression is using `this` as an identifier.
*
* @returns - 'this' as a string.
*/
function extractValueFromThisExpression() {
return 'this';
}

View File

@@ -0,0 +1,19 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromTypeCastExpression;
/**
* Extractor function for a TypeCastExpression type value node.
* A type cast expression looks like `(this.handleClick: (event: MouseEvent) => void))`
* This will return the expression `this.handleClick`.
*
* @param - value - AST Value object with type `TypeCastExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromTypeCastExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
return getValue(value.expression);
}

View File

@@ -0,0 +1,39 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromUnaryExpression;
/**
* Extractor function for a UnaryExpression type value node.
* A unary expression is an expression with a unary operator.
* For example, !"foobar" will evaluate to false, so this will return false.
*
* @param - value - AST Value object with type `UnaryExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromUnaryExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var operator = value.operator,
argument = value.argument;
switch (operator) {
case '-':
return -getValue(argument);
case '+':
return +getValue(argument); // eslint-disable-line no-implicit-coercion
case '!':
return !getValue(argument);
case '~':
return ~getValue(argument); // eslint-disable-line no-bitwise
case 'delete':
// I believe delete statements evaluate to true.
return true;
case 'typeof':
case 'void':
default:
return undefined;
}
}

View File

@@ -0,0 +1,33 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = extractValueFromUpdateExpression;
/**
* Extractor function for an UpdateExpression type value node.
* An update expression is an expression with an update operator.
* For example, foo++ will evaluate to foo + 1.
*
* @param - value - AST Value object with type `UpdateExpression`
* @returns - The extracted value converted to correct type.
*/
function extractValueFromUpdateExpression(value) {
// eslint-disable-next-line global-require
var getValue = require('.').default;
var operator = value.operator,
argument = value.argument,
prefix = value.prefix;
var val = getValue(argument);
switch (operator) {
case '++':
return prefix ? ++val : val++; // eslint-disable-line no-plusplus
case '--':
return prefix ? --val : val--; // eslint-disable-line no-plusplus
default:
return undefined;
}
}

View File

@@ -0,0 +1,288 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.default = extract;
exports.extractLiteral = extractLiteral;
var _Literal = require('../Literal');
var _Literal2 = _interopRequireDefault(_Literal);
var _JSXElement = require('../JSXElement');
var _JSXElement2 = _interopRequireDefault(_JSXElement);
var _JSXFragment = require('../JSXFragment');
var _JSXFragment2 = _interopRequireDefault(_JSXFragment);
var _JSXText = require('../JSXText');
var _JSXText2 = _interopRequireDefault(_JSXText);
var _Identifier = require('./Identifier');
var _Identifier2 = _interopRequireDefault(_Identifier);
var _TaggedTemplateExpression = require('./TaggedTemplateExpression');
var _TaggedTemplateExpression2 = _interopRequireDefault(_TaggedTemplateExpression);
var _TemplateLiteral = require('./TemplateLiteral');
var _TemplateLiteral2 = _interopRequireDefault(_TemplateLiteral);
var _FunctionExpression = require('./FunctionExpression');
var _FunctionExpression2 = _interopRequireDefault(_FunctionExpression);
var _LogicalExpression = require('./LogicalExpression');
var _LogicalExpression2 = _interopRequireDefault(_LogicalExpression);
var _MemberExpression = require('./MemberExpression');
var _MemberExpression2 = _interopRequireDefault(_MemberExpression);
var _ChainExpression = require('./ChainExpression');
var _ChainExpression2 = _interopRequireDefault(_ChainExpression);
var _OptionalCallExpression = require('./OptionalCallExpression');
var _OptionalCallExpression2 = _interopRequireDefault(_OptionalCallExpression);
var _OptionalMemberExpression = require('./OptionalMemberExpression');
var _OptionalMemberExpression2 = _interopRequireDefault(_OptionalMemberExpression);
var _CallExpression = require('./CallExpression');
var _CallExpression2 = _interopRequireDefault(_CallExpression);
var _UnaryExpression = require('./UnaryExpression');
var _UnaryExpression2 = _interopRequireDefault(_UnaryExpression);
var _ThisExpression = require('./ThisExpression');
var _ThisExpression2 = _interopRequireDefault(_ThisExpression);
var _ConditionalExpression = require('./ConditionalExpression');
var _ConditionalExpression2 = _interopRequireDefault(_ConditionalExpression);
var _BinaryExpression = require('./BinaryExpression');
var _BinaryExpression2 = _interopRequireDefault(_BinaryExpression);
var _ObjectExpression = require('./ObjectExpression');
var _ObjectExpression2 = _interopRequireDefault(_ObjectExpression);
var _NewExpression = require('./NewExpression');
var _NewExpression2 = _interopRequireDefault(_NewExpression);
var _UpdateExpression = require('./UpdateExpression');
var _UpdateExpression2 = _interopRequireDefault(_UpdateExpression);
var _ArrayExpression = require('./ArrayExpression');
var _ArrayExpression2 = _interopRequireDefault(_ArrayExpression);
var _BindExpression = require('./BindExpression');
var _BindExpression2 = _interopRequireDefault(_BindExpression);
var _SpreadElement = require('./SpreadElement');
var _SpreadElement2 = _interopRequireDefault(_SpreadElement);
var _TypeCastExpression = require('./TypeCastExpression');
var _TypeCastExpression2 = _interopRequireDefault(_TypeCastExpression);
var _SequenceExpression = require('./SequenceExpression');
var _SequenceExpression2 = _interopRequireDefault(_SequenceExpression);
var _TSNonNullExpression = require('./TSNonNullExpression');
var _TSNonNullExpression2 = _interopRequireDefault(_TSNonNullExpression);
var _AssignmentExpression = require('./AssignmentExpression');
var _AssignmentExpression2 = _interopRequireDefault(_AssignmentExpression);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Composition map of types to their extractor functions.
var TYPES = {
Identifier: _Identifier2.default,
Literal: _Literal2.default,
JSXElement: _JSXElement2.default,
JSXFragment: _JSXFragment2.default,
JSXText: _JSXText2.default,
TaggedTemplateExpression: _TaggedTemplateExpression2.default,
TemplateLiteral: _TemplateLiteral2.default,
ArrowFunctionExpression: _FunctionExpression2.default,
FunctionExpression: _FunctionExpression2.default,
LogicalExpression: _LogicalExpression2.default,
MemberExpression: _MemberExpression2.default,
ChainExpression: _ChainExpression2.default,
OptionalCallExpression: _OptionalCallExpression2.default,
OptionalMemberExpression: _OptionalMemberExpression2.default,
CallExpression: _CallExpression2.default,
UnaryExpression: _UnaryExpression2.default,
ThisExpression: _ThisExpression2.default,
ConditionalExpression: _ConditionalExpression2.default,
BinaryExpression: _BinaryExpression2.default,
ObjectExpression: _ObjectExpression2.default,
NewExpression: _NewExpression2.default,
UpdateExpression: _UpdateExpression2.default,
ArrayExpression: _ArrayExpression2.default,
BindExpression: _BindExpression2.default,
SpreadElement: _SpreadElement2.default,
TypeCastExpression: _TypeCastExpression2.default,
SequenceExpression: _SequenceExpression2.default,
TSNonNullExpression: _TSNonNullExpression2.default,
AssignmentExpression: _AssignmentExpression2.default
};
var noop = function noop() {
return null;
};
var errorMessage = function errorMessage(expression) {
return 'The prop value with an expression type of ' + expression + ' could not be resolved. Please file an issue ( https://github.com/jsx-eslint/jsx-ast-utils/issues/new ) to get this fixed immediately.';
};
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *all* possible expression types.
*
* @param - value - AST Value object with type `JSXExpressionContainer`
* @returns The extracted value.
*/
function extract(value) {
// Value will not have the expression property when we recurse.
// The type for expression on ArrowFunctionExpression is a boolean.
var expression = void 0;
if (typeof value.expression !== 'boolean' && value.expression) {
expression = value.expression; // eslint-disable-line prefer-destructuring
} else {
expression = value;
}
var _expression = expression,
type = _expression.type;
// Typescript NonNull Expression is wrapped & it would end up in the wrong extractor
if (expression.object && expression.object.type === 'TSNonNullExpression') {
type = 'TSNonNullExpression';
}
while (type === 'TSAsExpression') {
var _expression2 = expression;
type = _expression2.type;
if (expression.expression) {
var _expression3 = expression;
expression = _expression3.expression;
}
}
if (TYPES[type] === undefined) {
// eslint-disable-next-line no-console
console.error(errorMessage(type));
return null;
}
return TYPES[type](expression);
}
// Composition map of types to their extractor functions to handle literals.
var LITERAL_TYPES = _extends({}, TYPES, {
Literal: function Literal(value) {
var extractedVal = TYPES.Literal.call(undefined, value);
var isNull = extractedVal === null;
// This will be convention for attributes that have null
// value explicitly defined (<div prop={null} /> maps to 'null').
return isNull ? 'null' : extractedVal;
},
Identifier: function Identifier(value) {
var isUndefined = TYPES.Identifier.call(undefined, value) === undefined;
return isUndefined ? undefined : null;
},
JSXElement: noop,
JSXFragment: noop,
JSXText: noop,
ArrowFunctionExpression: noop,
FunctionExpression: noop,
LogicalExpression: noop,
MemberExpression: noop,
OptionalCallExpression: noop,
OptionalMemberExpression: noop,
CallExpression: noop,
UnaryExpression: function UnaryExpression(value) {
var extractedVal = TYPES.UnaryExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
UpdateExpression: function UpdateExpression(value) {
var extractedVal = TYPES.UpdateExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
ThisExpression: noop,
ConditionalExpression: noop,
BinaryExpression: noop,
ObjectExpression: noop,
NewExpression: noop,
ArrayExpression: function ArrayExpression(value) {
var extractedVal = TYPES.ArrayExpression.call(undefined, value);
return extractedVal.filter(function (val) {
return val !== null;
});
},
BindExpression: noop,
SpreadElement: noop,
TSNonNullExpression: noop,
TSAsExpression: noop,
TypeCastExpression: noop,
SequenceExpression: noop,
ChainExpression: noop
});
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *some* possible types that map to literals.
*
* @param - value - AST Value object with type `JSXExpressionContainer`
* @returns The extracted value.
*/
function extractLiteral(value) {
// Value will not have the expression property when we recurse.
var expression = value.expression || value;
var type = expression.type;
if (LITERAL_TYPES[type] === undefined) {
// eslint-disable-next-line no-console
console.error(errorMessage(type));
return null;
}
return LITERAL_TYPES[type](expression);
}

View File

@@ -0,0 +1,76 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.default = getValue;
exports.getLiteralValue = getLiteralValue;
var _Literal = require('./Literal');
var _Literal2 = _interopRequireDefault(_Literal);
var _JSXElement = require('./JSXElement');
var _JSXElement2 = _interopRequireDefault(_JSXElement);
var _JSXText = require('./JSXText');
var _JSXText2 = _interopRequireDefault(_JSXText);
var _JSXFragment = require('./JSXFragment');
var _JSXFragment2 = _interopRequireDefault(_JSXFragment);
var _expressions = require('./expressions');
var _expressions2 = _interopRequireDefault(_expressions);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Composition map of types to their extractor functions.
var TYPES = {
Literal: _Literal2.default,
JSXElement: _JSXElement2.default,
JSXExpressionContainer: _expressions2.default,
JSXText: _JSXText2.default,
JSXFragment: _JSXFragment2.default
};
// Composition map of types to their extractor functions to handle literals.
var LITERAL_TYPES = _extends({}, TYPES, {
JSXElement: function JSXElement() {
return null;
},
JSXExpressionContainer: _expressions.extractLiteral
});
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *all* possible types.
*
* @param value - AST Value object on a JSX Attribute.
*/
function getValue(value) {
if (!TYPES[value.type]) console.log(value.type);
return TYPES[value.type](value);
}
/**
* This function maps an AST value node
* to its correct extractor function for its
* given type.
*
* This will map correctly for *some* possible types that map to literals.
*
* @param value - AST Value object on a JSX Attribute.
*/
function getLiteralValue(value) {
return LITERAL_TYPES[value.type](value);
}

View File

@@ -0,0 +1,85 @@
{
"name": "jsx-ast-utils",
"version": "3.3.5",
"description": "AST utility module for statically analyzing JSX",
"main": "lib/index.js",
"scripts": {
"prepack": "npmignore --auto --commentLines=autogenerated && npm run build",
"prebuild": "rimraf lib",
"build": "babel src --out-dir lib",
"prepublishOnly": "safe-publish-latest && npm test",
"prepublish": "not-in-publish || npm run prepublishOnly",
"prelint": "npm run build",
"lint": "eslint .",
"pretest": "npm run lint",
"test": "npm run tests-only --",
"posttest": "aud --production",
"tests-only": "jest --coverage",
"test:watch": "npm run tests-only -- --watch",
"version": "auto-changelog && git add CHANGELOG.md",
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
},
"devDependencies": {
"@babel/core": "^7.22.9",
"@babel/eslint-parser": "^7.22.9",
"@babel/parser": "^7.22.7",
"aud": "^2.0.3",
"auto-changelog": "^2.4.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-jest": "^20.0.3",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-replace-object-assign": "^1.0.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babylon": "^6.18.0",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.27.5",
"flow-parser": "^0.126.1",
"in-publish": "^2.0.1",
"jest": "^20.0.4",
"jest-cli": "^20.0.4",
"npmignore": "^0.3.0",
"object.entries": "^1.1.6",
"object.fromentries": "^2.0.6",
"rimraf": "^2.7.1",
"safe-publish-latest": "^2.0.0"
},
"engines": {
"node": ">=4.0"
},
"keywords": [
"jsx",
"ast",
"lint",
"eslint"
],
"author": "Ethan Cohen",
"repository": {
"type": "git",
"url": "https://github.com/jsx-eslint/jsx-ast-utils"
},
"license": "MIT",
"dependencies": {
"array-includes": "^3.1.6",
"array.prototype.flat": "^1.3.1",
"object.assign": "^4.1.4",
"object.values": "^1.1.6"
},
"auto-changelog": {
"output": "CHANGELOG.md",
"template": "keepachangelog",
"unreleased": false,
"commitLimit": false,
"backfillLimit": false,
"hideCredit": true,
"startingVersion": "3.3.4"
},
"publishConfig": {
"ignore": [
".github/workflows",
"jest.config.js"
]
}
}

View File

@@ -0,0 +1 @@
module.exports = require('./lib').propName; // eslint-disable-line import/no-unresolved

View File

@@ -0,0 +1,33 @@
function resolveMemberExpressions(object = {}, property = {}) {
if (object.type === 'JSXMemberExpression') {
return `${resolveMemberExpressions(object.object, object.property)}.${property.name}`;
}
return `${object.name}.${property.name}`;
}
/**
* Returns the tagName associated with a JSXElement.
*/
export default function elementType(node = {}) {
const { name } = node;
if (node.type === 'JSXOpeningFragment') {
return '<>';
}
if (!name) {
throw new Error('The argument provided is not a JSXElement node.');
}
if (name.type === 'JSXMemberExpression') {
const { object = {}, property = {} } = name;
return resolveMemberExpressions(object, property);
}
if (name.type === 'JSXNamespacedName') {
return `${name.namespace.name}:${name.name.name}`;
}
return node.name.name;
}

View File

@@ -0,0 +1,110 @@
import flat from 'array.prototype.flat';
import values from 'object.values';
/**
* Common event handlers for JSX element event binding.
*/
const eventHandlersByType = {
clipboard: [
'onCopy',
'onCut',
'onPaste',
],
composition: [
'onCompositionEnd',
'onCompositionStart',
'onCompositionUpdate',
],
keyboard: [
'onKeyDown',
'onKeyPress',
'onKeyUp',
],
focus: [
'onFocus',
'onBlur',
],
form: [
'onChange',
'onInput',
'onSubmit',
],
mouse: [
'onClick',
'onContextMenu',
'onDblClick',
'onDoubleClick',
'onDrag',
'onDragEnd',
'onDragEnter',
'onDragExit',
'onDragLeave',
'onDragOver',
'onDragStart',
'onDrop',
'onMouseDown',
'onMouseEnter',
'onMouseLeave',
'onMouseMove',
'onMouseOut',
'onMouseOver',
'onMouseUp',
],
selection: [
'onSelect',
],
touch: [
'onTouchCancel',
'onTouchEnd',
'onTouchMove',
'onTouchStart',
],
ui: [
'onScroll',
],
wheel: [
'onWheel',
],
media: [
'onAbort',
'onCanPlay',
'onCanPlayThrough',
'onDurationChange',
'onEmptied',
'onEncrypted',
'onEnded',
'onError',
'onLoadedData',
'onLoadedMetadata',
'onLoadStart',
'onPause',
'onPlay',
'onPlaying',
'onProgress',
'onRateChange',
'onSeeked',
'onSeeking',
'onStalled',
'onSuspend',
'onTimeUpdate',
'onVolumeChange',
'onWaiting',
],
image: [
'onLoad',
'onError',
],
animation: [
'onAnimationStart',
'onAnimationEnd',
'onAnimationIteration',
],
transition: [
'onTransitionEnd',
],
};
export default flat(values(eventHandlersByType));
export { eventHandlersByType };

View File

@@ -0,0 +1,91 @@
import propName from './propName';
const DEFAULT_OPTIONS = {
ignoreCase: true,
};
/**
* Returns the JSXAttribute itself or undefined, indicating the prop
* is not present on the JSXOpeningElement.
*
*/
export default function getProp(props = [], prop = '', options = DEFAULT_OPTIONS) {
function getName(name) { return options.ignoreCase ? name.toUpperCase() : name; }
const propToFind = getName(prop);
function isPropToFind(property) {
return property.type === 'Property'
&& property.key.type === 'Identifier'
&& propToFind === getName(property.key.name);
}
const foundAttribute = props.find((attribute) => {
// If the props contain a spread prop, try to find the property in the object expression.
if (attribute.type === 'JSXSpreadAttribute') {
return attribute.argument.type === 'ObjectExpression'
&& propToFind !== getName('key') // https://github.com/reactjs/rfcs/pull/107
&& attribute.argument.properties.some(isPropToFind);
}
return propToFind === getName(propName(attribute));
});
if (foundAttribute && foundAttribute.type === 'JSXSpreadAttribute') {
return propertyToJSXAttribute(foundAttribute.argument.properties.find(isPropToFind));
}
return foundAttribute;
}
function propertyToJSXAttribute(node) {
const { key, value } = node;
return {
type: 'JSXAttribute',
name: { type: 'JSXIdentifier', name: key.name, ...getBaseProps(key) },
value: value.type === 'Literal'
? adjustRangeOfNode(value)
: { type: 'JSXExpressionContainer', expression: adjustExpressionRange(value), ...getBaseProps(value) },
...getBaseProps(node),
};
}
function adjustRangeOfNode(node) {
const [start, end] = node.range || [node.start, node.end];
return {
...node,
end: undefined,
range: [start, end],
start: undefined,
};
}
function adjustExpressionRange({ expressions, quasis, ...expression }) {
return {
...adjustRangeOfNode(expression),
...(expressions ? { expressions: expressions.map(adjustRangeOfNode) } : {}),
...(quasis ? { quasis: quasis.map(adjustRangeOfNode) } : {}),
};
}
function getBaseProps({ loc, ...node }) {
const { range } = adjustRangeOfNode(node);
return {
loc: getBaseLocation(loc),
range,
};
}
function getBaseLocation({
start,
end,
source,
filename,
}) {
return {
start,
end,
...(source !== undefined ? { source } : {}),
...(filename !== undefined ? { filename } : {}),
};
}

View File

@@ -0,0 +1,45 @@
import getValue, { getLiteralValue } from './values';
const extractValue = (attribute, extractor) => {
if (attribute && attribute.type === 'JSXAttribute') {
if (attribute.value === null) {
// Null valued attributes imply truthiness.
// For example: <div aria-hidden />
// See: https://facebook.github.io/react/docs/jsx-in-depth.html#boolean-attributes
return true;
}
return extractor(attribute.value);
}
return undefined;
};
/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return the most *closely* associated
* value with the intention of the JSX.
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
export default function getPropValue(attribute) {
return extractValue(attribute, getValue);
}
/**
* Returns the value of a given attribute.
* Different types of attributes have their associated
* values in different properties on the object.
*
* This function should return a value only if we can extract
* a literal value from its attribute (i.e. values that have generic
* types in JavaScript - strings, numbers, booleans, etc.)
*
* @param attribute - The JSXAttribute collected by AST parser.
*/
export function getLiteralPropValue(attribute) {
return extractValue(attribute, getLiteralValue);
}

View File

@@ -0,0 +1,47 @@
import propName from './propName';
const DEFAULT_OPTIONS = {
spreadStrict: true,
ignoreCase: true,
};
/**
* Returns boolean indicating whether an prop exists on the props
* property of a JSX element node.
*/
export default function hasProp(props = [], prop = '', options = DEFAULT_OPTIONS) {
const propToCheck = options.ignoreCase ? prop.toUpperCase() : prop;
return props.some((attribute) => {
// If the props contain a spread prop, then refer to strict param.
if (attribute.type === 'JSXSpreadAttribute') {
return !options.spreadStrict;
}
const currentProp = options.ignoreCase
? propName(attribute).toUpperCase()
: propName(attribute);
return propToCheck === currentProp;
});
}
/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if any of them exist on the node.
*/
export function hasAnyProp(nodeProps = [], props = [], options = DEFAULT_OPTIONS) {
const propsToCheck = typeof props === 'string' ? props.split(' ') : props;
return propsToCheck.some((prop) => hasProp(nodeProps, prop, options));
}
/**
* Given the props on a node and a list of props to check, this returns a boolean
* indicating if all of them exist on the node
*/
export function hasEveryProp(nodeProps = [], props = [], options = DEFAULT_OPTIONS) {
const propsToCheck = typeof props === 'string' ? props.split(' ') : props;
return propsToCheck.every((prop) => hasProp(nodeProps, prop, options));
}

View File

@@ -0,0 +1,19 @@
import hasProp, { hasAnyProp, hasEveryProp } from './hasProp';
import elementType from './elementType';
import eventHandlers, { eventHandlersByType } from './eventHandlers';
import getProp from './getProp';
import getPropValue, { getLiteralPropValue } from './getPropValue';
import propName from './propName';
module.exports = {
hasProp,
hasAnyProp,
hasEveryProp,
elementType,
eventHandlers,
eventHandlersByType,
getProp,
getPropValue,
getLiteralPropValue,
propName,
};

View File

@@ -0,0 +1,14 @@
/**
* Returns the name of the prop given the JSXAttribute object.
*/
export default function propName(prop = {}) {
if (!prop.type || prop.type !== 'JSXAttribute') {
throw new Error('The prop must be a JSXAttribute collected by the AST parser.');
}
if (prop.name.type === 'JSXNamespacedName') {
return `${prop.name.namespace.name}:${prop.name.name.name}`;
}
return prop.name.name;
}

View File

@@ -0,0 +1,15 @@
/**
* Extractor function for a JSXElement type value node.
*
* Returns self-closing element with correct name.
*/
export default function extractValueFromJSXElement(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const Tag = value.openingElement.name.name;
if (value.openingElement.selfClosing) {
return `<${Tag} />`;
}
return `<${Tag}>${[].concat(value.children).map((x) => getValue(x)).join('')}</${Tag}>`;
}

View File

@@ -0,0 +1,14 @@
/**
* Extractor function for a JSXFragment type value node.
*
* Returns self-closing element with correct name.
*/
export default function extractValueFromJSXFragment(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
if (value.children.length === 0) {
return '<></>';
}
return `<>${[].concat(value.children).map((x) => getValue(x)).join('')}</>`;
}

View File

@@ -0,0 +1,8 @@
/**
* Extractor function for a JSXText type value node.
*
* Returns self-closing element with correct name.
*/
export default function extractValueFromJSXText(value) {
return value.raw;
}

View File

@@ -0,0 +1,20 @@
/**
* Extractor function for a Literal type value node.
*
* @param - value - AST Value object with type `Literal`
* @returns { String|Boolean } - The extracted value converted to correct type.
*/
export default function extractValueFromLiteral(value) {
const { value: extractedValue } = value;
const normalizedStringValue = typeof extractedValue === 'string' && extractedValue.toLowerCase();
if (normalizedStringValue === 'true') {
return true;
}
if (normalizedStringValue === 'false') {
return false;
}
return extractedValue;
}

View File

@@ -0,0 +1,14 @@
/**
* Extractor function for an ArrayExpression type value node.
* An array expression is an expression with [] syntax.
*
* @returns - An array of the extracted elements.
*/
export default function extractValueFromArrayExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return value.elements.map((element) => {
if (element === null) return undefined;
return getValue(element);
});
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a AssignmentExpression type value node.
* An assignment expression looks like `x = y` or `x += y` in expression position.
* This will return the assignment as the value.
*
* @param - value - AST Value object with type `AssignmentExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromAssignmentExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return `${getValue(value.left)} ${value.operator} ${getValue(value.right)}`;
}

View File

@@ -0,0 +1,69 @@
/**
* Extractor function for a BinaryExpression type value node.
* A binary expression has a left and right side separated by an operator
* such as `a + b`.
*
* @param - value - AST Value object with type `BinaryExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromBinaryExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const { operator, left, right } = value;
const leftVal = getValue(left);
const rightVal = getValue(right);
switch (operator) {
case '==':
return leftVal == rightVal; // eslint-disable-line
case '!=':
return leftVal != rightVal; // eslint-disable-line
case '===':
return leftVal === rightVal;
case '!==':
return leftVal !== rightVal;
case '<':
return leftVal < rightVal;
case '<=':
return leftVal <= rightVal;
case '>':
return leftVal > rightVal;
case '>=':
return leftVal >= rightVal;
case '<<':
return leftVal << rightVal; // eslint-disable-line no-bitwise
case '>>':
return leftVal >> rightVal; // eslint-disable-line no-bitwise
case '>>>':
return leftVal >>> rightVal; // eslint-disable-line no-bitwise
case '+':
return leftVal + rightVal;
case '-':
return leftVal - rightVal;
case '*':
return leftVal * rightVal;
case '/':
return leftVal / rightVal;
case '%':
return leftVal % rightVal;
case '|':
return leftVal | rightVal; // eslint-disable-line no-bitwise
case '^':
return leftVal ^ rightVal; // eslint-disable-line no-bitwise
case '&':
return leftVal & rightVal; // eslint-disable-line no-bitwise
case 'in':
try {
return leftVal in rightVal;
} catch (err) {
return false;
}
case 'instanceof':
if (typeof rightVal !== 'function') {
return false;
}
return leftVal instanceof rightVal;
default:
return undefined;
}
}

View File

@@ -0,0 +1,24 @@
/**
* Extractor function for a BindExpression type value node.
* A bind expression looks like `::this.foo`
* This will return `this.foo.bind(this)` as the value to indicate its existence,
* since we can not execute the function this.foo.bind(this) in a static environment.
*
* @param - value - AST Value object with type `BindExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromBindExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const callee = getValue(value.callee);
// If value.object === null, the callee must be a MemberExpression.
// https://github.com/babel/babylon/blob/master/ast/spec.md#bindexpression
const object = value.object === null ? getValue(value.callee.object) : getValue(value.object);
if (value.object && value.object.property) {
return `${object}.${callee}.bind(${object})`;
}
return `${callee}.bind(${object})`;
}

View File

@@ -0,0 +1,15 @@
/**
* Extractor function for a CallExpression type value node.
* A call expression looks like `bar()`
* This will return `bar` as the value to indicate its existence,
* since we can not execute the function bar in a static environment.
*
* @param - value - AST Value object with type `CallExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromCallExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const args = Array.isArray(value.arguments) ? value.arguments.map((x) => getValue(x)).join(', ') : '';
return `${getValue(value.callee)}${value.optional ? '?.' : ''}(${args})`;
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a ChainExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `ChainExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj?.property` convention.
*/
export default function extractValueFromChainExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return getValue(value.expression || value);
}

View File

@@ -0,0 +1,17 @@
/**
* Extractor function for a ConditionalExpression type value node.
*
* @param - value - AST Value object with type `ConditionalExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromConditionalExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const {
test,
alternate,
consequent,
} = value;
return getValue(test) ? getValue(consequent) : getValue(alternate);
}

View File

@@ -0,0 +1,11 @@
/**
* Extractor function for a FunctionExpression type value node.
* Statically, we can't execute the given function, so just return a function
* to indicate that the value is present.
*
* @param - value - AST Value object with type `FunctionExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromFunctionExpression(value) {
return () => value;
}

View File

@@ -0,0 +1,28 @@
const JS_RESERVED = {
Array,
Date,
Infinity,
Math,
Number,
Object,
String,
undefined,
};
/**
* Extractor function for a Identifier type value node.
* An Identifier is usually a reference to a variable.
* Just return variable name to determine its existence.
*
* @param - value - AST Value object with type `Identifier`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromIdentifier(value) {
const { name } = value;
if (Object.hasOwnProperty.call(JS_RESERVED, name)) {
return JS_RESERVED[name];
}
return name;
}

View File

@@ -0,0 +1,24 @@
/**
* Extractor function for a LogicalExpression type value node.
* A logical expression is `a && b` or `a || b`, so we evaluate both sides
* and return the extracted value of the expression.
*
* @param - value - AST Value object with type `LogicalExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromLogicalExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
const { operator, left, right } = value;
const leftVal = getValue(left);
const rightVal = getValue(right);
if (operator === '&&') {
return leftVal && rightVal;
}
if (operator === '??') {
// return leftVal ?? rightVal; // TODO: update to babel 7
return (leftVal === null || typeof leftVal === 'undefined') ? rightVal : leftVal;
}
return leftVal || rightVal;
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a MemberExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `MemberExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property` convention.
*/
export default function extractValueFromMemberExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return `${getValue(value.object)}${value.optional ? '?.' : '.'}${getValue(value.property)}`;
}

View File

@@ -0,0 +1,9 @@
/**
* Extractor function for a NewExpression type value node.
* A new expression instantiates an object with `new` keyword.
*
* @returns - an empty object.
*/
export default function extractValueFromNewExpression() {
return new Object(); // eslint-disable-line
}

View File

@@ -0,0 +1,23 @@
import assign from 'object.assign';
/**
* Extractor function for an ObjectExpression type value node.
* An object expression is using {}.
*
* @returns - a representation of the object
*/
export default function extractValueFromObjectExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return value.properties.reduce((obj, property) => {
// Support types: SpreadProperty and ExperimentalSpreadProperty
if (/^(?:Experimental)?Spread(?:Property|Element)$/.test(property.type)) {
if (property.argument.type === 'ObjectExpression') {
return assign({}, obj, extractValueFromObjectExpression(property.argument));
}
} else {
return assign({}, obj, { [getValue(property.key)]: getValue(property.value) });
}
return obj;
}, {});
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a OptionalCallExpression type value node.
* A member expression is accessing a property on an object `obj.property` and invoking it.
*
* @param - value - AST Value object with type `OptionalCallExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property?.()` convention.
*/
export default function extractValueFromOptionalCallExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return `${getValue(value.callee)}?.(${value.arguments.map((x) => getValue(x)).join(', ')})`;
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a OptionalMemberExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
*
* @param - value - AST Value object with type `OptionalMemberExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj?.property` convention.
*/
export default function extractValueFromOptionalMemberExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return `${getValue(value.object)}?.${getValue(value.property)}`;
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a SequenceExpression type value node.
* A Sequence expression is an object with an attribute named
* expressions which contains an array of different types
* of expression objects.
*
* @returns - An array of the extracted elements.
*/
export default function extractValueFromSequenceExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return value.expressions.map((element) => getValue(element));
}

View File

@@ -0,0 +1,11 @@
/**
* Extractor function for a SpreadElement type value node.
* We can't statically evaluate an array spread, so just return
* undefined.
*
* @param - value - AST Value object with type `SpreadElement`
* @returns - An prototypeless object.
*/
export default function extractValueFromSpreadElement() {
return undefined;
}

View File

@@ -0,0 +1,97 @@
const extractValueFromThisExpression = require('./ThisExpression').default;
const extractValueFromCallExpression = require('./CallExpression').default;
function navigate(obj, prop, value) {
if (value.computed) {
return value.optional ? `${obj}?.[${prop}]` : `${obj}[${prop}]`;
}
return value.optional ? `${obj}?.${prop}` : `${obj}.${prop}`;
}
/**
* Extractor function for a TSNonNullExpression type value node.
* A TSNonNullExpression is accessing a TypeScript Non-Null Assertion
* Operator !
*
* @param - value - AST Value object with type `TSNonNullExpression`
* @returns - The extracted value converted to correct type
* and maintaing `obj.property` convention.
*/
export default function extractValueFromTSNonNullExpression(value) {
// eslint-disable-next-line global-require
// const getValue = require('.').default;
const errorMessage = 'The prop value with an expression type of TSNonNullExpression could not be resolved. Please file an issue ( https://github.com/jsx-eslint/jsx-ast-utils/issues/new ) to get this fixed immediately.';
// it's just the name
if (value.type === 'Identifier') {
const { name } = value;
return name;
}
if (value.type === 'Literal') {
return value.value;
}
if (value.type === 'TSAsExpression') {
return extractValueFromTSNonNullExpression(value.expression);
}
if (value.type === 'CallExpression') {
return extractValueFromCallExpression(value);
}
if (value.type === 'ThisExpression') {
return extractValueFromThisExpression();
}
// does not contains properties & is not parenthesized
if (value.type === 'TSNonNullExpression' && (!value.extra || value.extra.parenthesized === false)) {
const { expression } = value;
return `${extractValueFromTSNonNullExpression(expression)}${'!'}`;
}
// does not contains properties & is parenthesized
if (value.type === 'TSNonNullExpression' && value.extra && value.extra.parenthesized === true) {
const { expression } = value;
return `${'('}${extractValueFromTSNonNullExpression(expression)}${'!'}${')'}`;
}
if (value.type === 'MemberExpression') {
// contains a property & is not parenthesized
if ((!value.extra || value.extra.parenthesized === false)) {
return navigate(
extractValueFromTSNonNullExpression(value.object),
extractValueFromTSNonNullExpression(value.property),
value,
);
}
// contains a property & is parenthesized
if (value.extra && value.extra.parenthesized === true) {
const result = navigate(
extractValueFromTSNonNullExpression(value.object),
extractValueFromTSNonNullExpression(value.property),
value,
);
return `(${result})`;
}
}
// try to fail silently, if specs for TSNonNullExpression change
// not throw, only log error. Similar to how it was done previously
if (value.expression) {
let { expression } = value;
while (expression) {
if (expression.type === 'Identifier') {
// eslint-disable-next-line no-console
console.error(errorMessage);
return expression.name;
}
({ expression } = expression);
}
}
// eslint-disable-next-line no-console
console.error(errorMessage);
return '';
}

View File

@@ -0,0 +1,9 @@
import extractValueFromTemplateLiteral from './TemplateLiteral';
/**
* Returns the string value of a tagged template literal object.
* Redirects the bulk of the work to `TemplateLiteral`.
*/
export default function extractValueFromTaggedTemplateExpression(value) {
return extractValueFromTemplateLiteral(value.quasi);
}

View File

@@ -0,0 +1,35 @@
function sortStarts(a, b) {
return (a.range ? a.range[0] : a.start) - (b.range ? b.range[0] : b.start);
}
/**
* Returns the string value of a template literal object.
* Tries to build it as best as it can based on the passed
* prop. For instance `This is a ${prop}` will return 'This is a {prop}'.
*
* If the template literal builds to undefined (`${undefined}`), then
* this should return "undefined".
*/
export default function extractValueFromTemplateLiteral(value) {
const {
quasis,
expressions,
} = value;
const partitions = quasis.concat(expressions);
return partitions.sort(sortStarts).map(({ type, value: { raw } = {}, name }) => {
if (type === 'TemplateElement') {
return raw;
}
if (type === 'Identifier') {
return name === 'undefined' ? name : `{${name}}`;
}
if (type.indexOf('Expression') > -1) {
return `{${type}}`;
}
return '';
}).join('');
}

View File

@@ -0,0 +1,9 @@
/**
* Extractor function for a ThisExpression type value node.
* A this expression is using `this` as an identifier.
*
* @returns - 'this' as a string.
*/
export default function extractValueFromThisExpression() {
return 'this';
}

View File

@@ -0,0 +1,13 @@
/**
* Extractor function for a TypeCastExpression type value node.
* A type cast expression looks like `(this.handleClick: (event: MouseEvent) => void))`
* This will return the expression `this.handleClick`.
*
* @param - value - AST Value object with type `TypeCastExpression`
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromTypeCastExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('.').default;
return getValue(value.expression);
}

Some files were not shown because too many files have changed in this diff Show More