Skip to content

Commit 844bdd4

Browse files
authored
Make Content Layer unit testable (#15659)
1 parent cb625b6 commit 844bdd4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4450
-888
lines changed

packages/astro/src/content/content-layer.ts

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ import {
3232
} from './utils.js';
3333
import { createWatcherWrapper, type WrappedWatcher } from './watcher.js';
3434

35-
interface ContentLayerOptions {
35+
export interface ContentLayerOptions {
3636
store: MutableDataStore;
3737
settings: AstroSettings;
3838
logger: Logger;
3939
watcher?: FSWatcher;
40+
contentConfigObserver?: ContentObservable;
4041
}
4142

4243
type CollectionLoader<TData> = () =>
@@ -45,7 +46,7 @@ type CollectionLoader<TData> = () =>
4546
| Record<string, Record<string, unknown>>
4647
| Promise<Record<string, Record<string, unknown>>>;
4748

48-
class ContentLayer {
49+
export class ContentLayer {
4950
#logger: Logger;
5051
#store: MutableDataStore;
5152
#settings: AstroSettings;
@@ -54,16 +55,24 @@ class ContentLayer {
5455
#unsubscribe?: () => void;
5556
#markdownProcessor?: MarkdownProcessor;
5657
#generateDigest?: (data: Record<string, unknown> | string) => string;
58+
#contentConfigObserver: ContentObservable;
5759

5860
#queue: PQueue;
5961

60-
constructor({ settings, logger, store, watcher }: ContentLayerOptions) {
62+
constructor({
63+
settings,
64+
logger,
65+
store,
66+
watcher,
67+
contentConfigObserver = globalContentConfigObserver,
68+
}: ContentLayerOptions) {
6169
// The default max listeners is 10, which can be exceeded when using a lot of loaders
6270
watcher?.setMaxListeners(50);
6371

6472
this.#logger = logger;
6573
this.#store = store;
6674
this.#settings = settings;
75+
this.#contentConfigObserver = contentConfigObserver;
6776
if (watcher) {
6877
this.#watcher = createWatcherWrapper(watcher);
6978
}
@@ -82,7 +91,7 @@ class ContentLayer {
8291
*/
8392
watchContentConfig() {
8493
this.#unsubscribe?.();
85-
this.#unsubscribe = globalContentConfigObserver.subscribe(async (ctx) => {
94+
this.#unsubscribe = this.#contentConfigObserver.subscribe(async (ctx) => {
8695
if (ctx.status === 'loaded' && ctx.config.digest !== this.#lastConfigDigest) {
8796
this.sync();
8897
}
@@ -172,13 +181,13 @@ class ContentLayer {
172181
}
173182

174183
async #doSync(options: RefreshContentOptions) {
175-
let contentConfig = globalContentConfigObserver.get();
184+
let contentConfig = this.#contentConfigObserver.get();
176185
const logger = this.#logger.forkIntegrationLogger('content');
177186

178187
if (contentConfig?.status === 'loading') {
179188
contentConfig = await Promise.race<ReturnType<ContentObservable['get']>>([
180189
new Promise((resolve) => {
181-
const unsub = globalContentConfigObserver.subscribe((ctx) => {
190+
const unsub = this.#contentConfigObserver.subscribe((ctx) => {
182191
unsub();
183192
resolve(ctx);
184193
});
@@ -230,9 +239,9 @@ class ContentLayer {
230239
this.#lastConfigDigest = currentConfigDigest;
231240

232241
let shouldClear = false;
233-
const previousConfigDigest = await this.#store.metaStore().get('content-config-digest');
234-
const previousAstroConfigDigest = await this.#store.metaStore().get('astro-config-digest');
235-
const previousAstroVersion = await this.#store.metaStore().get('astro-version');
242+
const previousConfigDigest = this.#store.metaStore().get('content-config-digest');
243+
const previousAstroConfigDigest = this.#store.metaStore().get('astro-config-digest');
244+
const previousAstroVersion = this.#store.metaStore().get('astro-version');
236245

237246
if (previousAstroConfigDigest && previousAstroConfigDigest !== astroConfigDigest) {
238247
logger.info('Astro config changed');
@@ -252,13 +261,13 @@ class ContentLayer {
252261
this.#store.clearAll();
253262
}
254263
if (process.env.ASTRO_VERSION) {
255-
await this.#store.metaStore().set('astro-version', process.env.ASTRO_VERSION);
264+
this.#store.metaStore().set('astro-version', process.env.ASTRO_VERSION);
256265
}
257266
if (currentConfigDigest) {
258-
await this.#store.metaStore().set('content-config-digest', currentConfigDigest);
267+
this.#store.metaStore().set('content-config-digest', currentConfigDigest);
259268
}
260269
if (astroConfigDigest) {
261-
await this.#store.metaStore().set('astro-config-digest', astroConfigDigest);
270+
this.#store.metaStore().set('astro-config-digest', astroConfigDigest);
262271
}
263272

264273
if (!options?.loaders?.length) {
@@ -459,21 +468,3 @@ async function simpleLoader<TData extends { id: string }>(
459468
export function getDataStoreFile(settings: AstroSettings, isDev: boolean) {
460469
return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir);
461470
}
462-
463-
function contentLayerSingleton() {
464-
let instance: ContentLayer | null = null;
465-
return {
466-
init: (options: ContentLayerOptions) => {
467-
instance?.dispose();
468-
instance = new ContentLayer(options);
469-
return instance;
470-
},
471-
get: () => instance,
472-
dispose: () => {
473-
instance?.dispose();
474-
instance = null;
475-
},
476-
};
477-
}
478-
479-
export const globalContentLayer = contentLayerSingleton();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { FSWatcher } from 'vite';
2+
import { ContentLayer } from './content-layer.js';
3+
import type { Logger } from '../core/logger/core.js';
4+
import type { AstroSettings } from '../types/astro.js';
5+
import type { MutableDataStore } from './mutable-data-store.js';
6+
7+
interface ContentLayerOptions {
8+
store: MutableDataStore;
9+
settings: AstroSettings;
10+
logger: Logger;
11+
watcher?: FSWatcher;
12+
}
13+
14+
function contentLayerSingleton() {
15+
let instance: ContentLayer | null = null;
16+
return {
17+
init: (options: ContentLayerOptions) => {
18+
instance?.dispose();
19+
instance = new ContentLayer(options);
20+
return instance;
21+
},
22+
get: () => instance,
23+
dispose: () => {
24+
instance?.dispose();
25+
instance = null;
26+
},
27+
};
28+
}
29+
30+
export const globalContentLayer = contentLayerSingleton();

packages/astro/src/core/dev/dev.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { performance } from 'node:perf_hooks';
55
import colors from 'piccolore';
66
import { gt, major, minor, patch } from 'semver';
77
import type * as vite from 'vite';
8-
import { getDataStoreFile, globalContentLayer } from '../../content/content-layer.js';
8+
import { getDataStoreFile } from '../../content/content-layer.js';
9+
import { globalContentLayer } from '../../content/instance.js';
910
import { attachContentServerListeners } from '../../content/index.js';
1011
import { MutableDataStore } from '../../content/mutable-data-store.js';
1112
import { globalContentConfigObserver } from '../../content/utils.js';

packages/astro/src/core/dev/restart.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type nodeFs from 'node:fs';
22
import { fileURLToPath } from 'node:url';
33
import * as vite from 'vite';
4-
import { globalContentLayer } from '../../content/content-layer.js';
4+
import { globalContentLayer } from '../../content/instance.js';
55
import { attachContentServerListeners } from '../../content/server-listeners.js';
66
import { eventCliSession, telemetry } from '../../events/index.js';
77
import { SETTINGS_FILE } from '../../preferences/constants.js';

packages/astro/src/core/sync/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import colors from 'piccolore';
66
import { createServer, type FSWatcher, type HotPayload, type ViteDevServer } from 'vite';
77
import { syncFonts } from '../../assets/fonts/sync.js';
88
import { CONTENT_TYPES_FILE } from '../../content/consts.js';
9-
import { getDataStoreFile, globalContentLayer } from '../../content/content-layer.js';
9+
import { getDataStoreFile } from '../../content/content-layer.js';
10+
import { globalContentLayer } from '../../content/instance.js';
1011
import { createContentTypesGenerator } from '../../content/index.js';
1112
import { MutableDataStore } from '../../content/mutable-data-store.js';
1213
import { getContentPaths, globalContentConfigObserver } from '../../content/utils.js';

packages/astro/src/integrations/hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { mergeConfig as mergeViteConfig } from 'vite';
77
import astroIntegrationActionsRouteHandler from '../actions/integration.js';
88
import { isActionsFilePresent } from '../actions/utils.js';
99
import { CONTENT_LAYER_TYPE } from '../content/consts.js';
10-
import { globalContentLayer } from '../content/content-layer.js';
10+
import { globalContentLayer } from '../content/instance.js';
1111
import { globalContentConfigObserver } from '../content/utils.js';
1212
import type { SerializedSSRManifest } from '../core/app/types.js';
1313
import type { PageBuildData } from '../core/build/types.js';

0 commit comments

Comments
 (0)