Skip to content

Commit

Permalink
Use additional return instead of option
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-hemphill committed Oct 29, 2023
1 parent 2676cbd commit 9451383
Show file tree
Hide file tree
Showing 26 changed files with 5,294 additions and 89 deletions.
68 changes: 19 additions & 49 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ export const config = {
defaults: defaultOptions,
};

export type FaviconHtmlElement = {
readonly tag: string;
readonly attrs: Record<string, string | boolean>;
};
export class FaviconElement implements FaviconHtmlElement {
export type FaviconHtmlElement = string;
export class FaviconHtmlTag {
readonly tag: string;
readonly attrs: Record<string, string | boolean>;

Expand All @@ -46,25 +43,18 @@ export class FaviconElement implements FaviconHtmlElement {
}
}

export interface FaviconResponse<T> {
export interface FaviconResponse {
readonly images: FaviconImage[];
readonly files: FaviconFile[];
readonly html: T[];
readonly html: FaviconHtmlElement[];
readonly htmlTags: FaviconHtmlTag[];
}

export type FaviconsSource = string | Buffer | (string | Buffer)[];
export async function favicons(
source: FaviconsSource,
options: FaviconOptions & { readonly htmlUnStringified: true },
): Promise<FaviconResponse<FaviconElement>>;
export async function favicons(
source: FaviconsSource,
options: FaviconOptions & { readonly htmlUnStringified: false },
): Promise<FaviconResponse<string>>;
export async function favicons(
source: FaviconsSource,
options: FaviconOptions & { readonly htmlUnStringified?: boolean } = {},
): Promise<FaviconResponse<FaviconElement | string>> {
): Promise<FaviconResponse> {
options = {
...defaultOptions,
...options,
Expand All @@ -82,7 +72,7 @@ export async function favicons(
return a.localeCompare(b);
});

const responses: FaviconResponse<FaviconElement | string>[] = [];
const responses: FaviconResponse[] = [];

for (const platformName of platforms) {
const platform = getPlatform(platformName, options);
Expand All @@ -94,6 +84,7 @@ export async function favicons(
images: responses.flatMap((r) => r.images),
files: responses.flatMap((r) => r.files),
html: responses.flatMap((r) => r.html),
htmlTags: responses.flatMap((r) => r.htmlTags),
};
}

Expand All @@ -105,23 +96,18 @@ export interface FaviconStreamOptions extends FaviconOptions {
readonly emitBuffers?: boolean;
}

export type HandleHTML<K> = (html: K[]) => void;
export type HandleHTML = (
html: FaviconHtmlElement[],
htmlTags: FaviconHtmlTag[],
) => void;

class FaviconStream<T> extends Transform {
class FaviconStream extends Transform {
#options: FaviconStreamOptions & { readonly htmlUnStringified?: boolean };
#handleHTML: HandleHTML<T extends true ? FaviconElement : string>;
#handleHTML: HandleHTML;

constructor(
options: FaviconStreamOptions & { readonly htmlUnStringified: T & false },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
);
constructor(
options: FaviconStreamOptions & { readonly htmlUnStringified: T & true },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
);
constructor(
options: FaviconStreamOptions & { readonly htmlUnStringified?: boolean },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
handleHTML: HandleHTML,
) {
super({ objectMode: true });
this.#options = options;
Expand All @@ -136,7 +122,7 @@ class FaviconStream<T> extends Transform {
const { html: htmlPath, pipeHTML, ...options } = this.#options;

favicons(file, { ...options, htmlUnStringified: true })
.then(({ images, files, html }) => {
.then(({ images, files, html, htmlTags }) => {
for (const { name, contents } of [...images, ...files]) {
this.push({
name,
Expand All @@ -145,9 +131,7 @@ class FaviconStream<T> extends Transform {
}

if (this.#handleHTML) {
this.#handleHTML(
<(T extends true ? FaviconElement : string)[]>(<unknown>html),
);
this.#handleHTML(html, htmlTags);
}

if (pipeHTML) {
Expand All @@ -169,20 +153,6 @@ class FaviconStream<T> extends Transform {
}
}

export function stream<T>(
options: FaviconStreamOptions & { readonly htmlUnStringified: T & false },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
): FaviconStream<false>;
export function stream<T>(
options: FaviconStreamOptions & { readonly htmlUnStringified: T & true },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
): FaviconStream<true>;
export function stream<T>(
options: FaviconStreamOptions & { readonly htmlUnStringified: T },
handleHTML: HandleHTML<T extends true ? FaviconElement : string>,
) {
return new FaviconStream(
options as typeof options & { readonly htmlUnStringified: T & true },
handleHTML,
) as T extends true ? FaviconStream<true> : FaviconStream<false>;
export function stream(options: FaviconStreamOptions, handleHTML: HandleHTML) {
return new FaviconStream(options, handleHTML);
}
16 changes: 8 additions & 8 deletions src/platforms/android.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import escapeHtml from "escape-html";
import { FaviconElement, FaviconFile, FaviconImage } from "../index";
import { FaviconHtmlTag, FaviconFile, FaviconImage } from "../index";
import {
FaviconOptions,
IconOptions,
Expand Down Expand Up @@ -136,32 +136,32 @@ export class AndroidPlatform extends Platform {
return [this.manifest()];
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
return [
this.options.loadManifestWithCredentials
? new FaviconElement("link", {
? new FaviconHtmlTag("link", {
rel: "manifest",
href: this.cacheBusting(this.relative(this.manifestFileName())),
crossOrigin: "use-credentials",
})
: new FaviconElement("link", {
: new FaviconHtmlTag("link", {
rel: "manifest",
href: this.cacheBusting(this.relative(this.manifestFileName())),
}),
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "mobile-web-app-capable",
content: "yes",
}),
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "theme-color",
content: this.options.theme_color || this.options.background,
}),
this.options.appName
? new FaviconElement("meta", {
? new FaviconHtmlTag("meta", {
name: "application-name",
content: escapeHtml(this.options.appName),
})
: new FaviconElement("meta", {
: new FaviconHtmlTag("meta", {
name: "application-name",
}),
];
Expand Down
14 changes: 7 additions & 7 deletions src/platforms/appleIcon.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import escapeHtml from "escape-html";
import { FaviconElement } from "../index";
import { FaviconHtmlTag } from "../index";
import { FaviconOptions, NamedIconOptions } from "../config/defaults";
import { opaqueIcon } from "../config/icons";
import { Platform, uniformIconOptions } from "./base";
Expand Down Expand Up @@ -28,12 +28,12 @@ export class AppleIconPlatform extends Platform {
);
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
const icons = this.iconOptions
.filter(({ name }) => /\d/.test(name)) // with a size in a name
.map((options) => {
const { width, height } = options.sizes[0];
return new FaviconElement("link", {
return new FaviconHtmlTag("link", {
rel: "apple-touch-icon",
sizes: `${width}x${height}`,
href: this.cacheBusting(this.relative(options.name)),
Expand All @@ -44,20 +44,20 @@ export class AppleIconPlatform extends Platform {

return [
...icons,
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "apple-mobile-web-app-capable",
content: "yes",
}),
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "apple-mobile-web-app-status-bar-style",
content: this.options.appleStatusBarStyle,
}),
name
? new FaviconElement("meta", {
? new FaviconHtmlTag("meta", {
name: "apple-mobile-web-app-title",
content: escapeHtml(name),
})
: new FaviconElement("meta", {
: new FaviconHtmlTag("meta", {
name: "apple-mobile-web-app-title",
}),
];
Expand Down
6 changes: 3 additions & 3 deletions src/platforms/appleStartup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FaviconElement } from "../index";
import { FaviconHtmlTag } from "../index";
import { FaviconOptions, NamedIconOptions } from "../config/defaults";
import { opaqueIcon } from "../config/icons";
import { Platform, uniformIconOptions } from "./base";
Expand Down Expand Up @@ -66,10 +66,10 @@ export class AppleStartupPlatform extends Platform<AppleStartupImage> {
);
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
return this.iconOptions.map(
(item) =>
new FaviconElement("link", {
new FaviconHtmlTag("link", {
rel: "apple-touch-startup-image",
media: `(device-width: ${item.deviceWidth}px) and (device-height: ${item.deviceHeight}px) and (-webkit-device-pixel-ratio: ${item.pixelRatio}) and (orientation: ${item.orientation})`,
href: this.cacheBusting(this.relative(item.name)),
Expand Down
18 changes: 7 additions & 11 deletions src/platforms/base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
FaviconFile,
FaviconElement,
FaviconHtmlTag,
FaviconImage,
FaviconResponse,
} from "../index";
Expand Down Expand Up @@ -72,23 +72,19 @@ export class Platform<IO extends NamedIconOptions = NamedIconOptions> {
this.iconOptions = iconOptions;
}

async create(
sourceset: SourceImage[],
): Promise<FaviconResponse<FaviconElement | string>> {
async create(sourceset: SourceImage[]): Promise<FaviconResponse> {
const { output } = this.options;
const images = output.images ? await this.createImages(sourceset) : [];
const files = output.files ? await this.createFiles() : [];
let html = [];
let htmlTags = [];
if (output.html) {
const htmlElements = await this.createHtml();
html = this.options.htmlUnStringified
? htmlElements
: htmlElements.map((element) => element.stringify());
htmlTags = await this.createHtml();
}
return {
images,
files,
html,
html: htmlTags.map((element) => element.stringify()),
htmlTags,
};
}

Expand All @@ -104,7 +100,7 @@ export class Platform<IO extends NamedIconOptions = NamedIconOptions> {
return [];
}

async createHtml(): Promise<FaviconElement[]> {
async createHtml(): Promise<FaviconHtmlTag[]> {
return [];
}

Expand Down
6 changes: 3 additions & 3 deletions src/platforms/favicons.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FaviconElement } from "../index";
import { FaviconHtmlTag } from "../index";
import { FaviconOptions, NamedIconOptions } from "../config/defaults";
import { transparentIcon, transparentIcons } from "../config/icons";
import { OptionalMixin, Platform, uniformIconOptions } from "./base";
Expand All @@ -19,7 +19,7 @@ export class FaviconsPlatform extends Platform {
);
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
return this.iconOptions.map(({ name, ...options }) => {
const baseAttrs: Record<string, string> = {
rel: "icon",
Expand All @@ -33,7 +33,7 @@ export class FaviconsPlatform extends Platform {
const { width, height } = options.sizes[0];
baseAttrs.sizes = `${width}x${height}`;
}
return new FaviconElement("link", {
return new FaviconHtmlTag("link", {
...baseAttrs,
href: this.cacheBusting(this.relative(name)),
});
Expand Down
10 changes: 5 additions & 5 deletions src/platforms/windows.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import xml2js from "xml2js";
import { FaviconElement, FaviconFile } from "../index";
import { FaviconHtmlTag, FaviconFile } from "../index";
import { FaviconOptions, IconSize, NamedIconOptions } from "../config/defaults";
import { transparentIcon } from "../config/icons";
import { relativeTo } from "../helpers";
Expand Down Expand Up @@ -43,21 +43,21 @@ export class WindowsPlatform extends Platform {
return [this.browserConfig()];
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
const tile = "mstile-144x144.png";

return [
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "msapplication-TileColor",
content: this.options.background,
}),
this.iconOptions.find((iconOption) => iconOption.name === tile)
? new FaviconElement("meta", {
? new FaviconHtmlTag("meta", {
name: "msapplication-TileImage",
content: this.cacheBusting(this.relative(tile)),
})
: undefined,
new FaviconElement("meta", {
new FaviconHtmlTag("meta", {
name: "msapplication-config",
content: this.cacheBusting(this.relative(this.manifestFileName())),
}),
Expand Down
6 changes: 3 additions & 3 deletions src/platforms/yandex.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FaviconFile, FaviconElement } from "../index";
import { FaviconFile, FaviconHtmlTag } from "../index";
import { FaviconOptions, NamedIconOptions } from "../config/defaults";
import { transparentIcon } from "../config/icons";
import { relativeTo } from "../helpers";
Expand All @@ -20,9 +20,9 @@ export class YandexPlatform extends Platform {
return [this.manifest()];
}

override async createHtml(): Promise<FaviconElement[]> {
override async createHtml(): Promise<FaviconHtmlTag[]> {
return [
new FaviconElement("link", {
new FaviconHtmlTag("link", {
rel: "yandex-tableau-widget",
href: this.cacheBusting(this.relative(this.manifestFileName())),
}),
Expand Down
Loading

0 comments on commit 9451383

Please sign in to comment.