function statically_analyse_page_options(filename, input) {
	// if there's a chance there are no page exports or export all declaration,
	// then we can skip the AST parsing which is expensive
	if (!skip_parsing_regex.test(input)) {
		return {};
	}

	try {
		const source = parser.parse(input, {
			sourceType: 'module',
			ecmaVersion: 'latest'
		});

		/** @type {Map<string, import('acorn').Literal['value']>} */
		const page_options = new Map();

		for (const statement of source.body) {
			// ignore export all declarations with aliases that are not page options
			if (
				statement.type === 'ExportAllDeclaration' &&
				statement.exported &&
				!valid_page_options.has(get_name(statement.exported))
			) {
				continue;
			}

			if (
				statement.type === 'ExportDefaultDeclaration' ||
				statement.type === 'ExportAllDeclaration'
			) {
				return null;
			} else if (statement.type !== 'ExportNamedDeclaration') {
				continue;
			}

			if (statement.specifiers.length) {
				/** @type {Map<string, string>} */
				const export_specifiers = new Map();
				for (const specifier of statement.specifiers) {
					const exported_name = get_name(specifier.exported);
					if (!valid_page_options.has(exported_name)) {
						continue;
					}

					if (statement.source) {
						return null;
					}

					export_specifiers.set(get_name(specifier.local), exported_name);
				}

				for (const statement of source.body) {
					switch (statement.type) {
						case 'ImportDeclaration': {
							for (const import_specifier of statement.specifiers) {
								if (export_specifiers.has(import_specifier.local.name)) {
									return null;
								}
							}
							break;
						}
						case 'ExportNamedDeclaration':
						case 'VariableDeclaration':
						case 'FunctionDeclaration':
						case 'ClassDeclaration': {
							const declaration =
								statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement;

							if (!declaration) {
								break;
							}

							// class and function declarations
							if (declaration.type !== 'VariableDeclaration') {
								if (export_specifiers.has(declaration.id.name)) {
									return null;
								}
								break;
							}

							for (const variable_declarator of declaration.declarations) {
								if (
									variable_declarator.id.type !== 'Identifier' ||
									!export_specifiers.has(variable_declarator.id.name)
								) {
									continue;
								}

								if (variable_declarator.init?.type === 'Literal') {
									page_options.set(
										/** @type {string} */ (export_specifiers.get(variable_declarator.id.name)),
										variable_declarator.init.value
									);
									export_specifiers.delete(variable_declarator.id.name);
									continue;
								}

								// references a declaration we can't easily evaluate statically
								return null;
							}
							break;
						}
					}
				}

				// there were some export specifiers that we couldn't resolve
				if (export_specifiers.size) {
					return null;
				}
				continue;
			}

			if (!statement.declaration) {
				continue;
			}

			// class and function declarations
			if (statement.declaration.type !== 'VariableDeclaration') {
				if (valid_page_options.has(statement.declaration.id.name)) {
					return null;
				}
				continue;
			}

			for (const declaration of statement.declaration.declarations) {
				if (declaration.id.type !== 'Identifier') {
					return null;
				}

				if (!valid_page_options.has(declaration.id.name)) {
					continue;
				}

				if (declaration.init?.type === 'Literal') {
					page_options.set(declaration.id.name, declaration.init.value);
					continue;
				}

				// references a declaration we can't easily evaluate statically
				return null;
			}
		}

		return Object.fromEntries(page_options);
	} catch (error) {
		if (error instanceof Error) {
			error.message = `Failed to statically analyse page options for ${filename}. ${error.message}`;
		}
		throw error;
	}
}
Collects page options from a +page.js/+layout.js file, ignoring reassignments
and using the declared value. Returns `null` if any export is too difficult to analyse.
@param {string} filename The name of the file to report when an error occurs
@param {string} input
@returns {Record<string, any> | null}