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

refactor: improve internal babel types #271

Merged
merged 8 commits into from
Jul 26, 2024
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"test:bun": "bun --bun test test/bun"
},
"devDependencies": {
"@babel/helper-module-imports": "^7.24.7",
"@babel/core": "^7.24.9",
"@babel/helper-module-transforms": "^7.24.9",
"@babel/helper-plugin-utils": "^7.24.8",
Expand All @@ -59,9 +60,13 @@
"@babel/plugin-transform-typescript": "^7.24.8",
"@babel/preset-typescript": "^7.24.7",
"@babel/template": "^7.24.7",
"@babel/traverse": "^7.24.7",
"@babel/types": "^7.24.9",
"@types/babel__core": "^7.20.5",
"@types/babel__helper-module-imports": "^7.18.3",
"@types/babel__helper-plugin-utils": "^7.10.3",
"@types/babel__template": "^7.4.4",
"@types/babel__traverse": "^7.20.6",
"@types/node": "^20.14.12",
"@vitest/coverage-v8": "^2.0.4",
"acorn": "^8.12.1",
Expand Down
30 changes: 30 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/_types/babel-core.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { HubInterface } from "@babel/traverse";

declare module "@babel/core" {
export interface BabelFile
extends HubInterface,
Pick<PluginPass, "get" | "set"> {}
}

export {};
203 changes: 203 additions & 0 deletions src/_types/babel-helper-module-transforms.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
declare module "@babel/helper-module-transforms" {
import type { NodePath } from "@babel/core";
import { types as t } from "@babel/core";

interface LocalExportMetadata {
/**
* names of exports
*/
names: string[];
kind: "import" | "hoisted" | "block" | "var";
}

type InteropType =
/**
* Babel interop for default-only imports
*/
| "default"
/**
* Babel interop for namespace or default+named imports
*/
| "namespace"
/**
* Node.js interop for default-only imports
*/
| "node-default"
/**
* Node.js interop for namespace or default+named imports
*/
| "node-namespace"
/**
* No interop, or named-only imports
*/
| "none";

interface SourceModuleMetadata {
/**
* A unique variable name to use for this namespace object.
* Centralized for simplicity.
*/
name: string;
loc: t.SourceLocation | undefined | null;
interop: InteropType;
/**
* Local binding to reference from this source namespace.
* Key: Local name, value: Import name
*/
imports: Map<string, string>;
/**
* Local names that reference namespace object.
*/
importsNamespace: Set<string>;
/**
* Reexports to create for namespace. Key: Export name, value: Import name
*/
reexports: Map<string, string>;
/**
* List of names to re-export namespace as.
*/
reexportNamespace: Set<string>;
/**
* Tracks if the source should be re-exported.
*/
reexportAll: null | {
loc: t.SourceLocation | undefined | null;
};
wrap?: unknown;
referenced: boolean;
}

interface ModuleMetadata {
exportName: string;
/**
* The name of the variable that will reference an object
* containing export names.
*/
exportNameListName: null | string;
hasExports: boolean;
/**
* Lookup from local binding to export information.
*/
local: Map<string, LocalExportMetadata>;
/**
* Lookup of source file to source file metadata.
*/
source: Map<string, SourceModuleMetadata>;
/**
* List of names that should only be printed as string literals.
* i.e. `import { "any unicode" as foo } from "some-module"`
* `stringSpecifiers` is `Set(1) ["any unicode"]`
* In most cases `stringSpecifiers` is an empty Set
*/
stringSpecifiers: Set<string>;
}

type ImportInterop =
| "none"
| "babel"
| "node"
| ((source: string, filename?: string) => "none" | "babel" | "node");

type Lazy = boolean | string[] | ((source: string) => boolean);

type RootOptions = {
filename?: string | null;
filenameRelative?: string | null;
sourceRoot?: string | null;
};

export type PluginOptions = {
moduleId?: string;
moduleIds?: boolean;
getModuleId?: (moduleName: string) => string | null | undefined;
moduleRoot?: string;
};

export function getModuleName(
rootOpts: RootOptions,
pluginOpts: PluginOptions,
): string | null;

export interface RewriteModuleStatementsAndPrepareHeaderOptions {
exportName?: string;
strict?: boolean;
allowTopLevelThis?: boolean;
strictMode?: boolean;
loose?: boolean;
importInterop?: ImportInterop;
noInterop?: boolean;
lazy?: Lazy;
getWrapperPayload?: (
source: string,
metadata: SourceModuleMetadata,
importNodes: t.Node[],
) => unknown;
wrapReference?: (
ref: t.Expression,
payload: unknown,
) => t.Expression | null | undefined;
esNamespaceOnly?: boolean;
filename: string | undefined | null;
constantReexports?: boolean | void;
enumerableModuleMeta?: boolean | void;
noIncompleteNsImportDetection?: boolean | void;
}

/**
* Perform all of the generic ES6 module rewriting needed to handle initial
* module processing. This function will rewrite the majority of the given
* program to reference the modules described by the returned metadata,
* and returns a list of statements for use when initializing the module.
*/
export function rewriteModuleStatementsAndPrepareHeader(
path: NodePath<t.Program>,
options: RewriteModuleStatementsAndPrepareHeaderOptions,
): {
meta: ModuleMetadata;
headers: t.Statement[];
};

/**
* Check if a given source is an anonymous import, e.g. `import 'foo';`
*/
export function isSideEffectImport(source: SourceModuleMetadata): boolean;

/**
* Create the runtime initialization statements for a given requested source.
* These will initialize all of the runtime import/export logic that
* can't be handled statically by the statements created by
* `buildExportInitializationStatements()`.
*/
export function buildNamespaceInitStatements(
metadata: ModuleMetadata,
sourceMetadata: SourceModuleMetadata,
constantReexports?: boolean | void,
wrapReference?: (
ref: t.Identifier,
payload: unknown,
) => t.Expression | null | undefined,
): t.Statement[];

/**
* Flag a set of statements as hoisted above all else so that module init
* statements all run before user code.
*/
export function ensureStatementsHoisted(statements: t.Statement[]): void;

/**
* Given an expression for a standard import object, like `require('foo')`,
* wrap it in a call to the interop helpers based on the type.
*/
export function wrapInterop(
programPath: NodePath<t.Program>,
expr: t.Expression,
type: InteropType,
): t.CallExpression;

export function buildDynamicImport(
node: t.CallExpression | t.ImportExpression,
deferToThen: boolean,
wrapWithPromise: boolean,
builder: (specifier: t.Expression) => t.Expression,
): t.Expression;
}
64 changes: 64 additions & 0 deletions src/_types/babel-helper-plugin-utils.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { ConfigAPI } from "@babel/core";

declare module "@babel/helper-plugin-utils" {
const knownAssumptions: readonly [
"arrayLikeIsIterable",
"constantReexports",
"constantSuper",
"enumerableModuleMeta",
"ignoreFunctionLength",
"ignoreToPrimitiveHint",
"iterableIsArray",
"mutableTemplateObject",
"noClassCalls",
"noDocumentAll",
"noIncompleteNsImportDetection",
"noNewArrows",
"noUninitializedPrivateFieldAccess",
"objectRestNoSymbols",
"privateFieldsAsSymbols",
"privateFieldsAsProperties",
"pureGetters",
"setClassMethods",
"setComputedProperties",
"setPublicClassFields",
"setSpreadProperties",
"skipForOfIteratorClosing",
"superIsCallableConstructor",
];

export type AssumptionName = (typeof knownAssumptions)[number];

type AssumptionFunction = (name: AssumptionName) => boolean | undefined;

export type Target =
| "node"
| "deno"
| "chrome"
| "opera"
| "edge"
| "firefox"
| "safari"
| "ie"
| "ios"
| "android"
| "electron"
| "samsung"
| "opera_mobile";

export type Targets = {
[target in Target]?: string;
};

type TargetsFunction = () => Targets;

export type PresetAPI = {
targets: TargetsFunction;
addExternalDependency: (ref: string) => void;
} & ConfigAPI;

export type PluginAPI = {
assumption: AssumptionFunction;
} & PresetAPI &
BabelAPI;
}
9 changes: 9 additions & 0 deletions src/_types/babel-helper-simple-access.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module "@babel/helper-simple-access" {
import type { NodePath } from "@babel/traverse";

export default function simplifyAccess(
path: NodePath,
bindingNames: Set<string>,
includeUpdateExpression?: boolean,
): void;
}
5 changes: 5 additions & 0 deletions src/_types/babel-plugin-parameter-decorator.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module "babel-plugin-parameter-decorator" {
import type { declare } from "@babel/helper-plugin-utils";
const parameterDecoratorPlugin: ReturnType<typeof declare>;
export default parameterDecoratorPlugin;
}
14 changes: 14 additions & 0 deletions src/_types/babel-plugin-proposal-decorators.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
declare module "@babel/plugin-proposal-decorators" {
import type { declare } from "@babel/helper-plugin-utils";
import type { Options as SyntaxOptions } from "@babel/plugin-syntax-decorators";

export interface Options extends SyntaxOptions {
/**
* @deprecated use `constantSuper` assumption instead. Only supported in 2021-12 version.
*/
loose?: boolean;
}

const proposalDecoratorsPlugin: ReturnType<typeof declare<Options>>;
export default proposalDecoratorsPlugin;
}
Loading