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 module transform packages typings #14608

Merged
merged 5 commits into from May 30, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 34 additions & 21 deletions packages/babel-helper-module-transforms/src/index.ts
Expand Up @@ -27,7 +27,9 @@ import normalizeModuleAndLoadMetadata, {
validateImportInteropOption,
} from "./normalize-and-load-metadata";
import type {
ImportInterop,
InteropType,
Lazy,
ModuleMetadata,
SourceModuleMetadata,
} from "./normalize-and-load-metadata";
Expand All @@ -38,6 +40,22 @@ export type { PluginOptions } from "./get-module-name";

export { hasExports, isSideEffectImport, isModule, rewriteThis };

export interface RewriteModuleStatementsAndPrepareHeaderOptions {
exportName?: string;
strict: boolean;
allowTopLevelThis?: boolean;
strictMode: boolean;
loose?: boolean;
importInterop?: ImportInterop;
noInterop?: boolean;
lazy?: Lazy;
esNamespaceOnly?: boolean;
filename: string | undefined;
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
Expand All @@ -63,21 +81,7 @@ export function rewriteModuleStatementsAndPrepareHeader(
constantReexports = loose,
enumerableModuleMeta = loose,
noIncompleteNsImportDetection,
}: {
exportName?;
strict;
allowTopLevelThis?;
strictMode;
loose?;
importInterop?: "none" | "babel" | "node";
noInterop?;
lazy?;
esNamespaceOnly?;
filename: string | undefined;
constantReexports?;
enumerableModuleMeta?;
noIncompleteNsImportDetection?: boolean;
},
}: RewriteModuleStatementsAndPrepareHeaderOptions,
) {
validateImportInteropOption(importInterop);
assert(isModule(path), "Cannot process module statements in a script");
Expand Down Expand Up @@ -138,9 +142,10 @@ export function rewriteModuleStatementsAndPrepareHeader(
* Flag a set of statements as hoisted above all else so that module init
* statements all run before user code.
*/
export function ensureStatementsHoisted(statements) {
export function ensureStatementsHoisted(statements: t.Statement[]) {
// Force all of the header fields to be at the top of the file.
statements.forEach(header => {
// @ts-ignore Fixme: handle _blockHoist property
header._blockHoist = 3;
});
}
Expand Down Expand Up @@ -303,7 +308,7 @@ const buildReexportsFromMeta = (
*/
function buildESModuleHeader(
metadata: ModuleMetadata,
enumerableModuleMeta: boolean = false,
enumerableModuleMeta: boolean | void = false,
) {
return (
enumerableModuleMeta
Expand All @@ -321,7 +326,11 @@ function buildESModuleHeader(
/**
* Create a re-export initialization loop for a specific imported namespace.
*/
function buildNamespaceReexport(metadata, namespace, constantReexports) {
function buildNamespaceReexport(
metadata: ModuleMetadata,
namespace: t.Identifier | t.CallExpression,
constantReexports: boolean | void,
) {
return (
constantReexports
? template.statement`
Expand Down Expand Up @@ -413,8 +422,8 @@ function buildExportNameListDeclaration(
function buildExportInitializationStatements(
programPath: NodePath,
metadata: ModuleMetadata,
constantReexports: boolean = false,
noIncompleteNsImportDetection = false,
constantReexports: boolean | void = false,
noIncompleteNsImportDetection: boolean | void = false,
) {
const initStatements: Array<[string, t.Statement | null]> = [];

Expand Down Expand Up @@ -514,7 +523,11 @@ const InitTemplate = {
default: template.expression`EXPORTS.NAME = VALUE`,
};

function buildInitStatement(metadata: ModuleMetadata, exportNames, initExpr) {
function buildInitStatement(
metadata: ModuleMetadata,
exportNames: string[],
initExpr: t.Expression,
) {
const { stringSpecifiers, exportName: EXPORTS } = metadata;
return expressionStatement(
exportNames.reduce((acc, exportName) => {
Expand Down
Expand Up @@ -28,6 +28,14 @@ export type InteropType =
| "node-namespace" // Node.js interop for namespace or default+named imports
| "none"; // No interop, or named-only imports

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

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

export interface SourceModuleMetadata {
// A unique variable name to use for this namespace object. Centralized for simplicity.
name: string;
Expand All @@ -45,7 +53,7 @@ export interface SourceModuleMetadata {
reexportAll: null | {
loc: t.SourceLocation | undefined | null;
};
lazy?;
lazy?: Lazy;
}

export interface LocalExportMetadata {
Expand Down Expand Up @@ -75,7 +83,7 @@ export function isSideEffectImport(source: SourceModuleMetadata) {

export function validateImportInteropOption(
importInterop: any,
): importInterop is "none" | "babel" | "node" | Function {
): importInterop is ImportInterop {
if (
typeof importInterop !== "function" &&
importInterop !== "none" &&
Expand All @@ -90,8 +98,8 @@ export function validateImportInteropOption(
}

function resolveImportInterop(
importInterop,
source,
importInterop: ImportInterop,
source: string,
filename: string | undefined,
) {
if (typeof importInterop === "function") {
Expand All @@ -113,6 +121,12 @@ export default function normalizeModuleAndLoadMetadata(
lazy = false,
esNamespaceOnly = false,
filename,
}: {
importInterop: ImportInterop;
initializeReexports: boolean | void;
lazy: Lazy;
esNamespaceOnly: boolean;
filename: string;
},
): ModuleMetadata {
if (!exportName) {
Expand Down Expand Up @@ -219,8 +233,8 @@ function getModuleMetadata(
initializeReexports,
}: {
// todo(flow-ts) changed from boolean, to match expected usage inside the function
lazy: boolean | string[] | Function;
initializeReexports: boolean;
lazy: boolean | string[] | ((source: string) => boolean);
initializeReexports: boolean | void;
},
stringSpecifiers: Set<string>,
) {
Expand All @@ -231,7 +245,7 @@ function getModuleMetadata(
);

const sourceData = new Map();
const getData = sourceNode => {
const getData = (sourceNode: t.StringLiteral) => {
const source = sourceNode.value;

let data = sourceData.get(source);
Expand Down Expand Up @@ -409,22 +423,26 @@ function getModuleMetadata(
};
}

type ModuleBindingKind = "import" | "hoisted" | "block" | "var";
/**
* Get metadata about local variables that are exported.
*/
function getLocalExportMetadata(
programPath: NodePath<t.Program>,
initializeReexports: boolean,
initializeReexports: boolean | void,
stringSpecifiers: Set<string>,
): Map<string, LocalExportMetadata> {
const bindingKindLookup = new Map();

programPath.get("body").forEach((child: any) => {
let kind;
programPath.get("body").forEach(child => {
let kind: ModuleBindingKind;
if (child.isImportDeclaration()) {
kind = "import";
} else {
if (child.isExportDefaultDeclaration()) child = child.get("declaration");
if (child.isExportDefaultDeclaration()) {
// @ts-ignore
child = child.get("declaration");
}
if (child.isExportNamedDeclaration()) {
if (child.node.declaration) {
child = child.get("declaration");
Expand Down Expand Up @@ -460,7 +478,7 @@ function getLocalExportMetadata(
});

const localMetadata = new Map();
const getLocalMetadata = idPath => {
const getLocalMetadata = (idPath: NodePath<t.Identifier>) => {
const localName = idPath.node.name;
let metadata = localMetadata.get(localName);

Expand Down
Expand Up @@ -27,24 +27,24 @@ import type { ModuleMetadata } from "./normalize-and-load-metadata";
interface RewriteReferencesVisitorState {
exported: Map<any, any>;
metadata: ModuleMetadata;
requeueInParent: (path) => void;
requeueInParent: (path: NodePath) => void;
scope: Scope;
imported: Map<any, any>;
buildImportReference: (
[source, importName, localName]: readonly [any, any, any],
identNode,
[source, importName, localName]: readonly [string, string, string],
identNode: t.Identifier | t.CallExpression | t.JSXIdentifier,
) => any;
seen: WeakSet<object>;
}

interface RewriteBindingInitVisitorState {
exported: Map<any, any>;
metadata: ModuleMetadata;
requeueInParent: (path) => void;
requeueInParent: (path: NodePath) => void;
scope: Scope;
}

function isInType(path) {
function isInType(path: NodePath) {
do {
switch (path.parent.type) {
case "TSTypeAnnotation":
Expand All @@ -54,7 +54,13 @@ function isInType(path) {
case "TypeAlias":
return true;
case "ExportSpecifier":
return path.parentPath.parent.exportKind === "type";
return (
(
path.parentPath.parent as
| t.ExportDefaultDeclaration
| t.ExportNamedDeclaration
).exportKind === "type"
);
default:
if (path.parentPath.isStatement() || path.parentPath.isExpression()) {
return false;
Expand All @@ -69,7 +75,7 @@ export default function rewriteLiveReferences(
) {
const imported = new Map();
const exported = new Map();
const requeueInParent = path => {
const requeueInParent = (path: NodePath) => {
// Manually re-queue `exports.default =` expressions so that the ES3
// transform has an opportunity to convert them. Ideally this would
// happen automatically from the replaceWith above. See #4140 for
Expand Down Expand Up @@ -127,7 +133,13 @@ export default function rewriteLiveReferences(
const meta = metadata.source.get(source);

if (localName) {
if (meta.lazy) identNode = callExpression(identNode, []);
if (meta.lazy) {
identNode = callExpression(
// @ts-expect-error Fixme: we should handle the case when identNode is a JSXIdentifier
identNode,
[],
);
}
return identNode;
}

Expand Down Expand Up @@ -203,9 +215,9 @@ const rewriteBindingInitVisitor: Visitor<RewriteBindingInitVisitorState> = {
};

const buildBindingExportAssignmentExpression = (
metadata,
exportNames,
localExpr,
metadata: ModuleMetadata,
exportNames: string[],
localExpr: t.Expression,
) => {
return (exportNames || []).reduce((expr, exportName) => {
// class Foo {} export { Foo, Foo as Bar };
Expand All @@ -225,7 +237,7 @@ const buildBindingExportAssignmentExpression = (
}, localExpr);
};

const buildImportThrow = localName => {
const buildImportThrow = (localName: string) => {
return template.expression.ast`
(function() {
throw new Error('"' + '${localName}' + '" is read-only.');
Expand Down Expand Up @@ -403,7 +415,7 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
const assignment = path.node;

if (importData) {
assignment.left = buildImportReference(importData, assignment.left);
assignment.left = buildImportReference(importData, left.node);

assignment.right = sequenceExpression([
assignment.right,
Expand Down Expand Up @@ -437,7 +449,7 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {

// Complex ({a, b, c} = {}); export { a, c };
// => ({a, b, c} = {}), (exports.a = a, exports.c = c);
const items = [];
const items: t.Expression[] = [];
programScopeIds.forEach(localName => {
const exportedNames = exported.get(localName) || [];
if (exportedNames.length > 0) {
Expand Down
3 changes: 1 addition & 2 deletions packages/babel-helper-module-transforms/src/rewrite-this.ts
@@ -1,7 +1,6 @@
import environmentVisitor from "@babel/helper-environment-visitor";
import traverse from "@babel/traverse";
import { numericLiteral, unaryExpression } from "@babel/types";
import type * as t from "@babel/types";

import type { NodePath, Visitor } from "@babel/traverse";
export default function rewriteThis(programPath: NodePath) {
Expand All @@ -16,7 +15,7 @@ export default function rewriteThis(programPath: NodePath) {
const rewriteThisVisitor: Visitor = traverse.visitors.merge([
environmentVisitor,
{
ThisExpression(path: NodePath<t.ThisExpression>) {
ThisExpression(path) {
path.replaceWith(unaryExpression("void", numericLiteral(0), true));
},
},
Expand Down