Skip to content

Commit 69cbd42

Browse files
authored
Merge pull request #504 from adbutterfield/perf-improvements
Perf improvements
2 parents f5b5503 + fea6da1 commit 69cbd42

File tree

2 files changed

+84
-58
lines changed

2 files changed

+84
-58
lines changed

src/parser.ts

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ export class Parser {
225225
private readonly savePropValueAsString: boolean;
226226
private readonly shouldIncludePropTagMap: boolean;
227227
private readonly shouldIncludeExpression: boolean;
228+
private propertiesOfPropsCache: Map<string, PropItem> = new Map();
229+
private componentsInfoCache: Map<string, ComponentDoc | null> = new Map();
228230

229231
constructor(program: ts.Program, opts: ParserOptions) {
230232
const {
@@ -299,11 +301,17 @@ export class Parser {
299301
const typeSymbol = type.symbol || type.aliasSymbol;
300302
const originalName = rootExp.getName();
301303
const filePath = source.fileName;
304+
const cacheKey = `${filePath}_${originalName}`;
305+
306+
if (this.componentsInfoCache.has(cacheKey)) {
307+
return this.componentsInfoCache.get(cacheKey) as ComponentDoc | null;
308+
}
302309

303310
if (!rootExp.valueDeclaration) {
304311
if (!typeSymbol && (rootExp.flags & ts.SymbolFlags.Alias) !== 0) {
305312
commentSource = this.checker.getAliasedSymbol(commentSource);
306313
} else if (!typeSymbol) {
314+
this.componentsInfoCache.set(cacheKey, null);
307315
return null;
308316
} else {
309317
rootExp = typeSymbol;
@@ -346,6 +354,7 @@ export class Parser {
346354
(typeSymbol.getEscapedName() === 'Requireable' ||
347355
typeSymbol.getEscapedName() === 'Validator')
348356
) {
357+
this.componentsInfoCache.set(cacheKey, null);
349358
return null;
350359
}
351360

@@ -365,6 +374,7 @@ export class Parser {
365374
let result: ComponentDoc | null = null;
366375
if (propsType) {
367376
if (!commentSource.valueDeclaration) {
377+
this.componentsInfoCache.set(cacheKey, null);
368378
return null;
369379
}
370380
const defaultProps = this.extractDefaultPropsFromComponent(
@@ -404,6 +414,7 @@ export class Parser {
404414
result.rootExpression = exp;
405415
}
406416

417+
this.componentsInfoCache.set(cacheKey, result);
407418
return result;
408419
}
409420

@@ -701,60 +712,73 @@ export class Parser {
701712

702713
propertiesOfProps.forEach(prop => {
703714
const propName = prop.getName();
715+
const parent = getParentType(prop);
716+
const cacheKey = `${parent?.fileName}_${propName}`;
717+
if (this.propertiesOfPropsCache.has(cacheKey)) {
718+
result[propName] = this.propertiesOfPropsCache.get(
719+
cacheKey
720+
) as PropItem;
721+
} else {
722+
// Find type of prop by looking in context of the props object itself.
723+
const propType = this.checker.getTypeOfSymbolAtLocation(
724+
prop,
725+
propsObj.valueDeclaration!
726+
);
704727

705-
// Find type of prop by looking in context of the props object itself.
706-
const propType = this.checker.getTypeOfSymbolAtLocation(
707-
prop,
708-
propsObj.valueDeclaration!
709-
);
728+
const jsDocComment = this.findDocComment(prop);
729+
const hasCodeBasedDefault = defaultProps[propName] !== undefined;
710730

711-
const jsDocComment = this.findDocComment(prop);
712-
const hasCodeBasedDefault = defaultProps[propName] !== undefined;
731+
let defaultValue: { value: any } | null = null;
713732

714-
let defaultValue: { value: any } | null = null;
733+
if (hasCodeBasedDefault) {
734+
defaultValue = { value: defaultProps[propName] };
735+
} else if (jsDocComment.tags.default) {
736+
defaultValue = { value: jsDocComment.tags.default };
737+
}
715738

716-
if (hasCodeBasedDefault) {
717-
defaultValue = { value: defaultProps[propName] };
718-
} else if (jsDocComment.tags.default) {
719-
defaultValue = { value: jsDocComment.tags.default };
720-
}
739+
const parents = getDeclarations(prop);
740+
const declarations = prop.declarations || [];
741+
const baseProp = baseProps.find(p => p.getName() === propName);
721742

722-
const parent = getParentType(prop);
723-
const parents = getDeclarations(prop);
724-
const declarations = prop.declarations || [];
725-
const baseProp = baseProps.find(p => p.getName() === propName);
726-
727-
const required =
728-
!isOptional(prop) &&
729-
!hasCodeBasedDefault &&
730-
// If in a intersection or union check original declaration for "?"
731-
// @ts-ignore
732-
declarations.every(d => !d.questionToken) &&
733-
(!baseProp || !isOptional(baseProp));
734-
735-
const type = jsDocComment.tags.type
736-
? {
737-
name: jsDocComment.tags.type
738-
}
739-
: this.getDocgenType(propType, required);
740-
741-
const propTags = this.shouldIncludePropTagMap
742-
? { tags: jsDocComment.tags }
743-
: {};
744-
const description = this.shouldIncludePropTagMap
745-
? jsDocComment.description.replace(/\r\n/g, '\n')
746-
: jsDocComment.fullComment.replace(/\r\n/g, '\n');
747-
748-
result[propName] = {
749-
defaultValue,
750-
description: description,
751-
name: propName,
752-
parent,
753-
declarations: parents,
754-
required,
755-
type,
756-
...propTags
757-
};
743+
const required =
744+
!isOptional(prop) &&
745+
!hasCodeBasedDefault &&
746+
// If in a intersection or union check original declaration for "?"
747+
// @ts-ignore
748+
declarations.every(d => !d.questionToken) &&
749+
(!baseProp || !isOptional(baseProp));
750+
751+
const type = jsDocComment.tags.type
752+
? {
753+
name: jsDocComment.tags.type
754+
}
755+
: this.getDocgenType(propType, required);
756+
757+
const propTags = this.shouldIncludePropTagMap
758+
? { tags: jsDocComment.tags }
759+
: {};
760+
const description = this.shouldIncludePropTagMap
761+
? jsDocComment.description.replace(/\r\n/g, '\n')
762+
: jsDocComment.fullComment.replace(/\r\n/g, '\n');
763+
764+
const propItem: PropItem = {
765+
defaultValue,
766+
description: description,
767+
name: propName,
768+
parent,
769+
declarations: parents,
770+
required,
771+
type,
772+
...propTags
773+
};
774+
if (parent?.fileName.includes('node_modules')) {
775+
this.propertiesOfPropsCache.set(
776+
`${parent.fileName}_${propName}`,
777+
propItem
778+
);
779+
}
780+
result[propName] = propItem;
781+
}
758782
});
759783

760784
return result;

src/trimFileName.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import * as path from 'path';
22

33
const slashRegex = /[\\/]/g;
4-
4+
const fileNameCache = new Map<string, string>();
55
export function trimFileName(
66
fileName: string,
77
cwd: string = process.cwd(),
88
platform?: 'posix' | 'win32'
9-
) {
9+
): string {
10+
if (fileNameCache.has(fileName)) return fileNameCache.get(fileName) as string;
1011
// This allows tests to run regardless of current platform
1112
const pathLib = platform ? path[platform] : path;
1213

@@ -24,17 +25,18 @@ export function trimFileName(
2425
let parent = cwd;
2526
do {
2627
if (normalizedFileName.startsWith(parent)) {
27-
return (
28-
pathLib
29-
// Preserve the parent directory name to match existing behavior
30-
.relative(pathLib.dirname(parent), normalizedFileName)
31-
// Restore original type of slashes
32-
.replace(slashRegex, originalSep)
33-
);
28+
const finalPathName = pathLib
29+
// Preserve the parent directory name to match existing behavior
30+
.relative(pathLib.dirname(parent), normalizedFileName)
31+
// Restore original type of slashes
32+
.replace(slashRegex, originalSep);
33+
fileNameCache.set(fileName, finalPathName);
34+
return finalPathName;
3435
}
3536
parent = pathLib.dirname(parent);
3637
} while (parent !== root);
3738

39+
fileNameCache.set(fileName, fileName);
3840
// No common ancestor, so return the path as-is
3941
return fileName;
4042
}

0 commit comments

Comments
 (0)