Skip to content

stronger dynamic env types #7735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cold-cherries-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

create stronger types for dynamically generated env modules
41 changes: 29 additions & 12 deletions packages/kit/src/core/env.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { GENERATED_COMMENT } from '../constants.js';
import { runtime_base } from './utils.js';

/**
* @typedef {'public' | 'private'} EnvType
* @typedef {{
* public: Record<string, string>;
* private: Record<string, string>;
* prefix: string;
* }} EnvData
*/

/**
* @param {string} id
* @param {Record<string, string>} env
Expand All @@ -25,46 +34,54 @@ export function create_static_module(id, env) {
}

/**
* @param {'public' | 'private'} type
* @param {EnvType} type
* @param {Record<string, string> | undefined} dev_values If in a development mode, values to pre-populate the module with.
*/
export function create_dynamic_module(type, dev_values) {
if (dev_values) {
const objectKeys = Object.entries(dev_values).map(
const keys = Object.entries(dev_values).map(
([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`
);
return `const env = {\n${objectKeys.join(',\n')}\n}\n\nexport { env }`;
return `export const env = {\n${keys.join(',\n')}\n}`;
}
return `export { env } from '${runtime_base}/env-${type}.js';`;
}

/**
* @param {string} id
* @param {Record<string, string>} env
* @param {EnvType} id
* @param {EnvData} env
* @returns {string}
*/
export function create_static_types(id, env) {
const declarations = Object.keys(env)
const declarations = Object.keys(env[id])
.filter((k) => valid_identifier.test(k))
.map((k) => `\texport const ${k}: string;`)
.join('\n');

return `declare module '${id}' {\n${declarations}\n}`;
return `declare module '$env/static/${id}' {\n${declarations}\n}`;
}

/**
* @param {string} id
* @param {Record<string, string>} env
* @param {EnvType} id
* @param {EnvData} env
* @returns {string}
*/
export function create_dynamic_types(id, env) {
const properties = Object.keys(env)
const properties = Object.keys(env[id])
.filter((k) => valid_identifier.test(k))
.map((k) => `\t\t${k}: string;`);

properties.push(`\t\t[key: string]: string | undefined;`);
const prefixed = `[key: \`${env.prefix}\${string}\`]`;

if (id === 'private') {
properties.push(`\t\t${prefixed}: undefined;`);
properties.push(`\t\t[key: string]: string | undefined;`);
} else {
properties.push(`\t\t${prefixed}: string | undefined;`);
}

return `declare module '${id}' {\n\texport const env: {\n${properties.join('\n')}\n\t}\n}`;
const declaration = `export const env: {\n${properties.join('\n')}\n\t}`;
return `declare module '$env/dynamic/${id}' {\n\t${declaration}\n}`;
}

export const reserved = new Set([
Expand Down
15 changes: 9 additions & 6 deletions packages/kit/src/core/sync/write_ambient.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@ function read_description(filename) {
}

/**
* @param {{ public: Record<string, string>, private: Record<string, string> }} env
* @param {import('../env.js').EnvData} env
*/
const template = (env) => `
${GENERATED_COMMENT}

/// <reference types="@sveltejs/kit" />

${read_description('$env+static+private.md')}
${create_static_types('$env/static/private', env.private)}
${create_static_types('private', env)}

${read_description('$env+static+public.md')}
${create_static_types('$env/static/public', env.public)}
${create_static_types('public', env)}

${read_description('$env+dynamic+private.md')}
${create_dynamic_types('$env/dynamic/private', env.private)}
${create_dynamic_types('private', env)}

${read_description('$env+dynamic+public.md')}
${create_dynamic_types('$env/dynamic/public', env.public)}
${create_dynamic_types('public', env)}
`;

/**
Expand All @@ -49,5 +49,8 @@ ${create_dynamic_types('$env/dynamic/public', env.public)}
export function write_ambient(config, mode) {
const env = get_env(config.env, mode);

write_if_changed(path.join(config.outDir, 'ambient.d.ts'), template(env));
write_if_changed(
path.join(config.outDir, 'ambient.d.ts'),
template({ ...env, prefix: config.env.publicPrefix })
);
}