Skip to content

Commit 7744645

Browse files
larbishfarnabaz
andauthored
feat(collections): create studio collections for AI if detected (#3709)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
1 parent c3f5108 commit 7744645

File tree

5 files changed

+87
-12
lines changed

5 files changed

+87
-12
lines changed

src/utils/config.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { loadConfig, watchConfig, createDefineConfig } from 'c12'
22
import { relative } from 'pathe'
3+
import { hasNuxtModule, useNuxt } from '@nuxt/kit'
34
import type { Nuxt } from '@nuxt/schema'
45
import type { DefinedCollection, ModuleOptions } from '../types'
56
import { defineCollection, resolveCollections } from './collection'
67
import { logger } from './dev'
8+
import { resolveStudioCollection } from './studio'
79

810
type NuxtContentConfig = {
911
collections: Record<string, DefinedCollection>
1012
}
1113

12-
const defaultConfig: NuxtContentConfig = {
13-
collections: {
14-
content: defineCollection({
15-
type: 'page',
16-
source: '**/*',
17-
}),
18-
},
19-
}
14+
const createDefaultCollections = (): NuxtContentConfig['collections'] => ({
15+
content: defineCollection({
16+
type: 'page',
17+
source: '**/*',
18+
}),
19+
})
2020

2121
export const defineContentConfig = createDefineConfig<NuxtContentConfig>()
2222

@@ -68,7 +68,14 @@ export async function loadContentConfig(nuxt: Nuxt, options?: ModuleOptions) {
6868
logger.warn('No content configuration found, falling back to default collection. In order to have full control over your collections, create the config file in project root. See: https://content.nuxt.com/docs/getting-started/installation')
6969
}
7070

71-
const collections = resolveCollections(hasNoCollections ? defaultConfig.collections : collectionsConfig)
71+
const finalCollectionsConfig = hasNoCollections ? createDefaultCollections() : collectionsConfig
72+
73+
// If nuxt-studio is installed, automatically configure studio collection
74+
if (hasNuxtModule('nuxt-studio', nuxt || useNuxt())) {
75+
resolveStudioCollection(nuxt, finalCollectionsConfig)
76+
}
77+
78+
const collections = resolveCollections(finalCollectionsConfig)
7279

7380
return { collections }
7481
}

src/utils/studio.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { z } from 'zod'
2+
import type { Nuxt } from '@nuxt/schema'
3+
import type { DefinedCollection } from '../types'
4+
import { defineCollection } from './collection'
5+
6+
interface StudioAIConfig {
7+
apiKey?: string
8+
context?: {
9+
title?: string
10+
description?: string
11+
tone?: string
12+
style?: string
13+
collection?: {
14+
name?: string
15+
folder?: string
16+
}
17+
}
18+
}
19+
20+
const DEFAULT_STUDIO_COLLECTION_NAME = 'studio'
21+
const DEFAULT_STUDIO_COLLECTION_FOLDER = '.studio'
22+
23+
/**
24+
* Resolves studio collection configuration when nuxt-studio is installed.
25+
* Automatically creates a studio collection and adds exclude patterns to other collections.
26+
*/
27+
export function resolveStudioCollection(
28+
nuxt: Nuxt,
29+
collectionsConfig: Record<string, DefinedCollection>,
30+
): void {
31+
/* @ts-expect-error - studio is not typed */
32+
const studioAIConfig: StudioAIConfig = nuxt.options.studio?.ai || {}
33+
if (!studioAIConfig.apiKey) {
34+
return
35+
}
36+
37+
const studioCollectionName = studioAIConfig.context?.collection?.name || DEFAULT_STUDIO_COLLECTION_NAME
38+
const studioFolder = studioAIConfig.context?.collection?.folder || DEFAULT_STUDIO_COLLECTION_FOLDER
39+
const studioPattern = `${studioFolder}/**`
40+
41+
// Add studio collection if it doesn't exist
42+
if (!collectionsConfig[studioCollectionName]) {
43+
collectionsConfig[studioCollectionName] = defineCollection({
44+
type: 'data',
45+
source: studioPattern,
46+
schema: z.object({
47+
rawbody: z.string(),
48+
}),
49+
})
50+
}
51+
52+
// Add exclude pattern to all existing collections except studio
53+
for (const [name, collection] of Object.entries(collectionsConfig)) {
54+
if (name === studioCollectionName || !collection.source) {
55+
continue
56+
}
57+
58+
// Add exclude pattern to each source
59+
for (const source of collection.source) {
60+
if (!source.exclude) {
61+
source.exclude = []
62+
}
63+
if (!source.exclude.includes(studioPattern)) {
64+
source.exclude.push(studioPattern)
65+
}
66+
}
67+
}
68+
}

test/basic.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('basic', async () => {
3434
describe('`content.config.ts`', async () => {
3535
test('Default collection is defined', async () => {
3636
const rootDir = resolver.resolve('./fixtures/basic')
37-
const config = await loadContentConfig({ options: { _layers: [{ config: { rootDir } }] } } as Nuxt)
37+
const config = await loadContentConfig({ options: { _installedModules: [], modules: [], _layers: [{ config: { rootDir } }] } } as Nuxt)
3838

3939
// Pages collection + info collection
4040
expect(config.collections.length).toBe(2)

test/csv.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('csv single-file collection', async () => {
3232
describe('`content.config.ts`', async () => {
3333
test('single-file csv source is resolved', async () => {
3434
const rootDir = resolver.resolve('./fixtures/csv')
35-
const config = await loadContentConfig({ options: { _layers: [{ config: { rootDir } }] } } as Nuxt)
35+
const config = await loadContentConfig({ options: { _installedModules: [], modules: [], _layers: [{ config: { rootDir } }] } } as Nuxt)
3636

3737
expect(config.collections.map(c => c.name)).toContain('people')
3838

test/empty.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('empty', async () => {
3737
})
3838
test('Default collection is defined', async () => {
3939
const rootDir = resolver.resolve('./fixtures/empty')
40-
const config = await loadContentConfig({ options: { _layers: [{ config: { rootDir } }] } } as Nuxt)
40+
const config = await loadContentConfig({ options: { _installedModules: [], modules: [], _layers: [{ config: { rootDir } }] } } as Nuxt)
4141

4242
// Pages collection + info collection
4343
expect(config.collections.length).toBe(2)

0 commit comments

Comments
 (0)