Skip to content

Commit

Permalink
fix(feed2): fix output count might be less
Browse files Browse the repository at this point in the history
  • Loading branch information
Mister-Hope committed Jan 26, 2024
1 parent 11a4570 commit 4da42b1
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 163 deletions.
2 changes: 0 additions & 2 deletions packages/feed2/src/node/extractor/index.ts

This file was deleted.

Expand Up @@ -14,9 +14,7 @@ import {
isUrl,
} from "vuepress-shared/node";

import { getPageRenderContent } from "./content.js";
import type { Feed } from "../generator/feed.js";
import type { ResolvedFeedOptions } from "../options.js";
import type { ResolvedFeedOptions } from "./options.js";
import type {
FeedAuthor,
FeedCategory,
Expand All @@ -26,8 +24,12 @@ import type {
FeedGetter,
FeedItemInformation,
FeedPluginFrontmatter,
} from "../typings/index.js";
import { getImageMineType, resolveUrl } from "../utils/index.js";
} from "./typings/index.js";
import {
getImageMineType,
getPageRenderContent,
getUrl,
} from "./utils/index.js";

export class FeedItem {
private pageOptions: FeedFrontmatterOption;
Expand All @@ -43,7 +45,6 @@ export class FeedItem {
{ excerpt?: string; git?: GitData },
FeedPluginFrontmatter
>,
private feed: Feed,
) {
this.hostname = this.options.hostname;
this.base = this.app.options.base;
Expand All @@ -62,7 +63,7 @@ export class FeedItem {
private get link(): string {
if (isFunction(this.getter.link)) return this.getter.link(this.page);

return resolveUrl(this.hostname, this.base, this.page.path);
return getUrl(this.hostname, this.base, this.page.path);
}

private get description(): string | null {
Expand Down Expand Up @@ -179,22 +180,21 @@ export class FeedItem {
const { banner, cover } = this.frontmatter;

if (banner) {
if (isAbsoluteUrl(banner)) return resolveUrl(hostname, base, banner);
if (isAbsoluteUrl(banner)) return getUrl(hostname, base, banner);

if (isUrl(banner)) return banner;
}

if (cover) {
if (isAbsoluteUrl(cover)) return resolveUrl(hostname, base, cover);
if (isAbsoluteUrl(cover)) return getUrl(hostname, base, cover);

if (isUrl(cover)) return cover;
}

const result = /!\[.*?\]\((.*?)\)/iu.exec(this.page.content);

if (result) {
if (isAbsoluteUrl(result[1]))
return resolveUrl(hostname, base, result[1]);
if (isAbsoluteUrl(result[1])) return getUrl(hostname, base, result[1]);

if (isUrl(result[1])) return result[1];
}
Expand Down Expand Up @@ -248,13 +248,6 @@ export class FeedItem {
// we need at least title or description
if (!title && !description) return null;

// add category to feed
if (category) category.forEach((item) => this.feed.addCategory(item.name));

// add contributor to feed
if (contributor)
contributor.forEach((item) => this.feed.addContributor(item));

return {
title,
link,
Expand Down
12 changes: 6 additions & 6 deletions packages/feed2/src/node/generator/atom/index.ts
Expand Up @@ -9,7 +9,7 @@ import type {
} from "./typings.js";
import type { FeedAuthor, FeedCategory } from "../../typings/index.js";
import { FEED_GENERATOR, encodeXML } from "../../utils/index.js";
import type { Feed } from "../feed.js";
import type { FeedStore } from "../feedStore.js";

const getAuthor = (author: FeedAuthor): AtomAuthor => {
const { name = "Unknown", email, url } = author;
Expand Down Expand Up @@ -37,8 +37,8 @@ const genCategory = (category: FeedCategory): AtomCategory => {
*
* @see http://www.atomenabled.org/developers/syndication/
*/
export const renderAtom = (feed: Feed): string => {
const { channel, links } = feed.options;
export const generateAtomFeed = (feedStore: FeedStore): string => {
const { channel, links } = feedStore.options;

const content: AtomContent = {
_declaration: {
Expand Down Expand Up @@ -95,18 +95,18 @@ export const renderAtom = (feed: Feed): string => {

if (channel.copyright) content.feed.rights = channel.copyright;

content.feed.category = Array.from(feed.categories).map((category) => ({
content.feed.category = Array.from(feedStore.categories).map((category) => ({
_attributes: { term: category },
}));

content.feed.contributor = Array.from(feed.contributors)
content.feed.contributor = Array.from(feedStore.contributors)
.filter((contributor) => contributor.name)
.map((contributor) => getAuthor(contributor));

/**
* "entry" nodes
*/
content.feed.entry = feed.items.map((item) => {
content.feed.entry = feedStore.items.map((item) => {
// entry: required elements
const entry: AtomEntry = {
title: { _attributes: { type: "text" }, _text: item.title },
Expand Down
62 changes: 0 additions & 62 deletions packages/feed2/src/node/generator/feed.ts

This file was deleted.

70 changes: 70 additions & 0 deletions packages/feed2/src/node/generator/feedStore.ts
@@ -0,0 +1,70 @@
import { generateAtomFeed } from "./atom/index.js";
import { generateJSONFeed } from "./json/index.js";
import { generateRssFeed } from "./rss/index.js";
import type { FeedItem } from "../feedItem.js";
import type {
FeedCategory,
FeedContributor,
FeedInitOptions,
FeedItemInformation,
} from "../typings/index.js";

export class FeedStore {
public categories = new Set<string>();
public contributors: FeedContributor[] = [];
public items: FeedItemInformation[] = [];

private _contributorKeys = new Set<string>();

constructor(public options: FeedInitOptions) {}

/**
* Add category to store
*/
private addCategory = (category: FeedCategory): void => {
this.categories.add(category.name);
};

/**
* Add contributor to store
*/
private addContributor = (contributor: FeedContributor): void => {
// use keys to avoid adding same contributor
const key = contributor.email || contributor.name;

if (key && !this._contributorKeys.has(key)) {
this._contributorKeys.add(key);
this.contributors.push(contributor);
}
};

/**
* Add a feed item
*/
public add = (item: FeedItem): void => {
const info = item.getInfo();

if (info) {
const { category, contributor } = info;

this.items.push(info);
category?.forEach(this.addCategory);
contributor?.forEach(this.addContributor);
}
};

/**
* Returns a Atom 1.0 feed
*/
public atom = (): string => generateAtomFeed(this);

/**
* Returns a RSS 2.0 feed
*/
public rss = (): string => generateRssFeed(this);

/**
* Returns a JSON 1.1 feed
*/
public json = (): string => generateJSONFeed(this);
}
32 changes: 14 additions & 18 deletions packages/feed2/src/node/generator/generator.ts
Expand Up @@ -3,25 +3,25 @@ import type { App, Page } from "vuepress/core";
import { colors, fs, path } from "vuepress/utils";
import { entries, fromEntries } from "vuepress-shared/node";

import { Feed } from "./feed.js";
import { FeedItem } from "../extractor/index.js";
import { FeedStore } from "./feedStore.js";
import { FeedItem } from "../feedItem.js";
import type { ResolvedFeedOptionsMap } from "../options.js";
import { getFeedChannelOption, getFeedLinks, getFilename } from "../options.js";
import type { FeedPluginFrontmatter } from "../typings/index.js";
import { logger } from "../utils/index.js";

export class FeedGenerator {
/** feed 生成器 */
feedMap: Record<string, Feed>;
private map: Record<string, FeedStore>;

constructor(
private app: App,
private options: ResolvedFeedOptionsMap,
) {
this.feedMap = fromEntries(
this.map = fromEntries(
entries(options).map(([localePath, localeOptions]) => [
localePath,
new Feed({
new FeedStore({
channel: getFeedChannelOption(app, localeOptions, localePath),
links: getFeedLinks(app, localeOptions, localePath),
}),
Expand All @@ -30,31 +30,27 @@ export class FeedGenerator {
}

addPages(localePath: string): void {
const feed = this.feedMap[localePath];
const feedStore = this.map[localePath];
const localeOption = this.options[localePath];
const { count: feedCount = 100, filter, sorter } = localeOption;
const pages = this.app.pages
.filter((page) => page.pathLocale === localePath)
.filter(filter)
.sort(sorter)
.slice(0, feedCount);

let count = 0;
.sort(sorter);

for (const page of pages) {
const item = new FeedItem(
const feedItem = new FeedItem(
this.app,
localeOption,
<Page<{ git?: GitData }, FeedPluginFrontmatter>>page,
feed,
).getInfo();
);

if (item) {
feed.addItem(item);
count += 1;
}
feedStore.add(feedItem);
if (feedStore.items.length === feedCount) break;
}

const count = feedStore.items.length;

logger.succeed(
`added ${colors.cyan(
`${count} page${count > 1 ? "s" : ""}`,
Expand All @@ -71,7 +67,7 @@ export class FeedGenerator {
...entries(this.options).map(async ([localePath, localeOptions]) => {
// current locale has valid output
if (localeOptions.atom || localeOptions.json || localeOptions.rss) {
const feed = this.feedMap[localePath];
const feed = this.map[localePath];
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(localeOptions, localePath);

Expand Down
2 changes: 1 addition & 1 deletion packages/feed2/src/node/generator/index.ts
@@ -1,2 +1,2 @@
export * from "./feed.js";
export * from "./feedStore.js";
export * from "./generator.js";
8 changes: 4 additions & 4 deletions packages/feed2/src/node/generator/json/index.ts
Expand Up @@ -3,7 +3,7 @@ import { isArray } from "vuepress-shared/node";

import type { JSONAuthor, JSONContent, JSONItem } from "./typings.js";
import type { FeedAuthor } from "../../typings/index.js";
import type { Feed } from "../feed.js";
import type { FeedStore } from "../feedStore.js";

const formatAuthor = (author: FeedAuthor): JSONAuthor => ({
name: author.name!,
Expand All @@ -16,8 +16,8 @@ const formatAuthor = (author: FeedAuthor): JSONAuthor => ({
*
* @see https://jsonfeed.org/version/1.1
*/
export const renderJSON = (feed: Feed): string => {
const { channel, links } = feed.options;
export const generateJSONFeed = (feedStore: FeedStore): string => {
const { channel, links } = feedStore.options;

const content: JSONContent = {
version: "https://jsonfeed.org/version/1.1",
Expand All @@ -42,7 +42,7 @@ export const renderJSON = (feed: Feed): string => {
if (channelAuthors.length)
content.authors = channelAuthors.map((author) => formatAuthor(author));

content.items = feed.items.map((item) => {
content.items = feedStore.items.map((item) => {
const feedItem: JSONItem = {
title: item.title,
url: item.link,
Expand Down

0 comments on commit 4da42b1

Please sign in to comment.