import { FileType, ProjectPlugin, ProjectPluginStructure } from '@teleporthq/teleport-types' const NEXT_CONFIG_KEY = 'next.config' const MODULE_EXPORTS_OPENING = /module\.exports\s*=\s*\{/ const IMAGES_KEY = /(^|[\s,{])images\s*:/ /** * `next/image` settings of every generated site. The generator hands * next/image only the project's own files (`teleport-plugin-jsx-next-image` * converts an whose src is under /playground_assets), so no remote host * is allowed — the optimizer never fetches and decodes an image an attacker * chose, which the image-optimizer CVEs of Next 12 / sharp need — and an SVG, * which can carry script, is never optimized. Both are Next's defaults; they * are written out so a merge or an upgrade cannot widen them unnoticed. */ export const NEXT_IMAGE_SETTINGS_SOURCE = ` images: { remotePatterns: [], dangerouslyAllowSVG: false, },` /** * Adds the settings to the project's next.config, creating it when there is * none. An `images` key already there is someone else's decision and is left * alone. */ export const addNextConfigImageSettings = (structure: ProjectPluginStructure): void => { const configFile = structure.files .get(NEXT_CONFIG_KEY) ?.files.find((file) => file.name === NEXT_CONFIG_KEY && file.fileType === FileType.JS) if (!configFile) { structure.files.set(NEXT_CONFIG_KEY, { path: [], files: [ { name: NEXT_CONFIG_KEY, fileType: FileType.JS, content: `module.exports = {\n${NEXT_IMAGE_SETTINGS_SOURCE}\n}\n`, }, ], }) return } const content = configFile.content if (IMAGES_KEY.test(content)) { return } const opening = content.match(MODULE_EXPORTS_OPENING) if (!opening || opening.index === undefined) { return } const insertAt = opening.index + opening[0].length configFile.content = content.slice(0, insertAt) + `\n${NEXT_IMAGE_SETTINGS_SOURCE}` + content.slice(insertAt) } export class NextImageSettingsProjectPlugin implements ProjectPlugin { async runBefore(structure: ProjectPluginStructure): Promise { return structure } async runAfter(structure: ProjectPluginStructure): Promise { addNextConfigImageSettings(structure) return structure } }