Skip to content
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

improve standalone typings #14630

Merged
merged 2 commits into from Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 17 additions & 9 deletions packages/babel-standalone/src/index.ts
Expand Up @@ -26,6 +26,7 @@ import presetEnv from "@babel/preset-env";
import presetFlow from "@babel/preset-flow";
import presetReact from "@babel/preset-react";
import presetTypescript from "@babel/preset-typescript";
import type { InputOptions } from "@babel/core";

import { runScripts } from "./transformScriptTags";

Expand All @@ -40,7 +41,7 @@ const isArray =
* Returns undefined if the preset or plugin is not available; passes through
* name unmodified if it (or the first element of the pair) is not a string.
*/
function loadBuiltin(builtinTable, name) {
function loadBuiltin(builtinTable: Record<string, unknown>, name: any) {
if (isArray(name) && typeof name[0] === "string") {
if (Object.prototype.hasOwnProperty.call(builtinTable, name[0])) {
return [builtinTable[name[0]]].concat(name.slice(1));
Expand All @@ -56,7 +57,7 @@ function loadBuiltin(builtinTable, name) {
/**
* Parses plugin names and presets from the specified options.
*/
function processOptions(options) {
function processOptions(options: InputOptions) {
// Parse preset names
const presets = (options.presets || []).map(presetName => {
const preset = loadBuiltin(availablePresets, presetName);
Expand Down Expand Up @@ -100,15 +101,19 @@ function processOptions(options) {
};
}

export function transform(code: string, options: any) {
export function transform(code: string, options: InputOptions) {
return babelTransform(code, processOptions(options));
}

export function transformFromAst(ast: any, code: string, options: any) {
export function transformFromAst(
ast: any,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps AstRoot can be used.

code: string,
options: InputOptions,
) {
return babelTransformFromAst(ast, code, processOptions(options));
}
export const availablePlugins = {};
export const availablePresets = {};
export const availablePlugins: typeof all = {};

export const buildExternalHelpers = babelBuildExternalHelpers;
/**
* Registers a named plugin for use with Babel.
Expand Down Expand Up @@ -148,6 +153,7 @@ export function registerPreset(name: string, preset: any | Function): void {
);
}
}
// @ts-expect-error mutating available presets
availablePresets[name] = preset;
}
/**
Expand All @@ -170,7 +176,7 @@ registerPlugins(all);
// All the presets we should bundle
// Want to get rid of this list of allowed presets?
// Wait! Please read https://github.com/babel/babel/pull/6177 first.
registerPresets({
export const availablePresets = {
env: presetEnv,
es2015: preset2015,
es2016: () => {
Expand All @@ -197,7 +203,7 @@ registerPresets({
},
typescript: presetTypescript,
flow: presetFlow,
});
};

// @ts-ignore VERSION is to be replaced by rollup
export const version: string = VERSION;
Expand All @@ -216,7 +222,9 @@ if (typeof window !== "undefined" && window?.addEventListener) {
* Transform <script> tags with "text/babel" type.
* @param {Array} scriptTags specify script tags to transform, transform all in the <head> if not given
*/
export function transformScriptTags(scriptTags?: Array<any>) {
export function transformScriptTags(
scriptTags?: HTMLCollectionOf<HTMLScriptElement>,
) {
runScripts(transform, scriptTags);
}

Expand Down
52 changes: 42 additions & 10 deletions packages/babel-standalone/src/transformScriptTags.ts
Expand Up @@ -8,13 +8,32 @@

const scriptTypes = ["text/jsx", "text/babel"];

let headEl;
import { transform } from "./index";
import type { InputOptions } from "@babel/core";

let headEl: HTMLHeadElement;
let inlineScriptCount = 0;

type CompilationResult = {
async: boolean;
type: string;
error: boolean;
loaded: boolean;
content: string | null;
executed: boolean;
// todo: refine plugins/presets
plugins: InputOptions["plugins"];
presets: InputOptions["presets"];
url: string | null;
};

/**
* Actually transform the code.
*/
function transformCode(transformFn, script) {
function transformCode(
transformFn: typeof transform,
script: CompilationResult,
) {
let source;
if (script.url != null) {
source = script.url;
Expand All @@ -33,7 +52,7 @@ function transformCode(transformFn, script) {
* Builds the Babel options for transforming the specified script, using some
* sensible default presets and plugins if none were explicitly provided.
*/
function buildBabelOptions(script, filename) {
function buildBabelOptions(script: CompilationResult, filename: string) {
let presets = script.presets;
if (!presets) {
if (script.type === "module") {
Expand Down Expand Up @@ -62,7 +81,7 @@ function buildBabelOptions(script, filename) {
"proposal-object-rest-spread",
"transform-flow-strip-types",
],
sourceMaps: "inline",
sourceMaps: "inline" as const,
sourceFileName: filename,
};
}
Expand All @@ -71,7 +90,7 @@ function buildBabelOptions(script, filename) {
* Appends a script element at the end of the <head> with the content of code,
* after transforming it.
*/
function run(transformFn, script) {
function run(transformFn: typeof transform, script: CompilationResult) {
const scriptEl = document.createElement("script");
if (script.type) {
scriptEl.setAttribute("type", script.type);
Expand All @@ -83,7 +102,11 @@ function run(transformFn, script) {
/**
* Load script from the provided url and pass the content to the callback.
*/
function load(url, successCallback, errorCallback) {
function load(
url: string,
successCallback: (content: string) => void,
errorCallback: () => void,
) {
const xhr = new XMLHttpRequest();

// async, however scripts will be executed in the order they are in the
Expand All @@ -110,7 +133,10 @@ function load(url, successCallback, errorCallback) {
* the string is empty, returns an empty array. If the string is not defined,
* returns null.
*/
function getPluginsOrPresetsFromScript(script, attributeName) {
function getPluginsOrPresetsFromScript(
script: HTMLScriptElement,
attributeName: string,
) {
const rawValue = script.getAttribute(attributeName);
if (rawValue === "") {
// Empty string means to not load ANY presets or plugins
Expand All @@ -129,8 +155,11 @@ function getPluginsOrPresetsFromScript(script, attributeName) {
* inline script, or by using XHR. Transforms are applied if needed. The scripts
* are executed in the order they are found on the page.
*/
function loadScripts(transformFn, scripts) {
const result = [];
function loadScripts(
transformFn: typeof transform,
scripts: HTMLScriptElement[],
) {
const result: CompilationResult[] = [];
const count = scripts.length;

function check() {
Expand Down Expand Up @@ -196,7 +225,10 @@ function loadScripts(transformFn, scripts) {
* Run script tags with type="text/jsx".
* @param {Array} scriptTags specify script tags to run, run all in the <head> if not given
*/
export function runScripts(transformFn, scripts) {
export function runScripts(
transformFn: typeof transform,
scripts?: HTMLCollectionOf<HTMLScriptElement>,
) {
headEl = document.getElementsByTagName("head")[0];
if (!scripts) {
scripts = document.getElementsByTagName("script");
Expand Down