summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2023-02-03 16:48:34 -0500
committerGravatar GitHub <noreply@github.com> 2023-02-03 16:48:34 -0500
commit9f22ac3d097ef2cb3b2bbe5343b8a8a49d83425d (patch)
tree46abc25e124af9e761387646edf6882896dbafe1
parentf7f4721231c5a6ab4bae39d05abe1243f936415e (diff)
downloadastro-9f22ac3d097ef2cb3b2bbe5343b8a8a49d83425d.tar.gz
astro-9f22ac3d097ef2cb3b2bbe5343b8a8a49d83425d.tar.zst
astro-9f22ac3d097ef2cb3b2bbe5343b8a8a49d83425d.zip
[Content collections] Fix "underscore to ignore" warnings (#6122)
* refactor: fix underscore check * fix: add "ignore list" to always silence log * fix: hide log on file deleted * refactor: move getEntryType to util * test: getEntryType unit * fix: handle all unsupported cases * chore: changeset
-rw-r--r--.changeset/grumpy-bees-worry.md5
-rw-r--r--packages/astro/src/content/types-generator.ts45
-rw-r--r--packages/astro/src/content/utils.ts37
-rw-r--r--packages/astro/src/content/vite-plugin-content-imports.ts2
-rw-r--r--packages/astro/test/units/content-collections/get-entry-type.test.js62
5 files changed, 117 insertions, 34 deletions
diff --git a/.changeset/grumpy-bees-worry.md b/.changeset/grumpy-bees-worry.md
new file mode 100644
index 000000000..bab88ad25
--- /dev/null
+++ b/.changeset/grumpy-bees-worry.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Content collections: Fix accidental "use underscore to ignore" logs for `.DS_Store` files and underscored directory names.
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index da0e84dcc..50f8088de 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -6,8 +6,8 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import { normalizePath, ViteDevServer } 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 { contentFileExts, CONTENT_TYPES_FILE } from './consts.js';
+import { isRelativePath } from '../core/path.js';
+import { CONTENT_TYPES_FILE } from './consts.js';
import {
ContentConfig,
ContentObservable,
@@ -16,6 +16,7 @@ import {
getContentPaths,
getEntryInfo,
getEntrySlug,
+ getEntryType,
loadContentConfig,
NoCollectionError,
parseFrontmatter,
@@ -111,7 +112,7 @@ export async function createContentTypesGenerator({
return { shouldGenerateTypes: true };
}
const fileType = getEntryType(fileURLToPath(event.entry), contentPaths);
- if (fileType === 'generated-types') {
+ if (fileType === 'ignored') {
return { shouldGenerateTypes: false };
}
if (fileType === 'config') {
@@ -125,22 +126,21 @@ export async function createContentTypesGenerator({
return { shouldGenerateTypes: true };
}
- if (fileType === 'unknown') {
+ if (fileType === 'unsupported') {
+ // Avoid warning if file was deleted.
+ if (event.name === 'unlink') {
+ return { shouldGenerateTypes: false };
+ }
const entryInfo = getEntryInfo({
entry: event.entry,
contentDir: contentPaths.contentDir,
- // Allow underscore `_` files outside collection directories
+ // Skip invalid file check. We already know it’s invalid.
allowFilesOutsideCollection: true,
});
- if (entryInfo.id.startsWith('_') && (event.name === 'add' || event.name === 'change')) {
- // Silently ignore `_` files.
- return { shouldGenerateTypes: false };
- } else {
- return {
- shouldGenerateTypes: false,
- error: new UnsupportedFileTypeError(entryInfo.id),
- };
- }
+ return {
+ shouldGenerateTypes: false,
+ error: new UnsupportedFileTypeError(entryInfo.id),
+ };
}
const entryInfo = getEntryInfo({
entry: event.entry,
@@ -289,23 +289,6 @@ function removeEntry(contentTypes: ContentTypes, collectionKey: string, entryKey
delete contentTypes[collectionKey][entryKey];
}
-export function getEntryType(
- entryPath: string,
- paths: ContentPaths
-): 'content' | 'config' | 'unknown' | 'generated-types' {
- const { dir: rawDir, ext, base } = path.parse(entryPath);
- const dir = appendForwardSlash(pathToFileURL(rawDir).href);
- if ((contentFileExts as readonly string[]).includes(ext)) {
- return 'content';
- } else if (new URL(base, dir).href === paths.config.href) {
- return 'config';
- } else if (new URL(base, dir).href === new URL(CONTENT_TYPES_FILE, paths.cacheDir).href) {
- return 'generated-types';
- } else {
- return 'unknown';
- }
-}
-
async function writeContentFiles({
fs,
contentPaths,
diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts
index a2c463189..a1ddba757 100644
--- a/packages/astro/src/content/utils.ts
+++ b/packages/astro/src/content/utils.ts
@@ -2,12 +2,13 @@ import { slug as githubSlug } from 'github-slugger';
import matter from 'gray-matter';
import type fsMod from 'node:fs';
import path from 'node:path';
-import { fileURLToPath } from 'node:url';
+import { fileURLToPath, pathToFileURL } from 'node:url';
import { ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from 'vite';
import { z } from 'zod';
import { AstroConfig, AstroSettings } from '../@types/astro.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
-import { CONTENT_TYPES_FILE } from './consts.js';
+import { appendForwardSlash } from '../core/path.js';
+import { contentFileExts, CONTENT_TYPES_FILE } from './consts.js';
export const collectionConfigParser = z.object({
schema: z.any().optional(),
@@ -158,6 +159,38 @@ export function getEntryInfo({
return res;
}
+export function getEntryType(
+ entryPath: string,
+ paths: Pick<ContentPaths, 'config'>
+): 'content' | 'config' | 'ignored' | 'unsupported' {
+ const { dir: rawDir, ext, base } = path.parse(entryPath);
+ const dir = appendForwardSlash(pathToFileURL(rawDir).href);
+ const fileUrl = new URL(base, dir);
+
+ if (hasUnderscoreInPath(fileUrl) || isOnIgnoreList(fileUrl)) {
+ return 'ignored';
+ } else if ((contentFileExts as readonly string[]).includes(ext)) {
+ return 'content';
+ } else if (fileUrl.href === paths.config.href) {
+ return 'config';
+ } else {
+ return 'unsupported';
+ }
+}
+
+function isOnIgnoreList(fileUrl: URL) {
+ const { base } = path.parse(fileURLToPath(fileUrl));
+ return ['.DS_Store'].includes(base);
+}
+
+function hasUnderscoreInPath(fileUrl: URL): boolean {
+ const parts = fileUrl.pathname.split('/');
+ for (const part of parts) {
+ if (part.startsWith('_')) return true;
+ }
+ return false;
+}
+
const flattenErrorPath = (errorPath: (string | number)[]) => errorPath.join('.');
const errorMap: z.ZodErrorMap = (error, ctx) => {
diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts
index 66d20d703..7c7e8f65c 100644
--- a/packages/astro/src/content/vite-plugin-content-imports.ts
+++ b/packages/astro/src/content/vite-plugin-content-imports.ts
@@ -7,7 +7,7 @@ import { AstroErrorData } from '../core/errors/errors-data.js';
import { AstroError } from '../core/errors/errors.js';
import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js';
import { contentFileExts, CONTENT_FLAG } from './consts.js';
-import { getEntryType } from './types-generator.js';
+import { getEntryType } from './utils.js';
import {
ContentConfig,
getContentPaths,
diff --git a/packages/astro/test/units/content-collections/get-entry-type.test.js b/packages/astro/test/units/content-collections/get-entry-type.test.js
new file mode 100644
index 000000000..3248a88f6
--- /dev/null
+++ b/packages/astro/test/units/content-collections/get-entry-type.test.js
@@ -0,0 +1,62 @@
+import { getEntryType } from '../../../dist/content/utils.js';
+import { expect } from 'chai';
+import { fileURLToPath } from 'node:url';
+
+describe('Content Collections - getEntryType', () => {
+ const contentDir = new URL('src/content/', import.meta.url);
+ const contentPaths = {
+ config: new URL('src/content/config.ts', import.meta.url),
+ };
+
+ it('Returns "content" for Markdown files', () => {
+ for (const entryPath of ['blog/first-post.md', 'blog/first-post.mdx']) {
+ const entry = fileURLToPath(new URL(entryPath, contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('content');
+ }
+ });
+
+ it('Returns "content" for Markdown files in nested directories', () => {
+ for (const entryPath of ['blog/2021/01/01/index.md', 'blog/2021/01/01/index.mdx']) {
+ const entry = fileURLToPath(new URL(entryPath, contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('content');
+ }
+ });
+
+ it('Returns "config" for config files', () => {
+ const entry = fileURLToPath(contentPaths.config);
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('config');
+ });
+
+ it('Returns "unsupported" for non-Markdown files', () => {
+ const entry = fileURLToPath(new URL('blog/robots.txt', contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('unsupported');
+ });
+
+ it('Returns "ignored" for .DS_Store', () => {
+ const entry = fileURLToPath(new URL('blog/.DS_Store', contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('ignored');
+ });
+
+ it('Returns "ignored" for unsupported files using an underscore', () => {
+ const entry = fileURLToPath(new URL('blog/_draft-robots.txt', contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('ignored');
+ });
+
+ it('Returns "ignored" when using underscore on file name', () => {
+ const entry = fileURLToPath(new URL('blog/_first-post.md', contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('ignored');
+ });
+
+ it('Returns "ignored" when using underscore on directory name', () => {
+ const entry = fileURLToPath(new URL('blog/_draft/first-post.md', contentDir));
+ const type = getEntryType(entry, contentPaths);
+ expect(type).to.equal('ignored');
+ });
+});