Skip to content

[labs/analyzer] Support const function/class declarations#3662

Merged
kevinpschaaf merged 6 commits intomainfrom
analyzer-const-class-fn
Mar 3, 2023
Merged

[labs/analyzer] Support const function/class declarations#3662
kevinpschaaf merged 6 commits intomainfrom
analyzer-const-class-fn

Conversation

@kevinpschaaf
Copy link
Copy Markdown
Member

@kevinpschaaf kevinpschaaf commented Feb 11, 2023

Adds support for analyzing const variables initialized to class or function expressions as ClassDeclaration and FunctionDeclaration, respectively:

// Class declaration:
class Class1 { ... }
// Const variable initialized to a class expression (now also analyzed as a ClassDeclaration):
const Class2 = class { ... };
// Function declaration:
function fn1() { ... }
// Const variable initialized to a function expression (now also analyzed as a FunctionDeclaration):
const fn2 = function() { ... };
const fn3 = () => { ... }

Since we didn't previously have a classes test suite itself (the class analysis was mostly covered by a combination of the LitElement basic and jsdoc tests) and I needed to add some more clasess tests, I pulled the class-specific tests out of lit-element/jsdoc_test. and vanilla-element/jsdoc_test.js and moved them to a new javascript/classes_tests.js, and added the new const tests there. Now, the jsdoc test just contains CE-specific information that's only pulled out of jsdoc (e.g. slot, custom props, etc.). I think this makes the test organization more logical.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 11, 2023

🦋 Changeset detected

Latest commit: c2f29ed

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@lit-labs/analyzer Minor
@lit-labs/cli Patch
@lit-labs/gen-manifest Patch
@lit-labs/gen-utils Patch
@lit-labs/gen-wrapper-angular Patch
@lit-labs/gen-wrapper-react Patch
@lit-labs/gen-wrapper-vue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 11, 2023

📊 Tachometer Benchmark Results

Summary

nop-update

  • lit-html-kitchen-sink: unsure 🔍 -4% - +8% (-0.59ms - +1.36ms)
    this-change vs tip-of-tree

render

  • lit-element-list: 80.83ms - 85.36ms
  • lit-html-kitchen-sink: unsure 🔍 -7% - +7% (-2.27ms - +2.41ms)
    this-change vs tip-of-tree
  • lit-html-repeat: unsure 🔍 -5% - +5% (-0.62ms - +0.56ms)
    this-change vs tip-of-tree
  • lit-html-template-heavy: unsure 🔍 -2% - +4% (-0.89ms - +1.89ms)
    this-change vs tip-of-tree
  • reactive-element-list: unsure 🔍 -4% - +2% (-2.07ms - +0.87ms)
    this-change vs tip-of-tree

update

  • lit-element-list: 677.95ms - 686.88ms
  • lit-html-kitchen-sink: unsure 🔍 -4% - +4% (-3.28ms - +3.06ms)
    this-change vs tip-of-tree
  • lit-html-repeat: unsure 🔍 -3% - +2% (-9.16ms - +4.29ms)
    this-change vs tip-of-tree
  • lit-html-template-heavy: unsure 🔍 -0% - +1% (-0.42ms - +1.24ms)
    this-change vs tip-of-tree
  • reactive-element-list: unsure 🔍 -0% - +1% (-2.98ms - +4.72ms)
    this-change vs tip-of-tree

update-reflect

  • lit-element-list: 681.60ms - 689.04ms
  • reactive-element-list: unsure 🔍 -1% - +0% (-4.48ms - +2.87ms)
    this-change vs tip-of-tree

Results

lit-element-list

render

VersionAvg timevs
80.83ms - 85.36ms-

update

VersionAvg timevs
677.95ms - 686.88ms-

update-reflect

VersionAvg timevs
681.60ms - 689.04ms-
lit-html-kitchen-sink

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
32.03ms - 35.48ms-unsure 🔍
-7% - +7%
-2.27ms - +2.41ms
unsure 🔍
-6% - +8%
-1.92ms - +2.81ms
tip-of-tree
tip-of-tree
32.10ms - 35.27msunsure 🔍
-7% - +7%
-2.41ms - +2.27ms
-unsure 🔍
-6% - +8%
-1.89ms - +2.64ms
previous-release
previous-release
31.69ms - 34.93msunsure 🔍
-8% - +6%
-2.81ms - +1.92ms
unsure 🔍
-8% - +6%
-2.64ms - +1.89ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
75.71ms - 80.24ms-unsure 🔍
-4% - +4%
-3.28ms - +3.06ms
unsure 🔍
-3% - +4%
-2.17ms - +3.47ms
tip-of-tree
tip-of-tree
75.87ms - 80.30msunsure 🔍
-4% - +4%
-3.06ms - +3.28ms
-unsure 🔍
-3% - +5%
-2.02ms - +3.54ms
previous-release
previous-release
75.65ms - 79.00msunsure 🔍
-4% - +3%
-3.47ms - +2.17ms
unsure 🔍
-5% - +3%
-3.54ms - +2.02ms
-

nop-update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
16.21ms - 17.82ms-unsure 🔍
-4% - +8%
-0.59ms - +1.36ms
unsure 🔍
-2% - +9%
-0.29ms - +1.48ms
tip-of-tree
tip-of-tree
16.08ms - 17.17msunsure 🔍
-8% - +3%
-1.36ms - +0.59ms
-unsure 🔍
-3% - +5%
-0.46ms - +0.88ms
previous-release
previous-release
16.04ms - 16.79msunsure 🔍
-9% - +2%
-1.48ms - +0.29ms
unsure 🔍
-5% - +3%
-0.88ms - +0.46ms
-
lit-html-repeat

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
11.17ms - 11.97ms-unsure 🔍
-5% - +5%
-0.62ms - +0.56ms
unsure 🔍
-5% - +5%
-0.55ms - +0.63ms
tip-of-tree
tip-of-tree
11.17ms - 12.03msunsure 🔍
-5% - +5%
-0.56ms - +0.62ms
-unsure 🔍
-5% - +6%
-0.54ms - +0.69ms
previous-release
previous-release
11.09ms - 11.96msunsure 🔍
-5% - +5%
-0.63ms - +0.55ms
unsure 🔍
-6% - +5%
-0.69ms - +0.54ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
259.28ms - 268.41ms-unsure 🔍
-3% - +2%
-9.16ms - +4.29ms
unsure 🔍
-5% - +0%
-12.72ms - +1.31ms
tip-of-tree
tip-of-tree
261.34ms - 271.21msunsure 🔍
-2% - +3%
-4.29ms - +9.16ms
-unsure 🔍
-4% - +1%
-10.54ms - +4.00ms
previous-release
previous-release
264.22ms - 274.88msunsure 🔍
-1% - +5%
-1.31ms - +12.72ms
unsure 🔍
-2% - +4%
-4.00ms - +10.54ms
-
lit-html-template-heavy

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
52.01ms - 53.98ms-unsure 🔍
-2% - +4%
-0.89ms - +1.89ms
unsure 🔍
-2% - +3%
-1.17ms - +1.61ms
tip-of-tree
tip-of-tree
51.51ms - 53.48msunsure 🔍
-4% - +2%
-1.89ms - +0.89ms
-unsure 🔍
-3% - +2%
-1.67ms - +1.11ms
previous-release
previous-release
51.80ms - 53.75msunsure 🔍
-3% - +2%
-1.61ms - +1.17ms
unsure 🔍
-2% - +3%
-1.11ms - +1.67ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
104.47ms - 105.71ms-unsure 🔍
-0% - +1%
-0.42ms - +1.24ms
unsure 🔍
-1% - +1%
-1.02ms - +1.20ms
tip-of-tree
tip-of-tree
104.12ms - 105.23msunsure 🔍
-1% - +0%
-1.24ms - +0.42ms
-unsure 🔍
-1% - +1%
-1.39ms - +0.75ms
previous-release
previous-release
104.08ms - 105.92msunsure 🔍
-1% - +1%
-1.20ms - +1.02ms
unsure 🔍
-1% - +1%
-0.75ms - +1.39ms
-
reactive-element-list

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
53.62ms - 55.80ms-unsure 🔍
-4% - +2%
-2.07ms - +0.87ms
unsure 🔍
-1% - +5%
-0.66ms - +2.45ms
tip-of-tree
tip-of-tree
54.32ms - 56.30msunsure 🔍
-2% - +4%
-0.87ms - +2.07ms
-unsure 🔍
-0% - +6%
+0.01ms - +2.98ms
previous-release
previous-release
52.71ms - 54.92msunsure 🔍
-4% - +1%
-2.45ms - +0.66ms
faster ✔
0% - 5%
0.01ms - 2.98ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
679.48ms - 685.72ms-unsure 🔍
-0% - +1%
-2.98ms - +4.72ms
unsure 🔍
-0% - +1%
-0.68ms - +6.53ms
tip-of-tree
tip-of-tree
679.47ms - 683.99msunsure 🔍
-1% - +0%
-4.72ms - +2.98ms
-unsure 🔍
-0% - +1%
-0.84ms - +4.95ms
previous-release
previous-release
677.86ms - 681.49msunsure 🔍
-1% - +0%
-6.53ms - +0.68ms
unsure 🔍
-1% - +0%
-4.95ms - +0.84ms
-

update-reflect

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
711.21ms - 716.03ms-unsure 🔍
-1% - +0%
-4.48ms - +2.87ms
unsure 🔍
-1% - +0%
-4.44ms - +2.64ms
tip-of-tree
tip-of-tree
711.65ms - 717.20msunsure 🔍
-0% - +1%
-2.87ms - +4.48ms
-unsure 🔍
-1% - +1%
-3.89ms - +3.71ms
previous-release
previous-release
711.92ms - 717.12msunsure 🔍
-0% - +1%
-2.64ms - +4.44ms
unsure 🔍
-1% - +1%
-3.71ms - +3.89ms
-

tachometer-reporter-action v2 for Benchmarks

Comment on lines +43 to +227
test('tagged description and summary', ({getModule}) => {
const dec = getModule('classes').getDeclaration('TaggedDescription');
assert.ok(dec.isClassDeclaration());
assert.equal(
dec.description,
`TaggedDescription description. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.`
);
assert.equal(dec.summary, `TaggedDescription summary.`);
assert.equal(dec.deprecated, `TaggedDescription deprecated message.`);
});

test('untagged description', ({getModule}) => {
const dec = getModule('classes').getDeclaration('UntaggedDescription');
assert.ok(dec.isClassDeclaration());
assert.equal(
dec.description,
`UntaggedDescription description. Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.`
);
assert.equal(dec.summary, `UntaggedDescription summary.`);
assert.equal(dec.deprecated, `UntaggedDescription deprecated message.`);
});

// Fields

test('field1', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getField('field1');
assert.ok(member?.isClassField());
assert.equal(
member.description,
`Class field 1 description\nwith wraparound`
);
assert.equal(member.default, `'default1'`);
assert.equal(member.privacy, 'private');
assert.equal(member.type?.text, 'string');
});

test('field2', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getField('field2');
assert.ok(member?.isClassField());
assert.equal(member.summary, `Class field 2 summary\nwith wraparound`);
assert.equal(
member.description,
`Class field 2 description\nwith wraparound`
);
assert.equal(member.default, undefined);
assert.equal(member.privacy, 'protected');
assert.equal(member.type?.text, 'string | number');
});

test('field3', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getField('field3');
assert.ok(member?.isClassField());
assert.equal(
member.description,
`Class field 3 description\nwith wraparound`
);
assert.equal(member.default, undefined);
assert.equal(member.privacy, 'public');
assert.equal(member.type?.text, 'string');
assert.equal(member.deprecated, true);
});

test('field4', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getField('field4');
assert.ok(member?.isClassField());
assert.equal(member.summary, `Class field 4 summary\nwith wraparound`);
assert.equal(
member.description,
`Class field 4 description\nwith wraparound`
);
assert.equal(
member.default,
`new Promise${lang === 'ts' ? '<void>' : ''}((r) => r())`
);
assert.equal(member.type?.text, 'Promise<void>');
assert.equal(member.deprecated, 'Class field 4 deprecated');
});

test('static field1', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getStaticField('field1');
assert.ok(member?.isClassField());
assert.equal(member.summary, `Static class field 1 summary`);
assert.equal(member.description, `Static class field 1 description`);
assert.equal(member.default, undefined);
assert.equal(member.privacy, 'protected');
assert.equal(member.type?.text, 'string | number');
});

// Methods

test('method1', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getMethod('method1');
assert.ok(member?.isClassMethod());
assert.equal(member.description, `Method 1 description\nwith wraparound`);
assert.equal(member.parameters?.length, 0);
assert.equal(member.return?.type?.text, 'void');
});

test('method2', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getMethod('method2');
assert.ok(member?.isClassMethod());
assert.equal(member.summary, `Method 2 summary\nwith wraparound`);
assert.equal(member.description, `Method 2 description\nwith wraparound`);
assert.equal(member.parameters?.length, 3);
assert.equal(member.parameters?.[0].name, 'a');
assert.equal(member.parameters?.[0].description, 'Param a description');
assert.equal(member.parameters?.[0].summary, undefined);
assert.equal(member.parameters?.[0].type?.text, 'string');
assert.equal(member.parameters?.[0].default, undefined);
assert.equal(member.parameters?.[0].rest, false);
assert.equal(member.parameters?.[1].name, 'b');
assert.equal(
member.parameters?.[1].description,
'Param b description\nwith wraparound'
);
assert.equal(member.parameters?.[1].type?.text, 'boolean');
assert.equal(member.parameters?.[1].optional, true);
assert.equal(member.parameters?.[1].default, 'false');
assert.equal(member.parameters?.[1].rest, false);
assert.equal(member.parameters?.[2].name, 'c');
assert.equal(member.parameters?.[2].description, 'Param c description');
assert.equal(member.parameters?.[2].summary, undefined);
assert.equal(member.parameters?.[2].type?.text, 'number[]');
assert.equal(member.parameters?.[2].optional, false);
assert.equal(member.parameters?.[2].default, undefined);
assert.equal(member.parameters?.[2].rest, true);
assert.equal(member.return?.type?.text, 'string');
assert.equal(member.return?.description, 'Method 2 return description');
assert.equal(member.deprecated, 'Method 2 deprecated');
});

test('static method1', ({getModule}) => {
const dec = getModule('classes').getDeclaration('Class1');
assert.ok(dec.isClassDeclaration());
const member = dec.getStaticMethod('method1');
assert.ok(member?.isClassMethod());
assert.equal(member.summary, `Static method 1 summary`);
assert.equal(member.description, `Static method 1 description`);
assert.equal(member.parameters?.length, 3);
assert.equal(member.parameters?.[0].name, 'a');
assert.equal(member.parameters?.[0].description, 'Param a description');
assert.equal(member.parameters?.[0].summary, undefined);
assert.equal(member.parameters?.[0].type?.text, 'string');
assert.equal(member.parameters?.[0].default, undefined);
assert.equal(member.parameters?.[0].rest, false);
assert.equal(member.parameters?.[1].name, 'b');
assert.equal(member.parameters?.[1].description, 'Param b description');
assert.equal(member.parameters?.[1].type?.text, 'boolean');
assert.equal(member.parameters?.[1].optional, true);
assert.equal(member.parameters?.[1].default, 'false');
assert.equal(member.parameters?.[1].rest, false);
assert.equal(member.parameters?.[2].name, 'c');
assert.equal(member.parameters?.[2].description, 'Param c description');
assert.equal(member.parameters?.[2].summary, undefined);
assert.equal(member.parameters?.[2].type?.text, 'number[]');
assert.equal(member.parameters?.[2].optional, false);
assert.equal(member.parameters?.[2].default, undefined);
assert.equal(member.parameters?.[2].rest, true);
assert.equal(member.return?.type?.text, 'string');
assert.equal(
member.return?.description,
'Static method 1 return description'
);
assert.equal(member.deprecated, 'Static method 1 deprecated');
});
Copy link
Copy Markdown
Member Author

@kevinpschaaf kevinpschaaf Feb 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these tests are moved unchanged from lit-element/jsdoc_test.js (and their duplicates that were in vanilla-element/jsdoc_test.js into here, so that this file is now all of the class-related tests.

The new tests are the const tests below, plus the superClass test, so that we have a superClass test in the basic class tests (there is another in the LitElement tests, so there was some coverage, but this makes sure it works for vanilla classes also).

Comment on lines +239 to +491
// Doing module JSDoc tests in-memory, to test a number of variations
// without needing to maintain a file for each.

for (const hasFirstStatementDoc of [false, true]) {
const moduleTest = suite<{
analyzer: InMemoryAnalyzer;
}>(
`Module jsDoc tests, ${
hasFirstStatementDoc ? 'has' : 'no'
} first statement docs (${lang})`
);

moduleTest.before.each((ctx) => {
ctx.analyzer = new InMemoryAnalyzer(lang, {
'/package.json': JSON.stringify({name: '@lit-internal/in-memory-test'}),
});
});

const firstStatementDoc = hasFirstStatementDoc
? `
/**
* First statement description
* @summary First statement summary
*/
`
: '';

moduleTest('untagged module description with @module tag', ({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more description
* @module
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(module.description, 'Module description\nmore description');
});

moduleTest(
'untagged module description with @fileoverview tag',
({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more description
* @fileoverview
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore description'
);
}
);

moduleTest('module description in @fileoverview tag', ({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* @fileoverview Module description
* more description
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(module.description, 'Module description\nmore description');
});

moduleTest(
'untagged module description with @packageDocumentation tag',
({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more description
* @packageDocumentation
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore description'
);
}
);

moduleTest(
'module description in @packageDocumentation tag',
({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* @packageDocumentation Module description
* more description
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore description'
);
}
);

moduleTest(
'module description in @packageDocumentation tag with other tags',
({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* @packageDocumentation Module description
* more description
* @module foo
* @deprecated Module is deprecated
*/
${firstStatementDoc}
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore description'
);
assert.equal(module.deprecated, 'Module is deprecated');
}
);

moduleTest('untagged module description', ({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more module description
* @summary Module summary
* @deprecated
*/
/**
* First statement description
* @summary First statement summary
*/
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore module description'
);
assert.equal(module.summary, 'Module summary');
assert.equal(module.deprecated, true);
});

moduleTest('multiple untagged module descriptions', ({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more module description
*/
/**
* Even more module description
*/
/**
* First statement description
* @summary First statement summary
*/
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore module description\nEven more module description'
);
});

moduleTest(
'multiple untagged module descriptions with other tags',
({analyzer}) => {
analyzer.setFile(
'/module',
`
/**
* Module description
* more module description
* @deprecated
*/
/**
* Even more module description
* @summary Module summary
*/
/**
* First statement description
* @summary First statement summary
*/
export const foo = 42;
`
);
const module = analyzer.getModule(
getSourceFilename('/module', lang) as AbsolutePath
);
assert.equal(
module.description,
'Module description\nmore module description\nEven more module description'
);
assert.equal(module.summary, 'Module summary');
assert.equal(module.deprecated, true);
}
);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from lit-element/jsdoc_tests.js

});

test('field4', ({getModule}) => {
test('basic class analysis', ({getModule}) => {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved all the class-specific stuff to classes_test.js, and just left a basic class analysis test here.

Comment on lines +47 to +50
* Note, the `docNode` may differ from the `declaration` in
* the case of a const assignment to a class expression, as
* the docs will be on the VariableStatement rather than
* the class-like expression.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a getJSDocTags function in the TS repo where the docs claim it gets related JSDoc tags even if they're on other nodes. Would that work here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseNodeJSDocInfo uses that here:

const jsDocTags = ts.getJSDocTags(node);

But it doesn't seem to return the e.g. @description, etc. tag on the parent variable statement when the node passed to it is the class expression initializer.

Oddly it does do the thing you expected for const functions, just not for const classes. I had made the equivalent API's between classes and functions line up (i.e. take an optional docNode), but seems like it's not strictly required for functions for whatever reason. I guess I'll yank that back out of the function side...

Comment on lines 37 to 38
statement: ts.VariableStatement,
dec: ts.VariableDeclaration | ts.EnumDeclaration,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think statement can be retrieved from a VariableDeclaration with .parent.parent. Also, what is statement's relationship to dec when dec is an EnumDeclaration?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I just noticed there's a getEnumDeclaration and getEnumDeclarationInfo below. Does getVariableDeclaration need to handle both VariableDeclarations and EnumDeclarations?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the EnumDeclaration in that union was vestigial; prior to this getDeclarationInfo handled both variables and enums, but after introducing the statement arg, I had to split them out. Removed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think statement can be retrieved from a VariableDeclaration with .parent.parent.

Oh yeah good point. Hmm, it'd need to be cast though, since VariableDeclaration can exist in for/for of/for in statements also. Feels a little stricter as-is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about checking if .parent.parent is a VariableStatement?

@kevinpschaaf kevinpschaaf merged commit cabc618 into main Mar 3, 2023
@kevinpschaaf kevinpschaaf deleted the analyzer-const-class-fn branch March 3, 2023 00:34
@lit-robot lit-robot mentioned this pull request Mar 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants