mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Make globals configurable; populate a reasonable default list
This is a precursor to validating that all identifiers are defined - we need to know about gobals and module declarations, so this PR adds the ability to configure a Set<string> of defined globals. The default list is inspired by the globals that prepack defines, which just comes from the spec definition.
This commit is contained in:
@@ -13,7 +13,7 @@ export type PluginOptions = {
|
||||
*/
|
||||
enableOnlyOnUseForgetDirective: boolean;
|
||||
|
||||
environment: EnvironmentOptions | null;
|
||||
environment: Partial<EnvironmentOptions> | null;
|
||||
};
|
||||
|
||||
export const defaultOptions: PluginOptions = {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
mergeConsecutiveBlocks,
|
||||
ReactiveFunction,
|
||||
} from "./HIR";
|
||||
import { EnvironmentOptions } from "./HIR/Environment";
|
||||
import { EnvironmentOptions, mergeOptions } from "./HIR/Environment";
|
||||
import {
|
||||
analyseFunctions,
|
||||
dropMemoCalls,
|
||||
@@ -49,9 +49,9 @@ export type CompilerPipelineValue =
|
||||
|
||||
export function* run(
|
||||
func: NodePath<t.FunctionDeclaration>,
|
||||
options?: EnvironmentOptions | null
|
||||
options?: Partial<EnvironmentOptions> | null
|
||||
): Generator<CompilerPipelineValue, t.Function> {
|
||||
const hir = lower(func, options ?? null).unwrap();
|
||||
const hir = lower(func, mergeOptions(options ?? null)).unwrap();
|
||||
yield log({ kind: "hir", name: "HIR", value: hir });
|
||||
|
||||
mergeConsecutiveBlocks(hir);
|
||||
@@ -190,7 +190,7 @@ export function* run(
|
||||
|
||||
export function compile(
|
||||
func: NodePath<t.FunctionDeclaration>,
|
||||
options?: EnvironmentOptions | null
|
||||
options?: Partial<EnvironmentOptions> | null
|
||||
): t.Function {
|
||||
let generator = run(func, options);
|
||||
while (true) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { log } from "../Utils/logger";
|
||||
import { DEFAULT_GLOBALS, Global } from "./Globals";
|
||||
import { Effect, IdentifierId, makeIdentifierId, ValueKind } from "./HIR";
|
||||
import { BUILTIN_HOOKS, Hook } from "./Hooks";
|
||||
|
||||
@@ -5,12 +7,23 @@ const HOOK_PATTERN = /^_?use/;
|
||||
|
||||
export type EnvironmentOptions = {
|
||||
customHooks: Map<string, Hook>;
|
||||
globals: Set<string>;
|
||||
};
|
||||
|
||||
const DEFAULT_OPTIONS: EnvironmentOptions = {
|
||||
customHooks: new Map(),
|
||||
globals: DEFAULT_GLOBALS,
|
||||
};
|
||||
|
||||
export function mergeOptions(
|
||||
options: Partial<EnvironmentOptions> | null
|
||||
): EnvironmentOptions {
|
||||
return {
|
||||
...DEFAULT_OPTIONS,
|
||||
...(options ?? {}),
|
||||
};
|
||||
}
|
||||
|
||||
export class Environment {
|
||||
#options: EnvironmentOptions;
|
||||
#nextIdentifer: number = 0;
|
||||
@@ -27,6 +40,13 @@ export class Environment {
|
||||
return makeIdentifierId(this.#nextIdentifer++);
|
||||
}
|
||||
|
||||
getGlobalDeclaration(name: string): Global | null {
|
||||
if (!this.#options.globals.has(name)) {
|
||||
log(() => `Undefined global '${name}'`);
|
||||
}
|
||||
return { name };
|
||||
}
|
||||
|
||||
getHookDeclaration(name: string): Hook | null {
|
||||
if (!name.match(HOOK_PATTERN)) {
|
||||
return null;
|
||||
|
||||
@@ -5,25 +5,51 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import * as t from "@babel/types";
|
||||
|
||||
const GLOBALS: Map<string, t.Identifier> = new Map([
|
||||
["Map", t.identifier("Map")],
|
||||
["Set", t.identifier("Set")],
|
||||
["Math", t.identifier("Math")],
|
||||
export const DEFAULT_GLOBALS: Set<string> = new Set([
|
||||
"String",
|
||||
"Object",
|
||||
"Function",
|
||||
"Array",
|
||||
"Number",
|
||||
"RegExp",
|
||||
"Date",
|
||||
"Math",
|
||||
"Error",
|
||||
"Function",
|
||||
"TypeError",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"SyntaxError",
|
||||
"URIError",
|
||||
"EvalError",
|
||||
"Boolean",
|
||||
"DataView",
|
||||
"Float32Array",
|
||||
"Float64Array",
|
||||
"Int8Array",
|
||||
"Int16Array",
|
||||
"Int32Array",
|
||||
"Map",
|
||||
"Set",
|
||||
"WeakMap",
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
"Uint16Array",
|
||||
"Uint32Array",
|
||||
"ArrayBuffer",
|
||||
"JSON",
|
||||
"parseFloat",
|
||||
"parseInt",
|
||||
"console",
|
||||
"isNaN",
|
||||
"eval",
|
||||
"isFinite",
|
||||
"encodeURI",
|
||||
"decodeURI",
|
||||
"encodeURIComponent",
|
||||
"decodeURIComponent",
|
||||
]);
|
||||
|
||||
export type Global = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
// TODO: This will work as a stopgap but it isn't really correct. We need proper handling of globals
|
||||
// and module-scoped variables, which means understanding module constants and imports.
|
||||
export function getGlobalDeclaration(identifierName: string): Global | null {
|
||||
const ident = GLOBALS.get(identifierName);
|
||||
if (ident != null) {
|
||||
return ident;
|
||||
}
|
||||
// TODO: return null if not explicitly configured by the user
|
||||
return { name: identifierName };
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { CompilerError } from "../CompilerError";
|
||||
import { logHIR } from "../Utils/logger";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
import { Environment } from "./Environment";
|
||||
import { getGlobalDeclaration, Global } from "./Globals";
|
||||
import { Global } from "./Globals";
|
||||
import {
|
||||
BasicBlock,
|
||||
BlockId,
|
||||
@@ -137,7 +137,7 @@ export default class HIRBuilder {
|
||||
}
|
||||
|
||||
resolveGlobal(path: NodePath<t.Identifier | t.JSXIdentifier>): Global | null {
|
||||
return getGlobalDeclaration(path.node.name);
|
||||
return this.#env.getGlobalDeclaration(path.node.name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user