create-payload-app
Advanced tools
Comparing version
@@ -32,3 +32,3 @@ import { jest } from '@jest/globals'; | ||
'--db': 'mongodb', | ||
'--local-template': 'blank-3.0', | ||
'--local-template': 'blank', | ||
'--no-deps': true | ||
@@ -61,7 +61,7 @@ }; | ||
[ | ||
'blank-3.0', | ||
'blank', | ||
'mongodb' | ||
], | ||
[ | ||
'blank-3.0', | ||
'blank', | ||
'postgres' | ||
@@ -68,0 +68,0 @@ ] |
@@ -6,10 +6,19 @@ import execa from 'execa'; | ||
try { | ||
// Check for yarn.lock, package-lock.json, or pnpm-lock.yaml | ||
// Check for flag or lockfile | ||
let detected = 'npm'; | ||
if (cliArgs?.['--use-pnpm'] || fse.existsSync(`${projectDir}/pnpm-lock.yaml`) || await commandExists('pnpm')) { | ||
if (cliArgs?.['--use-pnpm'] || fse.existsSync(`${projectDir}/pnpm-lock.yaml`)) { | ||
detected = 'pnpm'; | ||
} else if (cliArgs?.['--use-yarn'] || fse.existsSync(`${projectDir}/yarn.lock`) || await commandExists('yarn')) { | ||
} else if (cliArgs?.['--use-yarn'] || fse.existsSync(`${projectDir}/yarn.lock`)) { | ||
detected = 'yarn'; | ||
} else if (cliArgs?.['--use-npm'] || fse.existsSync(`${projectDir}/package-lock.json`)) { | ||
detected = 'npm'; | ||
} else { | ||
// Otherwise check for existing commands | ||
if (await commandExists('pnpm')) { | ||
detected = 'pnpm'; | ||
} else if (await commandExists('yarn')) { | ||
detected = 'yarn'; | ||
} else { | ||
detected = 'npm'; | ||
} | ||
} | ||
@@ -16,0 +25,0 @@ return detected; |
@@ -53,3 +53,3 @@ import * as p from '@clack/prompts'; | ||
installSpinner.start('Installing Payload and dependencies...'); | ||
const configurationResult = installAndConfigurePayload({ | ||
const configurationResult = await installAndConfigurePayload({ | ||
...args, | ||
@@ -116,3 +116,3 @@ nextAppDetails, | ||
} | ||
function installAndConfigurePayload(args) { | ||
async function installAndConfigurePayload(args) { | ||
const { '--debug': debug, nextAppDetails: { isSrcDir, nextAppDir, nextConfigPath } = {}, nextConfigType, projectDir, useDistFiles } = args; | ||
@@ -134,3 +134,3 @@ if (!nextAppDir || !nextConfigPath) { | ||
} | ||
const templateFilesPath = dirname.endsWith('dist') || useDistFiles ? path.resolve(dirname, '../..', 'dist/template') : path.resolve(dirname, '../../../../templates/blank-3.0'); | ||
const templateFilesPath = dirname.endsWith('dist') || useDistFiles ? path.resolve(dirname, '../..', 'dist/template') : path.resolve(dirname, '../../../../templates/blank'); | ||
logDebug(`Using template files from: ${templateFilesPath}`); | ||
@@ -156,3 +156,3 @@ if (!fs.existsSync(templateFilesPath)) { | ||
// Wrap next.config.js with withPayload | ||
wrapNextConfig({ | ||
await wrapNextConfig({ | ||
nextConfigPath, | ||
@@ -184,3 +184,4 @@ nextConfigType | ||
const isSrcDir = fs.existsSync(path.resolve(projectDir, 'src')); | ||
const nextConfigPath = (await globby('next.config.*js', { | ||
// Match next.config.js, next.config.ts, next.config.mjs, next.config.cjs | ||
const nextConfigPath = (await globby('next.config.(\\w)?(t|j)s', { | ||
absolute: true, | ||
@@ -193,6 +194,38 @@ cwd: projectDir | ||
isSrcDir, | ||
nextConfigPath: undefined | ||
isSupportedNextVersion: false, | ||
nextConfigPath: undefined, | ||
nextVersion: null | ||
}; | ||
} | ||
const packageObj = await fse.readJson(path.resolve(projectDir, 'package.json')); | ||
// Check if Next.js version is new enough | ||
let nextVersion = null; | ||
if (packageObj.dependencies?.next) { | ||
nextVersion = packageObj.dependencies.next; | ||
// Match versions using regex matching groups | ||
const versionMatch = /(?<major>\d+)/.exec(nextVersion); | ||
if (!versionMatch) { | ||
p.log.warn(`Could not determine Next.js version from ${nextVersion}`); | ||
return { | ||
hasTopLevelLayout: false, | ||
isSrcDir, | ||
isSupportedNextVersion: false, | ||
nextConfigPath, | ||
nextVersion | ||
}; | ||
} | ||
const { major } = versionMatch.groups; | ||
const majorVersion = parseInt(major); | ||
if (majorVersion < 15) { | ||
return { | ||
hasTopLevelLayout: false, | ||
isSrcDir, | ||
isSupportedNextVersion: false, | ||
nextConfigPath, | ||
nextVersion | ||
}; | ||
} | ||
} | ||
const isSupportedNextVersion = true; | ||
// Check if Payload already installed | ||
if (packageObj.dependencies?.payload) { | ||
@@ -203,3 +236,5 @@ return { | ||
isSrcDir, | ||
nextConfigPath | ||
isSupportedNextVersion, | ||
nextConfigPath, | ||
nextVersion | ||
}; | ||
@@ -228,5 +263,7 @@ } | ||
isSrcDir, | ||
isSupportedNextVersion, | ||
nextAppDir, | ||
nextConfigPath, | ||
nextConfigType: configType | ||
nextConfigType: configType, | ||
nextVersion | ||
}; | ||
@@ -236,2 +273,5 @@ } | ||
const { nextConfigPath, packageObj } = args; | ||
if (nextConfigPath.endsWith('.ts')) { | ||
return 'ts'; | ||
} | ||
if (nextConfigPath.endsWith('.mjs')) { | ||
@@ -238,0 +278,0 @@ return 'esm'; |
@@ -22,5 +22,17 @@ const mongodbReplacement = { | ||
}; | ||
const sqliteReplacement = { | ||
configReplacement: (envName = 'DATABASE_URI')=>[ | ||
' db: sqliteAdapter({', | ||
' client: {', | ||
` url: process.env.${envName} || '',`, | ||
' },', | ||
' }),' | ||
], | ||
importReplacement: "import { sqliteAdapter } from '@payloadcms/db-sqlite'", | ||
packageName: '@payloadcms/db-sqlite' | ||
}; | ||
export const dbReplacements = { | ||
mongodb: mongodbReplacement, | ||
postgres: postgresReplacement | ||
postgres: postgresReplacement, | ||
sqlite: sqliteReplacement | ||
}; | ||
@@ -27,0 +39,0 @@ const vercelBlobStorageReplacement = { |
@@ -13,2 +13,8 @@ import * as p from '@clack/prompts'; | ||
value: 'postgres' | ||
}, | ||
sqlite: { | ||
dbConnectionPrefix: 'file:./', | ||
dbConnectionSuffix: '.db', | ||
title: 'SQLite (beta)', | ||
value: 'sqlite' | ||
} | ||
@@ -27,12 +33,6 @@ }; | ||
message: `Select a database`, | ||
options: [ | ||
{ | ||
label: 'MongoDB', | ||
value: 'mongodb' | ||
}, | ||
{ | ||
label: 'Postgres', | ||
value: 'postgres' | ||
} | ||
] | ||
options: Object.values(dbChoiceRecord).map((dbChoice)=>({ | ||
label: dbChoice.title, | ||
value: dbChoice.value | ||
})) | ||
}); | ||
@@ -43,3 +43,3 @@ if (p.isCancel(dbType)) process.exit(0); | ||
let dbUri = undefined; | ||
const initialDbUri = `${dbChoice.dbConnectionPrefix}${projectName === '.' ? `payload-${getRandomDigitSuffix()}` : slugify(projectName)}`; | ||
const initialDbUri = `${dbChoice.dbConnectionPrefix}${projectName === '.' ? `payload-${getRandomDigitSuffix()}` : slugify(projectName)}${dbChoice.dbConnectionSuffix || ''}`; | ||
if (args['--db-accept-recommended']) { | ||
@@ -46,0 +46,0 @@ dbUri = initialDbUri; |
@@ -17,3 +17,3 @@ import { error, info } from '../utils/log.js'; | ||
description: 'Blank 3.0 Template', | ||
url: 'https://github.com/payloadcms/payload/templates/blank-3.0#beta' | ||
url: 'https://github.com/payloadcms/payload/templates/blank#beta' | ||
}, | ||
@@ -20,0 +20,0 @@ { |
@@ -62,3 +62,3 @@ import execa from 'execa'; | ||
info(`Updating Payload Next.js files...`); | ||
const templateFilesPath = dirname.endsWith('dist') ? path.resolve(dirname, '../..', 'dist/template') : path.resolve(dirname, '../../../../templates/blank-3.0'); | ||
const templateFilesPath = process.env.JEST_WORKER_ID !== undefined ? path.resolve(dirname, '../../../../templates/blank') : path.resolve(dirname, '../..', 'dist/template'); | ||
const templateSrcDir = path.resolve(templateFilesPath, 'src/app/(payload)'); | ||
@@ -65,0 +65,0 @@ copyRecursiveSync(templateSrcDir, path.resolve(projectDir, appDetails.isSrcDir ? 'src/app' : 'app', '(payload)')); |
@@ -0,18 +1,18 @@ | ||
import type { NextConfigType } from '../types.js'; | ||
export declare const withPayloadStatement: { | ||
cjs: string; | ||
esm: string; | ||
ts: string; | ||
}; | ||
type NextConfigType = 'cjs' | 'esm'; | ||
export declare const wrapNextConfig: (args: { | ||
nextConfigPath: string; | ||
nextConfigType: NextConfigType; | ||
}) => void; | ||
}) => Promise<void>; | ||
/** | ||
* Parses config content with AST and wraps it with withPayload function | ||
*/ | ||
export declare function parseAndModifyConfigContent(content: string, configType: NextConfigType): { | ||
export declare function parseAndModifyConfigContent(content: string, configType: NextConfigType): Promise<{ | ||
modifiedConfigContent: string; | ||
success: boolean; | ||
}; | ||
export {}; | ||
}>; | ||
//# sourceMappingURL=wrap-next-config.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import { parse } from '@swc/core'; | ||
import chalk from 'chalk'; | ||
@@ -6,9 +7,10 @@ import { Syntax, parseModule } from 'esprima-next'; | ||
export const withPayloadStatement = { | ||
cjs: `const { withPayload } = require('@payloadcms/next/withPayload')\n`, | ||
esm: `import { withPayload } from '@payloadcms/next/withPayload'\n` | ||
cjs: `const { withPayload } = require("@payloadcms/next/withPayload");`, | ||
esm: `import { withPayload } from "@payloadcms/next/withPayload";`, | ||
ts: `import { withPayload } from "@payloadcms/next/withPayload";` | ||
}; | ||
export const wrapNextConfig = (args)=>{ | ||
export const wrapNextConfig = async (args)=>{ | ||
const { nextConfigPath, nextConfigType: configType } = args; | ||
const configContent = fs.readFileSync(nextConfigPath, 'utf8'); | ||
const { modifiedConfigContent: newConfig, success } = parseAndModifyConfigContent(configContent, configType); | ||
const { modifiedConfigContent: newConfig, success } = await parseAndModifyConfigContent(configContent, configType); | ||
if (!success) { | ||
@@ -21,54 +23,81 @@ return; | ||
* Parses config content with AST and wraps it with withPayload function | ||
*/ export function parseAndModifyConfigContent(content, configType) { | ||
content = withPayloadStatement[configType] + content; | ||
let ast; | ||
try { | ||
ast = parseModule(content, { | ||
loc: true | ||
}); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
warning(`Unable to parse Next config. Error: ${error.message} `); | ||
warnUserWrapNotSuccessful(configType); | ||
} | ||
return { | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
} | ||
if (configType === 'esm') { | ||
const exportDefaultDeclaration = ast.body.find((p)=>p.type === Syntax.ExportDefaultDeclaration); | ||
const exportNamedDeclaration = ast.body.find((p)=>p.type === Syntax.ExportNamedDeclaration); | ||
if (!exportDefaultDeclaration && !exportNamedDeclaration) { | ||
throw new Error('Could not find ExportDefaultDeclaration in next.config.js'); | ||
} | ||
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) { | ||
const modifiedConfigContent = insertBeforeAndAfter(content, exportDefaultDeclaration.declaration.loc); | ||
*/ export async function parseAndModifyConfigContent(content, configType) { | ||
content = withPayloadStatement[configType] + '\n' + content; | ||
console.log({ | ||
configType, | ||
content | ||
}); | ||
if (configType === 'cjs' || configType === 'esm') { | ||
try { | ||
const ast = parseModule(content, { | ||
loc: true | ||
}); | ||
if (configType === 'cjs') { | ||
// Find `module.exports = X` | ||
const moduleExports = ast.body.find((p)=>p.type === Syntax.ExpressionStatement && p.expression?.type === Syntax.AssignmentExpression && p.expression.left?.type === Syntax.MemberExpression && p.expression.left.object?.type === Syntax.Identifier && p.expression.left.object.name === 'module' && p.expression.left.property?.type === Syntax.Identifier && p.expression.left.property.name === 'exports'); | ||
if (moduleExports && moduleExports.expression.right?.loc) { | ||
const modifiedConfigContent = insertBeforeAndAfter(content, moduleExports.expression.right.loc); | ||
return { | ||
modifiedConfigContent, | ||
success: true | ||
}; | ||
} | ||
return Promise.resolve({ | ||
modifiedConfigContent: content, | ||
success: false | ||
}); | ||
} else if (configType === 'esm') { | ||
const exportDefaultDeclaration = ast.body.find((p)=>p.type === Syntax.ExportDefaultDeclaration); | ||
const exportNamedDeclaration = ast.body.find((p)=>p.type === Syntax.ExportNamedDeclaration); | ||
if (!exportDefaultDeclaration && !exportNamedDeclaration) { | ||
throw new Error('Could not find ExportDefaultDeclaration in next.config.js'); | ||
} | ||
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) { | ||
const modifiedConfigContent = insertBeforeAndAfter(content, exportDefaultDeclaration.declaration.loc); | ||
return { | ||
modifiedConfigContent, | ||
success: true | ||
}; | ||
} else if (exportNamedDeclaration) { | ||
const exportSpecifier = exportNamedDeclaration.specifiers.find((s)=>s.type === 'ExportSpecifier' && s.exported?.name === 'default' && s.local?.type === 'Identifier' && s.local?.name); | ||
if (exportSpecifier) { | ||
warning('Could not automatically wrap next.config.js with withPayload.'); | ||
warning('Automatic wrapping of named exports as default not supported yet.'); | ||
warnUserWrapNotSuccessful(configType); | ||
return { | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
} | ||
} | ||
warning('Could not automatically wrap Next config with withPayload.'); | ||
warnUserWrapNotSuccessful(configType); | ||
return Promise.resolve({ | ||
modifiedConfigContent: content, | ||
success: false | ||
}); | ||
} | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
warning(`Unable to parse Next config. Error: ${error.message} `); | ||
warnUserWrapNotSuccessful(configType); | ||
} | ||
return { | ||
modifiedConfigContent, | ||
success: true | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
} else if (exportNamedDeclaration) { | ||
const exportSpecifier = exportNamedDeclaration.specifiers.find((s)=>s.type === 'ExportSpecifier' && s.exported?.name === 'default' && s.local?.type === 'Identifier' && s.local?.name); | ||
if (exportSpecifier) { | ||
warning('Could not automatically wrap next.config.js with withPayload.'); | ||
warning('Automatic wrapping of named exports as default not supported yet.'); | ||
} | ||
} else if (configType === 'ts') { | ||
const { moduleItems, parseOffset } = await compileTypeScriptFileToAST(content); | ||
const exportDefaultDeclaration = moduleItems.find((m)=>m.type === 'ExportDefaultExpression' && (m.expression.type === 'Identifier' || m.expression.type === 'CallExpression')); | ||
if (exportDefaultDeclaration) { | ||
if (!('span' in exportDefaultDeclaration.expression)) { | ||
warning('Could not automatically wrap Next config with withPayload.'); | ||
warnUserWrapNotSuccessful(configType); | ||
return { | ||
return Promise.resolve({ | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
}); | ||
} | ||
} | ||
warning('Could not automatically wrap Next config with withPayload.'); | ||
warnUserWrapNotSuccessful(configType); | ||
return { | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
} else if (configType === 'cjs') { | ||
// Find `module.exports = X` | ||
const moduleExports = ast.body.find((p)=>p.type === Syntax.ExpressionStatement && p.expression?.type === Syntax.AssignmentExpression && p.expression.left?.type === Syntax.MemberExpression && p.expression.left.object?.type === Syntax.Identifier && p.expression.left.object.name === 'module' && p.expression.left.property?.type === Syntax.Identifier && p.expression.left.property.name === 'exports'); | ||
if (moduleExports && moduleExports.expression.right?.loc) { | ||
const modifiedConfigContent = insertBeforeAndAfter(content, moduleExports.expression.right.loc); | ||
const modifiedConfigContent = insertBeforeAndAfterSWC(content, exportDefaultDeclaration.expression.span, parseOffset); | ||
return { | ||
@@ -79,13 +108,9 @@ modifiedConfigContent, | ||
} | ||
return { | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
} | ||
warning('Could not automatically wrap Next config with withPayload.'); | ||
warnUserWrapNotSuccessful(configType); | ||
return { | ||
return Promise.resolve({ | ||
modifiedConfigContent: content, | ||
success: false | ||
}; | ||
}); | ||
} | ||
@@ -96,3 +121,3 @@ function warnUserWrapNotSuccessful(configType) { | ||
${chalk.bold(`Please manually wrap your existing next.config.js with the withPayload function. Here is an example:`)} | ||
${chalk.bold(`Please manually wrap your existing Next config with the withPayload function. Here is an example:`)} | ||
@@ -105,3 +130,3 @@ ${withPayloadStatement[configType]} | ||
${configType === 'esm' ? 'export default withPayload(nextConfig)' : 'module.exports = withPayload(nextConfig)'} | ||
${configType === 'cjs' ? 'module.exports = withPayload(nextConfig)' : 'export default withPayload(nextConfig)'} | ||
@@ -127,3 +152,42 @@ `; | ||
} | ||
function insertBeforeAndAfterSWC(content, span, /** | ||
* WARNING: This is ONLY for unit tests. Defaults to 0 otherwise. | ||
* | ||
* @see compileTypeScriptFileToAST | ||
*/ parseOffset) { | ||
const { end: preOffsetEnd, start: preOffsetStart } = span; | ||
const start = preOffsetStart - parseOffset; | ||
const end = preOffsetEnd - parseOffset; | ||
const insert = (pos, text)=>{ | ||
return content.slice(0, pos) + text + content.slice(pos); | ||
}; | ||
// insert ) after end | ||
content = insert(end - 1, ')'); | ||
// insert withPayload before start | ||
content = insert(start - 1, 'withPayload('); | ||
return content; | ||
} | ||
/** | ||
* Compile typescript to AST using the swc compiler | ||
*/ async function compileTypeScriptFileToAST(fileContent) { | ||
let parseOffset = 0; | ||
/** | ||
* WARNING: This is ONLY for unit tests. | ||
* | ||
* Multiple instances of swc DO NOT reset the .span.end value. | ||
* During unit tests, the .spawn.end value is read and accounted for. | ||
* | ||
* https://github.com/swc-project/swc/issues/1366 | ||
*/ if (process.env.NODE_ENV === 'test') { | ||
parseOffset = (await parse('')).span.end; | ||
} | ||
const module = await parse(fileContent, { | ||
syntax: 'typescript' | ||
}); | ||
return { | ||
moduleItems: module.body, | ||
parseOffset | ||
}; | ||
} | ||
//# sourceMappingURL=wrap-next-config.js.map |
import * as p from '@clack/prompts'; | ||
import { jest } from '@jest/globals'; | ||
import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js'; | ||
const tsConfigs = { | ||
defaultNextConfig: `import type { NextConfig } from "next"; | ||
const nextConfig: NextConfig = {}; | ||
export default nextConfig;`, | ||
nextConfigExportNamedDefault: `import type { NextConfig } from "next"; | ||
const nextConfig: NextConfig = {}; | ||
const wrapped = someFunc(asdf); | ||
export { wrapped as default }; | ||
`, | ||
nextConfigWithFunc: `import type { NextConfig } from "next"; | ||
const nextConfig: NextConfig = {}; | ||
export default someFunc(nextConfig); | ||
`, | ||
nextConfigWithFuncMultiline: `import type { NextConfig } from "next"; | ||
const nextConfig: NextConfig = {}; | ||
export default someFunc( | ||
nextConfig | ||
); | ||
`, | ||
nextConfigWithSpread: `import type { NextConfig } from "next"; | ||
const nextConfig: NextConfig = { | ||
...someConfig, | ||
}; | ||
export default nextConfig; | ||
` | ||
}; | ||
const esmConfigs = { | ||
@@ -51,21 +78,44 @@ defaultNextConfig: `/** @type {import('next').NextConfig} */ | ||
describe('parseAndInsertWithPayload', ()=>{ | ||
describe('ts', ()=>{ | ||
const configType = 'ts'; | ||
const importStatement = withPayloadStatement[configType]; | ||
it('should parse the default next config', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(tsConfigs.defaultNextConfig, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); | ||
}); | ||
it('should parse the config with a function', async ()=>{ | ||
const { modifiedConfigContent: modifiedConfigContent2 } = await parseAndModifyConfigContent(tsConfigs.nextConfigWithFunc, configType); | ||
expect(modifiedConfigContent2).toContain('withPayload(someFunc(nextConfig))'); | ||
}); | ||
it('should parse the config with a multi-lined function', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(tsConfigs.nextConfigWithFuncMultiline, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/); | ||
}); | ||
it('should parse the config with a spread', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(tsConfigs.nextConfigWithSpread, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); | ||
}); | ||
}); | ||
describe('esm', ()=>{ | ||
const configType = 'esm'; | ||
const importStatement = withPayloadStatement[configType]; | ||
it('should parse the default next config', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(esmConfigs.defaultNextConfig, configType); | ||
it('should parse the default next config', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(esmConfigs.defaultNextConfig, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); | ||
}); | ||
it('should parse the config with a function', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(esmConfigs.nextConfigWithFunc, configType); | ||
it('should parse the config with a function', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(esmConfigs.nextConfigWithFunc, configType); | ||
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))'); | ||
}); | ||
it('should parse the config with a function on a new line', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(esmConfigs.nextConfigWithFuncMultiline, configType); | ||
it('should parse the config with a multi-lined function', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(esmConfigs.nextConfigWithFuncMultiline, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/); | ||
}); | ||
it('should parse the config with a spread', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(esmConfigs.nextConfigWithSpread, configType); | ||
it('should parse the config with a spread', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(esmConfigs.nextConfigWithSpread, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
@@ -75,5 +125,5 @@ expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); | ||
// Unsupported: export { wrapped as default } | ||
it('should give warning with a named export as default', ()=>{ | ||
it('should give warning with a named export as default', async ()=>{ | ||
const warnLogSpy = jest.spyOn(p.log, 'warn').mockImplementation(()=>{}); | ||
const { modifiedConfigContent, success } = parseAndModifyConfigContent(esmConfigs.nextConfigExportNamedDefault, configType); | ||
const { modifiedConfigContent, success } = await parseAndModifyConfigContent(esmConfigs.nextConfigExportNamedDefault, configType); | ||
expect(modifiedConfigContent).toContain(importStatement); | ||
@@ -87,28 +137,28 @@ expect(success).toBe(false); | ||
const requireStatement = withPayloadStatement[configType]; | ||
it('should parse the default next config', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.defaultNextConfig, configType); | ||
it('should parse the default next config', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.defaultNextConfig, configType); | ||
expect(modifiedConfigContent).toContain(requireStatement); | ||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); | ||
}); | ||
it('should parse anonymous default config', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.anonConfig, configType); | ||
it('should parse anonymous default config', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.anonConfig, configType); | ||
expect(modifiedConfigContent).toContain(requireStatement); | ||
expect(modifiedConfigContent).toContain('withPayload({})'); | ||
}); | ||
it('should parse the config with a function', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.nextConfigWithFunc, configType); | ||
it('should parse the config with a function', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.nextConfigWithFunc, configType); | ||
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))'); | ||
}); | ||
it('should parse the config with a function on a new line', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.nextConfigWithFuncMultiline, configType); | ||
it('should parse the config with a multi-lined function', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.nextConfigWithFuncMultiline, configType); | ||
expect(modifiedConfigContent).toContain(requireStatement); | ||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/); | ||
}); | ||
it('should parse the config with a named export as default', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.nextConfigExportNamedDefault, configType); | ||
it('should parse the config with a named export as default', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.nextConfigExportNamedDefault, configType); | ||
expect(modifiedConfigContent).toContain(requireStatement); | ||
expect(modifiedConfigContent).toContain('withPayload(wrapped)'); | ||
}); | ||
it('should parse the config with a spread', ()=>{ | ||
const { modifiedConfigContent } = parseAndModifyConfigContent(cjsConfigs.nextConfigWithSpread, configType); | ||
it('should parse the config with a spread', async ()=>{ | ||
const { modifiedConfigContent } = await parseAndModifyConfigContent(cjsConfigs.nextConfigWithSpread, configType); | ||
expect(modifiedConfigContent).toContain(requireStatement); | ||
@@ -115,0 +165,0 @@ expect(modifiedConfigContent).toContain('withPayload(nextConfig)'); |
@@ -68,3 +68,8 @@ import * as p from '@clack/prompts'; | ||
const nextAppDetails = await getNextAppDetails(process.cwd()); | ||
const { hasTopLevelLayout, isPayloadInstalled, nextAppDir, nextConfigPath } = nextAppDetails; | ||
const { hasTopLevelLayout, isPayloadInstalled, isSupportedNextVersion, nextAppDir, nextConfigPath, nextVersion } = nextAppDetails; | ||
if (nextConfigPath && !isSupportedNextVersion) { | ||
p.log.warn(`Next.js v${nextVersion} is unsupported. Next.js >= 15 is required to use Payload.`); | ||
p.outro(feedbackOutro()); | ||
process.exit(0); | ||
} | ||
// Upgrade Payload in existing project | ||
@@ -71,0 +76,0 @@ if (isPayloadInstalled && nextConfigPath) { |
@@ -10,3 +10,3 @@ import fs from 'fs'; | ||
/** | ||
* Copy the necessary template files from `templates/blank-3.0` to `dist/template` | ||
* Copy the necessary template files from `templates/blank` to `dist/template` | ||
* | ||
@@ -17,3 +17,3 @@ * Eventually, this should be replaced with using tar.x to stream from the git repo | ||
const outputPath = path.resolve(dirname, '../../dist/template'); | ||
const sourceTemplatePath = path.resolve(root, 'templates/blank-3.0'); | ||
const sourceTemplatePath = path.resolve(root, 'templates/blank'); | ||
if (!fs.existsSync(sourceTemplatePath)) { | ||
@@ -27,3 +27,3 @@ throw new Error(`Source path does not exist: ${sourceTemplatePath}`); | ||
} | ||
// Copy the src directory from `templates/blank-3.0` to `dist` | ||
// Copy the src directory from `templates/blank` to `dist` | ||
const srcPath = path.resolve(sourceTemplatePath, 'src'); | ||
@@ -30,0 +30,0 @@ const distSrcPath = path.resolve(outputPath, 'src'); |
@@ -18,2 +18,5 @@ // storage-adapter-import-placeholder | ||
user: Users.slug, | ||
importMap: { | ||
baseDir: path.resolve(dirname), | ||
}, | ||
}, | ||
@@ -20,0 +23,0 @@ collections: [Users, Media], |
@@ -49,3 +49,3 @@ import type arg from 'arg'; | ||
export type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'; | ||
export type DbType = 'mongodb' | 'postgres'; | ||
export type DbType = 'mongodb' | 'postgres' | 'sqlite'; | ||
export type DbDetails = { | ||
@@ -60,9 +60,11 @@ dbUri: string; | ||
isSrcDir: boolean; | ||
isSupportedNextVersion: boolean; | ||
nextAppDir?: string; | ||
nextConfigPath?: string; | ||
nextConfigType?: NextConfigType; | ||
nextVersion: null | string; | ||
}; | ||
export type NextConfigType = 'cjs' | 'esm'; | ||
export type NextConfigType = 'cjs' | 'esm' | 'ts'; | ||
export type StorageAdapterType = 'localDisk' | 'payloadCloud' | 'vercelBlobStorage'; | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "create-payload-app", | ||
"version": "3.0.0-canary.b750ebf", | ||
"version": "3.0.0-canary.b8dd0db", | ||
"homepage": "https://payloadcms.com", | ||
@@ -44,2 +44,3 @@ "repository": { | ||
"@sindresorhus/slugify": "^1.1.0", | ||
"@swc/core": "1.7.10", | ||
"arg": "^5.0.0", | ||
@@ -67,3 +68,3 @@ "chalk": "^4.1.0", | ||
"clean": "rimraf {dist,*.tsbuildinfo}", | ||
"pack-template-files": "tsx src/scripts/pack-template-files.ts", | ||
"pack-template-files": "node --no-deprecation --import @swc-node/register/esm-register src/scripts/pack-template-files.ts", | ||
"test": "jest", | ||
@@ -70,0 +71,0 @@ "typecheck": "tsc" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
226886
11.31%112
1.82%2279
16.16%13
8.33%16
14.29%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added