add experimental integrations flag (#2894)

This commit is contained in:
Fred K. Schott 2022-03-25 17:11:36 -07:00 committed by GitHub
parent 068e3b4dee
commit 9d6e0b5dba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 15 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Add the "--experimental-integrations" flag to enable 3rd-party integrations.

View file

@ -34,6 +34,7 @@ export interface CLIFlags {
/** @deprecated */ /** @deprecated */
experimentalStaticBuild?: boolean; experimentalStaticBuild?: boolean;
experimentalSsr?: boolean; experimentalSsr?: boolean;
experimentalIntegrations?: boolean;
legacyBuild?: boolean; legacyBuild?: boolean;
drafts?: boolean; drafts?: boolean;
} }
@ -417,6 +418,12 @@ export interface AstroUserConfig {
trailingSlash?: 'always' | 'never' | 'ignore'; trailingSlash?: 'always' | 'never' | 'ignore';
}; };
/**
* Enable experimental support for 3rd-party integrations.
* Default: false
*/
experimentalIntegrations?: boolean;
/** /**
* @docs * @docs
* @name vite * @name vite

View file

@ -73,14 +73,7 @@ export const AstroConfigSchema = z.object({
// preprocess // preprocess
(val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val), (val) => (Array.isArray(val) ? val.flat(Infinity).filter(Boolean) : val),
// validate // validate
z z.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) })).default([])
.array(z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }))
.default([])
// validate: first-party integrations only
// TODO: Add `To use 3rd-party integrations or to create your own, use the --experimental-integrations flag.`,
.refine((arr) => arr.every((integration) => integration.name.startsWith('@astrojs/')), {
message: `Astro integrations are still experimental, and only official integrations are currently supported`,
})
), ),
adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(), adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
styleOptions: z styleOptions: z
@ -133,6 +126,7 @@ export const AstroConfigSchema = z.object({
}) })
.optional() .optional()
.default({}), .default({}),
experimentalIntegrations: z.boolean().optional().default(false),
vite: z.any().optional().default({}), // TODO: we dont need validation, but can we get better type inference? vite: z.any().optional().default({}), // TODO: we dont need validation, but can we get better type inference?
}); });
@ -209,10 +203,24 @@ export async function validateConfig(userConfig: any, root: string): Promise<Ast
.optional() .optional()
.default({}), .default({}),
}); });
return { // First-Pass Validation
const result = {
...(await AstroConfigRelativeSchema.parseAsync(userConfig)), ...(await AstroConfigRelativeSchema.parseAsync(userConfig)),
_ctx: { scripts: [], renderers: [], adapter: undefined }, _ctx: { scripts: [], renderers: [], adapter: undefined },
}; };
// Final-Pass Validation (perform checks that require the full config object)
if (!result.experimentalIntegrations && !result.integrations.every((int) => int.name.startsWith('@astrojs/'))) {
throw new Error([
`Astro integrations are still experimental.`,
``,
`Only official "@astrojs/*" integrations are currently supported.`,
`To enable 3rd-party integrations, use the "--experimental-integrations" flag.`,
`Breaking changes may occur in this API before Astro v1.0 is released.`,
``
].join('\n'));
}
// If successful, return the result as a verified AstroConfig object.
return result;
} }
/** Adds '/' to end of string but doesnt double-up */ /** Adds '/' to end of string but doesnt double-up */
@ -236,6 +244,7 @@ function resolveFlags(flags: Partial<Flags>): CLIFlags {
host: typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined, host: typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
legacyBuild: typeof flags.legacyBuild === 'boolean' ? flags.legacyBuild : false, legacyBuild: typeof flags.legacyBuild === 'boolean' ? flags.legacyBuild : false,
experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : false, experimentalSsr: typeof flags.experimentalSsr === 'boolean' ? flags.experimentalSsr : false,
experimentalIntegrations: typeof flags.experimentalIntegrations === 'boolean' ? flags.experimentalIntegrations : false,
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false, drafts: typeof flags.drafts === 'boolean' ? flags.drafts : false,
}; };
} }
@ -256,6 +265,7 @@ function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
astroConfig.buildOptions.legacyBuild = false; astroConfig.buildOptions.legacyBuild = false;
} }
} }
if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimentalIntegrations = flags.experimentalIntegrations;
if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts; if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts;
return astroConfig; return astroConfig;
} }
@ -311,6 +321,7 @@ export async function loadConfig(configOptions: LoadConfigOptions): Promise<Astr
export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}): Promise<AstroConfig> { export async function resolveConfig(userConfig: AstroUserConfig, root: string, flags: CLIFlags = {}): Promise<AstroConfig> {
const mergedConfig = mergeCLIFlags(userConfig, flags); const mergedConfig = mergeCLIFlags(userConfig, flags);
const validatedConfig = await validateConfig(mergedConfig, root); const validatedConfig = await validateConfig(mergedConfig, root);
return validatedConfig; return validatedConfig;
} }

View file

@ -64,11 +64,10 @@ describe('Config Validation', () => {
}); });
it('blocks third-party "integration" values', async () => { it('blocks third-party "integration" values', async () => {
const configError = await validateConfig({ integrations: [{ name: '@my-plugin/a' }] }, process.cwd()).catch((err) => err); const configError = await validateConfig({ integrations: [{ name: '@my-plugin/a' }] }, process.cwd()).catch((err) => err);
expect(configError instanceof z.ZodError).to.equal(true); expect(configError).to.be.instanceOf(Error);
const formattedError = stripAnsi(formatConfigError(configError)); expect(configError.message).to.include('Astro integrations are still experimental.');
expect(formattedError).to.equal( });
`[config] Astro found issue(s) with your configuration: it('allows third-party "integration" values with the --experimental-integrations flag', async () => {
! integrations Astro integrations are still experimental, and only official integrations are currently supported.` await validateConfig({ integrations: [{ name: '@my-plugin/a' }], experimentalIntegrations: true }, process.cwd()).catch((err) => err);
);
}); });
}); });