Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support PropertyDefinition #1127

Merged
merged 5 commits into from Apr 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 7 additions & 4 deletions rules/custom-error-definition.js
Expand Up @@ -54,12 +54,15 @@ const isAssignmentExpression = (node, name) => {
return lhs.property.name === name;
};

const isClassProperty = (node, name) => {
if (node.type !== 'ClassProperty' || node.computed) {
const isPropertyDefinition = (node, name) => {
const {type, computed, key} = node;
if (type !== 'PropertyDefinition' && type !== 'ClassProperty') {
return false;
}

const {key} = node;
if (computed) {
return false;
}

if (key.type !== 'Identifier') {
return false;
Expand Down Expand Up @@ -144,7 +147,7 @@ const customErrorDefinition = (context, node) => {

const nameExpression = constructorBody.find(x => isAssignmentExpression(x, 'name'));
if (!nameExpression) {
const nameProperty = body.find(node => isClassProperty(node, 'name'));
const nameProperty = body.find(node => isPropertyDefinition(node, 'name'));

if (!nameProperty || !nameProperty.value || nameProperty.value.value !== name) {
context.report({
Expand Down
21 changes: 12 additions & 9 deletions rules/no-static-only-class.js
Expand Up @@ -23,9 +23,14 @@ const isDeclarationOfExportDefaultDeclaration = node =>
node.parent.type === 'ExportDefaultDeclaration' &&
node.parent.declaration === node;

// https://github.com/estree/estree/blob/master/stage3/class-features.md#propertydefinition
const isPropertyDefinition = node => node.type === 'PropertyDefinition' ||
// Legacy node type
node.type === 'ClassProperty';
const isMethodDefinition = node => node.type === 'MethodDefinition';

function isStaticMember(node) {
const {
type,
private: isPrivate,
static: isStatic,
declare: isDeclare,
Expand All @@ -37,7 +42,7 @@ function isStaticMember(node) {

// Avoid matching unexpected node. For example: https://github.com/tc39/proposal-class-static-block
/* istanbul ignore next */
if (type !== 'ClassProperty' && type !== 'MethodDefinition') {
if (!isPropertyDefinition(node) && !isMethodDefinition(node)) {
return false;
}

Expand All @@ -60,8 +65,6 @@ function isStaticMember(node) {
}

function * switchClassMemberToObjectProperty(node, sourceCode, fixer) {
const {type} = node;

const staticToken = sourceCode.getFirstToken(node);
assertToken(staticToken, {
expected: [
Expand All @@ -75,12 +78,12 @@ function * switchClassMemberToObjectProperty(node, sourceCode, fixer) {
yield fixer.remove(staticToken);
yield removeSpacesAfter(staticToken, sourceCode, fixer);

const maybeSemicolonToken = type === 'ClassProperty' ?
const maybeSemicolonToken = isPropertyDefinition(node) ?
sourceCode.getLastToken(node) :
sourceCode.getTokenAfter(node);
const hasSemicolonToken = isSemicolonToken(maybeSemicolonToken);

if (type === 'ClassProperty') {
if (isPropertyDefinition(node)) {
const {key, value} = node;

if (value) {
Expand Down Expand Up @@ -132,11 +135,11 @@ function switchClassToObject(node, sourceCode) {

for (const node of body.body) {
if (
node.type === 'ClassProperty' &&
isPropertyDefinition(node) &&
(
node.typeAnnotation ||
// This is a stupid way to check if `value` of `ClassProperty` uses `this`
(node.value && sourceCode.getText(node).includes('this'))
// This is a stupid way to check if `value` of `PropertyDefinition` uses `this`
(node.value && sourceCode.getText(node.value).includes('this'))
)
) {
return;
Expand Down
2 changes: 1 addition & 1 deletion rules/prevent-abbreviations.js
Expand Up @@ -538,7 +538,7 @@ const shouldReportIdentifierAsProperty = identifier => {
}

if (
identifier.parent.type === 'ClassProperty' &&
(identifier.parent.type === 'ClassProperty' || identifier.parent.type === 'PropertyDefinition') &&
identifier.parent.key === identifier &&
!identifier.parent.computed
) {
Expand Down
22 changes: 22 additions & 0 deletions test/custom-error-definition.mjs
Expand Up @@ -504,6 +504,28 @@ runTest.babel({
}
`,
errors: [invalidNameError('ValidationError')]
},
// `computed`
{
code: outdent`
const name = 'computed-name';
class FooError extends Error {
[name] = 'FooError';
constructor(message) {
super(message);
}
}
`,
output: outdent`
const name = 'computed-name';
class FooError extends Error {
[name] = 'FooError';
constructor(message) {
super(message);
}
}
`,
errors: [invalidNameError('FooError')]
}
]
});
Expand Down
6 changes: 6 additions & 0 deletions test/no-static-only-class.mjs
Expand Up @@ -175,6 +175,12 @@ test.typescript({
static b = this.a;
}
`),
// `this` in `key` should fixable
{
code: 'class A {static [this.a] = 1}',
output: 'const A = {[this.a] : 1,};',
errors: 1
},
// This case should be fixable, but we simply check code of value includes `this`
noFixingCase(outdent`
class A {
Expand Down
14 changes: 8 additions & 6 deletions test/utils/test.mjs
Expand Up @@ -45,7 +45,13 @@ class Tester {
testerOptions.parserOptions = testerOptions.parserOptions || {};
testerOptions.parserOptions.babelOptions = testerOptions.parserOptions.babelOptions || {};
testerOptions.parserOptions.babelOptions.parserOpts = testerOptions.parserOptions.babelOptions.parserOpts || {};
testerOptions.parserOptions.babelOptions.parserOpts.plugins = testerOptions.parserOptions.babelOptions.parserOpts.plugins || [];
let babelPlugins = testerOptions.parserOptions.babelOptions.parserOpts.plugins || [];
babelPlugins = [
['estree', {classFeatures: true}],
'jsx',
'classProperties',
...babelPlugins
];

return this.runTest({
...tests,
Expand All @@ -62,11 +68,7 @@ class Tester {
...testerOptions.parserOptions.babelOptions,
parserOpts: {
...testerOptions.parserOptions.babelOptions.parserOpts,
plugins: [
'jsx',
'classProperties',
...testerOptions.parserOptions.babelOptions.parserOpts.plugins
]
plugins: babelPlugins
}
}
}
Expand Down