-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Replace espree and doctrine with typescript in docgen. #21238
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
Changes from all commits
3d792ec
fd0a4a6
e0165e0
c87aaff
eb4b14b
47b0f41
22b8388
d546688
ad2aea1
9372027
3528e37
6966050
69a6fa5
84671d4
528fa02
5b7aec9
05eea4c
b22acb8
5c52fe8
d98bb09
7e18aad
b1d1d21
34ea53b
7b3224b
2b2e52c
7ebc964
c83fc7e
67012d7
535efa5
6a47250
296c61e
5f90185
dd14b0f
294d4cd
c3c4137
c89e1a1
097cc9c
89ca742
859fecc
673fa13
4e522b5
4ac2228
6b0b0f6
86fc6b9
2f8076e
fa1d12d
843d4b6
4029682
9811795
f92fd7f
b879fb0
8654f4e
7f026d5
ada4448
f114bda
62014e8
28172ef
c621be2
1f8a54f
d869e45
d5f9b22
c6c9c99
ad088d8
8586be6
c5f7b88
e4c60f3
d150875
2f20e58
209271a
0ec03a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /** | ||
| * External dependencies | ||
| */ | ||
| const ts = require( 'typescript' ); | ||
| const { readFileSync } = require( 'fs' ); | ||
| const { inspect } = require( 'util' ); | ||
|
|
||
| const filename = process.argv[ 2 ]; | ||
|
|
||
| const sourceFile = ts.createSourceFile( | ||
| filename, | ||
| readFileSync( filename ).toString(), | ||
| ts.ScriptTarget.ESNext | ||
| ); | ||
|
|
||
| process.stdout.write( inspect( sourceFile, false, null ) ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| const ts = require( 'typescript' ); | ||
| const { readFileSync } = require( 'fs' ); | ||
|
|
||
| const { getExportStatements } = require( './get-export-statements' ); | ||
|
|
||
| /** | ||
| * Function that takes file path and returns compiled result | ||
| * | ||
| * @param {string} filePath the path to the file to be compiled | ||
| */ | ||
| module.exports = function( filePath ) { | ||
| const options = { | ||
| allowJs: true, | ||
| }; | ||
| const host = ts.createCompilerHost( options, true ); | ||
| const raw = readFileSync( filePath ).toString(); | ||
| const code = raw | ||
| // typescript interprets @wordpress in @example code as a JSDoc tag. | ||
| // So, it should be replaced for the time being. | ||
| // They're restored in get-jsdoc-from-statement.js | ||
| .replace( /@wordpress/g, '__WORDPRESS_IMPORT__' ) | ||
| // When <caption>ES(5|Next)<\/caption> exists next to @example tag, | ||
| // typescript cannot parse code correctly. | ||
| // So, they're removed. | ||
| .replace( /@example\s+<caption>ES(5|Next)<\/caption>/g, '@example' ); | ||
|
||
| const internalSourceFile = ts.createSourceFile( | ||
| filePath, | ||
| code, | ||
| options.target, | ||
| true | ||
| ); | ||
|
|
||
| host.getSourceFile = () => internalSourceFile; | ||
| host.readFile = () => code; | ||
|
|
||
| const program = ts.createProgram( [ filePath ], options, host ); | ||
|
|
||
| const typeChecker = program.getTypeChecker(); | ||
| const sourceFile = program.getSourceFile( filePath ); | ||
| const exportStatements = getExportStatements( sourceFile ); | ||
|
|
||
| // Without the line below, sourceFile.fileName is set to | ||
| // /gutenberg/node_modules/typescript/lib/lib.es2020.full.d.ts | ||
| sourceFile.fileName = filePath; | ||
|
|
||
| return { | ||
| program, | ||
| typeChecker, | ||
| sourceFile, | ||
| exportStatements, | ||
| }; | ||
| }; | ||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,103 +1,109 @@ | ||
| /** | ||
| * External dependencies | ||
| */ | ||
| const { get } = require( 'lodash' ); | ||
| const { SyntaxKind } = require( 'typescript' ); | ||
|
|
||
| const { hasExportModifier, hasDefaultModifier } = require( './has-modifier' ); | ||
|
|
||
| /** | ||
| * @typedef {import('typescript').Statement} Statement | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef ExportEntry | ||
| * | ||
| * @property {string} localName name of an exported entry in its local file. | ||
| * @property {string} exportedName name of an exported entry in export statement. | ||
| * @property {?string} module which file the name exported from. | ||
| */ | ||
|
|
||
| /** | ||
| * Returns the export entry records of the given export statement. | ||
| * Unlike [the standard](http://www.ecma-international.org/ecma-262/9.0/#exportentry-record), | ||
| * the `importName` and the `localName` are merged together. | ||
| * | ||
| * @param {Object} token Espree node representing an export. | ||
| * @param {Statement} statement TypeScript AST node representing an export. | ||
| * | ||
| * @return {Array} Exported entry records. Example: | ||
| * @return {Array<ExportEntry>} Exported entry records. Example: | ||
| * [ { | ||
| * localName: 'localName', | ||
| * exportName: 'exportedName', | ||
| * module: null, | ||
| * lineStart: 2, | ||
| * lineEnd: 3, | ||
| * } ] | ||
| */ | ||
| module.exports = function( token ) { | ||
| if ( token.type === 'ExportDefaultDeclaration' ) { | ||
| const getLocalName = ( t ) => { | ||
| let name; | ||
| switch ( t.declaration.type ) { | ||
| case 'Identifier': | ||
| name = t.declaration.name; | ||
| break; | ||
| case 'AssignmentExpression': | ||
| name = t.declaration.left.name; | ||
| break; | ||
| //case 'FunctionDeclaration' | ||
| //case 'ClassDeclaration' | ||
| default: | ||
| name = get( t.declaration, [ 'id', 'name' ], '*default*' ); | ||
| } | ||
| return name; | ||
| }; | ||
| module.exports = function( statement ) { | ||
| if ( hasExportModifier( statement ) ) { | ||
| if ( hasDefaultModifier( statement ) ) { | ||
| return [ | ||
| { | ||
| localName: statement.name | ||
| ? statement.name.text | ||
| : '*default*', | ||
| exportName: 'default', | ||
| module: null, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| if ( statement.kind === SyntaxKind.VariableStatement ) { | ||
| return statement.declarationList.declarations.map( ( decl ) => { | ||
| return { | ||
| localName: decl.name.text, | ||
| exportName: decl.name.text, | ||
| module: null, | ||
| }; | ||
| } ); | ||
| } | ||
|
|
||
| return [ | ||
| { | ||
| localName: getLocalName( token ), | ||
| exportName: 'default', | ||
| localName: statement.name.text, | ||
| exportName: statement.name.text, | ||
| module: null, | ||
| lineStart: token.loc.start.line, | ||
| lineEnd: token.loc.end.line, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| if ( token.type === 'ExportAllDeclaration' ) { | ||
| if ( statement.kind === SyntaxKind.ExportAssignment ) { | ||
| const getLocalName = ( s ) => { | ||
| switch ( s.expression.kind ) { | ||
| case SyntaxKind.Identifier: | ||
| return s.expression.text; | ||
| default: | ||
| return '*default*'; | ||
| } | ||
| }; | ||
|
|
||
| return [ | ||
| { | ||
| localName: '*', | ||
| exportName: null, | ||
| module: token.source.value, | ||
| lineStart: token.loc.start.line, | ||
| lineEnd: token.loc.end.line, | ||
| localName: getLocalName( statement ), | ||
| exportName: 'default', | ||
| module: null, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| const name = []; | ||
| if ( token.declaration === null ) { | ||
| token.specifiers.forEach( ( specifier ) => | ||
| name.push( { | ||
| localName: specifier.local.name, | ||
| exportName: specifier.exported.name, | ||
| module: get( token.source, [ 'value' ], null ), | ||
| lineStart: specifier.loc.start.line, | ||
| lineEnd: specifier.loc.end.line, | ||
| } ) | ||
| ); | ||
| return name; | ||
| } | ||
|
|
||
| switch ( token.declaration.type ) { | ||
| case 'ClassDeclaration': | ||
| case 'FunctionDeclaration': | ||
| name.push( { | ||
| localName: token.declaration.id.name, | ||
| exportName: token.declaration.id.name, | ||
| module: null, | ||
| lineStart: token.declaration.loc.start.line, | ||
| lineEnd: token.declaration.loc.end.line, | ||
| } ); | ||
| break; | ||
|
|
||
| case 'VariableDeclaration': | ||
| token.declaration.declarations.forEach( ( declaration ) => { | ||
| name.push( { | ||
| localName: declaration.id.name, | ||
| exportName: declaration.id.name, | ||
| module: null, | ||
| lineStart: token.declaration.loc.start.line, | ||
| lineEnd: token.declaration.loc.end.line, | ||
| } ); | ||
| } ); | ||
| break; | ||
| } | ||
| // statement.kind === SyntaxKind.ExportDeclaration | ||
|
|
||
| return name; | ||
| return statement.exportClause | ||
| ? // export { a, b } from './module' | ||
| statement.exportClause.elements.map( ( element ) => { | ||
| return { | ||
| localName: element.propertyName | ||
| ? element.propertyName.text | ||
| : element.name.text, | ||
| exportName: element.name.text, | ||
| module: statement.moduleSpecifier | ||
| ? statement.moduleSpecifier.text | ||
| : null, | ||
| }; | ||
| } ) | ||
| : // export * from './namespace-module'; | ||
| [ | ||
| { | ||
| localName: '*', | ||
| exportName: null, | ||
| module: statement.moduleSpecifier.text, | ||
| }, | ||
| ]; | ||
| }; |
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.
This replaces
@wordpressglobally in the source, not just comments?Are we tracking some condition when this could be removed?
Do you think we could hit issues where e.g.
import escapeHtml from '@wordpress/escape-html'becomes import escapeHtml from 'WORDPRESS_IMPORT/escape-html'?Uh oh!
There was an error while loading. Please reload this page.
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.
1. I commented when they're restored. (5ca2084)
2. That can be a problem when we have written code that exports imported items directly from other packages like this:
In this case, the parser tries to open
packages/escape-html/src/index.jsand find jsdoc ofescapeHtml. Then, it can fail because__WORDPRESS_IMPORT__doesn't exist. I guess it's more of a design flaw than a feature. Don't you think so?Maybe, but for those rare cases, we need to show human-readable reason to the users than
cannot find module '__WORDPRESS_IMPORT__'3. But your comment made me curious about this case:
I found that it shows
import( '__WORDPRESS_IMPORT__/element' ). I fixed it. (68d1198)