Skip to content

Commit

Permalink
[#70] Support OptionalMemberExpression AST nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
jessebeach committed Mar 24, 2019
1 parent a9d4159 commit dbd735d
Show file tree
Hide file tree
Showing 21 changed files with 123 additions and 83 deletions.
8 changes: 7 additions & 1 deletion __tests__/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ const parser = require('babylon');

function parse(code) {
return parser.parse(code, {
plugins: ['jsx', 'functionBind', 'estree', 'objectRestSpread'],
plugins: [
'estree',
'functionBind',
'jsx',
'objectRestSpread',
'optionalChaining',
],
});
}

Expand Down
12 changes: 6 additions & 6 deletions __tests__/src/getPropLiteralValue-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ describe('getLiteralPropValue', () => {

// -"bar" => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -277,7 +277,7 @@ describe('getLiteralPropValue', () => {

// +"bar" => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand Down Expand Up @@ -344,7 +344,7 @@ describe('getLiteralPropValue', () => {

// ++"bar" => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -354,7 +354,7 @@ describe('getLiteralPropValue', () => {

// --"bar" => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -364,7 +364,7 @@ describe('getLiteralPropValue', () => {

// "bar"++ => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -374,7 +374,7 @@ describe('getLiteralPropValue', () => {

// "bar"-- => NaN
const expected = true;
const actual = isNaN(getLiteralPropValue(prop));
const actual = Number.isNaN(getLiteralPropValue(prop));

assert.equal(expected, actual);
});
Expand Down
26 changes: 20 additions & 6 deletions __tests__/src/getPropValue-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,20 @@ describe('getPropValue', () => {

assert.equal(expected, actual);
});

it('should evaluate to a correct representation of member expression with a nullable member', () => {
// This tell will not throw when Babel is upgraded from 6 to 7. Remove
// the throw expectation wrapper at that time.
// eslint-disable-next-line no-undef
expect(() => {
const prop = extractProp('<div foo={bar?.baz} />');

const expected = 'bar?.baz';
const actual = getPropValue(prop);

assert.equal(expected, actual);
}).toThrow();
});
});

describe('Call expression', () => {
Expand Down Expand Up @@ -383,7 +397,7 @@ describe('getPropValue', () => {

// -"bar" => NaN
const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -402,7 +416,7 @@ describe('getPropValue', () => {

// +"bar" => NaN
const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand Down Expand Up @@ -469,7 +483,7 @@ describe('getPropValue', () => {

// ++"bar" => NaN
const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -478,7 +492,7 @@ describe('getPropValue', () => {
const prop = extractProp('<div foo={--bar} />');

const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -488,7 +502,7 @@ describe('getPropValue', () => {

// "bar"++ => NaN
const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand All @@ -497,7 +511,7 @@ describe('getPropValue', () => {
const prop = extractProp('<div foo={bar--} />');

const expected = true;
const actual = isNaN(getPropValue(prop));
const actual = Number.isNaN(getPropValue(prop));

assert.equal(expected, actual);
});
Expand Down
2 changes: 1 addition & 1 deletion elementType.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./lib').elementType; // eslint-disable-line import/no-unresolved
module.exports = require('./lib').elementType; // eslint-disable-line import/no-unresolved
4 changes: 3 additions & 1 deletion src/elementType.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export default function elementType(node = {}) {
if (name.type === 'JSXMemberExpression') {
const { object = {}, property = {} } = name;
return resolveMemberExpressions(object, property);
} else if (name.type === 'JSXNamespacedName') {
}

if (name.type === 'JSXNamespacedName') {
return `${name.namespace.name}:${name.name.name}`;
}

Expand Down
6 changes: 3 additions & 3 deletions src/getProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export default function getProp(props = [], prop = '', options = DEFAULT_OPTIONS
return false;
}

const currentProp = options.ignoreCase ?
propName(attribute).toUpperCase() :
propName(attribute);
const currentProp = options.ignoreCase
? propName(attribute).toUpperCase()
: propName(attribute);

return propToFind === currentProp;
});
Expand Down
6 changes: 3 additions & 3 deletions src/hasProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export default function hasProp(props = [], prop = '', options = DEFAULT_OPTIONS
return !options.spreadStrict;
}

const currentProp = options.ignoreCase ?
propName(attribute).toUpperCase() :
propName(attribute);
const currentProp = options.ignoreCase
? propName(attribute).toUpperCase()
: propName(attribute);

return propToCheck === currentProp;
});
Expand Down
4 changes: 3 additions & 1 deletion src/values/Literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export default function extractValueFromLiteral(value) {
const normalizedStringValue = typeof extractedValue === 'string' && extractedValue.toLowerCase();
if (normalizedStringValue === 'true') {
return true;
} else if (normalizedStringValue === 'false') {
}

if (normalizedStringValue === 'false') {
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/ArrayExpression.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import getValue from './index';

/**
* 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));
}
5 changes: 2 additions & 3 deletions src/values/expressions/BinaryExpression.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import getValue from './index';


/**
* Extractor function for a BinaryExpression type value node.
* A binary expression has a left and right side separated by an operator
Expand All @@ -10,6 +7,8 @@ import getValue from './index';
* @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);
Expand Down
5 changes: 2 additions & 3 deletions src/values/expressions/BindExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for a BindExpression type value node.
* A bind expression looks like `::this.foo`
Expand All @@ -10,7 +8,8 @@ import getValue from './index';
* @returns - The extracted value converted to correct type.
*/
export default function extractValueFromBindExpression(value) {
// console.log(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.
Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/CallExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for a CallExpression type value node.
* A call expression looks like `bar()`
Expand All @@ -10,5 +8,7 @@ import getValue from './index';
* @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;
return getValue(value.callee);
}
4 changes: 2 additions & 2 deletions src/values/expressions/ConditionalExpression.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import getValue from './index';

/**
* 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,
Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/LogicalExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for a LogicalExpression type value node.
* A logical expression is `a && b` or `a || b`, so we evaluate both sides
Expand All @@ -9,6 +7,8 @@ import getValue from './index';
* @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);
Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/MemberExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for a MemberExpression type value node.
* A member expression is accessing a property on an object `obj.property`.
Expand All @@ -9,5 +7,7 @@ import getValue from './index';
* 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)}.${getValue(value.property)}`;
}
8 changes: 4 additions & 4 deletions src/values/expressions/ObjectExpression.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import getValue from './index';

/**
* 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 = Object.assign({}, obj);
// Support types: SpreadProperty and ExperimentalSpreadProperty
if (/^(?:Experimental)?SpreadProperty$/.test(property.type)) {
if (/^(?:Experimental)?Spread(?:Property|Element)$/.test(property.type)) {
if (property.argument.type === 'ObjectExpression') {
return Object.assign(object, extractValueFromObjectExpression(property.argument));
return Object.assign(object, extractValueFromObjectExpression(property.argument, getValue));
}
} else {
object[getValue(property.key)] = getValue(property.value);
Expand Down
13 changes: 13 additions & 0 deletions src/values/expressions/OptionalMemberExpression.js
Original file line number Diff line number Diff line change
@@ -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)}`;
}
8 changes: 6 additions & 2 deletions src/values/expressions/TemplateLiteral.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ export default function extractValueFromTemplateLiteral(value) {
} = part;
if (type === 'TemplateElement') {
return raw + part.value.raw;
} else if (type === 'Identifier') {
}

if (type === 'Identifier') {
return part.name === 'undefined' ? `${raw}${part.name}` : `${raw}{${part.name}}`;
} else if (type.indexOf('Expression') > -1) {
}

if (type.indexOf('Expression') > -1) {
return `${raw}{${type}}`;
}

Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/UnaryExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for a UnaryExpression type value node.
* A unary expression is an expression with a unary operator.
Expand All @@ -9,6 +7,8 @@ import getValue from './index';
* @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) {
Expand Down
4 changes: 2 additions & 2 deletions src/values/expressions/UpdateExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import getValue from './index';

/**
* Extractor function for an UpdateExpression type value node.
* An update expression is an expression with an update operator.
Expand All @@ -9,6 +7,8 @@ import getValue from './index';
* @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);
Expand Down
Loading

0 comments on commit dbd735d

Please sign in to comment.