From a60023e66cc895df4e2e5910b470d7e3114791f9 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 10 Sep 2024 15:37:31 +0200 Subject: [PATCH 01/16] feat: update paths --- packages/astro/src/content/consts.ts | 6 ++++-- packages/astro/src/content/content-layer.ts | 19 +++++++++++-------- packages/astro/src/content/types-generator.ts | 17 +++++++++-------- packages/astro/src/core/dev/restart.ts | 3 ++- packages/astro/src/preferences/constants.ts | 1 + packages/astro/src/preferences/store.ts | 3 ++- 6 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 packages/astro/src/preferences/constants.ts diff --git a/packages/astro/src/content/consts.ts b/packages/astro/src/content/consts.ts index 71ef0344db88..71bd48864c83 100644 --- a/packages/astro/src/content/consts.ts +++ b/packages/astro/src/content/consts.ts @@ -36,7 +36,9 @@ export const CONTENT_FLAGS = [ export const CONTENT_TYPES_FILE = 'astro/content.d.ts'; export const DATA_STORE_FILE = 'data-store.json'; -export const ASSET_IMPORTS_FILE = 'assets.mjs'; -export const MODULES_IMPORTS_FILE = 'modules.mjs'; +export const ASSET_IMPORTS_FILE = 'astro/content-assets.mjs'; +export const MODULES_IMPORTS_FILE = 'astro/content-modules.mjs'; +export const COLLECTIONS_MANIFEST_FILE = 'astro/collections/collections.json'; +export const COLLECTIONS_DIR = 'astro/collections/' export const CONTENT_LAYER_TYPE = 'content_layer'; diff --git a/packages/astro/src/content/content-layer.ts b/packages/astro/src/content/content-layer.ts index bf3213901517..677b14acac19 100644 --- a/packages/astro/src/content/content-layer.ts +++ b/packages/astro/src/content/content-layer.ts @@ -7,6 +7,7 @@ import type { AstroSettings } from '../types/astro.js'; import type { ContentEntryType, RefreshContentOptions } from '../types/public/content.js'; import { ASSET_IMPORTS_FILE, + COLLECTIONS_MANIFEST_FILE, CONTENT_LAYER_TYPE, DATA_STORE_FILE, MODULES_IMPORTS_FILE, @@ -18,6 +19,8 @@ import { getEntryDataAndImages, globalContentConfigObserver, } from './utils.js'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; export interface ContentLayerOptions { store: MutableDataStore; @@ -213,15 +216,12 @@ export class ContentLayer { return collection.loader.load(context); }), ); - if (!existsSync(this.#settings.config.cacheDir)) { - await fs.mkdir(this.#settings.config.cacheDir, { recursive: true }); - } + await fs.mkdir(this.#settings.config.cacheDir, { recursive: true }); const cacheFile = getDataStoreFile(this.#settings); await this.#store.writeToDisk(cacheFile); - if (!existsSync(this.#settings.dotAstroDir)) { - await fs.mkdir(this.#settings.dotAstroDir, { recursive: true }); - } const assetImportsFile = new URL(ASSET_IMPORTS_FILE, this.#settings.dotAstroDir); + const dotAstroAstroDir = dirname(fileURLToPath(assetImportsFile)); + await fs.mkdir(dotAstroAstroDir, { recursive: true }); await this.#store.writeAssetImports(assetImportsFile); const modulesImportsFile = new URL(MODULES_IMPORTS_FILE, this.#settings.dotAstroDir); await this.#store.writeModuleImports(modulesImportsFile); @@ -232,7 +232,7 @@ export class ContentLayer { } async regenerateCollectionFileManifest() { - const collectionsManifest = new URL('collections/collections.json', this.#settings.dotAstroDir); + const collectionsManifest = new URL(COLLECTIONS_MANIFEST_FILE, this.#settings.dotAstroDir); this.#logger.debug('content', 'Regenerating collection file manifest'); if (existsSync(collectionsManifest)) { try { @@ -283,7 +283,10 @@ export async function simpleLoader( */ export function getDataStoreFile(settings: AstroSettings, isDev?: boolean) { isDev ??= process?.env.NODE_ENV === 'development'; - return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir); + return new URL( + DATA_STORE_FILE, + isDev ? new URL('./astro/', settings.dotAstroDir) : settings.config.cacheDir, + ); } function contentLayerSingleton() { diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index 9923a0c343d7..3f19841a3c1d 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -13,7 +13,12 @@ import type { Logger } from '../core/logger/core.js'; import { isRelativePath } from '../core/path.js'; import type { AstroSettings } from '../types/astro.js'; import type { ContentEntryType } from '../types/public/content.js'; -import { CONTENT_LAYER_TYPE, CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js'; +import { + COLLECTIONS_DIR, + CONTENT_LAYER_TYPE, + CONTENT_TYPES_FILE, + VIRTUAL_MODULE_ID, +} from './consts.js'; import { type CollectionConfig, type ContentConfig, @@ -428,10 +433,8 @@ async function writeContentFiles({ let contentTypesStr = ''; let dataTypesStr = ''; - const collectionSchemasDir = new URL('./collections/', settings.dotAstroDir); - if (!fs.existsSync(collectionSchemasDir)) { - fs.mkdirSync(collectionSchemasDir, { recursive: true }); - } + const collectionSchemasDir = new URL(COLLECTIONS_DIR, settings.dotAstroDir); + fs.mkdirSync(collectionSchemasDir, { recursive: true }); for (const [collection, config] of Object.entries(contentConfig?.collections ?? {})) { collectionEntryMap[JSON.stringify(collection)] ??= { @@ -568,9 +571,7 @@ async function writeContentFiles({ ); } - if (!fs.existsSync(settings.dotAstroDir)) { - fs.mkdirSync(settings.dotAstroDir, { recursive: true }); - } + fs.mkdirSync(settings.dotAstroDir, { recursive: true }); const configPathRelativeToCacheDir = normalizeConfigPath( new URL('astro', settings.dotAstroDir).pathname, diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts index a19f56e8a6d7..92dcc28ae0b7 100644 --- a/packages/astro/src/core/dev/restart.ts +++ b/packages/astro/src/core/dev/restart.ts @@ -12,6 +12,7 @@ import { createSafeError } from '../errors/index.js'; import { formatErrorMessage } from '../messages.js'; import type { Container } from './container.js'; import { createContainer, startContainer } from './container.js'; +import { SETTINGS_FILE } from '../../preferences/constants.js'; async function createRestartedContainer( container: Container, @@ -50,7 +51,7 @@ function shouldRestartContainer( else { shouldRestart = configRE.test(normalizedChangedFile); const settingsPath = vite.normalizePath( - fileURLToPath(new URL('settings.json', settings.dotAstroDir)), + fileURLToPath(new URL(SETTINGS_FILE, settings.dotAstroDir)), ); if (settingsPath.endsWith(normalizedChangedFile)) { shouldRestart = settings.preferences.ignoreNextPreferenceReload ? false : true; diff --git a/packages/astro/src/preferences/constants.ts b/packages/astro/src/preferences/constants.ts new file mode 100644 index 000000000000..9fd21af05351 --- /dev/null +++ b/packages/astro/src/preferences/constants.ts @@ -0,0 +1 @@ +export const SETTINGS_FILE = 'astro/settings.json'; diff --git a/packages/astro/src/preferences/store.ts b/packages/astro/src/preferences/store.ts index c999566e81b1..373ec88c165f 100644 --- a/packages/astro/src/preferences/store.ts +++ b/packages/astro/src/preferences/store.ts @@ -2,13 +2,14 @@ import fs from 'node:fs'; import path from 'node:path'; import dget from 'dlv'; import { dset } from 'dset'; +import { SETTINGS_FILE } from './constants.js'; export class PreferenceStore { private file: string; constructor( private dir: string, - filename = 'settings.json', + filename = SETTINGS_FILE, ) { this.file = path.join(this.dir, filename); } From a28f00ea35ecbe20245843f12105ddb653f7d662 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 10 Sep 2024 15:47:30 +0200 Subject: [PATCH 02/16] chore: changeset --- .changeset/lazy-oranges-draw.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .changeset/lazy-oranges-draw.md diff --git a/.changeset/lazy-oranges-draw.md b/.changeset/lazy-oranges-draw.md new file mode 100644 index 000000000000..4f6c2641683e --- /dev/null +++ b/.changeset/lazy-oranges-draw.md @@ -0,0 +1,16 @@ +--- +'astro': major +--- + +Updates where files are generated by `astro sync`. + +To avoid collisions with files generated by integrations, any file generated by Astro in `/.astro/` is now moved to `/.astro/astro/`. It should only break usage of JSON Schemas for legacy data collections: + +```diff +{ +- "$schema": "../../../.astro/collections/authors.schema.json", ++ "$schema": "../../../.astro/astro/collections/authors.schema.json", + "name": "Armand", + "skills": ["Astro", "Starlight"] +} +``` From 74174b40eeee30fddc412ffaf820ce587c0d97eb Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 10 Sep 2024 16:17:07 +0200 Subject: [PATCH 03/16] fix: tests --- packages/astro/test/content-intellisense.test.js | 4 ++-- packages/astro/test/content-layer.test.js | 2 +- packages/astro/test/data-collections-schema.test.js | 10 +++++----- packages/astro/test/units/dev/restart.test.js | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/astro/test/content-intellisense.test.js b/packages/astro/test/content-intellisense.test.js index dc93919999a1..b3b243691381 100644 --- a/packages/astro/test/content-intellisense.test.js +++ b/packages/astro/test/content-intellisense.test.js @@ -16,8 +16,8 @@ describe('Content Intellisense', () => { fixture = await loadFixture({ root: './fixtures/content-intellisense/' }); await fixture.build(); - collectionsDir = await fixture.readdir('../.astro/collections'); - manifest = JSON.parse(await fixture.readFile('../.astro/collections/collections.json')); + collectionsDir = await fixture.readdir('../.astro/astro/collections'); + manifest = JSON.parse(await fixture.readFile('../.astro/astro/collections/collections.json')); }); it('generate JSON schemas for content collections', async () => { diff --git a/packages/astro/test/content-layer.test.js b/packages/astro/test/content-layer.test.js index 6b833085df86..061fd74301c0 100644 --- a/packages/astro/test/content-layer.test.js +++ b/packages/astro/test/content-layer.test.js @@ -19,7 +19,7 @@ describe('Content Layer', () => { before(async () => { fixture = await loadFixture({ root: './fixtures/content-layer/' }); await fs - .unlink(new URL('./node_modules/.astro/data-store.json', fixture.config.root)) + .unlink(new URL('./node_modules/.astro/astro/data-store.json', fixture.config.root)) .catch(() => {}); await fixture.build(); const rawJson = await fixture.readFile('/collections.json'); diff --git a/packages/astro/test/data-collections-schema.test.js b/packages/astro/test/data-collections-schema.test.js index bd7bf598e410..9ede3b2557f8 100644 --- a/packages/astro/test/data-collections-schema.test.js +++ b/packages/astro/test/data-collections-schema.test.js @@ -11,17 +11,17 @@ describe('Content Collections - data collections', () => { describe('Translations Collection', () => { it('Generates schema file', async () => { - const schemaExists = await fixture.pathExists('../.astro/collections/i18n.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/astro/collections/i18n.schema.json'); assert.equal(schemaExists, true); }); it('Generates schema file when the schema is a function', async () => { - const schemaExists = await fixture.pathExists('../.astro/collections/func.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/astro/collections/func.schema.json'); assert.equal(schemaExists, true); }); it('Generates valid schema file', async () => { - const rawJson = await fixture.readFile('../.astro/collections/i18n.schema.json'); + const rawJson = await fixture.readFile('../.astro/astro/collections/i18n.schema.json'); assert.deepEqual( JSON.stringify({ $ref: '#/definitions/i18n', @@ -57,12 +57,12 @@ describe('Content Collections - data collections', () => { }); it('Generates schema file when the schema uses the image function', async () => { - const schemaExists = await fixture.pathExists('../.astro/collections/image.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/astro/collections/image.schema.json'); assert.equal(schemaExists, true); }); it('Generates valid schema file for an image', async () => { - const rawJson = await fixture.readFile('../.astro/collections/image.schema.json'); + const rawJson = await fixture.readFile('../.astro/astro/collections/image.schema.json'); assert.deepEqual( JSON.stringify({ $ref: '#/definitions/image', diff --git a/packages/astro/test/units/dev/restart.test.js b/packages/astro/test/units/dev/restart.test.js index 339b95fc1acb..f4ed91d638b9 100644 --- a/packages/astro/test/units/dev/restart.test.js +++ b/packages/astro/test/units/dev/restart.test.js @@ -195,11 +195,11 @@ describe('dev container restarts', () => { } }); - it('Is able to restart project on .astro/settings.json changes', async () => { + it('Is able to restart project on .astro/astro/settings.json changes', async () => { const fs = createFs( { '/src/pages/index.astro': ``, - '/.astro/settings.json': `{}`, + '/.astro/astro/settings.json': `{}`, }, root, ); @@ -213,9 +213,9 @@ describe('dev container restarts', () => { try { let restartComplete = restart.restarted(); - fs.mkdirSync('/.astro/', { recursive: true }); - fs.writeFileSync('/.astro/settings.json', `{ }`); - triggerFSEvent(restart.container, fs, '/.astro/settings.json', 'change'); + fs.mkdirSync('/.astro/astro/', { recursive: true }); + fs.writeFileSync('/.astro/astro/settings.json', `{ }`); + triggerFSEvent(restart.container, fs, '/.astro/astro/settings.json', 'change'); await restartComplete; } finally { await restart.container.close(); From eb0c1440711343ea7d4641546d4e69197b5b942d Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 10 Sep 2024 16:59:07 +0200 Subject: [PATCH 04/16] Update test-utils.js --- packages/astro/test/test-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index 00a8099f4f51..161290b38821 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -186,7 +186,7 @@ export async function loadFixture(inlineConfig) { return Promise.reject(new Error('No dev server running')); } - const dataStoreFile = path.join(root, '.astro', 'data-store.json'); + const dataStoreFile = path.join(root, '.astro/astro/data-store.json'); return new Promise((resolve, reject) => { const changeHandler = (fileName) => { From 540d2a9663baaa25cff75d5290997756df34082e Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:57:02 +0200 Subject: [PATCH 05/16] Discard changes to packages/astro/test/units/dev/restart.test.js --- packages/astro/test/units/dev/restart.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/astro/test/units/dev/restart.test.js b/packages/astro/test/units/dev/restart.test.js index f4ed91d638b9..339b95fc1acb 100644 --- a/packages/astro/test/units/dev/restart.test.js +++ b/packages/astro/test/units/dev/restart.test.js @@ -195,11 +195,11 @@ describe('dev container restarts', () => { } }); - it('Is able to restart project on .astro/astro/settings.json changes', async () => { + it('Is able to restart project on .astro/settings.json changes', async () => { const fs = createFs( { '/src/pages/index.astro': ``, - '/.astro/astro/settings.json': `{}`, + '/.astro/settings.json': `{}`, }, root, ); @@ -213,9 +213,9 @@ describe('dev container restarts', () => { try { let restartComplete = restart.restarted(); - fs.mkdirSync('/.astro/astro/', { recursive: true }); - fs.writeFileSync('/.astro/astro/settings.json', `{ }`); - triggerFSEvent(restart.container, fs, '/.astro/astro/settings.json', 'change'); + fs.mkdirSync('/.astro/', { recursive: true }); + fs.writeFileSync('/.astro/settings.json', `{ }`); + triggerFSEvent(restart.container, fs, '/.astro/settings.json', 'change'); await restartComplete; } finally { await restart.container.close(); From e963c879365600706ad93275fd64a167d3d4dc09 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:57:05 +0200 Subject: [PATCH 06/16] Discard changes to packages/astro/test/test-utils.js --- packages/astro/test/test-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index 161290b38821..00a8099f4f51 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -186,7 +186,7 @@ export async function loadFixture(inlineConfig) { return Promise.reject(new Error('No dev server running')); } - const dataStoreFile = path.join(root, '.astro/astro/data-store.json'); + const dataStoreFile = path.join(root, '.astro', 'data-store.json'); return new Promise((resolve, reject) => { const changeHandler = (fileName) => { From 7438ef7c6b9b17f82a462619a58513ddeb4ff662 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:57:10 +0200 Subject: [PATCH 07/16] Discard changes to packages/astro/test/data-collections-schema.test.js --- packages/astro/test/data-collections-schema.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/astro/test/data-collections-schema.test.js b/packages/astro/test/data-collections-schema.test.js index 9ede3b2557f8..bd7bf598e410 100644 --- a/packages/astro/test/data-collections-schema.test.js +++ b/packages/astro/test/data-collections-schema.test.js @@ -11,17 +11,17 @@ describe('Content Collections - data collections', () => { describe('Translations Collection', () => { it('Generates schema file', async () => { - const schemaExists = await fixture.pathExists('../.astro/astro/collections/i18n.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/collections/i18n.schema.json'); assert.equal(schemaExists, true); }); it('Generates schema file when the schema is a function', async () => { - const schemaExists = await fixture.pathExists('../.astro/astro/collections/func.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/collections/func.schema.json'); assert.equal(schemaExists, true); }); it('Generates valid schema file', async () => { - const rawJson = await fixture.readFile('../.astro/astro/collections/i18n.schema.json'); + const rawJson = await fixture.readFile('../.astro/collections/i18n.schema.json'); assert.deepEqual( JSON.stringify({ $ref: '#/definitions/i18n', @@ -57,12 +57,12 @@ describe('Content Collections - data collections', () => { }); it('Generates schema file when the schema uses the image function', async () => { - const schemaExists = await fixture.pathExists('../.astro/astro/collections/image.schema.json'); + const schemaExists = await fixture.pathExists('../.astro/collections/image.schema.json'); assert.equal(schemaExists, true); }); it('Generates valid schema file for an image', async () => { - const rawJson = await fixture.readFile('../.astro/astro/collections/image.schema.json'); + const rawJson = await fixture.readFile('../.astro/collections/image.schema.json'); assert.deepEqual( JSON.stringify({ $ref: '#/definitions/image', From 575a77406c19da7c8e617b4aeaaf65a1bba1b74d Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:57:14 +0200 Subject: [PATCH 08/16] Discard changes to packages/astro/test/content-layer.test.js --- packages/astro/test/content-layer.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/test/content-layer.test.js b/packages/astro/test/content-layer.test.js index 061fd74301c0..6b833085df86 100644 --- a/packages/astro/test/content-layer.test.js +++ b/packages/astro/test/content-layer.test.js @@ -19,7 +19,7 @@ describe('Content Layer', () => { before(async () => { fixture = await loadFixture({ root: './fixtures/content-layer/' }); await fs - .unlink(new URL('./node_modules/.astro/astro/data-store.json', fixture.config.root)) + .unlink(new URL('./node_modules/.astro/data-store.json', fixture.config.root)) .catch(() => {}); await fixture.build(); const rawJson = await fixture.readFile('/collections.json'); From 7de290137a55c49c34a8e5e78d122010e1e52657 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:57:18 +0200 Subject: [PATCH 09/16] Discard changes to packages/astro/test/content-intellisense.test.js --- packages/astro/test/content-intellisense.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/test/content-intellisense.test.js b/packages/astro/test/content-intellisense.test.js index b3b243691381..dc93919999a1 100644 --- a/packages/astro/test/content-intellisense.test.js +++ b/packages/astro/test/content-intellisense.test.js @@ -16,8 +16,8 @@ describe('Content Intellisense', () => { fixture = await loadFixture({ root: './fixtures/content-intellisense/' }); await fixture.build(); - collectionsDir = await fixture.readdir('../.astro/astro/collections'); - manifest = JSON.parse(await fixture.readFile('../.astro/astro/collections/collections.json')); + collectionsDir = await fixture.readdir('../.astro/collections'); + manifest = JSON.parse(await fixture.readFile('../.astro/collections/collections.json')); }); it('generate JSON schemas for content collections', async () => { From 186aa60566e288309de0fbf38cb7153365ae65d7 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 13:59:39 +0200 Subject: [PATCH 10/16] chore: remove changeset --- .changeset/lazy-oranges-draw.md | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .changeset/lazy-oranges-draw.md diff --git a/.changeset/lazy-oranges-draw.md b/.changeset/lazy-oranges-draw.md deleted file mode 100644 index 4f6c2641683e..000000000000 --- a/.changeset/lazy-oranges-draw.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'astro': major ---- - -Updates where files are generated by `astro sync`. - -To avoid collisions with files generated by integrations, any file generated by Astro in `/.astro/` is now moved to `/.astro/astro/`. It should only break usage of JSON Schemas for legacy data collections: - -```diff -{ -- "$schema": "../../../.astro/collections/authors.schema.json", -+ "$schema": "../../../.astro/astro/collections/authors.schema.json", - "name": "Armand", - "skills": ["Astro", "Starlight"] -} -``` From 9109991c606dfc00967773626743410e4a90517a Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 14:02:11 +0200 Subject: [PATCH 11/16] feat: adjust --- packages/astro/src/content/consts.ts | 11 +++++------ packages/astro/src/content/content-layer.ts | 10 ++-------- packages/astro/src/preferences/constants.ts | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/astro/src/content/consts.ts b/packages/astro/src/content/consts.ts index 71bd48864c83..51eb6b78ed02 100644 --- a/packages/astro/src/content/consts.ts +++ b/packages/astro/src/content/consts.ts @@ -33,12 +33,11 @@ export const CONTENT_FLAGS = [ CONTENT_MODULE_FLAG, ] as const; -export const CONTENT_TYPES_FILE = 'astro/content.d.ts'; - +export const CONTENT_TYPES_FILE = 'content.d.ts'; export const DATA_STORE_FILE = 'data-store.json'; -export const ASSET_IMPORTS_FILE = 'astro/content-assets.mjs'; -export const MODULES_IMPORTS_FILE = 'astro/content-modules.mjs'; -export const COLLECTIONS_MANIFEST_FILE = 'astro/collections/collections.json'; -export const COLLECTIONS_DIR = 'astro/collections/' +export const ASSET_IMPORTS_FILE = 'content-assets.mjs'; +export const MODULES_IMPORTS_FILE = 'content-modules.mjs'; +export const COLLECTIONS_MANIFEST_FILE = 'collections/collections.json'; +export const COLLECTIONS_DIR = 'collections/' export const CONTENT_LAYER_TYPE = 'content_layer'; diff --git a/packages/astro/src/content/content-layer.ts b/packages/astro/src/content/content-layer.ts index 677b14acac19..6a0e0045fb63 100644 --- a/packages/astro/src/content/content-layer.ts +++ b/packages/astro/src/content/content-layer.ts @@ -19,8 +19,6 @@ import { getEntryDataAndImages, globalContentConfigObserver, } from './utils.js'; -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; export interface ContentLayerOptions { store: MutableDataStore; @@ -217,11 +215,10 @@ export class ContentLayer { }), ); await fs.mkdir(this.#settings.config.cacheDir, { recursive: true }); + await fs.mkdir(this.#settings.dotAstroDir, { recursive: true }); const cacheFile = getDataStoreFile(this.#settings); await this.#store.writeToDisk(cacheFile); const assetImportsFile = new URL(ASSET_IMPORTS_FILE, this.#settings.dotAstroDir); - const dotAstroAstroDir = dirname(fileURLToPath(assetImportsFile)); - await fs.mkdir(dotAstroAstroDir, { recursive: true }); await this.#store.writeAssetImports(assetImportsFile); const modulesImportsFile = new URL(MODULES_IMPORTS_FILE, this.#settings.dotAstroDir); await this.#store.writeModuleImports(modulesImportsFile); @@ -283,10 +280,7 @@ export async function simpleLoader( */ export function getDataStoreFile(settings: AstroSettings, isDev?: boolean) { isDev ??= process?.env.NODE_ENV === 'development'; - return new URL( - DATA_STORE_FILE, - isDev ? new URL('./astro/', settings.dotAstroDir) : settings.config.cacheDir, - ); + return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir); } function contentLayerSingleton() { diff --git a/packages/astro/src/preferences/constants.ts b/packages/astro/src/preferences/constants.ts index 9fd21af05351..108787a28bbb 100644 --- a/packages/astro/src/preferences/constants.ts +++ b/packages/astro/src/preferences/constants.ts @@ -1 +1 @@ -export const SETTINGS_FILE = 'astro/settings.json'; +export const SETTINGS_FILE = 'settings.json'; From 92bdac73c15499248e22ced18ce7dd8a7ea44612 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 14:05:51 +0200 Subject: [PATCH 12/16] feat: move dts to root --- packages/astro/src/actions/consts.ts | 2 +- packages/astro/src/content/types-generator.ts | 13 ++++++------ packages/astro/src/env/constants.ts | 2 +- packages/astro/test/astro-sync.test.js | 20 +++++++++---------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/astro/src/actions/consts.ts b/packages/astro/src/actions/consts.ts index beb8c45b641d..6a55386d869a 100644 --- a/packages/astro/src/actions/consts.ts +++ b/packages/astro/src/actions/consts.ts @@ -1,6 +1,6 @@ export const VIRTUAL_MODULE_ID = 'astro:actions'; export const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID; -export const ACTIONS_TYPES_FILE = 'astro/actions.d.ts'; +export const ACTIONS_TYPES_FILE = 'actions.d.ts'; export const VIRTUAL_INTERNAL_MODULE_ID = 'astro:internal-actions'; export const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = '\0astro:internal-actions'; export const NOOP_ACTIONS = '\0noop-actions'; diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index 3f19841a3c1d..dc01f06ae002 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -571,10 +571,8 @@ async function writeContentFiles({ ); } - fs.mkdirSync(settings.dotAstroDir, { recursive: true }); - const configPathRelativeToCacheDir = normalizeConfigPath( - new URL('astro', settings.dotAstroDir).pathname, + settings.dotAstroDir.pathname, contentPaths.config.url.pathname, ); @@ -590,11 +588,14 @@ async function writeContentFiles({ contentConfig ? `typeof import(${configPathRelativeToCacheDir})` : 'never', ); + fs.mkdirSync(settings.dotAstroDir, { recursive: true }); // If it's the first time, we inject types the usual way. sync() will handle creating files and references. If it's not the first time, we just override the dts content if (settings.injectedTypes.some((t) => t.filename === CONTENT_TYPES_FILE)) { - const filePath = fileURLToPath(new URL(CONTENT_TYPES_FILE, settings.dotAstroDir)); - await fs.promises.mkdir(path.dirname(filePath), { recursive: true }); - await fs.promises.writeFile(filePath, typeTemplateContent, 'utf-8'); + await fs.promises.writeFile( + new URL(CONTENT_TYPES_FILE, settings.dotAstroDir), + typeTemplateContent, + 'utf-8', + ); } else { settings.injectedTypes.push({ filename: CONTENT_TYPES_FILE, diff --git a/packages/astro/src/env/constants.ts b/packages/astro/src/env/constants.ts index ac2c2c297ff6..220f63373c16 100644 --- a/packages/astro/src/env/constants.ts +++ b/packages/astro/src/env/constants.ts @@ -5,7 +5,7 @@ export const VIRTUAL_MODULES_IDS = { }; export const VIRTUAL_MODULES_IDS_VALUES = new Set(Object.values(VIRTUAL_MODULES_IDS)); -export const ENV_TYPES_FILE = 'astro/env.d.ts'; +export const ENV_TYPES_FILE = 'env.d.ts'; const PKG_BASE = new URL('../../', import.meta.url); export const MODULE_TEMPLATE_URL = new URL('templates/env.mjs', PKG_BASE); diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index f12fb5bc42ed..ef9ec92d45a3 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -125,13 +125,13 @@ describe('astro sync', () => { '.astro/types.d.ts', `/// `, ); - fixture.thenFileShouldExist('.astro/astro/content.d.ts'); + fixture.thenFileShouldExist('.astro/content.d.ts'); fixture.thenFileContentShouldInclude( - '.astro/astro/content.d.ts', + '.astro/content.d.ts', `declare module 'astro:content' {`, 'Types file does not include `astro:content` module declaration', ); - fixture.thenFileShouldBeValidTypescript('.astro/astro/content.d.ts'); + fixture.thenFileShouldBeValidTypescript('.astro/content.d.ts'); }); it('Writes types for empty collections', async () => { @@ -139,7 +139,7 @@ describe('astro sync', () => { fixture.clean(); await fixture.whenSyncing(); fixture.thenFileContentShouldInclude( - '.astro/astro/content.d.ts', + '.astro/content.d.ts', `"blog": Record { 'Types file does not include empty collection type', ); fixture.thenFileContentShouldInclude( - '.astro/astro/content.d.ts', + '.astro/content.d.ts', `"blogMeta": Record { '.astro/types.d.ts', `/// `, ); - fixture.thenFileShouldExist('.astro/astro/env.d.ts'); + fixture.thenFileShouldExist('.astro/env.d.ts'); fixture.thenFileContentShouldInclude( - '.astro/astro/env.d.ts', + '.astro/env.d.ts', `declare module 'astro:env/client' {`, 'Types file does not include `astro:env` module declaration', ); @@ -212,13 +212,13 @@ describe('astro sync', () => { '.astro/types.d.ts', `/// `, ); - fixture.thenFileShouldExist('.astro/astro/actions.d.ts'); + fixture.thenFileShouldExist('.astro/actions.d.ts'); fixture.thenFileContentShouldInclude( - '.astro/astro/actions.d.ts', + '.astro/actions.d.ts', `declare module "astro:actions" {`, 'Types file does not include `astro:actions` module declaration', ); - fixture.thenFileShouldBeValidTypescript('.astro/astro/actions.d.ts'); + fixture.thenFileShouldBeValidTypescript('.astro/actions.d.ts'); }); }); }); From a8503949c8bcdfc90aeff5c5db47773e57abbed7 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 14:07:51 +0200 Subject: [PATCH 13/16] chore: remove duplicate folder creation --- packages/astro/src/content/types-generator.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index dc01f06ae002..330c1973dad7 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -588,7 +588,6 @@ async function writeContentFiles({ contentConfig ? `typeof import(${configPathRelativeToCacheDir})` : 'never', ); - fs.mkdirSync(settings.dotAstroDir, { recursive: true }); // If it's the first time, we inject types the usual way. sync() will handle creating files and references. If it's not the first time, we just override the dts content if (settings.injectedTypes.some((t) => t.filename === CONTENT_TYPES_FILE)) { await fs.promises.writeFile( From 091dbe594e9b15a629d810a7216edf101952bb60 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 14:25:10 +0200 Subject: [PATCH 14/16] feat: fix test and add codegenDir --- packages/astro/src/integrations/hooks.ts | 10 +++++++++- packages/astro/src/types/public/integrations.ts | 1 + packages/astro/test/astro-sync.test.js | 6 +++--- packages/astro/test/units/integrations/api.test.js | 8 ++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 5ac21c435a5f..1bd6c21651b6 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -112,13 +112,17 @@ export function getToolbarServerCommunicationHelpers(server: ViteDevServer) { // Will match any invalid characters (will be converted to _). We only allow a-zA-Z0-9.-_ const SAFE_CHARS_RE = /[^\w.-]/g; +export function normalizeCodegenDir(integrationName: string): string { + return `./integrations/${integrationName.replace(SAFE_CHARS_RE, '_')}/`; +} + export function normalizeInjectedTypeFilename(filename: string, integrationName: string): string { if (!filename.endsWith('.d.ts')) { throw new Error( `Integration ${bold(integrationName)} is injecting a type that does not end with "${bold('.d.ts')}"`, ); } - return `./integrations/${integrationName.replace(SAFE_CHARS_RE, '_')}/${filename.replace(SAFE_CHARS_RE, '_')}`; + return `${normalizeCodegenDir(integrationName)}${filename.replace(SAFE_CHARS_RE, '_')}`; } export async function runHookConfigSetup({ @@ -151,6 +155,9 @@ export async function runHookConfigSetup({ for (let i = 0; i < updatedConfig.integrations.length; i++) { const integration = updatedConfig.integrations[i]; + const codegenDir = new URL(normalizeCodegenDir(integration.name), settings.dotAstroDir); + await fs.promises.mkdir(codegenDir, { recursive: true }); + /** * By making integration hooks optional, Astro can now ignore null or undefined Integrations * instead of giving an internal error most people can't read @@ -170,6 +177,7 @@ export async function runHookConfigSetup({ config: updatedConfig, command, isRestart, + codegenDir, addRenderer(renderer: AstroRenderer) { if (!renderer.name) { throw new Error(`Integration ${bold(integration.name)} has an unnamed renderer.`); diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 78c4104f1bd1..9621f750e27d 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -168,6 +168,7 @@ export interface BaseIntegrationHooks { config: AstroConfig; command: 'dev' | 'build' | 'preview' | 'sync'; isRestart: boolean; + codegenDir: URL; updateConfig: (newConfig: DeepPartial) => AstroConfig; addRenderer: (renderer: AstroRenderer) => void; addWatchFile: (path: URL | string) => void; diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js index ef9ec92d45a3..c8a2de49c5ac 100644 --- a/packages/astro/test/astro-sync.test.js +++ b/packages/astro/test/astro-sync.test.js @@ -123,7 +123,7 @@ describe('astro sync', () => { fixture.thenFileShouldExist('.astro/types.d.ts'); fixture.thenFileContentShouldInclude( '.astro/types.d.ts', - `/// `, + `/// `, ); fixture.thenFileShouldExist('.astro/content.d.ts'); fixture.thenFileContentShouldInclude( @@ -170,7 +170,7 @@ describe('astro sync', () => { fixture.thenFileShouldExist('.astro/types.d.ts'); fixture.thenFileContentShouldInclude( '.astro/types.d.ts', - `/// `, + `/// `, ); fixture.thenFileShouldExist('.astro/env.d.ts'); fixture.thenFileContentShouldInclude( @@ -210,7 +210,7 @@ describe('astro sync', () => { fixture.thenFileShouldExist('.astro/types.d.ts'); fixture.thenFileContentShouldInclude( '.astro/types.d.ts', - `/// `, + `/// `, ); fixture.thenFileShouldExist('.astro/actions.d.ts'); fixture.thenFileContentShouldInclude( diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index 0a0233215061..f2365c006b39 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -2,6 +2,7 @@ import * as assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { validateSupportedFeatures } from '../../../dist/integrations/features-validation.js'; import { + normalizeCodegenDir, normalizeInjectedTypeFilename, runHookBuildSetup, runHookConfigSetup, @@ -12,6 +13,7 @@ const defaultConfig = { root: new URL('./', import.meta.url), srcDir: new URL('src/', import.meta.url), }; +const dotAstroDir = new URL('./.astro/', defaultConfig.root); describe('Integration API', () => { it('runHookBuildSetup should work', async () => { @@ -87,6 +89,7 @@ describe('Integration API', () => { }, ], }, + dotAstroDir, }, }); assert.equal(updatedSettings.config.site, site); @@ -122,6 +125,7 @@ describe('Integration API', () => { }, ], }, + dotAstroDir, }, }); assert.equal(updatedSettings.config.site, site); @@ -270,3 +274,7 @@ describe('normalizeInjectedTypeFilename', () => { './integrations/aA1-_____./types.d.ts', ); }); + +describe('normalizeCodegenDir', () => { + assert.equal(normalizeCodegenDir('aA1-*/_"~.'), './integrations/aA1-_____./'); +}); From 3edbe688d80282fb2164280d0c41d0e26fb1b33f Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 14:44:07 +0200 Subject: [PATCH 15/16] chore: changeset --- .changeset/three-olives-reflect.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .changeset/three-olives-reflect.md diff --git a/.changeset/three-olives-reflect.md b/.changeset/three-olives-reflect.md new file mode 100644 index 000000000000..0bbfd19600b6 --- /dev/null +++ b/.changeset/three-olives-reflect.md @@ -0,0 +1,22 @@ +--- +'astro': minor +--- + +Adds `codegenDir` to integrations `astro:config:setup` hook + +In 4.14, we introduced `injectTypes` on `astro:config:done`. Under the hood, it creates a file at `/.astro/integrations/`. + +In this release, the folder URL is now available in `astro:config:setup` as `codegenDir`. It allows you to have space without risking being overriden by another integration, Astro or overriding another integration. This directory is always created before any hook so it's safe to write files directly: + +```js +import { writeFileSync } from 'node:fs' + +const integration = { + name: 'my-integration', + hooks: { + 'astro:config:setup': ({ codegenDir }) => { + writeFileSync(new URL('cache.json', codegenDir), '{}', 'utf-8') + } + } +} +``` From 0c30ceb1dc4ba9e1e24b7e4d5b1360479ae97799 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 18 Sep 2024 15:35:03 +0200 Subject: [PATCH 16/16] Update three-olives-reflect.md --- .changeset/three-olives-reflect.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.changeset/three-olives-reflect.md b/.changeset/three-olives-reflect.md index 0bbfd19600b6..5f8ea9f2b166 100644 --- a/.changeset/three-olives-reflect.md +++ b/.changeset/three-olives-reflect.md @@ -2,11 +2,13 @@ 'astro': minor --- -Adds `codegenDir` to integrations `astro:config:setup` hook +Adds a new `codegenDir` URL to integrations `astro:config:setup` hook -In 4.14, we introduced `injectTypes` on `astro:config:done`. Under the hood, it creates a file at `/.astro/integrations/`. +In 4.14, we introduced the `injectTypes` utility on the `astro:config:done` hook. It allows to create `.d.ts` files and make their types available to users projects automatically. Under the hood, it creates a file in `/.astro/integrations/`. -In this release, the folder URL is now available in `astro:config:setup` as `codegenDir`. It allows you to have space without risking being overriden by another integration, Astro or overriding another integration. This directory is always created before any hook so it's safe to write files directly: +While `.astro` has always been the preferred place to write code generated files, it has also been prone to mistakes. For example, you can write a `.astro/types.d.ts` file, breaking Astro types. Or you can create a file that overrides a file created by another integration. + +In this release, `/.astro/integrations/` is now exposed in the `astro:config:setup` hook as `codegenDir`. It allows you to have a dedicated folder, avoiding conflicts with another integration or Astro. This directory is always created before any hook runs so it's safe to write files to it directly: ```js import { writeFileSync } from 'node:fs'