[Content collections] Move generated types to .astro
directory (#5786)
* feat: change cacheDir to `.astro` * feat: write reference in env.d.ts if none exists * chore: update with-content types * test: env.d.ts transform * nit: setUp -> add * refactor: content.d.ts -> types.d.ts * chore: update confirmation log * chore: changeset * feat: inject env.d.ts if none exists * feat: set up env.d.ts on `astro sync` * chore: duplicate envTsPathRelative * docs: update changeset * fix: make srcDir if none exists * fix: types.generated -> .astro in gitignore * feat: add env.d.ts to test gitignore * chore: remove env.d.ts from content-collections * test: move sync tests to `astro sync`, add file write test * refactor: simplify test gitignore to base * fix: add / to `.astro` bc that scares me
This commit is contained in:
parent
813073addd
commit
c2180746b4
21 changed files with 263 additions and 97 deletions
9
.changeset/curvy-foxes-reply.md
Normal file
9
.changeset/curvy-foxes-reply.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
Move generated content collection types to a `.astro` directory. This replaces the previously generated `src/content/types.generated.d.ts` file.
|
||||
|
||||
If you're using Git for version control, we recommend ignoring this generated directory by adding `.astro` to your .gitignore.
|
||||
|
||||
Astro will also generate the [TypeScript reference path](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-path-) to include `.astro` types in your project. This will update your project's `src/env.d.ts` file, or write one if none exists.
|
|
@ -55,44 +55,45 @@ declare module 'astro:content' {
|
|||
};
|
||||
|
||||
const entryMap: {
|
||||
blog: {
|
||||
'first-post.md': {
|
||||
id: 'first-post.md';
|
||||
slug: 'first-post';
|
||||
body: string;
|
||||
collection: 'blog';
|
||||
data: InferEntrySchema<'blog'>;
|
||||
};
|
||||
'markdown-style-guide.md': {
|
||||
id: 'markdown-style-guide.md';
|
||||
slug: 'markdown-style-guide';
|
||||
body: string;
|
||||
collection: 'blog';
|
||||
data: InferEntrySchema<'blog'>;
|
||||
};
|
||||
'second-post.md': {
|
||||
id: 'second-post.md';
|
||||
slug: 'second-post';
|
||||
body: string;
|
||||
collection: 'blog';
|
||||
data: InferEntrySchema<'blog'>;
|
||||
};
|
||||
'third-post.md': {
|
||||
id: 'third-post.md';
|
||||
slug: 'third-post';
|
||||
body: string;
|
||||
collection: 'blog';
|
||||
data: InferEntrySchema<'blog'>;
|
||||
};
|
||||
'using-mdx.mdx': {
|
||||
id: 'using-mdx.mdx';
|
||||
slug: 'using-mdx';
|
||||
body: string;
|
||||
collection: 'blog';
|
||||
data: InferEntrySchema<'blog'>;
|
||||
};
|
||||
};
|
||||
"blog": {
|
||||
"first-post.md": {
|
||||
id: "first-post.md",
|
||||
slug: "first-post",
|
||||
body: string,
|
||||
collection: "blog",
|
||||
data: InferEntrySchema<"blog">
|
||||
},
|
||||
"markdown-style-guide.md": {
|
||||
id: "markdown-style-guide.md",
|
||||
slug: "markdown-style-guide",
|
||||
body: string,
|
||||
collection: "blog",
|
||||
data: InferEntrySchema<"blog">
|
||||
},
|
||||
"second-post.md": {
|
||||
id: "second-post.md",
|
||||
slug: "second-post",
|
||||
body: string,
|
||||
collection: "blog",
|
||||
data: InferEntrySchema<"blog">
|
||||
},
|
||||
"third-post.md": {
|
||||
id: "third-post.md",
|
||||
slug: "third-post",
|
||||
body: string,
|
||||
collection: "blog",
|
||||
data: InferEntrySchema<"blog">
|
||||
},
|
||||
"using-mdx.mdx": {
|
||||
id: "using-mdx.mdx",
|
||||
slug: "using-mdx",
|
||||
body: string,
|
||||
collection: "blog",
|
||||
data: InferEntrySchema<"blog">
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
type ContentConfig = typeof import('./config');
|
||||
type ContentConfig = typeof import("../src/content/config");
|
||||
}
|
1
examples/with-content/src/env.d.ts
vendored
1
examples/with-content/src/env.d.ts
vendored
|
@ -1 +1,2 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
|
|
|
@ -6,6 +6,7 @@ import { contentObservable, createContentTypesGenerator } from '../../content/in
|
|||
import { getTimeStat } from '../../core/build/util.js';
|
||||
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
||||
import { info, LogOptions } from '../../core/logger/core.js';
|
||||
import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js';
|
||||
|
||||
export async function sync(
|
||||
settings: AstroSettings,
|
||||
|
@ -26,6 +27,7 @@ export async function sync(
|
|||
}
|
||||
|
||||
info(logging, 'content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`);
|
||||
await setUpEnvTs({ settings, logging, fs });
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,4 @@ export const VIRTUAL_MODULE_ID = 'astro:content';
|
|||
export const LINKS_PLACEHOLDER = '@@ASTRO-LINKS@@';
|
||||
export const STYLES_PLACEHOLDER = '@@ASTRO-STYLES@@';
|
||||
|
||||
export const CONTENT_BASE = 'types.generated';
|
||||
export const CONTENT_FILE = CONTENT_BASE + '.mjs';
|
||||
export const CONTENT_TYPES_FILE = CONTENT_BASE + '.d.ts';
|
||||
export const CONTENT_TYPES_FILE = 'types.d.ts';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export { createContentTypesGenerator } from './types-generator.js';
|
||||
export { contentObservable, getContentPaths } from './utils.js';
|
||||
export { contentObservable, getContentPaths, getDotAstroTypeReference } from './utils.js';
|
||||
export {
|
||||
astroBundleDelayedAssetPlugin,
|
||||
astroDelayedAssetPlugin,
|
||||
|
|
|
@ -7,12 +7,14 @@ import { normalizePath } from 'vite';
|
|||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { info, LogOptions, warn } from '../core/logger/core.js';
|
||||
import { appendForwardSlash, isRelativePath } from '../core/path.js';
|
||||
import { getEnvTsPath } from '../vite-plugin-inject-env-ts/index.js';
|
||||
import { contentFileExts, CONTENT_TYPES_FILE } from './consts.js';
|
||||
import {
|
||||
ContentConfig,
|
||||
ContentObservable,
|
||||
ContentPaths,
|
||||
getContentPaths,
|
||||
getDotAstroTypeReference,
|
||||
getEntryInfo,
|
||||
loadContentConfig,
|
||||
NoCollectionError,
|
||||
|
@ -48,15 +50,12 @@ export async function createContentTypesGenerator({
|
|||
settings,
|
||||
}: CreateContentGeneratorParams): Promise<GenerateContentTypes> {
|
||||
const contentTypes: ContentTypes = {};
|
||||
const contentPaths: ContentPaths = getContentPaths({ srcDir: settings.config.srcDir });
|
||||
const contentPaths = getContentPaths(settings.config);
|
||||
|
||||
let events: Promise<{ shouldGenerateTypes: boolean; error?: Error }>[] = [];
|
||||
let debounceTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
const contentTypesBase = await fs.promises.readFile(
|
||||
new URL(CONTENT_TYPES_FILE, contentPaths.generatedInputDir),
|
||||
'utf-8'
|
||||
);
|
||||
const contentTypesBase = await fs.promises.readFile(contentPaths.typesTemplate, 'utf-8');
|
||||
|
||||
async function init() {
|
||||
await handleEvent({ name: 'add', entry: contentPaths.config }, { logLevel: 'warn' });
|
||||
|
@ -306,6 +305,10 @@ async function writeContentFiles({
|
|||
contentTypesStr += `},\n`;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(contentPaths.cacheDir)) {
|
||||
fs.mkdirSync(contentPaths.cacheDir, { recursive: true });
|
||||
}
|
||||
|
||||
let configPathRelativeToCacheDir = normalizePath(
|
||||
path.relative(contentPaths.cacheDir.pathname, contentPaths.config.pathname)
|
||||
);
|
||||
|
|
|
@ -5,8 +5,9 @@ import path from 'node:path';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import { createServer, ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from 'vite';
|
||||
import { z } from 'zod';
|
||||
import { AstroSettings } from '../@types/astro.js';
|
||||
import { AstroConfig, AstroSettings } from '../@types/astro.js';
|
||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
import { CONTENT_TYPES_FILE } from './consts.js';
|
||||
import { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';
|
||||
|
||||
export const collectionConfigParser = z.object({
|
||||
|
@ -26,6 +27,15 @@ export const collectionConfigParser = z.object({
|
|||
.optional(),
|
||||
});
|
||||
|
||||
export function getDotAstroTypeReference({ root, srcDir }: { root: URL; srcDir: URL }) {
|
||||
const { cacheDir } = getContentPaths({ root, srcDir });
|
||||
const contentTypesRelativeToSrcDir = normalizePath(
|
||||
path.relative(fileURLToPath(srcDir), fileURLToPath(new URL(CONTENT_TYPES_FILE, cacheDir)))
|
||||
);
|
||||
|
||||
return `/// <reference path=${JSON.stringify(contentTypesRelativeToSrcDir)} />`;
|
||||
}
|
||||
|
||||
export const contentConfigParser = z.object({
|
||||
collections: z.record(collectionConfigParser),
|
||||
});
|
||||
|
@ -201,7 +211,7 @@ export async function loadContentConfig({
|
|||
fs: typeof fsMod;
|
||||
settings: AstroSettings;
|
||||
}): Promise<ContentConfig | Error> {
|
||||
const contentPaths = getContentPaths({ srcDir: settings.config.srcDir });
|
||||
const contentPaths = getContentPaths(settings.config);
|
||||
const tempConfigServer: ViteDevServer = await createServer({
|
||||
root: fileURLToPath(settings.config.root),
|
||||
server: { middlewareMode: true, hmr: false },
|
||||
|
@ -267,16 +277,21 @@ export function contentObservable(initialCtx: ContentCtx): ContentObservable {
|
|||
export type ContentPaths = {
|
||||
contentDir: URL;
|
||||
cacheDir: URL;
|
||||
generatedInputDir: URL;
|
||||
typesTemplate: URL;
|
||||
virtualModTemplate: URL;
|
||||
config: URL;
|
||||
};
|
||||
|
||||
export function getContentPaths({ srcDir }: { srcDir: URL }): ContentPaths {
|
||||
export function getContentPaths({
|
||||
srcDir,
|
||||
root,
|
||||
}: Pick<AstroConfig, 'root' | 'srcDir'>): ContentPaths {
|
||||
const templateDir = new URL('../../src/content/template/', import.meta.url);
|
||||
return {
|
||||
// Output generated types in content directory. May change in the future!
|
||||
cacheDir: new URL('./content/', srcDir),
|
||||
cacheDir: new URL('.astro/', root),
|
||||
contentDir: new URL('./content/', srcDir),
|
||||
generatedInputDir: new URL('../../src/content/template/', import.meta.url),
|
||||
typesTemplate: new URL('types.d.ts', templateDir),
|
||||
virtualModTemplate: new URL('virtual-mod.mjs', templateDir),
|
||||
config: new URL('./content/config', srcDir),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
import {
|
||||
ContentConfig,
|
||||
contentObservable,
|
||||
ContentPaths,
|
||||
getContentPaths,
|
||||
getEntryData,
|
||||
getEntryInfo,
|
||||
|
@ -36,7 +35,7 @@ export function astroContentServerPlugin({
|
|||
logging,
|
||||
mode,
|
||||
}: AstroContentServerPluginParams): Plugin[] {
|
||||
const contentPaths: ContentPaths = getContentPaths({ srcDir: settings.config.srcDir });
|
||||
const contentPaths = getContentPaths(settings.config);
|
||||
let contentDirExists = false;
|
||||
let contentGenerator: GenerateContentTypes;
|
||||
const contentConfigObserver = contentObservable({ status: 'loading' });
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { Plugin } from 'vite';
|
|||
import { normalizePath } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { appendForwardSlash, prependForwardSlash } from '../core/path.js';
|
||||
import { contentFileExts, CONTENT_FILE, VIRTUAL_MODULE_ID } from './consts.js';
|
||||
import { contentFileExts, VIRTUAL_MODULE_ID } from './consts.js';
|
||||
import { getContentPaths } from './utils.js';
|
||||
|
||||
interface AstroContentVirtualModPluginParams {
|
||||
|
@ -14,15 +14,17 @@ interface AstroContentVirtualModPluginParams {
|
|||
export function astroContentVirtualModPlugin({
|
||||
settings,
|
||||
}: AstroContentVirtualModPluginParams): Plugin {
|
||||
const paths = getContentPaths({ srcDir: settings.config.srcDir });
|
||||
const contentPaths = getContentPaths(settings.config);
|
||||
const relContentDir = normalizePath(
|
||||
appendForwardSlash(
|
||||
prependForwardSlash(path.relative(settings.config.root.pathname, paths.contentDir.pathname))
|
||||
prependForwardSlash(
|
||||
path.relative(settings.config.root.pathname, contentPaths.contentDir.pathname)
|
||||
)
|
||||
)
|
||||
);
|
||||
const entryGlob = `${relContentDir}**/*{${contentFileExts.join(',')}}`;
|
||||
const astroContentModContents = fsMod
|
||||
.readFileSync(new URL(CONTENT_FILE, paths.generatedInputDir), 'utf-8')
|
||||
const virtualModContents = fsMod
|
||||
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
|
||||
.replace('@@CONTENT_DIR@@', relContentDir)
|
||||
.replace('@@ENTRY_GLOB_PATH@@', entryGlob)
|
||||
.replace('@@RENDER_ENTRY_GLOB_PATH@@', entryGlob);
|
||||
|
@ -40,7 +42,7 @@ export function astroContentVirtualModPlugin({
|
|||
load(id) {
|
||||
if (id === astroContentVirtualModuleId) {
|
||||
return {
|
||||
code: astroContentModContents,
|
||||
code: virtualModContents,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
@ -24,6 +24,7 @@ import markdownVitePlugin from '../vite-plugin-markdown/index.js';
|
|||
import astroScannerPlugin from '../vite-plugin-scanner/index.js';
|
||||
import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
|
||||
import astroScriptsPageSSRPlugin from '../vite-plugin-scripts/page-ssr.js';
|
||||
import { astroInjectEnvTsPlugin } from '../vite-plugin-inject-env-ts/index.js';
|
||||
|
||||
interface CreateViteOptions {
|
||||
settings: AstroSettings;
|
||||
|
@ -102,6 +103,7 @@ export async function createVite(
|
|||
astroScriptsPageSSRPlugin({ settings }),
|
||||
astroHeadPropagationPlugin({ settings }),
|
||||
astroScannerPlugin({ settings, logging }),
|
||||
astroInjectEnvTsPlugin({ settings, logging, fs }),
|
||||
...(settings.config.experimental.contentCollections
|
||||
? [
|
||||
astroContentVirtualModPlugin({ settings }),
|
||||
|
|
79
packages/astro/src/vite-plugin-inject-env-ts/index.ts
Normal file
79
packages/astro/src/vite-plugin-inject-env-ts/index.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import type fsMod from 'node:fs';
|
||||
import { normalizePath, Plugin } from 'vite';
|
||||
import path from 'node:path';
|
||||
import { getContentPaths, getDotAstroTypeReference } from '../content/index.js';
|
||||
import { info, LogOptions } from '../core/logger/core.js';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { bold } from 'kleur/colors';
|
||||
|
||||
export function getEnvTsPath({ srcDir }: { srcDir: URL }) {
|
||||
return new URL('env.d.ts', srcDir);
|
||||
}
|
||||
|
||||
export function astroInjectEnvTsPlugin({
|
||||
settings,
|
||||
logging,
|
||||
fs,
|
||||
}: {
|
||||
settings: AstroSettings;
|
||||
logging: LogOptions;
|
||||
fs: typeof fsMod;
|
||||
}): Plugin {
|
||||
return {
|
||||
name: 'astro-inject-env-ts',
|
||||
// Use `post` to ensure project setup is complete
|
||||
// Ex. `.astro` types have been written
|
||||
enforce: 'post',
|
||||
async config() {
|
||||
await setUpEnvTs({ settings, logging, fs });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function setUpEnvTs({
|
||||
settings,
|
||||
logging,
|
||||
fs,
|
||||
}: {
|
||||
settings: AstroSettings;
|
||||
logging: LogOptions;
|
||||
fs: typeof fsMod;
|
||||
}) {
|
||||
const envTsPath = getEnvTsPath(settings.config);
|
||||
const dotAstroDir = getContentPaths(settings.config).cacheDir;
|
||||
const dotAstroTypeReference = getDotAstroTypeReference(settings.config);
|
||||
const envTsPathRelativetoRoot = normalizePath(
|
||||
path.relative(fileURLToPath(settings.config.root), fileURLToPath(envTsPath))
|
||||
);
|
||||
|
||||
if (fs.existsSync(envTsPath)) {
|
||||
// Add `.astro` types reference if none exists
|
||||
if (!fs.existsSync(dotAstroDir)) return;
|
||||
|
||||
let typesEnvContents = await fs.promises.readFile(envTsPath, 'utf-8');
|
||||
const expectedTypeReference = getDotAstroTypeReference(settings.config);
|
||||
|
||||
if (!typesEnvContents.includes(expectedTypeReference)) {
|
||||
typesEnvContents = `${expectedTypeReference}\n${typesEnvContents}`;
|
||||
await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
|
||||
info(logging, 'content', `Added ${bold(envTsPathRelativetoRoot)} types`);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, inject the `env.d.ts` file
|
||||
let referenceDefs: string[] = [];
|
||||
if (settings.config.integrations.find((i) => i.name === '@astrojs/image')) {
|
||||
referenceDefs.push('/// <reference types="@astrojs/image/client" />');
|
||||
} else {
|
||||
referenceDefs.push('/// <reference types="astro/client" />');
|
||||
}
|
||||
|
||||
if (fs.existsSync(dotAstroDir)) {
|
||||
referenceDefs.push(dotAstroTypeReference);
|
||||
}
|
||||
|
||||
await fs.promises.mkdir(settings.config.srcDir, { recursive: true });
|
||||
await fs.promises.writeFile(envTsPath, referenceDefs.join('\n'), 'utf-8');
|
||||
info(logging, 'astro', `Added ${bold(envTsPathRelativetoRoot)} types`);
|
||||
}
|
||||
}
|
88
packages/astro/test/astro-sync.test.js
Normal file
88
packages/astro/test/astro-sync.test.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
import * as fs from 'node:fs';
|
||||
import { expect } from 'chai';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
describe('astro sync', () => {
|
||||
let fixture;
|
||||
before(async () => {
|
||||
fixture = await loadFixture({ root: './fixtures/content-collections/' });
|
||||
});
|
||||
|
||||
it('Writes types to `.astro`', async () => {
|
||||
let writtenFiles = {};
|
||||
const fsMock = {
|
||||
...fs,
|
||||
promises: {
|
||||
...fs.promises,
|
||||
async writeFile(path, contents) {
|
||||
writtenFiles[path] = contents;
|
||||
},
|
||||
},
|
||||
};
|
||||
await fixture.sync({ fs: fsMock });
|
||||
|
||||
const expectedTypesFile = new URL('.astro/types.d.ts', fixture.config.root).href;
|
||||
expect(writtenFiles).to.haveOwnProperty(expectedTypesFile);
|
||||
// smoke test `astro check` asserts whether content types pass.
|
||||
expect(writtenFiles[expectedTypesFile]).to.include(
|
||||
`declare module 'astro:content' {`,
|
||||
'Types file does not include `astro:content` module declaration'
|
||||
);
|
||||
});
|
||||
|
||||
it('Adds type reference to `src/env.d.ts`', async () => {
|
||||
let writtenFiles = {};
|
||||
const typesEnvPath = new URL('env.d.ts', fixture.config.srcDir).href;
|
||||
const fsMock = {
|
||||
...fs,
|
||||
existsSync(path, ...args) {
|
||||
if (path.toString() === typesEnvPath) {
|
||||
return true;
|
||||
}
|
||||
return fs.existsSync(path, ...args);
|
||||
},
|
||||
promises: {
|
||||
...fs.promises,
|
||||
async readFile(path, ...args) {
|
||||
if (path.toString() === typesEnvPath) {
|
||||
return `/// <reference path="astro/client" />`;
|
||||
} else {
|
||||
return fs.promises.readFile(path, ...args);
|
||||
}
|
||||
},
|
||||
async writeFile(path, contents) {
|
||||
writtenFiles[path] = contents;
|
||||
},
|
||||
},
|
||||
};
|
||||
await fixture.sync({ fs: fsMock });
|
||||
|
||||
expect(writtenFiles, 'Did not try to update env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
||||
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference path="../.astro/types.d.ts" />`);
|
||||
});
|
||||
|
||||
it('Writes `src/env.d.ts` if none exists', async () => {
|
||||
let writtenFiles = {};
|
||||
const typesEnvPath = new URL('env.d.ts', fixture.config.srcDir).href;
|
||||
const fsMock = {
|
||||
...fs,
|
||||
existsSync(path, ...args) {
|
||||
if (path.toString() === typesEnvPath) {
|
||||
return false;
|
||||
}
|
||||
return fs.existsSync(path, ...args);
|
||||
},
|
||||
promises: {
|
||||
...fs.promises,
|
||||
async writeFile(path, contents) {
|
||||
writtenFiles[path] = contents;
|
||||
},
|
||||
},
|
||||
};
|
||||
await fixture.sync({ fs: fsMock });
|
||||
|
||||
expect(writtenFiles, 'Did not try to write env.d.ts file.').to.haveOwnProperty(typesEnvPath);
|
||||
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference types="astro/client" />`);
|
||||
expect(writtenFiles[typesEnvPath]).to.include(`/// <reference path="../.astro/types.d.ts" />`);
|
||||
});
|
||||
});
|
|
@ -1,4 +1,3 @@
|
|||
import * as fs from 'node:fs';
|
||||
import * as devalue from 'devalue';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { expect } from 'chai';
|
||||
|
@ -6,36 +5,6 @@ import { loadFixture } from './test-utils.js';
|
|||
import testAdapter from './test-adapter.js';
|
||||
|
||||
describe('Content Collections', () => {
|
||||
describe('Type generation', () => {
|
||||
let fixture;
|
||||
before(async () => {
|
||||
fixture = await loadFixture({ root: './fixtures/content-collections/' });
|
||||
});
|
||||
|
||||
it('Writes types to `src/content/`', async () => {
|
||||
let writtenFiles = {};
|
||||
const fsMock = {
|
||||
...fs,
|
||||
promises: {
|
||||
...fs.promises,
|
||||
async writeFile(path, contents) {
|
||||
writtenFiles[path] = contents;
|
||||
},
|
||||
},
|
||||
};
|
||||
const expectedTypesFile = new URL('./content/types.generated.d.ts', fixture.config.srcDir)
|
||||
.href;
|
||||
await fixture.sync({ fs: fsMock });
|
||||
expect(Object.keys(writtenFiles)).to.have.lengthOf(1);
|
||||
expect(writtenFiles).to.haveOwnProperty(expectedTypesFile);
|
||||
// smoke test `astro check` asserts whether content types pass.
|
||||
expect(writtenFiles[expectedTypesFile]).to.include(
|
||||
`declare module 'astro:content' {`,
|
||||
'Types file does not include `astro:content` module declaration'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Query', () => {
|
||||
let fixture;
|
||||
before(async () => {
|
||||
|
|
2
packages/astro/test/fixtures/.gitignore
vendored
Normal file
2
packages/astro/test/fixtures/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.astro/
|
||||
env.d.ts
|
|
@ -1 +0,0 @@
|
|||
types.generated.d.ts
|
|
@ -1 +0,0 @@
|
|||
types.generated.d.ts
|
|
@ -1 +0,0 @@
|
|||
types.generated.d.ts
|
|
@ -1 +0,0 @@
|
|||
types.generated.d.ts
|
Loading…
Reference in a new issue