-
Notifications
You must be signed in to change notification settings - Fork 878
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
[labs/analyzer] Add support for analyzing function declarations #3655
Changes from all commits
fb0459e
db897d1
06bc662
79a1028
4ef6c0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@lit-labs/analyzer': minor | ||
--- | ||
|
||
Added support for analyzing function declarations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/** | ||
* @license | ||
* Copyright 2022 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
import {suite} from 'uvu'; | ||
// eslint-disable-next-line import/extensions | ||
import * as assert from 'uvu/assert'; | ||
import {fileURLToPath} from 'url'; | ||
import {getSourceFilename, languages} from '../utils.js'; | ||
|
||
import { | ||
createPackageAnalyzer, | ||
Analyzer, | ||
AbsolutePath, | ||
Module, | ||
} from '../../index.js'; | ||
|
||
for (const lang of languages) { | ||
const test = suite<{ | ||
analyzer: Analyzer; | ||
packagePath: AbsolutePath; | ||
module: Module; | ||
}>(`Module tests (${lang})`); | ||
|
||
test.before((ctx) => { | ||
try { | ||
const packagePath = fileURLToPath( | ||
new URL(`../../test-files/${lang}/functions`, import.meta.url).href | ||
) as AbsolutePath; | ||
const analyzer = createPackageAnalyzer(packagePath); | ||
|
||
const result = analyzer.getPackage(); | ||
const file = getSourceFilename('functions', lang); | ||
const module = result.modules.find((m) => m.sourcePath === file); | ||
if (module === undefined) { | ||
throw new Error(`Analyzer did not analyze file '${file}'`); | ||
} | ||
|
||
ctx.packagePath = packagePath; | ||
ctx.analyzer = analyzer; | ||
ctx.module = module; | ||
} catch (error) { | ||
// Uvu has a bug where it silently ignores failures in before and after, | ||
// see https://github.com/lukeed/uvu/issues/191. | ||
console.error('uvu before error', error); | ||
process.exit(1); | ||
} | ||
Comment on lines
+28
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's also a chunk like this in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will separate into follow-up PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
}); | ||
|
||
test('Function 1', ({module}) => { | ||
const exportedFn = module.getResolvedExport('function1'); | ||
const fn = module.getDeclaration('function1'); | ||
assert.equal(fn, exportedFn); | ||
assert.ok(fn?.isFunctionDeclaration()); | ||
assert.equal(fn.name, `function1`); | ||
assert.equal(fn.description, `Function 1 description`); | ||
assert.equal(fn.summary, undefined); | ||
assert.equal(fn.parameters?.length, 0); | ||
assert.equal(fn.deprecated, undefined); | ||
}); | ||
|
||
test('Function 2', ({module}) => { | ||
const exportedFn = module.getResolvedExport('function2'); | ||
const fn = module.getDeclaration('function2'); | ||
assert.equal(fn, exportedFn); | ||
assert.ok(fn?.isFunctionDeclaration()); | ||
assert.equal(fn.name, `function2`); | ||
assert.equal(fn.summary, `Function 2 summary\nwith wraparound`); | ||
assert.equal(fn.description, `Function 2 description\nwith wraparound`); | ||
assert.equal(fn.parameters?.length, 3); | ||
assert.equal(fn.parameters?.[0].name, 'a'); | ||
assert.equal(fn.parameters?.[0].description, 'Param a description'); | ||
assert.equal(fn.parameters?.[0].summary, undefined); | ||
assert.equal(fn.parameters?.[0].type?.text, 'string'); | ||
assert.equal(fn.parameters?.[0].default, undefined); | ||
assert.equal(fn.parameters?.[0].rest, false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uvu's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to do pretty bad things with classes, so gonna avoid for now. |
||
assert.equal(fn.parameters?.[1].name, 'b'); | ||
assert.equal( | ||
fn.parameters?.[1].description, | ||
'Param b description\nwith wraparound' | ||
); | ||
assert.equal(fn.parameters?.[1].type?.text, 'boolean'); | ||
assert.equal(fn.parameters?.[1].optional, true); | ||
assert.equal(fn.parameters?.[1].default, 'false'); | ||
assert.equal(fn.parameters?.[1].rest, false); | ||
assert.equal(fn.parameters?.[2].name, 'c'); | ||
assert.equal(fn.parameters?.[2].description, 'Param c description'); | ||
assert.equal(fn.parameters?.[2].summary, undefined); | ||
assert.equal(fn.parameters?.[2].type?.text, 'number[]'); | ||
assert.equal(fn.parameters?.[2].optional, false); | ||
assert.equal(fn.parameters?.[2].default, undefined); | ||
assert.equal(fn.parameters?.[2].rest, true); | ||
assert.equal(fn.return?.type?.text, 'string'); | ||
assert.equal(fn.return?.description, 'Function 2 return description'); | ||
assert.equal(fn.deprecated, 'Function 2 deprecated'); | ||
}); | ||
|
||
test('Default function', ({module}) => { | ||
const exportedFn = module.getResolvedExport('default'); | ||
const fn = module.getDeclaration('default'); | ||
assert.equal(fn, exportedFn); | ||
assert.ok(fn?.isFunctionDeclaration()); | ||
assert.equal(fn.name, `default`); | ||
assert.equal(fn.description, `Default function description`); | ||
assert.equal(fn.summary, undefined); | ||
assert.equal(fn.parameters?.length, 0); | ||
assert.equal(fn.return?.type?.text, 'string'); | ||
assert.equal(fn.return?.description, 'Default function return description'); | ||
assert.equal(fn.deprecated, undefined); | ||
}); | ||
|
||
test.run(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* @license | ||
* Copyright 2022 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
/** | ||
* Function 1 description | ||
*/ | ||
export function function1() {} | ||
|
||
/** | ||
* @summary Function 2 summary | ||
* with wraparound | ||
* | ||
* @description Function 2 description | ||
* with wraparound | ||
* | ||
* @param {string} a Param a description | ||
* @param {boolean} b Param b description | ||
* with wraparound | ||
* | ||
* @param {number[]} c Param c description | ||
* @returns {string} Function 2 return description | ||
* | ||
* @deprecated Function 2 deprecated | ||
*/ | ||
export function function2(a, b = false, ...c) { | ||
return b ? a : c[0].toFixed(); | ||
} | ||
|
||
/** | ||
* Default function description | ||
* @returns {string} Default function return description | ||
*/ | ||
export default function () { | ||
return 'default'; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"name": "@lit-internal/test-functions", | ||
"dependencies": { | ||
"lit": "^2.0.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"name": "@lit-internal/test-functions", | ||
"dependencies": { | ||
"lit": "^2.0.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* @license | ||
* Copyright 2022 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
/** | ||
* Function 1 description | ||
*/ | ||
export function function1() {} | ||
|
||
/** | ||
* @summary Function 2 summary | ||
* with wraparound | ||
* | ||
* @description Function 2 description | ||
* with wraparound | ||
* | ||
* @param a Param a description | ||
* @param b Param b description | ||
* with wraparound | ||
* | ||
* @param c Param c description | ||
* @returns Function 2 return description | ||
* | ||
* @deprecated Function 2 deprecated | ||
*/ | ||
export function function2(a: string, b = false, ...c: number[]) { | ||
return b ? a : c[0].toFixed(); | ||
} | ||
|
||
/** | ||
* Default function description | ||
* @returns Default function return description | ||
*/ | ||
export default function () { | ||
return 'default'; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es2020", | ||
"lib": ["es2020", "DOM"], | ||
"module": "ES2020", | ||
"rootDir": "./src", | ||
"outDir": "./", | ||
"moduleResolution": "node", | ||
"experimentalDecorators": true, | ||
"skipDefaultLibCheck": true, | ||
"skipLibCheck": true, | ||
"noEmit": true | ||
}, | ||
"include": ["src/**/*.ts"], | ||
"exclude": [] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the other stuff in
getFunctionLikeInfo()
too expensive to call here? This feels like something that should be rolled into it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getFunctionLikeInfo()
is called here and inClassMethod