Skip to content

Commit ab7eab6

Browse files
committed
Require input globs to have posix path sep
Resolves #2825 Hopefully this works on Windows without too many more changes...
1 parent 772133e commit ab7eab6

35 files changed

+607
-408
lines changed

.config/mocha.fast.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"spec": ["src/test/**/*.test.ts", "src/test/**/*.test.tsx"],
66
"timeout": 5000,
77
"watch-files": ["src/**/*.ts", "src/**/*.tsx"],
8-
"node-option": ["import=tsx"]
8+
"node-option": ["import=tsx", "conditions=typedoc-ts"]
99
}

.config/mocha.full.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"timeout": 0,
44
"spec": ["src/test/**/*.test.ts", "src/test/**/*.test.tsx"],
55
"exclude": ["src/test/packages/**"],
6-
"node-option": ["import=tsx"]
6+
"node-option": ["import=tsx", "conditions=typedoc-ts"]
77
}

.config/mocha.test-explorer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"extension": ["ts"],
44
"ignore": ["src/test/slow/**", "src/test/packages/**"],
55
"package": "./package.json",
6-
"node-option": ["import=tsx"],
6+
"node-option": ["import=tsx", "conditions=typedoc-ts"],
77
"slow": 500,
88
"spec": ["src/**/*.test.ts", "src/**/*.test.tsx"],
99
"timeout": 0,

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"editor.tabSize": 4
3434
},
3535

36-
"mochaExplorer.nodeArgv": ["--import=tsx"],
36+
"mochaExplorer.nodeArgv": ["--import=tsx", "--conditions=typedoc-ts"],
3737

3838
"eslint.workingDirectories": [".", "./example"],
3939
"mochaExplorer.configFile": ".config/mocha.test-explorer.json",

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ title: Changelog
44

55
## Beta
66

7+
- TypeDoc now expects all input globs paths to be specified with `/` path separators, #2825.
78
- Added a `--router` option which can be used to modify TypeDoc's output folder
89
structure. This can be extended with plugins, #2111.
910
- TypeDoc will now only create references for symbols re-exported from modules.
11+
- API: `Path` and `PathArray` parameter types now always contain normalized paths.
1012
- API: Introduced a `Router` which is used for URL creation. `Reflection.url`,
1113
`Reflection.anchor`, and `Reflection.hasOwnDocument` have been removed.
1214
- Removed `jp` translations from `lang`, to migrate switch to `ja`.

package.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@
105105
]
106106
},
107107
"imports": {
108-
"#utils": "./dist/lib/utils-common/index.js"
108+
"#utils": {
109+
"typedoc-ts": "./src/lib/utils-common/index.ts",
110+
"default": "./dist/lib/utils-common/index.js"
111+
},
112+
"#node-utils": {
113+
"typedoc-ts": "./src/lib/utils/index.ts",
114+
"default": "./dist/lib/utils/index.js"
115+
}
109116
}
110117
}

src/lib/application.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919

2020
import { Option, Options } from "./utils/index.js";
2121
import type { TypeDocOptions } from "./utils/options/declaration.js";
22-
import { unique } from "#utils";
22+
import { type GlobString, unique } from "#utils";
2323
import { ok } from "assert";
2424
import {
2525
type DocumentationEntryPoint,
@@ -35,8 +35,7 @@ import { validateExports } from "./validation/exports.js";
3535
import { validateDocumentation } from "./validation/documentation.js";
3636
import { validateLinks } from "./validation/links.js";
3737
import { ApplicationEvents } from "./application-events.js";
38-
import { findTsConfigFile } from "./utils/tsconfig.js";
39-
import { deriveRootDir, glob, readFile } from "./utils/fs.js";
38+
import { deriveRootDir, findTsConfigFile, glob, readFile } from "#node-utils";
4039
import { addInferredDeclarationMapPaths } from "./models/reflections/ReflectionSymbolId.js";
4140
import { Internationalization, type TranslatedString } from "./internationalization/internationalization.js";
4241
import { FileRegistry, ValidatingFileRegistry } from "./models/FileRegistry.js";
@@ -162,7 +161,7 @@ export class Application extends AbstractComponent<
162161

163162
/** @internal */
164163
@Option("entryPoints")
165-
accessor entryPoints!: string[];
164+
accessor entryPoints!: GlobString[];
166165

167166
/**
168167
* The version number of TypeDoc.

src/lib/converter/converter.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ import { getDocumentEntryPoints, MinimalSourceFile, Option, readFile } from "../
2222
import { convertType } from "./types.js";
2323
import { ConverterEvents } from "./converter-events.js";
2424
import { convertSymbol } from "./symbols.js";
25-
import { createMinimatch, matchesAny, nicePath } from "../utils/paths.js";
26-
import type { Minimatch } from "minimatch";
27-
import { hasAllFlags, hasAnyFlag, unique } from "#utils";
25+
import { MinimatchSet, nicePath } from "../utils/paths.js";
26+
import { type GlobString, hasAllFlags, hasAnyFlag, unique } from "#utils";
2827
import type { DocumentationEntryPoint } from "../utils/entry-point.js";
2928
import type { CommentParserConfig } from "./comments/index.js";
3029
import type { CommentStyle, ValidationOptions } from "../utils/options/declaration.js";
@@ -88,9 +87,9 @@ export interface ConverterEvents {
8887
export class Converter extends AbstractComponent<Application, ConverterEvents> {
8988
/** @internal */
9089
@Option("externalPattern")
91-
accessor externalPattern!: string[];
92-
private externalPatternCache?: Minimatch[];
93-
private excludeCache?: Minimatch[];
90+
accessor externalPattern!: GlobString[];
91+
private externalPatternCache?: MinimatchSet;
92+
private excludeCache?: MinimatchSet;
9493

9594
/** @internal */
9695
@Option("excludeExternals")
@@ -588,17 +587,17 @@ export class Converter extends AbstractComponent<Application, ConverterEvents> {
588587
}
589588

590589
private isExcluded(symbol: ts.Symbol) {
591-
this.excludeCache ??= createMinimatch(
590+
this.excludeCache ??= new MinimatchSet(
592591
this.application.options.getValue("exclude"),
593592
);
594593
const cache = this.excludeCache;
595594

596-
return (symbol.getDeclarations() ?? []).some((node) => matchesAny(cache, node.getSourceFile().fileName));
595+
return (symbol.getDeclarations() ?? []).some((node) => cache.matchesAny(node.getSourceFile().fileName));
597596
}
598597

599598
/** @internal */
600599
isExternal(symbol: ts.Symbol) {
601-
this.externalPatternCache ??= createMinimatch(this.externalPattern);
600+
this.externalPatternCache ??= new MinimatchSet(this.externalPattern);
602601
const cache = this.externalPatternCache;
603602

604603
const declarations = symbol.getDeclarations();
@@ -613,7 +612,7 @@ export class Converter extends AbstractComponent<Application, ConverterEvents> {
613612
// If there are any non-external declarations, treat it as non-external
614613
// This is possible with declaration merging against external namespaces
615614
// (e.g. merging with HTMLElementTagNameMap)
616-
return declarations.every((node) => matchesAny(cache, node.getSourceFile().fileName));
615+
return declarations.every((node) => cache.matchesAny(node.getSourceFile().fileName));
617616
}
618617

619618
processDocumentTags(reflection: Reflection, parent: ContainerReflection) {

src/lib/converter/plugins/PackagePlugin.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@ import * as Path from "path";
22

33
import { ConverterComponent } from "../components.js";
44
import type { Context } from "../context.js";
5-
import { EntryPointStrategy, Option, readFile } from "../../utils/index.js";
6-
import { deriveRootDir, discoverInParentDir, discoverPackageJson } from "../../utils/fs.js";
7-
import { nicePath } from "../../utils/paths.js";
8-
import { MinimalSourceFile } from "../../utils/minimalSourceFile.js";
95
import type { ProjectReflection } from "../../models/index.js";
106
import { ApplicationEvents } from "../../application-events.js";
11-
import { join } from "path";
127
import { ConverterEvents } from "../converter-events.js";
138
import type { Converter } from "../converter.js";
9+
import type { GlobString } from "#utils";
10+
import {
11+
discoverInParentDir,
12+
discoverPackageJson,
13+
type EntryPointStrategy,
14+
getCommonDirectory,
15+
MinimalSourceFile,
16+
nicePath,
17+
Option,
18+
readFile,
19+
} from "#node-utils";
1420

1521
/**
1622
* A handler that tries to find the package.json and readme.md files of the
@@ -24,7 +30,7 @@ export class PackagePlugin extends ConverterComponent {
2430
accessor entryPointStrategy!: EntryPointStrategy;
2531

2632
@Option("entryPoints")
27-
accessor entryPoints!: string[];
33+
accessor entryPoints!: GlobString[];
2834

2935
@Option("includeVersion")
3036
accessor includeVersion!: boolean;
@@ -72,12 +78,8 @@ export class PackagePlugin extends ConverterComponent {
7278
this.readmeContents = undefined;
7379
this.packageJson = undefined;
7480

75-
const entryFiles = this.entryPointStrategy === EntryPointStrategy.Packages
76-
? this.entryPoints.map((d) => join(d, "package.json"))
77-
: this.entryPoints;
78-
7981
const dirName = this.application.options.packageDir ??
80-
Path.resolve(deriveRootDir(entryFiles));
82+
Path.resolve(getCommonDirectory(this.entryPoints.map(g => `${g}/`)));
8183

8284
this.application.logger.verbose(
8385
`Begin readme.md/package.json search at ${nicePath(dirName)}`,

src/lib/converter/plugins/SourcePlugin.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { SourceReference } from "../../models/index.js";
1010
import { gitIsInstalled, RepositoryManager } from "../utils/repository.js";
1111
import { ConverterEvents } from "../converter-events.js";
1212
import type { Converter } from "../converter.js";
13+
import type { NormalizedPath } from "#utils";
1314

1415
/**
1516
* A handler that attaches source file information to reflections.
@@ -31,7 +32,7 @@ export class SourcePlugin extends ConverterComponent {
3132
accessor sourceLinkTemplate!: string;
3233

3334
@Option("basePath")
34-
accessor basePath!: string;
35+
accessor basePath!: NormalizedPath;
3536

3637
/**
3738
* All file names to find the base path from.

src/lib/internationalization/locales/en.cts

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export = {
196196
use_expand_or_glob_for_files_in_dir:
197197
`If you wanted to include files inside this directory, set --entryPointStrategy to expand or specify a glob`,
198198
glob_0_did_not_match_any_files: `The glob {0} did not match any files`,
199+
glob_should_use_posix_slash: `Try replacing Windows path separators (\\) with posix path separators (/)`,
199200
entry_point_0_did_not_match_any_files_after_exclude:
200201
`The glob {0} did not match any files after applying exclude patterns`,
201202
entry_point_0_did_not_exist: `Provided entry point {0} does not exist`,

src/lib/internationalization/locales/ja.cts

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export = localeUtils.buildIncompleteTranslation({
138138
use_expand_or_glob_for_files_in_dir:
139139
"このディレクトリ内のファイルを含める場合は、--entryPointStrategyを設定して展開するか、globを指定します。",
140140
glob_0_did_not_match_any_files: "グロブ {0} はどのファイルにも一致しませんでした",
141+
// glob_should_use_posix_slash
141142
entry_point_0_did_not_match_any_files_after_exclude:
142143
"除外パターンを適用した後、グロブ {0} はどのファイルにも一致しませんでした",
143144
entry_point_0_did_not_exist: "指定されたエントリ ポイント {0} は存在しません",

src/lib/internationalization/locales/zh.cts

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export = localeUtils.buildIncompleteTranslation({
140140
failed_to_resolve_0_to_ts_path: "无法将 package.json 中的入口点 {0} 解析至 TypeScript 源文件",
141141
use_expand_or_glob_for_files_in_dir: "如果要包含此目录中的文件,请设置 --entryPointStrategy 以展开或指定 glob",
142142
glob_0_did_not_match_any_files: "glob {0} 与任何文件均不匹配",
143+
// glob_should_use_posix_slash
143144
entry_point_0_did_not_match_any_files_after_exclude: "应用排除模式后,glob {0} 没有匹配任何文件",
144145
entry_point_0_did_not_exist: "提供的入口点 {0} 不存在",
145146
entry_point_0_did_not_match_any_packages: "入口点 glob {0} 与任何包含 package.json 的目录不匹配",

src/lib/models/reflections/ReflectionSymbolId.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { existsSync } from "fs";
22
import { isAbsolute, join, relative, resolve } from "path";
33
import ts from "typescript";
44
import type { JSONOutput, Serializer } from "../../serialization/index.js";
5-
import { findPackageForPath, getCommonDirectory, readFile } from "../../utils/fs.js";
6-
import { normalizePath } from "../../utils/paths.js";
7-
import { getQualifiedName } from "../../utils/tsutils.js";
5+
import { findPackageForPath, getCommonDirectory, getQualifiedName, normalizePath, readFile } from "#node-utils";
86
import { Validation } from "#utils";
97
import type { DeclarationReference } from "../../converter/index.js";
108
import { splitUnquotedString } from "./utils.js";

src/lib/models/types.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -963,9 +963,7 @@ export class ReferenceType extends Type {
963963
symbol.flags & ts.SymbolFlags.TypeParameter
964964
);
965965

966-
const symbolPath = symbol.declarations?.[0]
967-
?.getSourceFile()
968-
.fileName.replace(/\\/g, "/");
966+
const symbolPath = symbol.declarations?.[0]?.getSourceFile().fileName;
969967
if (!symbolPath) return ref;
970968

971969
ref.package = findPackageForPath(symbolPath);

src/lib/output/plugins/AssetsPlugin.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { RendererEvent } from "../events.js";
33
import { copySync, readFile, writeFileSync } from "../../utils/fs.js";
44
import { DefaultTheme } from "../themes/default/DefaultTheme.js";
55
import { getStyles } from "../../utils/highlighter.js";
6-
import { type EnumKeys, getEnumKeys } from "#utils";
6+
import { type EnumKeys, getEnumKeys, type NormalizedPath } from "#utils";
77
import { existsSync } from "fs";
88
import { extname, join } from "path";
99
import { fileURLToPath } from "url";
@@ -17,13 +17,13 @@ import { Option } from "../../utils/index.js";
1717
*/
1818
export class AssetsPlugin extends RendererComponent {
1919
@Option("favicon")
20-
private accessor favicon!: string;
20+
private accessor favicon!: NormalizedPath;
2121

2222
@Option("customCss")
23-
private accessor customCss!: string;
23+
private accessor customCss!: NormalizedPath;
2424

2525
@Option("customJs")
26-
private accessor customJs!: string;
26+
private accessor customJs!: NormalizedPath;
2727

2828
constructor(owner: Renderer) {
2929
super(owner);

src/lib/utils-common/general.ts

-78
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { DefaultMap } from "./map.js";
2-
31
/**
42
* This type provides a flag that can be used to turn off more lax overloads intended for
53
* plugin use only to catch type errors in the TypeDoc codebase. The prepublishOnly npm
@@ -36,12 +34,6 @@ export type IfInternal<T, F> = InternalOnly extends true ? T : F;
3634
*/
3735
export type NeverIfInternal<T> = IfInternal<never, T>;
3836

39-
/**
40-
* Resolves a string type into a union of characters, `"ab"` turns into `"a" | "b"`.
41-
*/
42-
export type Chars<T extends string> = T extends `${infer C}${infer R}` ? C | Chars<R> :
43-
never;
44-
4537
/**
4638
* Utility to help type checking ensure that there is no uncovered case.
4739
*/
@@ -51,76 +43,6 @@ export function assertNever(x: never): never {
5143
);
5244
}
5345

54-
// From MDN
55-
export function escapeRegExp(s: string) {
56-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
57-
}
58-
59-
export function dedent(text: string) {
60-
const lines = text.split(/\r?\n/);
61-
while (lines.length && lines[0].search(/\S/) === -1) {
62-
lines.shift();
63-
}
64-
while (lines.length && lines[lines.length - 1].search(/\S/) === -1) {
65-
lines.pop();
66-
}
67-
68-
const minIndent = lines.reduce(
69-
(indent, line) => line.length ? Math.min(indent, line.search(/\S/)) : indent,
70-
Infinity,
71-
);
72-
73-
return lines.map((line) => line.substring(minIndent)).join("\n");
74-
}
75-
76-
// Based on https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows
77-
// Slightly modified for improved match results for options
78-
export function editDistance(s: string, t: string): number {
79-
if (s.length < t.length) return editDistance(t, s);
80-
81-
let v0 = Array.from({ length: t.length + 1 }, (_, i) => i);
82-
let v1 = Array.from({ length: t.length + 1 }, () => 0);
83-
84-
for (let i = 0; i < s.length; i++) {
85-
v1[0] = i + 1;
86-
87-
for (let j = 0; j < s.length; j++) {
88-
const deletionCost = v0[j + 1] + 1;
89-
const insertionCost = v1[j] + 1;
90-
let substitutionCost: number;
91-
if (s[i] === t[j]) {
92-
substitutionCost = v0[j];
93-
} else if (s[i]?.toUpperCase() === t[j]?.toUpperCase()) {
94-
substitutionCost = v0[j] + 1;
95-
} else {
96-
substitutionCost = v0[j] + 3;
97-
}
98-
99-
v1[j + 1] = Math.min(deletionCost, insertionCost, substitutionCost);
100-
}
101-
102-
[v0, v1] = [v1, v0];
103-
}
104-
105-
return v0[t.length];
106-
}
107-
108-
export function getSimilarValues(values: Iterable<string>, compareTo: string) {
109-
const results = new DefaultMap<number, string[]>(() => []);
110-
let lowest = Infinity;
111-
for (const name of values) {
112-
const distance = editDistance(compareTo, name);
113-
lowest = Math.min(lowest, distance);
114-
results.get(distance).push(name);
115-
}
116-
117-
// Experimenting a bit, it seems an edit distance of 3 is roughly the
118-
// right metric for relevant "similar" results without showing obviously wrong suggestions
119-
return results
120-
.get(lowest)
121-
.concat(results.get(lowest + 1), results.get(lowest + 2));
122-
}
123-
12446
export function NonEnumerable(
12547
_cls: unknown,
12648
context: ClassFieldDecoratorContext,

src/lib/utils-common/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ export * from "./html.js";
1010
export * from "./index.js";
1111
export * as JSX from "./jsx.js";
1212
export * from "./map.js";
13+
export * from "./path.js";
1314
export * from "./set.js";
15+
export * from "./string.js";
1416
export * as Validation from "./validation.js";

0 commit comments

Comments
 (0)