0.2.0 - Mid migration

This commit is contained in:
Daniel Mason 2022-04-25 14:47:15 +12:00
parent 139e6a915e
commit 7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions

33
web/node_modules/jsx-ast-utils/src/elementType.js generated vendored Normal file
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;
}

112
web/node_modules/jsx-ast-utils/src/eventHandlers.js generated vendored Normal file
View file

@ -0,0 +1,112 @@
/**
* 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',
],
};
const eventHandlers = Object.keys(eventHandlersByType).reduce(
(accumulator, type) => accumulator.concat(eventHandlersByType[type]),
[],
);
export default eventHandlers;
export { eventHandlersByType };

91
web/node_modules/jsx-ast-utils/src/getProp.js generated vendored Normal file
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 } : {}),
};
}

45
web/node_modules/jsx-ast-utils/src/getPropValue.js generated vendored Normal file
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);
}

47
web/node_modules/jsx-ast-utils/src/hasProp.js generated vendored Normal file
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));
}

19
web/node_modules/jsx-ast-utils/src/index.js generated vendored Normal file
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,
};

14
web/node_modules/jsx-ast-utils/src/propName.js generated vendored Normal file
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,8 @@
/**
* Extractor function for a JSXElement type value node.
*
* Returns self-closing element with correct name.
*/
export default function extractValueFromJSXElement(value) {
return `<${value.openingElement.name.name} />`;
}

20
web/node_modules/jsx-ast-utils/src/values/Literal.js generated vendored Normal file
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,11 @@
/**
* 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('./index.js').default;
return value.elements.map((element) => 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('./index.js').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('./index.js').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('./index.js').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('./index.js').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('./index.js').default;
return getValue(value.expression);
}

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('./index.js').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('./index.js').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('./index.js').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,24 @@
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('./index.js').default;
return value.properties.reduce((obj, property) => {
const object = { ...obj };
// Support types: SpreadProperty and ExperimentalSpreadProperty
if (/^(?:Experimental)?Spread(?:Property|Element)$/.test(property.type)) {
if (property.argument.type === 'ObjectExpression') {
return assign(object, extractValueFromObjectExpression(property.argument));
}
} else {
object[getValue(property.key)] = getValue(property.value);
}
return object;
}, {});
}

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('./index.js').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('./index.js').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,66 @@
const extractValueFromThisExpression = require('./ThisExpression').default;
/**
* 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 issue to get this fixed immediately.';
// it's just the name
if (value.type === 'Identifier') {
const { name } = value;
return name;
}
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)}${'!'}${')'}`;
}
// contains a property & is not parenthesized
if (value.type === 'MemberExpression' && (!value.extra || value.extra.parenthesized === false)) {
return `${extractValueFromTSNonNullExpression(value.object)}${value.optional ? '?.' : '.'}${extractValueFromTSNonNullExpression(value.property)}`;
}
// contains a property & is parenthesized
if (value.type === 'MemberExpression' && value.extra && value.extra.parenthesized === true) {
return `${'('}${extractValueFromTSNonNullExpression(value.object)}${value.optional ? '?.' : '.'}${extractValueFromTSNonNullExpression(value.property)}${')'}`;
}
// 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,38 @@
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).reduce((raw, part) => {
const {
type,
} = part;
if (type === 'TemplateElement') {
return raw + part.value.raw;
}
if (type === 'Identifier') {
return part.name === 'undefined' ? `${raw}${part.name}` : `${raw}{${part.name}}`;
}
if (type.indexOf('Expression') > -1) {
return `${raw}{${type}}`;
}
return raw;
}, '');
}

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('./index.js').default;
return getValue(value.expression);
}

View file

@ -0,0 +1,31 @@
/**
* 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.
*/
export default function extractValueFromUnaryExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('./index.js').default;
const { operator, argument } = value;
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,24 @@
/**
* 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.
*/
export default function extractValueFromUpdateExpression(value) {
// eslint-disable-next-line global-require
const getValue = require('./index.js').default;
const { operator, argument, prefix } = value;
let 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,177 @@
import Literal from '../Literal';
import JSXElement from '../JSXElement';
import Identifier from './Identifier';
import TaggedTemplateExpression from './TaggedTemplateExpression';
import TemplateLiteral from './TemplateLiteral';
import FunctionExpression from './FunctionExpression';
import LogicalExpression from './LogicalExpression';
import MemberExpression from './MemberExpression';
import ChainExpression from './ChainExpression';
import OptionalCallExpression from './OptionalCallExpression';
import OptionalMemberExpression from './OptionalMemberExpression';
import CallExpression from './CallExpression';
import UnaryExpression from './UnaryExpression';
import ThisExpression from './ThisExpression';
import ConditionalExpression from './ConditionalExpression';
import BinaryExpression from './BinaryExpression';
import ObjectExpression from './ObjectExpression';
import NewExpression from './NewExpression';
import UpdateExpression from './UpdateExpression';
import ArrayExpression from './ArrayExpression';
import BindExpression from './BindExpression';
import SpreadElement from './SpreadElement';
import TypeCastExpression from './TypeCastExpression';
import SequenceExpression from './SequenceExpression';
import TSNonNullExpression from './TSNonNullExpression';
import AssignmentExpression from './AssignmentExpression';
// Composition map of types to their extractor functions.
const TYPES = {
Identifier,
Literal,
JSXElement,
TaggedTemplateExpression,
TemplateLiteral,
ArrowFunctionExpression: FunctionExpression,
FunctionExpression,
LogicalExpression,
MemberExpression,
ChainExpression,
OptionalCallExpression,
OptionalMemberExpression,
CallExpression,
UnaryExpression,
ThisExpression,
ConditionalExpression,
BinaryExpression,
ObjectExpression,
NewExpression,
UpdateExpression,
ArrayExpression,
BindExpression,
SpreadElement,
TypeCastExpression,
SequenceExpression,
TSNonNullExpression,
AssignmentExpression,
};
const noop = () => null;
const errorMessage = (expression) => `The prop value with an expression type of ${expression} could not be resolved. Please file issue 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.
*/
export default function extract(value) {
// Value will not have the expression property when we recurse.
// The type for expression on ArrowFunctionExpression is a boolean.
let expression;
if (
typeof value.expression !== 'boolean'
&& value.expression
) {
expression = value.expression; // eslint-disable-line prefer-destructuring
} else {
expression = value;
}
let { type } = expression;
// 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') {
({ type } = expression);
if (expression.expression) {
({ expression } = 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.
const LITERAL_TYPES = {
...TYPES,
Literal: (value) => {
const extractedVal = TYPES.Literal.call(undefined, value);
const 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: (value) => {
const isUndefined = TYPES.Identifier.call(undefined, value) === undefined;
return isUndefined ? undefined : null;
},
JSXElement: noop,
ArrowFunctionExpression: noop,
FunctionExpression: noop,
LogicalExpression: noop,
MemberExpression: noop,
OptionalCallExpression: noop,
OptionalMemberExpression: noop,
CallExpression: noop,
UnaryExpression: (value) => {
const extractedVal = TYPES.UnaryExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
UpdateExpression: (value) => {
const extractedVal = TYPES.UpdateExpression.call(undefined, value);
return extractedVal === undefined ? null : extractedVal;
},
ThisExpression: noop,
ConditionalExpression: noop,
BinaryExpression: noop,
ObjectExpression: noop,
NewExpression: noop,
ArrayExpression: (value) => {
const extractedVal = TYPES.ArrayExpression.call(undefined, value);
return extractedVal.filter((val) => val !== null);
},
BindExpression: noop,
SpreadElement: noop,
TSNonNullExpression: noop,
TSAsExpression: noop,
TypeCastExpression: noop,
SequenceExpression: 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.
*/
export function extractLiteral(value) {
// Value will not have the expression property when we recurse.
const expression = value.expression || value;
const { type } = expression;
if (LITERAL_TYPES[type] === undefined) {
// eslint-disable-next-line no-console
console.error(errorMessage(type));
return null;
}
return LITERAL_TYPES[type](expression);
}

43
web/node_modules/jsx-ast-utils/src/values/index.js generated vendored Normal file
View file

@ -0,0 +1,43 @@
import Literal from './Literal';
import JSXElement from './JSXElement';
import JSXExpressionContainer, { extractLiteral } from './expressions';
// Composition map of types to their extractor functions.
const TYPES = {
Literal,
JSXElement,
JSXExpressionContainer,
};
// Composition map of types to their extractor functions to handle literals.
const LITERAL_TYPES = {
...TYPES,
JSXElement: () => null,
JSXExpressionContainer: 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.
*/
export default function getValue(value) {
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.
*/
export function getLiteralValue(value) {
return LITERAL_TYPES[value.type](value);
}