Skip to content

Commit

Permalink
Support URLs in favicons
Browse files Browse the repository at this point in the history
Resolves #2851
  • Loading branch information
Gerrit0 committed Feb 14, 2025
1 parent 13f6ae3 commit da50ac0
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 8 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ title: Changelog

## Unreleased

### Features

- The `--favicon` option may now be given a link starting with `https?://` instead of a path, #2851.

### Bug Fixes

- Fixed an issue where unrecognized languages would incorrectly be listed in the list of languages with translations, #2852.

## v0.27.7 (2025-02-09)

### Features
Expand Down
2 changes: 1 addition & 1 deletion src/lib/internationalization/locales/en.cts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ export = {
useHostedBaseUrlForAbsoluteLinks_requires_hostedBaseUrl:
"The useHostedBaseUrlForAbsoluteLinks option requires that hostedBaseUrl be set",
favicon_must_have_one_of_the_following_extensions_0:
"Favicon must have on of the following extensions: {0}",
"Favicon must have one of the following extensions: {0}",
option_0_must_be_an_object: "The '{0}' option must be a non-array object",
option_0_must_be_a_function: "The '{0}' option must be a function",
option_0_must_be_object_with_urls: `{0} must be an object with string labels as keys and URL values`,
Expand Down
5 changes: 4 additions & 1 deletion src/lib/output/plugins/AssetsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ export class AssetsPlugin extends RendererComponent {
private onRenderBegin(event: RendererEvent) {
const dest = join(event.outputDirectory, "assets");

if ([".ico", ".png", ".svg"].includes(extname(this.favicon))) {
if (
!/^https?:\/\//i.test(this.favicon) &&
[".ico", ".png", ".svg"].includes(extname(this.favicon))
) {
copySync(
this.favicon,
join(dest, "favicon" + extname(this.favicon)),
Expand Down
2 changes: 1 addition & 1 deletion src/lib/output/themes/MarkedPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export class MarkedPlugin extends ContextAwareRendererComponent {
// that becomes a real thing.
if (
this.markdownLinkExternal &&
/https?:\/\//i.test(href) &&
/^https?:\/\//i.test(href) &&
!(href + "/").startsWith(this.hostedBaseUrl)
) {
token.attrSet("target", "_blank");
Expand Down
4 changes: 4 additions & 0 deletions src/lib/output/themes/default/layouts/default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ function favicon(context: DefaultThemeRenderContext) {
const fav = context.options.getValue("favicon");
if (!fav) return null;

if (/^https?:\/\//i.test(fav)) {
return <link rel="icon" href={fav} />;
}

switch (extname(fav)) {
case ".ico":
return <link rel="icon" href={context.relativeURL("assets/favicon.ico", true)} />;
Expand Down
34 changes: 32 additions & 2 deletions src/lib/utils/options/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ export enum ParameterType {
* Resolved according to the config directory.
*/
Path,
/**
* Resolved according to the config directory unless it starts with https?://
*/
UrlOrPath,
Number,
Boolean,
Map,
Expand Down Expand Up @@ -418,10 +422,10 @@ export interface StringDeclarationOption extends DeclarationOptionBase {
* Specifies the resolution strategy. If `Path` is provided, values will be resolved according to their
* location in a file. If `String` or no value is provided, values will not be resolved.
*/
type?: ParameterType.String | ParameterType.Path;
type?: ParameterType.String | ParameterType.Path | ParameterType.UrlOrPath;

/**
* If not specified defaults to the empty string for both `String` and `Path`.
* If not specified defaults to the empty string for all types.
*/
defaultValue?: string;

Expand Down Expand Up @@ -569,6 +573,7 @@ export type DeclarationOption =
export interface ParameterTypeToOptionTypeMap {
[ParameterType.String]: string;
[ParameterType.Path]: string;
[ParameterType.UrlOrPath]: string;
[ParameterType.Number]: number;
[ParameterType.Boolean]: boolean;
[ParameterType.Mixed]: unknown;
Expand Down Expand Up @@ -612,6 +617,19 @@ const converters: {
option.validate?.(stringValue, i18n);
return stringValue;
},
[ParameterType.UrlOrPath](value, option, i18n, configPath) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
const stringValue = value == null ? "" : String(value);

if (/^https?:\/\//i.test(stringValue)) {
option.validate?.(stringValue, i18n);
return stringValue;
}

const resolved = resolve(configPath, stringValue);
option.validate?.(resolved, i18n);
return resolved;
},
[ParameterType.Number](value, option, i18n) {
const numValue = parseInt(String(value), 10) || 0;
if (!valueIsWithinBounds(numValue, option.minValue, option.maxValue)) {
Expand Down Expand Up @@ -792,6 +810,18 @@ const defaultGetters: {
? defaultStr
: join(process.cwd(), defaultStr);
},
[ParameterType.UrlOrPath](option) {
const defaultStr = option.defaultValue ?? "";
if (defaultStr == "") {
return "";
}
if (/^https?:\/\//i.test(defaultStr)) {
return defaultStr;
}
return isAbsolute(defaultStr)
? defaultStr
: join(process.cwd(), defaultStr);
},
[ParameterType.Number](option) {
return option.defaultValue ?? 0;
},
Expand Down
9 changes: 6 additions & 3 deletions src/lib/utils/options/sources/typedoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,15 +477,18 @@ export function addTypeDocOptions(options: Pick<Options, "addDeclaration">) {
help: (i18n) => i18n.help_favicon(),
validate(value, i18n) {
const allowedExtension = [".ico", ".png", ".svg"];
if (!allowedExtension.includes(extname(value))) {
if (
!/^https?:\/\//i.test(value) &&
!allowedExtension.includes(extname(value))
) {
throw new Error(
i18n.favicon_must_have_one_of_the_following_extensions_0(
allowedExtension.join(", "),
),
);
}
},
type: ParameterType.Path,
type: ParameterType.UrlOrPath,
});
options.addDeclaration({
name: "sourceLinkExternal",
Expand All @@ -508,7 +511,7 @@ export function addTypeDocOptions(options: Pick<Options, "addDeclaration">) {
name: "hostedBaseUrl",
help: (i18n) => i18n.help_hostedBaseUrl(),
validate(value, i18n) {
if (!/https?:\/\//i.test(value)) {
if (!/^https?:\/\//i.test(value)) {
throw new Error(i18n.hostedBaseUrl_must_start_with_http());
}
},
Expand Down

0 comments on commit da50ac0

Please sign in to comment.