Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
38 changes: 19 additions & 19 deletions package-lock.json

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

24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,34 @@
"@types/fs-extra": "5.0.1",
"@types/handlebars": "4.0.36",
"@types/highlight.js": "9.12.2",
"@types/lodash": "4.14.104",
"@types/lodash": "4.14.106",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Next time, avoid updating dependencies unnecessarially. It creates merge conflicts with other contributions.

Copy link
Copy Markdown
Contributor Author

@Tokimon Tokimon Apr 13, 2018

Choose a reason for hiding this comment

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

ok got it... I will revert it

"@types/marked": "0.3.0",
"@types/minimatch": "3.0.3",
"@types/shelljs": "0.7.8",
"fs-extra": "^5.0.0",
"handlebars": "^4.0.6",
"highlight.js": "^9.0.0",
"handlebars": "^4.0.11",
"highlight.js": "^9.12.0",
"lodash": "^4.17.5",
"marked": "^0.3.17",
"minimatch": "^3.0.0",
"marked": "^0.3.19",
"minimatch": "^3.0.4",
"progress": "^2.0.0",
"shelljs": "^0.8.1",
"typedoc-default-themes": "^0.5.0",
"typescript": "2.7.2"
"typescript": "2.8.1"
},
"devDependencies": {
"@types/mocha": "2.2.48",
"@types/mocha": "5.0.0",
"grunt": "^1.0.2",
"grunt-cli": "^1.2.0",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-clean": "^1.1.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-mocha-istanbul": "^5.0.1",
"grunt-string-replace": "^1.2.0",
"grunt-mocha-istanbul": "^5.0.2",
"grunt-string-replace": "^1.3.1",
"grunt-ts": "^5.5.1",
"grunt-tslint": "^5.0.1",
"istanbul": "^0.4.1",
"mocha": "^5.0.4",
"istanbul": "^0.4.5",
"mocha": "^5.0.5",
"tslint": "^5.9.1"
},
"files": [
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { Application } from './lib/application';
export { CliApplication } from './lib/cli';

export { EventDispatcher, Event } from './lib/utils/events';
export { pathToMinimatch } from './lib/utils/paths';
export { resetReflectionID } from './lib/models/reflections/abstract';
export { normalizePath } from './lib/utils/fs';
export * from './lib/models/reflections';
Expand Down
8 changes: 6 additions & 2 deletions src/lib/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
import * as Path from 'path';
import * as FS from 'fs';
import * as typescript from 'typescript';
import { Minimatch, IMinimatch } from 'minimatch';
import { IMinimatch } from 'minimatch';

import { Converter } from './converter/index';
import { Renderer } from './output/renderer';
import { Serializer } from './serialization';
import { ProjectReflection } from './models/index';
import { Logger, ConsoleLogger, CallbackLogger, PluginHost, writeFile } from './utils/index';
import { pathToMinimatch } from './utils/paths';

import { AbstractComponent, ChildableComponent, Component, Option } from './utils/component';
import { Options, OptionsReadMode, OptionsReadResult } from './utils/options/index';
Expand Down Expand Up @@ -248,7 +249,10 @@ export class Application extends ChildableComponent<Application, AbstractCompone
*/
public expandInputFiles(inputFiles?: string[]): string[] {
let files: string[] = [];
const exclude: Array<IMinimatch> = this.exclude ? this.exclude.map(pattern => new Minimatch(pattern)) : [];

const exclude: IMinimatch[] = this.exclude
? <IMinimatch[]> pathToMinimatch(this.exclude)
: [];

function isExcluded(fileName: string): boolean {
return exclude.some(mm => mm.match(fileName));
Expand Down
13 changes: 7 additions & 6 deletions src/lib/converter/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as ts from 'typescript';
import { Minimatch, IMinimatch } from 'minimatch';
import { IMinimatch } from 'minimatch';

import { Logger } from '../utils/loggers';
import { pathToMinimatch } from '../utils/paths';
import { Reflection, ProjectReflection, ContainerReflection, Type } from '../models/index';

import { createTypeParameter } from './factories/type-parameter';
import { Converter } from './converter';

Expand Down Expand Up @@ -93,7 +95,7 @@ export class Context {
/**
* The pattern that should be used to flag external source files.
*/
private externalPattern: IMinimatch;
private externalPattern: Array<IMinimatch>;

/**
* Create a new Context instance.
Expand All @@ -114,7 +116,7 @@ export class Context {
this.scope = project;

if (converter.externalPattern) {
this.externalPattern = new Minimatch(converter.externalPattern);
this.externalPattern = <IMinimatch[]> pathToMinimatch(converter.externalPattern);
}
}

Expand Down Expand Up @@ -216,10 +218,9 @@ export class Context {
* @param callback The callback that should be executed.
*/
withSourceFile(node: ts.SourceFile, callback: Function) {
const externalPattern = this.externalPattern;
let isExternal = this.fileNames.indexOf(node.fileName) === -1;
if (externalPattern) {
isExternal = isExternal || externalPattern.match(node.fileName);
if (!isExternal && this.externalPattern) {
isExternal = this.externalPattern.some(mm => mm.match(node.fileName));
}

if (isExternal && this.converter.excludeExternals) {
Expand Down
5 changes: 3 additions & 2 deletions src/lib/converter/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ export class Converter extends ChildableComponent<Application, ConverterComponen

@Option({
name: 'externalPattern',
help: 'Define a pattern for files that should be considered being external.'
help: 'Define patterns for files that should be considered being external.',
type: ParameterType.Array
})
externalPattern: string;
externalPattern: Array<string>;

@Option({
name: 'includeDeclarations',
Expand Down
40 changes: 23 additions & 17 deletions src/lib/utils/options/readers/tsconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,32 @@ export class TSConfigReader extends OptionsComponent {
return;
}

let file: string;

if (TSConfigReader.OPTIONS_KEY in event.data) {
this.load(event, Path.resolve(event.data[TSConfigReader.OPTIONS_KEY]));
const tsconfig = event.data[TSConfigReader.OPTIONS_KEY];

if (/tsconfig\.json$/.test(tsconfig)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think that this line is responsible for making typedoc 0.14 a breaking change for my projects.

The path that I use for my config file is something like node_modules/my-config-project/config/typedoc.config.json

This worked fine in 0.13 but breaks in 0.14.

I now need to update the path on 60+ projects..

file = Path.resolve(tsconfig);
} else {
file = ts.findConfigFile(tsconfig, ts.sys.fileExists);
}

if (!file || !FS.existsSync(file)) {
event.addError('The tsconfig file %s does not exist.', file);
return;
}
} else if (TSConfigReader.PROJECT_KEY in event.data) {
// The `project` option may be a directory or file, so use TS to find it
let file: string = ts.findConfigFile(event.data[TSConfigReader.PROJECT_KEY], ts.sys.fileExists);
// If file is undefined, we found no file to load.
if (file) {
this.load(event, file);
}
file = ts.findConfigFile(event.data[TSConfigReader.PROJECT_KEY], ts.sys.fileExists);
} else if (this.application.isCLI) {
let file: string = ts.findConfigFile('.', ts.sys.fileExists);
// If file is undefined, we found no file to load.
if (file) {
this.load(event, file);
}
// No file or directory has been specified so find the file in the root of the project
file = ts.findConfigFile('.', ts.sys.fileExists);
}

// If file is undefined, we found no file to load.
if (file) {
this.load(event, file);
}
}

Expand All @@ -65,14 +76,9 @@ export class TSConfigReader extends OptionsComponent {
* @param fileName The absolute path and file name of the tsconfig file.
*/
load(event: DiscoverEvent, fileName: string) {
if (!FS.existsSync(fileName)) {
event.addError('The tsconfig file %s does not exist.', fileName);
return;
}

const { config } = ts.readConfigFile(fileName, ts.sys.readFile);
if (config === undefined) {
event.addError('The tsconfig file %s does not contain valid JSON.', fileName);
event.addError('No valid tsconfig file found.', fileName);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I changed the text since it now is used when there is no file as well as an invalid file

return;
}
if (!_.isPlainObject(config)) {
Expand Down
51 changes: 39 additions & 12 deletions src/lib/utils/options/readers/typedoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,57 @@ export class TypedocReader extends OptionsComponent {
return;
}

let file: string;

if (TypedocReader.OPTIONS_KEY in event.data) {
this.load(event, Path.resolve(event.data[TypedocReader.OPTIONS_KEY]));
} else if (this.application.isCLI) {
const file = Path.resolve('typedoc.js');
if (FS.existsSync(file)) {
this.load(event, file);
let opts = event.data[TypedocReader.OPTIONS_KEY];

if (opts && opts[0] === '.') {
opts = Path.resolve(opts);
}

file = this.findTypedocFile(opts);

if (!FS.existsSync(file)) {
event.addError('The options file could not be found with the given path %s.', opts);
return;
}
} else if (this.application.isCLI) {
file = this.findTypedocFile();
}

file && this.load(event, file);
}

/**
* Search for the typedoc.js or typedoc.json file from the given path
*
* @param path Path to the typedoc.(js|json) file. If path is a directory
* typedoc file will be attempted to be found at the root of this path
* @return the typedoc.(js|json) file path or undefined
*/
findTypedocFile(path: string = process.cwd()): string | undefined {
if (/typedoc\.js(on)?$/.test(path)) {
return path;
}

let file = Path.join(path, 'typedoc.js');
if (FS.existsSync(file)) {
return file;
}

file += 'on'; // look for JSON file
return FS.existsSync(file) ? file : undefined;
}

/**
* Load the specified option file.
*
* @param event The event object from the DISCOVER event.
* @param optionFile The absolute path and file name of the option file.
* @param ignoreUnknownArgs Should unknown arguments be ignored? If so the parser
* will simply skip all unknown arguments.
* @returns TRUE on success, otherwise FALSE.
*/
load(event: DiscoverEvent, optionFile: string) {
if (!FS.existsSync(optionFile)) {
event.addError('The option file %s does not exist.', optionFile);
return;
}

let data = require(optionFile);
if (typeof data === 'function') {
data = data(this.application);
Expand Down
17 changes: 17 additions & 0 deletions src/lib/utils/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as Path from 'path';
import { isArray } from 'util';
import { Minimatch, IMinimatch } from 'minimatch';

function createMinimatch(pattern: string): IMinimatch {
if (pattern[0] === '.' || pattern[0] === '/' || /^\w+(?!:)($|[/\\])/.test(pattern)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you explain this regex? I don't have the skills to understand it.

Is there any of this that Minimatch handles already?

Copy link
Copy Markdown
Contributor Author

@Tokimon Tokimon Apr 13, 2018

Choose a reason for hiding this comment

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

Ok so this if is to check if a path like these:

  • ./some/path
  • ../some/path
  • some/path
  • path

Which are all relative paths and should be resolved relative to process.cwd() (Path.resolve(path)).

The regex is to test that windows absolute paths like C:/some/path wont be confused for a relative path like c/some/path. So I use a negative look ahead to ensure there is no : after the letters in the first part of the path (path/ will be a relative path and path:/ won't)

I could have used one regex to test for all of these cases, but it is a lot faster to do the simple tests first and only do the regex if really needed.

The main issue is that generally in other libraries that uses GLOB expressions you can just type ./some/path and that would be treated as relative to the project root, but this have not been the case for this project where **/some/path was needed to ensure correct path matching, which has been counter-intuitive for many developers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

But I can see I made a mistake: pattern[0] === '/' would match /some/path as relative, which isn't the case. I will fix this.

pattern = Path.resolve(pattern);
}

return new Minimatch(pattern.replace(/[\\]/g, '/'), { dot: true });
}

export function pathToMinimatch(pattern: string | string[]): IMinimatch | IMinimatch[] {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this function really needed? From the usage I saw, it seems that createMinimatch would be sufficient. The overloading of a parameter that is sometimes an array means that you frequently need to cast the result.

I'd prefer to inline the arr.map(createMinimatch) in files.

Copy link
Copy Markdown
Contributor Author

@Tokimon Tokimon Apr 13, 2018

Choose a reason for hiding this comment

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

It is true that the two methods could be combined. I separated them in an attempt to make the code less bulky and easier to read. But if you prefer to combine them I can. It is also a bit slower to recreate a function inside a function, so there is also a minor performance gain of having them separate.

EDIT
So reading my code again I Remember why I made it as a separate function. It is to keep the given pattern argument as a string or Array which ever format it has. So I use the same method in two different scenarios.
But if you want I can do a method override to make it clearer.

Copy link
Copy Markdown
Contributor Author

@Tokimon Tokimon Apr 13, 2018

Choose a reason for hiding this comment

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

regarding the pattern: string | string[] is because the given path can be one or several paths (as parsed from the CLI arguments). When only one path is given it is just a string otherwise an array of strings is given, hence the double type definition.

return isArray(pattern)
? pattern.map(createMinimatch)
: createMinimatch(pattern);
}
2 changes: 2 additions & 0 deletions src/test/renderer/specs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ <h4 id="typescript-compiler">TypeScript compiler</h4>
Specify module code generation: &quot;commonjs&quot;, &quot;amd&quot;, &quot;system&quot; or &quot;umd&quot;.</li>
<li><code>--target &lt;ES3, ES5, or ES6&gt;</code><br>
Specify ECMAScript target version: &quot;ES3&quot; (default), &quot;ES5&quot; or &quot;ES6&quot;</li>
<li><code>--tsconfig &lt;path/to/tsconfig.json&gt;</code><br>
Specify a typescript config file that should be loaded. If not specified TypeDoc will look for &#39;tsconfig.json&#39; in the current directory.</li>
</ul>
<h4 id="theming">Theming</h4>
<ul>
Expand Down
Loading