Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
3d792ec
Update TypeScript to 3.8.3
sainthkh Mar 29, 2020
fd0a4a6
Extract getExportTokens and rename it to getExportStatements
sainthkh Mar 17, 2020
e0165e0
Add script: dump-ast.
sainthkh Mar 17, 2020
c87aaff
Refactor getExportEntries.
sainthkh Mar 18, 2020
eb4b14b
hasExportKeyword -> hasExportModifier, hasDefaultKeyword -> hasDefaul…
sainthkh Mar 18, 2020
47b0f41
Remove doctrine and unnecessary files/code. Edit comment.
sainthkh Mar 19, 2020
22b8388
Refactor getJsdocFromToken
sainthkh Mar 19, 2020
d546688
getJsdocFromToken -> getJsdocFromStatement.
sainthkh Mar 19, 2020
ad2aea1
Handle the case when there is no tag.
sainthkh Mar 19, 2020
9372027
Refactor getIntermediateRepresentation.
sainthkh Mar 20, 2020
3528e37
Fix index.js
sainthkh Mar 22, 2020
6966050
Remove getIRFromStatement from public API.
sainthkh Mar 22, 2020
69a6fa5
Fix the case for `import 'x'`.
sainthkh Mar 22, 2020
84671d4
Remove unnecessary comment.
sainthkh Mar 22, 2020
528fa02
TypeScript compiles @wordpress as a tag. Fixed it.
sainthkh Mar 22, 2020
5b7aec9
Fix fileName.
sainthkh Mar 22, 2020
05eea4c
Add test for generating types.
sainthkh Mar 22, 2020
b22acb8
Add types to test.
sainthkh Mar 23, 2020
5c52fe8
Removed unnecessary files and espree
sainthkh Mar 25, 2020
d98bb09
Remove type checker.
sainthkh Mar 23, 2020
7e18aad
Add primitive types.
sainthkh Mar 23, 2020
b1d1d21
Add more type generations.
sainthkh Mar 24, 2020
34ea53b
Add function and object.
sainthkh Mar 24, 2020
7b3224b
Add more types.
sainthkh Mar 25, 2020
2b2e52c
Add explanation comment for __WORDPRESS_IMPORT__
sainthkh Mar 25, 2020
7ebc964
import -> require
sainthkh Mar 25, 2020
c83fc7e
Handle @typedef.
sainthkh Mar 25, 2020
67012d7
Uncomment tests.
sainthkh Mar 25, 2020
535efa5
type field for typedef.
sainthkh Mar 25, 2020
6a47250
Format typedef.
sainthkh Mar 26, 2020
296c61e
Show default value.
sainthkh Mar 26, 2020
5f90185
When a doc has no description but has tags, it's documented.
sainthkh Mar 26, 2020
dd14b0f
Replace __WORDPRESS_IMPORT__
sainthkh Mar 26, 2020
294d4cd
Remove arg name and dot.
sainthkh Mar 26, 2020
c3c4137
Format jsdoc object param definition
sainthkh Mar 26, 2020
c89e1a1
escapedText adds one more _. So, changed them to text.
sainthkh Mar 26, 2020
097cc9c
Fix lone qualified name.
sainthkh Mar 26, 2020
89ca742
Restore @wordpress in description.
sainthkh Mar 26, 2020
859fecc
Handle generics.
sainthkh Mar 27, 2020
673fa13
Handle <caption>ES(5|Next)</caption> tags.
sainthkh Mar 27, 2020
4e522b5
escapedText -> text.
sainthkh Mar 27, 2020
4ac2228
Remove unnecessary script.
sainthkh Mar 27, 2020
6b0b0f6
Remove unnecessary exports.json.
sainthkh Mar 27, 2020
86fc6b9
Fix when the type of jsdoc type literal has a type option like {?object}
sainthkh Mar 27, 2020
2f8076e
Remove unnecessary code.
sainthkh Mar 27, 2020
fa1d12d
Add known issues.
sainthkh Mar 29, 2020
843d4b6
Respect WP coding style.
sainthkh Mar 29, 2020
4029682
Add jsdoc comments.
sainthkh Mar 29, 2020
9811795
Add cases to help understand code.
sainthkh Mar 29, 2020
f92fd7f
Use optional chaining + optional catch binding!
sainthkh Mar 29, 2020
b879fb0
Show type error.
sainthkh Mar 29, 2020
8654f4e
Fix package.json lint error.
sainthkh Mar 29, 2020
7f026d5
Fix test failures.
sainthkh Mar 29, 2020
ada4448
Remove unnecessary script in package.json.
sainthkh Mar 31, 2020
f114bda
Remove ES2020 or rename it to ESNext.
sainthkh Mar 31, 2020
62014e8
Add comment when __WORDPRESS_IMPORT__ is restored.
sainthkh Mar 31, 2020
28172ef
Replace @wordpress in type names.
sainthkh Mar 31, 2020
c621be2
Remove getLocalName().
sainthkh Mar 31, 2020
1f8a54f
Add more sample cases in the comment to getExportStatements.
sainthkh Mar 31, 2020
d869e45
Remove unnecessary code.
sainthkh Mar 31, 2020
d5f9b22
Fix curly.
sainthkh Mar 31, 2020
c6c9c99
Handle when there is no "export" in the file.
sainthkh Mar 31, 2020
ad088d8
Comment where I got the list of types.
sainthkh Apr 1, 2020
8586be6
Remove invalid test case.
sainthkh Apr 1, 2020
c5f7b88
Update docs
sainthkh Apr 1, 2020
e4c60f3
sF -> internalSourceFile.
sainthkh Apr 3, 2020
d150875
console.log -> process.stdout.write
sainthkh Apr 3, 2020
2f20e58
Parse new syntaxes correctly.
sainthkh Apr 3, 2020
209271a
Revert "Use optional chaining + optional catch binding!"
sainthkh Apr 3, 2020
0ec03a5
Revert "Update docs"
sainthkh Apr 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 1 addition & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions packages/docgen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@
"docgen": "./bin/cli.js"
},
"dependencies": {
"doctrine": "^2.1.0",
"espree": "^4.0.0",
"lodash": "^4.17.15",
"mdast-util-inject": "1.1.0",
"optionator": "0.8.2",
"remark": "10.0.1",
"remark-parse": "6.0.3",
"typescript": "3.8.3",
"unified": "7.1.0"
},
"publishConfig": {
Expand Down
16 changes: 16 additions & 0 deletions packages/docgen/scripts/dump-ast.js
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 ) );
52 changes: 52 additions & 0 deletions packages/docgen/src/compile.js
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__' )
Copy link
Member

Choose a reason for hiding this comment

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

This replaces @wordpress globally in the source, not just comments?

So, it should be replaced for the time being.

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'?

Copy link
Contributor Author

@sainthkh sainthkh Mar 31, 2020

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:

// packages/some-package/src/index.js

import escapeHtml from '@wordpress/escape-html';

export { escapeHtml }

In this case, the parser tries to open packages/escape-html/src/index.js and find jsdoc of escapeHtml. 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:

/**
* @param {import('@wordpress/element').WPSyntheticEvent} p what if @wordpress?
*/

I found that it shows import( '__WORDPRESS_IMPORT__/element' ). I fixed it. (68d1198)

// 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' );
Comment on lines +22 to +25
Copy link
Member

Choose a reason for hiding this comment

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

It'd probably be fine to address separately, but our usage of HTML after the @example tag feels weird. I wonder if it would help avoid this logic if we at least moved those <caption> tags onto the line immediately following @example ?

Copy link
Contributor Author

@sainthkh sainthkh Apr 3, 2020

Choose a reason for hiding this comment

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

Yes, it does. Check this out

But I think we should add it to the 'later works' list. To fix it, we need to change another 10 more files.

Copy link
Member

@aduth aduth Apr 3, 2020

Choose a reason for hiding this comment

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

But I think we should add it to the 'later works' list. To fix it, we need to change another 10 more files.

What I find can work well in these situations is: Create a separate pull request which includes those smaller independent changes. At the time it's merged, the branch of this pull request can be rebased to account for those new revisions. For this case, I expect it means we wouldn't need this code anymore to handle this syntax.

An example of another large pull request broken down this way: #3745 (comment)

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,
};
};
60 changes: 0 additions & 60 deletions packages/docgen/src/engine.js

This file was deleted.

3 changes: 0 additions & 3 deletions packages/docgen/src/get-dependency-path.js

This file was deleted.

150 changes: 78 additions & 72 deletions packages/docgen/src/get-export-entries.js
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,
},
];
};
Loading