Skip to content

Commit

Permalink
refactor: improve collection source management
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz committed Nov 2, 2024
1 parent 79629dc commit 53a86ae
Show file tree
Hide file tree
Showing 18 changed files with 78 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/presets/cloudflare-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default definePreset({
nitroConfig.publicAssets.push({ dir: join(nitroConfig.buildDir!, 'content', 'raw'), maxAge: 60 })
nitroConfig.handlers.push({
route: '/api/content/:collection/database.sql',
handler: resolver.resolve('./runtime/presets/cloudflare-pages/database.sql'),
handler: resolver.resolve('./runtime/presets/cloudflare-pages/database-handler'),
})
},

Expand Down
2 changes: 1 addition & 1 deletion src/presets/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default definePreset({
nitroConfig.alias['#content/dump'] = addTemplate(fullDatabaseCompressedDumpTemplate(manifest)).dst
nitroConfig.handlers.push({
route: '/api/content/:collection/database.sql',
handler: resolver.resolve('./runtime/presets/node/database.sql'),
handler: resolver.resolve('./runtime/presets/node/database-handler'),
})
},
})
File renamed without changes.
3 changes: 2 additions & 1 deletion src/types/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type CollectionSource = {
}

export interface ResolvedCollectionSource extends CollectionSource {
_resolved: true
prepare?: (nuxt: Nuxt) => Promise<void>
cwd: string
}
Expand All @@ -37,7 +38,7 @@ export type Collection<T extends ZodRawShape = ZodRawShape> = PageCollection<T>

export interface DefinedCollection<T extends ZodRawShape = ZodRawShape> {
type: CollectionType
source: CollectionSource | string | undefined
source: ResolvedCollectionSource | undefined
schema: ZodObject<T>
extendedSchema: ZodObject<T>
}
Expand Down
43 changes: 15 additions & 28 deletions src/utils/collection.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { join } from 'node:path'
import { pascalCase } from 'scule'
import type { ZodObject, ZodOptionalDef, ZodRawShape, ZodStringDef, ZodType } from 'zod'
import type { Collection, ResolvedCollection, CollectionSource, DefinedCollection, ResolvedCollectionSource } from '../types/collection'
import { defineLocalSource, defineGitHubSource } from './source'
import { metaSchema, pageSchema } from './schema'
import type { ZodFieldType } from './zod'
import { getUnderlyingType, ZodToSqlFieldTypes, z } from './zod'
import { downloadRepository, parseGitHubUrl } from './git'
import { logger } from './dev'

interface ResolveOptions {
rootDir: string
}

const JSON_FIELDS_TYPES = ['ZodObject', 'ZodArray', 'ZodRecord', 'ZodIntersection', 'ZodUnion', 'ZodAny']

const getTableName = (name: string) => `content_${name}`
Expand All @@ -26,13 +21,13 @@ export function defineCollection<T extends ZodRawShape>(collection: Collection<T

return {
type: collection.type,
source: collection.source,
source: resolveSource(collection.source),
schema: collection.schema || z.object({}),
extendedSchema: schema,
}
}

export function resolveCollection(name: string, collection: DefinedCollection, opts: ResolveOptions): ResolvedCollection | undefined {
export function resolveCollection(name: string, collection: DefinedCollection): ResolvedCollection | undefined {
if (/^[a-z_]\w*$/i.test(name) === false) {
logger.warn([
`Collection name "${name}" is invalid. Collection names must be valid JavaScript identifiers. This collection will be ignored.`,
Expand All @@ -46,7 +41,7 @@ export function resolveCollection(name: string, collection: DefinedCollection, o
name,
type: collection.type || 'page',
pascalName: pascalCase(name),
source: resolveSource(collection.source, opts),
source: collection.source,
tableName: getTableName(name),
tableDefinition: generateCollectionTableDefinition(name, collection, { drop: true }),
generatedFields: {
Expand All @@ -62,7 +57,7 @@ export function resolveCollection(name: string, collection: DefinedCollection, o
}
}

export function resolveCollections(collections: Record<string, DefinedCollection>, opts: ResolveOptions): ResolvedCollection[] {
export function resolveCollections(collections: Record<string, DefinedCollection>): ResolvedCollection[] {
collections._info = defineCollection({
type: 'data',
schema: z.object({
Expand All @@ -71,39 +66,31 @@ export function resolveCollections(collections: Record<string, DefinedCollection
})

return Object.entries(collections)
.map(([name, collection]) => resolveCollection(name, collection, opts))
.map(([name, collection]) => resolveCollection(name, collection))
.filter(Boolean) as ResolvedCollection[]
}

/**
* Process collection source and return refined source
*/
function resolveSource(source: string | CollectionSource | undefined, opts: ResolveOptions): ResolvedCollectionSource | undefined {
function resolveSource(source: string | CollectionSource | undefined): ResolvedCollectionSource | undefined {
if (!source) {
return undefined
}

const result: ResolvedCollectionSource = {
cwd: '',
...(typeof source === 'string' ? { path: source } : source),
if (typeof source === 'string') {
return defineLocalSource({ path: source })
}

const repository = result?.repository && parseGitHubUrl(result.repository!)
if (repository) {
const { org, repo, branch } = repository
result.cwd = join(opts.rootDir, '.data', 'content', `github-${org}-${repo}-${branch}`)

result.prepare = async () => {
await downloadRepository(
`https://github.com/${org}/${repo}/archive/refs/heads/${branch}.tar.gz`,
result.cwd!,
)
}
if ((source as ResolvedCollectionSource)._resolved) {
return source as ResolvedCollectionSource
}

result.cwd = result.cwd || join(opts.rootDir, 'content')
if (source.repository) {
return defineGitHubSource(source)
}

return result
return defineLocalSource(source)
}

export function parseSourceBase(source: CollectionSource) {
Expand Down
6 changes: 3 additions & 3 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const defaultConfig = {
export async function loadContentConfig(rootDir: string, opts: { defaultFallback?: boolean } = {}) {
const { config, configFile } = await loadConfig({ name: 'content', cwd: rootDir })

if (!configFile && opts?.defaultFallback) {
if ((!configFile || configFile === 'content.config') && opts.defaultFallback) {
logger.warn('`content.config.ts` is not 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/getting-started/installation')
return {
collections: resolveCollections(defaultConfig.collections, { rootDir }),
collections: resolveCollections(defaultConfig.collections),
}
}

return {
collections: resolveCollections(config.collections || {}, { rootDir }),
collections: resolveCollections(config.collections || {}),
}
}
36 changes: 36 additions & 0 deletions src/utils/source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { join } from 'pathe'
import type { CollectionSource, ResolvedCollectionSource } from '../types/collection'
import { downloadRepository, parseGitHubUrl } from './git'

export function defineLocalSource(source: CollectionSource): ResolvedCollectionSource {
const resolvedSource: ResolvedCollectionSource = {
_resolved: true,
...source,
cwd: '',
prepare: async (nuxt) => {
resolvedSource.cwd = source.cwd || join(nuxt.options.rootDir, 'content')
},
}
return resolvedSource
}

export function defineGitHubSource(source: CollectionSource): ResolvedCollectionSource {
const resolvedSource: ResolvedCollectionSource = {
_resolved: true,
...source,
cwd: '',
prepare: async (nuxt) => {
const repository = source?.repository && parseGitHubUrl(source.repository!)
if (repository) {
const { org, repo, branch } = repository
resolvedSource.cwd = join(nuxt.options.rootDir, '.data', 'content', `github-${org}-${repo}-${branch}`)

await downloadRepository(
`https://github.com/${org}/${repo}/archive/refs/heads/${branch}.tar.gz`,
resolvedSource.cwd!,
)
}
},
}
return resolvedSource
}
1 change: 1 addition & 0 deletions test/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('empty', async () => {
test('Default collection is defined', async () => {
const rootDir = fileURLToPath(new URL('./fixtures/empty', import.meta.url))
const config = await loadContentConfig(rootDir, { defaultFallback: true })
console.log(config.collections)

// Pages collection + _info collection
expect(config.collections.length).toBe(2)
Expand Down
12 changes: 10 additions & 2 deletions test/unit/defineCollection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ describe('defineCollection', () => {
})
expect(collection).toMatchObject({
type: 'page',
source: 'pages/**',
source: {
_resolved: true,
cwd: '',
path: 'pages/**',
},
})

expect(collection.schema.shape).not.ownProperty('title')
Expand Down Expand Up @@ -81,7 +85,11 @@ describe('defineCollection', () => {

expect(collection).toMatchObject({
type: 'data',
source: 'data/**',
source: {
_resolved: true,
cwd: '',
path: 'data/**',
},
})

expect(collection.schema.shape).toHaveProperty('customField')
Expand Down
4 changes: 2 additions & 2 deletions test/unit/generateCollectionInsert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('generateCollectionInsert', () => {
otherField2: z.boolean().default(true),
date: z.date().default(new Date('2022-01-01')),
}),
}), { rootDir: '~' })!
}))!
const sql = generateCollectionInsert(collection, {
_id: 'foo.md',
stem: 'foo',
Expand All @@ -39,7 +39,7 @@ describe('generateCollectionInsert', () => {
otherField2: z.boolean().default(true),
date: z.date().default(new Date('2022-01-01')),
}),
}), { rootDir: '~' })!
}))!
const sql = generateCollectionInsert(collection, {
_id: 'foo.md',
stem: 'foo',
Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.csv.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('Parser (.csv)', () => {
schema: z.object({
body: z.any(),
}),
}), { rootDir: '~' })!
}))!
for (const csv of csvs) {
test(`${csv.replace(/\n/g, '-')}`, async () => {
const parsed = await parseContent('content/index.csv', csv, collection)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Parser (json)', () => {
schema: z.object({
body: z.any(),
}),
}), { rootDir: '~' })!
}))!
test('key:value', async () => {
const parsed = await parseContent('content/index.json', json, collection)

Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.md-highlighter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Highlighter', () => {
source: 'content/**',
schema: z.object({
}),
}), { rootDir: '~' })!
}))!

test('themed', async () => {
const parsed = await parseContent('content/index.md', [
Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.md.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Parser (.md)', () => {
source: 'content/**',
schema: z.object({
}),
}), { rootDir: '~' })!
}))!

test('Index file', async () => {
const parsed = await parseContent('content/index.md', '# Index', collection, nuxtMock)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.path-meta.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe('Transformer (path-meta)', () => {
source: 'content/**',
schema: z.object({
}),
}), { rootDir: '~' })!
}))!

Object.entries(testCases).forEach(([id, expected]) => {
test(id, async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/parseContent.yaml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('Parser (.yml)', () => {
schema: z.object({
body: z.any(),
}),
}), { rootDir: '~' })!
}))!
test('key:value', async () => {
const parsed = await parseContent('content/index.yml', 'key: value', collection)

Expand Down
2 changes: 1 addition & 1 deletion test/unit/resolveCollection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('resolveCollection', () => {
type: 'page',
source: 'pages/**',
})
const resolvedCollection = resolveCollection('invalid-name', collection, { rootDir: '' })
const resolvedCollection = resolveCollection('invalid-name', collection)
expect(resolvedCollection).toBeUndefined()
})
})

0 comments on commit 53a86ae

Please sign in to comment.