react-refresh
Advanced tools
Comparing version 0.16.0-canary-fd0da3eef-20240404 to 0.16.0-rc-38e3b23483-20240529
'use strict'; | ||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('./cjs/react-refresh-babel.production.min.js'); | ||
module.exports = require('./cjs/react-refresh-babel.production.js'); | ||
} else { | ||
module.exports = require('./cjs/react-refresh-babel.development.js'); | ||
} |
/** | ||
* @license React | ||
* react-refresh-babel.production.min.js | ||
* react-refresh-babel.production.js | ||
* | ||
@@ -11,847 +11,577 @@ * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
'use strict'; | ||
function ReactFreshBabelPlugin (babel) { | ||
let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
if (typeof babel.env === 'function') { | ||
// Only available in Babel 7. | ||
const env = babel.env(); | ||
if (env !== 'development' && !opts.skipEnvCheck) { | ||
throw new Error('React Refresh Babel transform should only be enabled in development environment. ' + 'Instead, the environment is: "' + env + '". If you want to override this check, pass {skipEnvCheck: true} as plugin options.'); | ||
} | ||
} | ||
const t = babel.types; | ||
const refreshReg = t.identifier(opts.refreshReg || '$RefreshReg$'); | ||
const refreshSig = t.identifier(opts.refreshSig || '$RefreshSig$'); | ||
const registrationsByProgramPath = new Map(); | ||
"use strict"; | ||
module.exports = function (babel) { | ||
function createRegistration(programPath, persistentID) { | ||
const handle = programPath.scope.generateUidIdentifier('c'); | ||
if (!registrationsByProgramPath.has(programPath)) { | ||
var handle = programPath.scope.generateUidIdentifier("c"); | ||
registrationsByProgramPath.has(programPath) || | ||
registrationsByProgramPath.set(programPath, []); | ||
} | ||
const registrations = registrationsByProgramPath.get(programPath); | ||
registrations.push({ | ||
handle, | ||
persistentID | ||
}); | ||
registrationsByProgramPath | ||
.get(programPath) | ||
.push({ handle: handle, persistentID: persistentID }); | ||
return handle; | ||
} | ||
function isComponentishName(name) { | ||
return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z'; | ||
return "string" === typeof name && "A" <= name[0] && "Z" >= name[0]; | ||
} | ||
function findInnerComponents(inferredName, path, callback) { | ||
const node = path.node; | ||
var node = path.node; | ||
switch (node.type) { | ||
case 'Identifier': | ||
{ | ||
if (!isComponentishName(node.name)) { | ||
return false; | ||
} // export default hoc(Foo) | ||
// const X = hoc(Foo) | ||
callback(inferredName, node, null); | ||
return true; | ||
case "Identifier": | ||
if (!isComponentishName(node.name)) break; | ||
callback(inferredName, node, null); | ||
return !0; | ||
case "FunctionDeclaration": | ||
return callback(inferredName, node.id, null), !0; | ||
case "ArrowFunctionExpression": | ||
if ("ArrowFunctionExpression" === node.body.type) break; | ||
callback(inferredName, node, path); | ||
return !0; | ||
case "FunctionExpression": | ||
return callback(inferredName, node, path), !0; | ||
case "CallExpression": | ||
var argsPath = path.get("arguments"); | ||
if (void 0 === argsPath || 0 === argsPath.length) break; | ||
var calleePath = path.get("callee"); | ||
switch (calleePath.node.type) { | ||
case "MemberExpression": | ||
case "Identifier": | ||
calleePath = calleePath.getSource(); | ||
if ( | ||
!findInnerComponents( | ||
inferredName + "$" + calleePath, | ||
argsPath[0], | ||
callback | ||
) | ||
) | ||
return !1; | ||
callback(inferredName, node, path); | ||
return !0; | ||
default: | ||
return !1; | ||
} | ||
case 'FunctionDeclaration': | ||
{ | ||
// function Foo() {} | ||
// export function Foo() {} | ||
// export default function Foo() {} | ||
callback(inferredName, node.id, null); | ||
return true; | ||
} | ||
case 'ArrowFunctionExpression': | ||
{ | ||
if (node.body.type === 'ArrowFunctionExpression') { | ||
return false; | ||
} // let Foo = () => {} | ||
// export default hoc1(hoc2(() => {})) | ||
callback(inferredName, node, path); | ||
return true; | ||
} | ||
case 'FunctionExpression': | ||
{ | ||
// let Foo = function() {} | ||
// const Foo = hoc1(forwardRef(function renderFoo() {})) | ||
// export default memo(function() {}) | ||
callback(inferredName, node, path); | ||
return true; | ||
} | ||
case 'CallExpression': | ||
{ | ||
const argsPath = path.get('arguments'); | ||
if (argsPath === undefined || argsPath.length === 0) { | ||
return false; | ||
} | ||
const calleePath = path.get('callee'); | ||
switch (calleePath.node.type) { | ||
case 'MemberExpression': | ||
case 'Identifier': | ||
{ | ||
const calleeSource = calleePath.getSource(); | ||
const firstArgPath = argsPath[0]; | ||
const innerName = inferredName + '$' + calleeSource; | ||
const foundInside = findInnerComponents(innerName, firstArgPath, callback); | ||
if (!foundInside) { | ||
return false; | ||
} // const Foo = hoc1(hoc2(() => {})) | ||
// export default memo(React.forwardRef(function() {})) | ||
callback(inferredName, node, path); | ||
return true; | ||
} | ||
default: | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
case 'VariableDeclarator': | ||
{ | ||
const init = node.init; | ||
if (init === null) { | ||
return false; | ||
} | ||
const name = node.id.name; | ||
if (!isComponentishName(name)) { | ||
return false; | ||
} | ||
switch (init.type) { | ||
case 'ArrowFunctionExpression': | ||
case 'FunctionExpression': | ||
// Likely component definitions. | ||
case "VariableDeclarator": | ||
if ( | ||
((argsPath = node.init), | ||
null !== argsPath && | ||
((calleePath = node.id.name), isComponentishName(calleePath))) | ||
) { | ||
switch (argsPath.type) { | ||
case "ArrowFunctionExpression": | ||
case "FunctionExpression": | ||
break; | ||
case 'CallExpression': | ||
{ | ||
// Maybe a HOC. | ||
// Try to determine if this is some form of import. | ||
const callee = init.callee; | ||
const calleeType = callee.type; | ||
if (calleeType === 'Import') { | ||
return false; | ||
} else if (calleeType === 'Identifier') { | ||
if (callee.name.indexOf('require') === 0) { | ||
return false; | ||
} else if (callee.name.indexOf('import') === 0) { | ||
return false; | ||
} // Neither require nor import. Might be a HOC. | ||
// Pass through. | ||
} else ; | ||
break; | ||
} | ||
case 'TaggedTemplateExpression': | ||
// Maybe something like styled.div`...` | ||
case "CallExpression": | ||
node = argsPath.callee; | ||
var calleeType = node.type; | ||
if ( | ||
"Import" === calleeType || | ||
("Identifier" === calleeType && | ||
(0 === node.name.indexOf("require") || | ||
0 === node.name.indexOf("import"))) | ||
) | ||
return !1; | ||
break; | ||
case "TaggedTemplateExpression": | ||
break; | ||
default: | ||
return false; | ||
return !1; | ||
} | ||
const initPath = path.get('init'); | ||
const foundInside = findInnerComponents(inferredName, initPath, callback); | ||
if (foundInside) { | ||
return true; | ||
} // See if this identifier is used in JSX. Then it's a component. | ||
const binding = path.scope.getBinding(name); | ||
if (binding === undefined) { | ||
return; | ||
} | ||
let isLikelyUsedAsType = false; | ||
const referencePaths = binding.referencePaths; | ||
for (let i = 0; i < referencePaths.length; i++) { | ||
const ref = referencePaths[i]; | ||
if (ref.node && ref.node.type !== 'JSXIdentifier' && ref.node.type !== 'Identifier') { | ||
continue; | ||
} | ||
const refParent = ref.parent; | ||
if (refParent.type === 'JSXOpeningElement') { | ||
isLikelyUsedAsType = true; | ||
} else if (refParent.type === 'CallExpression') { | ||
const callee = refParent.callee; | ||
let fnName; | ||
switch (callee.type) { | ||
case 'Identifier': | ||
fnName = callee.name; | ||
break; | ||
case 'MemberExpression': | ||
fnName = callee.property.name; | ||
break; | ||
node = path.get("init"); | ||
if (findInnerComponents(inferredName, node, callback)) return !0; | ||
calleePath = path.scope.getBinding(calleePath); | ||
if (void 0 === calleePath) return; | ||
path = !1; | ||
calleePath = calleePath.referencePaths; | ||
for (calleeType = 0; calleeType < calleePath.length; calleeType++) { | ||
var ref = calleePath[calleeType]; | ||
if ( | ||
!ref.node || | ||
"JSXIdentifier" === ref.node.type || | ||
"Identifier" === ref.node.type | ||
) { | ||
ref = ref.parent; | ||
if ("JSXOpeningElement" === ref.type) path = !0; | ||
else if ("CallExpression" === ref.type) { | ||
ref = ref.callee; | ||
var fnName = void 0; | ||
switch (ref.type) { | ||
case "Identifier": | ||
fnName = ref.name; | ||
break; | ||
case "MemberExpression": | ||
fnName = ref.property.name; | ||
} | ||
switch (fnName) { | ||
case "createElement": | ||
case "jsx": | ||
case "jsxDEV": | ||
case "jsxs": | ||
path = !0; | ||
} | ||
} | ||
switch (fnName) { | ||
case 'createElement': | ||
case 'jsx': | ||
case 'jsxDEV': | ||
case 'jsxs': | ||
isLikelyUsedAsType = true; | ||
break; | ||
} | ||
if (path) return callback(inferredName, argsPath, node), !0; | ||
} | ||
if (isLikelyUsedAsType) { | ||
// const X = ... + later <X /> | ||
callback(inferredName, init, initPath); | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
return !1; | ||
} | ||
function isBuiltinHook(hookName) { | ||
switch (hookName) { | ||
case 'useState': | ||
case 'React.useState': | ||
case 'useReducer': | ||
case 'React.useReducer': | ||
case 'useEffect': | ||
case 'React.useEffect': | ||
case 'useLayoutEffect': | ||
case 'React.useLayoutEffect': | ||
case 'useMemo': | ||
case 'React.useMemo': | ||
case 'useCallback': | ||
case 'React.useCallback': | ||
case 'useRef': | ||
case 'React.useRef': | ||
case 'useContext': | ||
case 'React.useContext': | ||
case 'useImperativeHandle': | ||
case 'React.useImperativeHandle': | ||
case 'useDebugValue': | ||
case 'React.useDebugValue': | ||
case 'useId': | ||
case 'React.useId': | ||
case 'useDeferredValue': | ||
case 'React.useDeferredValue': | ||
case 'useTransition': | ||
case 'React.useTransition': | ||
case 'useInsertionEffect': | ||
case 'React.useInsertionEffect': | ||
case 'useSyncExternalStore': | ||
case 'React.useSyncExternalStore': | ||
case 'useFormStatus': | ||
case 'React.useFormStatus': | ||
case 'useFormState': | ||
case 'React.useFormState': | ||
case 'useActionState': | ||
case 'React.useActionState': | ||
case 'useOptimistic': | ||
case 'React.useOptimistic': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
function getHookCallsSignature(functionNode) { | ||
const fnHookCalls = hookCalls.get(functionNode); | ||
if (fnHookCalls === undefined) { | ||
return null; | ||
} | ||
return { | ||
key: fnHookCalls.map(call => call.name + '{' + call.key + '}').join('\n'), | ||
customHooks: fnHookCalls.filter(call => !isBuiltinHook(call.name)).map(call => t.cloneDeep(call.callee)) | ||
}; | ||
functionNode = hookCalls.get(functionNode); | ||
return void 0 === functionNode | ||
? null | ||
: { | ||
key: functionNode | ||
.map(function (call) { | ||
return call.name + "{" + call.key + "}"; | ||
}) | ||
.join("\n"), | ||
customHooks: functionNode | ||
.filter(function (call) { | ||
a: switch (call.name) { | ||
case "useState": | ||
case "React.useState": | ||
case "useReducer": | ||
case "React.useReducer": | ||
case "useEffect": | ||
case "React.useEffect": | ||
case "useLayoutEffect": | ||
case "React.useLayoutEffect": | ||
case "useMemo": | ||
case "React.useMemo": | ||
case "useCallback": | ||
case "React.useCallback": | ||
case "useRef": | ||
case "React.useRef": | ||
case "useContext": | ||
case "React.useContext": | ||
case "useImperativeHandle": | ||
case "React.useImperativeHandle": | ||
case "useDebugValue": | ||
case "React.useDebugValue": | ||
case "useId": | ||
case "React.useId": | ||
case "useDeferredValue": | ||
case "React.useDeferredValue": | ||
case "useTransition": | ||
case "React.useTransition": | ||
case "useInsertionEffect": | ||
case "React.useInsertionEffect": | ||
case "useSyncExternalStore": | ||
case "React.useSyncExternalStore": | ||
case "useFormStatus": | ||
case "React.useFormStatus": | ||
case "useFormState": | ||
case "React.useFormState": | ||
case "useActionState": | ||
case "React.useActionState": | ||
case "useOptimistic": | ||
case "React.useOptimistic": | ||
call = !0; | ||
break a; | ||
default: | ||
call = !1; | ||
} | ||
return !call; | ||
}) | ||
.map(function (call) { | ||
return t.cloneDeep(call.callee); | ||
}) | ||
}; | ||
} | ||
const hasForceResetCommentByFile = new WeakMap(); // We let user do /* @refresh reset */ to reset state in the whole file. | ||
function hasForceResetComment(path) { | ||
const file = path.hub.file; | ||
let hasForceReset = hasForceResetCommentByFile.get(file); | ||
if (hasForceReset !== undefined) { | ||
return hasForceReset; | ||
} | ||
hasForceReset = false; | ||
const comments = file.ast.comments; | ||
for (let i = 0; i < comments.length; i++) { | ||
const cmt = comments[i]; | ||
if (cmt.value.indexOf('@refresh reset') !== -1) { | ||
hasForceReset = true; | ||
path = path.hub.file; | ||
var hasForceReset = hasForceResetCommentByFile.get(path); | ||
if (void 0 !== hasForceReset) return hasForceReset; | ||
hasForceReset = !1; | ||
for (var comments = path.ast.comments, i = 0; i < comments.length; i++) | ||
if (-1 !== comments[i].value.indexOf("@refresh reset")) { | ||
hasForceReset = !0; | ||
break; | ||
} | ||
} | ||
hasForceResetCommentByFile.set(file, hasForceReset); | ||
hasForceResetCommentByFile.set(path, hasForceReset); | ||
return hasForceReset; | ||
} | ||
function createArgumentsForSignature(node, signature, scope) { | ||
const key = signature.key, | ||
customHooks = signature.customHooks; | ||
let forceReset = hasForceResetComment(scope.path); | ||
const customHooksInScope = []; | ||
customHooks.forEach(callee => { | ||
// Check if a corresponding binding exists where we emit the signature. | ||
let bindingName; | ||
var key = signature.key; | ||
signature = signature.customHooks; | ||
var forceReset = hasForceResetComment(scope.path), | ||
customHooksInScope = []; | ||
signature.forEach(function (callee) { | ||
switch (callee.type) { | ||
case 'MemberExpression': | ||
if (callee.object.type === 'Identifier') { | ||
bindingName = callee.object.name; | ||
} | ||
case "MemberExpression": | ||
if ("Identifier" === callee.object.type) | ||
var bindingName = callee.object.name; | ||
break; | ||
case 'Identifier': | ||
case "Identifier": | ||
bindingName = callee.name; | ||
break; | ||
} | ||
if (scope.hasBinding(bindingName)) { | ||
customHooksInScope.push(callee); | ||
} else { | ||
// We don't have anything to put in the array because Hook is out of scope. | ||
// Since it could potentially have been edited, remount the component. | ||
forceReset = true; | ||
} | ||
scope.hasBinding(bindingName) | ||
? customHooksInScope.push(callee) | ||
: (forceReset = !0); | ||
}); | ||
let finalKey = key; | ||
if (typeof require === 'function' && !opts.emitFullSignatures) { | ||
// Prefer to hash when we can (e.g. outside of ASTExplorer). | ||
// This makes it deterministically compact, even if there's | ||
// e.g. a useState initializer with some code inside. | ||
// We also need it for www that has transforms like cx() | ||
// that don't understand if something is part of a string. | ||
finalKey = require('crypto').createHash('sha1').update(key).digest('base64'); | ||
} | ||
const args = [node, t.stringLiteral(finalKey)]; | ||
if (forceReset || customHooksInScope.length > 0) { | ||
args.push(t.booleanLiteral(forceReset)); | ||
} | ||
if (customHooksInScope.length > 0) { | ||
args.push( // TODO: We could use an arrow here to be more compact. | ||
// However, don't do it until AMA can run them natively. | ||
t.functionExpression(null, [], t.blockStatement([t.returnStatement(t.arrayExpression(customHooksInScope))]))); | ||
} | ||
return args; | ||
signature = key; | ||
"function" !== typeof require || | ||
opts.emitFullSignatures || | ||
(signature = require("crypto") | ||
.createHash("sha1") | ||
.update(key) | ||
.digest("base64")); | ||
node = [node, t.stringLiteral(signature)]; | ||
(forceReset || 0 < customHooksInScope.length) && | ||
node.push(t.booleanLiteral(forceReset)); | ||
0 < customHooksInScope.length && | ||
node.push( | ||
t.functionExpression( | ||
null, | ||
[], | ||
t.blockStatement([ | ||
t.returnStatement(t.arrayExpression(customHooksInScope)) | ||
]) | ||
) | ||
); | ||
return node; | ||
} | ||
function findHOCCallPathsAbove(path) { | ||
const calls = []; | ||
while (true) { | ||
if (!path) { | ||
return calls; | ||
} | ||
const parentPath = path.parentPath; | ||
if (!parentPath) { | ||
return calls; | ||
} | ||
if ( // hoc(_c = function() { }) | ||
parentPath.node.type === 'AssignmentExpression' && path.node === parentPath.node.right) { | ||
// Ignore registrations. | ||
for (var calls = []; ; ) { | ||
if (!path) return calls; | ||
var parentPath = path.parentPath; | ||
if (!parentPath) return calls; | ||
if ( | ||
"AssignmentExpression" === parentPath.node.type && | ||
path.node === parentPath.node.right | ||
) | ||
path = parentPath; | ||
continue; | ||
} | ||
if ( // hoc1(hoc2(...)) | ||
parentPath.node.type === 'CallExpression' && path.node !== parentPath.node.callee) { | ||
calls.push(parentPath); | ||
path = parentPath; | ||
continue; | ||
} | ||
return calls; // Stop at other types. | ||
else if ( | ||
"CallExpression" === parentPath.node.type && | ||
path.node !== parentPath.node.callee | ||
) | ||
calls.push(parentPath), (path = parentPath); | ||
else return calls; | ||
} | ||
} | ||
const seenForRegistration = new WeakSet(); | ||
const seenForSignature = new WeakSet(); | ||
const seenForOutro = new WeakSet(); | ||
const hookCalls = new WeakMap(); | ||
const HookCallsVisitor = { | ||
CallExpression(path) { | ||
const node = path.node; | ||
const callee = node.callee; // Note: this visitor MUST NOT mutate the tree in any way. | ||
// It runs early in a separate traversal and should be very fast. | ||
let name = null; | ||
switch (callee.type) { | ||
case 'Identifier': | ||
name = callee.name; | ||
break; | ||
case 'MemberExpression': | ||
name = callee.property.name; | ||
break; | ||
var opts = | ||
1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {}; | ||
if ("function" === typeof babel.env) { | ||
var env = babel.env(); | ||
if ("development" !== env && !opts.skipEnvCheck) | ||
throw Error( | ||
'React Refresh Babel transform should only be enabled in development environment. Instead, the environment is: "' + | ||
env + | ||
'". If you want to override this check, pass {skipEnvCheck: true} as plugin options.' | ||
); | ||
} | ||
var t = babel.types, | ||
refreshReg = t.identifier(opts.refreshReg || "$RefreshReg$"), | ||
refreshSig = t.identifier(opts.refreshSig || "$RefreshSig$"), | ||
registrationsByProgramPath = new Map(), | ||
hasForceResetCommentByFile = new WeakMap(), | ||
seenForRegistration = new WeakSet(), | ||
seenForSignature = new WeakSet(), | ||
seenForOutro = new WeakSet(), | ||
hookCalls = new WeakMap(), | ||
HookCallsVisitor = { | ||
CallExpression: function (path) { | ||
var callee = path.node.callee, | ||
name = null; | ||
switch (callee.type) { | ||
case "Identifier": | ||
name = callee.name; | ||
break; | ||
case "MemberExpression": | ||
name = callee.property.name; | ||
} | ||
if ( | ||
null !== name && | ||
/^use[A-Z]/.test(name) && | ||
((callee = path.scope.getFunctionParent()), null !== callee) | ||
) { | ||
callee = callee.block; | ||
hookCalls.has(callee) || hookCalls.set(callee, []); | ||
callee = hookCalls.get(callee); | ||
var key = ""; | ||
"VariableDeclarator" === path.parent.type && | ||
(key = path.parentPath.get("id").getSource()); | ||
var args = path.get("arguments"); | ||
"useState" === name && 0 < args.length | ||
? (key += "(" + args[0].getSource() + ")") | ||
: "useReducer" === name && | ||
1 < args.length && | ||
(key += "(" + args[1].getSource() + ")"); | ||
callee.push({ callee: path.node.callee, name: name, key: key }); | ||
} | ||
} | ||
if (name === null || !/^use[A-Z]/.test(name)) { | ||
return; | ||
} | ||
const fnScope = path.scope.getFunctionParent(); | ||
if (fnScope === null) { | ||
return; | ||
} // This is a Hook call. Record it. | ||
const fnNode = fnScope.block; | ||
if (!hookCalls.has(fnNode)) { | ||
hookCalls.set(fnNode, []); | ||
} | ||
const hookCallsForFn = hookCalls.get(fnNode); | ||
let key = ''; | ||
if (path.parent.type === 'VariableDeclarator') { | ||
// TODO: if there is no LHS, consider some other heuristic. | ||
key = path.parentPath.get('id').getSource(); | ||
} // Some built-in Hooks reset on edits to arguments. | ||
const args = path.get('arguments'); | ||
if (name === 'useState' && args.length > 0) { | ||
// useState second argument is initial state. | ||
key += '(' + args[0].getSource() + ')'; | ||
} else if (name === 'useReducer' && args.length > 1) { | ||
// useReducer second argument is initial state. | ||
key += '(' + args[1].getSource() + ')'; | ||
} | ||
hookCallsForFn.push({ | ||
callee: path.node.callee, | ||
name, | ||
key | ||
}); | ||
} | ||
}; | ||
}; | ||
return { | ||
visitor: { | ||
ExportDefaultDeclaration(path) { | ||
const node = path.node; | ||
const decl = node.declaration; | ||
const declPath = path.get('declaration'); | ||
if (decl.type !== 'CallExpression') { | ||
// For now, we only support possible HOC calls here. | ||
// Named function declarations are handled in FunctionDeclaration. | ||
// Anonymous direct exports like export default function() {} | ||
// are currently ignored. | ||
return; | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
if (seenForRegistration.has(node)) { | ||
return; | ||
ExportDefaultDeclaration: function (path) { | ||
var node = path.node, | ||
decl = node.declaration, | ||
declPath = path.get("declaration"); | ||
if ("CallExpression" === decl.type && !seenForRegistration.has(node)) { | ||
seenForRegistration.add(node); | ||
var programPath = path.parentPath; | ||
findInnerComponents( | ||
"%default%", | ||
declPath, | ||
function (persistentID, targetExpr, targetPath) { | ||
null !== targetPath && | ||
((persistentID = createRegistration(programPath, persistentID)), | ||
targetPath.replaceWith( | ||
t.assignmentExpression("=", persistentID, targetExpr) | ||
)); | ||
} | ||
); | ||
} | ||
seenForRegistration.add(node); // Don't mutate the tree above this point. | ||
// This code path handles nested cases like: | ||
// export default memo(() => {}) | ||
// In those cases it is more plausible people will omit names | ||
// so they're worth handling despite possible false positives. | ||
// More importantly, it handles the named case: | ||
// export default memo(function Named() {}) | ||
const inferredName = '%default%'; | ||
const programPath = path.parentPath; | ||
findInnerComponents(inferredName, declPath, (persistentID, targetExpr, targetPath) => { | ||
if (targetPath === null) { | ||
// For case like: | ||
// export default hoc(Foo) | ||
// we don't want to wrap Foo inside the call. | ||
// Instead we assume it's registered at definition. | ||
return; | ||
} | ||
const handle = createRegistration(programPath, persistentID); | ||
targetPath.replaceWith(t.assignmentExpression('=', handle, targetExpr)); | ||
}); | ||
}, | ||
FunctionDeclaration: { | ||
enter(path) { | ||
const node = path.node; | ||
let programPath; | ||
let insertAfterPath; | ||
let modulePrefix = ''; | ||
enter: function (path) { | ||
var node = path.node, | ||
modulePrefix = ""; | ||
switch (path.parent.type) { | ||
case 'Program': | ||
insertAfterPath = path; | ||
programPath = path.parentPath; | ||
case "Program": | ||
var insertAfterPath = path; | ||
var programPath = path.parentPath; | ||
break; | ||
case 'TSModuleBlock': | ||
case "TSModuleBlock": | ||
insertAfterPath = path; | ||
programPath = insertAfterPath.parentPath.parentPath; | ||
break; | ||
case 'ExportNamedDeclaration': | ||
case "ExportNamedDeclaration": | ||
insertAfterPath = path.parentPath; | ||
programPath = insertAfterPath.parentPath; | ||
break; | ||
case 'ExportDefaultDeclaration': | ||
case "ExportDefaultDeclaration": | ||
insertAfterPath = path.parentPath; | ||
programPath = insertAfterPath.parentPath; | ||
break; | ||
default: | ||
return; | ||
} // These types can be nested in typescript namespace | ||
// We need to find the export chain | ||
// Or return if it stays local | ||
if (path.parent.type === 'TSModuleBlock' || path.parent.type === 'ExportNamedDeclaration') { | ||
while (programPath.type !== 'Program') { | ||
if (programPath.type === 'TSModuleDeclaration') { | ||
if (programPath.parentPath.type !== 'Program' && programPath.parentPath.type !== 'ExportNamedDeclaration') { | ||
} | ||
if ( | ||
"TSModuleBlock" === path.parent.type || | ||
"ExportNamedDeclaration" === path.parent.type | ||
) | ||
for (; "Program" !== programPath.type; ) { | ||
if ("TSModuleDeclaration" === programPath.type) { | ||
if ( | ||
"Program" !== programPath.parentPath.type && | ||
"ExportNamedDeclaration" !== programPath.parentPath.type | ||
) | ||
return; | ||
} | ||
modulePrefix = programPath.node.id.name + '$' + modulePrefix; | ||
modulePrefix = programPath.node.id.name + "$" + modulePrefix; | ||
} | ||
programPath = programPath.parentPath; | ||
} | ||
} | ||
const id = node.id; | ||
if (id === null) { | ||
// We don't currently handle anonymous default exports. | ||
return; | ||
} | ||
const inferredName = id.name; | ||
if (!isComponentishName(inferredName)) { | ||
return; | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
if (seenForRegistration.has(node)) { | ||
return; | ||
} | ||
seenForRegistration.add(node); // Don't mutate the tree above this point. | ||
const innerName = modulePrefix + inferredName; // export function Named() {} | ||
// function Named() {} | ||
findInnerComponents(innerName, path, (persistentID, targetExpr) => { | ||
const handle = createRegistration(programPath, persistentID); | ||
insertAfterPath.insertAfter(t.expressionStatement(t.assignmentExpression('=', handle, targetExpr))); | ||
}); | ||
var id = node.id; | ||
null !== id && | ||
((id = id.name), | ||
isComponentishName(id) && | ||
!seenForRegistration.has(node) && | ||
(seenForRegistration.add(node), | ||
findInnerComponents( | ||
modulePrefix + id, | ||
path, | ||
function (persistentID, targetExpr) { | ||
persistentID = createRegistration(programPath, persistentID); | ||
insertAfterPath.insertAfter( | ||
t.expressionStatement( | ||
t.assignmentExpression("=", persistentID, targetExpr) | ||
) | ||
); | ||
} | ||
))); | ||
}, | ||
exit(path) { | ||
const node = path.node; | ||
const id = node.id; | ||
if (id === null) { | ||
return; | ||
} | ||
const signature = getHookCallsSignature(node); | ||
if (signature === null) { | ||
return; | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
if (seenForSignature.has(node)) { | ||
return; | ||
} | ||
seenForSignature.add(node); // Don't mutate the tree above this point. | ||
const sigCallID = path.scope.generateUidIdentifier('_s'); | ||
path.scope.parent.push({ | ||
id: sigCallID, | ||
init: t.callExpression(refreshSig, []) | ||
}); // The signature call is split in two parts. One part is called inside the function. | ||
// This is used to signal when first render happens. | ||
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, []))); // The second call is around the function itself. | ||
// This is used to associate a type with a signature. | ||
// Unlike with $RefreshReg$, this needs to work for nested | ||
// declarations too. So we need to search for a path where | ||
// we can insert a statement rather than hard coding it. | ||
let insertAfterPath = null; | ||
path.find(p => { | ||
if (p.parentPath.isBlock()) { | ||
insertAfterPath = p; | ||
return true; | ||
exit: function (path) { | ||
var node = path.node, | ||
id = node.id; | ||
if (null !== id) { | ||
var signature = getHookCallsSignature(node); | ||
if (null !== signature && !seenForSignature.has(node)) { | ||
seenForSignature.add(node); | ||
node = path.scope.generateUidIdentifier("_s"); | ||
path.scope.parent.push({ | ||
id: node, | ||
init: t.callExpression(refreshSig, []) | ||
}); | ||
path | ||
.get("body") | ||
.unshiftContainer( | ||
"body", | ||
t.expressionStatement(t.callExpression(node, [])) | ||
); | ||
var insertAfterPath = null; | ||
path.find(function (p) { | ||
if (p.parentPath.isBlock()) return (insertAfterPath = p), !0; | ||
}); | ||
null !== insertAfterPath && | ||
insertAfterPath.insertAfter( | ||
t.expressionStatement( | ||
t.callExpression( | ||
node, | ||
createArgumentsForSignature( | ||
id, | ||
signature, | ||
insertAfterPath.scope | ||
) | ||
) | ||
) | ||
); | ||
} | ||
}); | ||
if (insertAfterPath === null) { | ||
return; | ||
} | ||
insertAfterPath.insertAfter(t.expressionStatement(t.callExpression(sigCallID, createArgumentsForSignature(id, signature, insertAfterPath.scope)))); | ||
} | ||
}, | ||
'ArrowFunctionExpression|FunctionExpression': { | ||
exit(path) { | ||
const node = path.node; | ||
const signature = getHookCallsSignature(node); | ||
if (signature === null) { | ||
return; | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
if (seenForSignature.has(node)) { | ||
return; | ||
} | ||
seenForSignature.add(node); // Don't mutate the tree above this point. | ||
const sigCallID = path.scope.generateUidIdentifier('_s'); | ||
path.scope.parent.push({ | ||
id: sigCallID, | ||
init: t.callExpression(refreshSig, []) | ||
}); // The signature call is split in two parts. One part is called inside the function. | ||
// This is used to signal when first render happens. | ||
if (path.node.body.type !== 'BlockStatement') { | ||
path.node.body = t.blockStatement([t.returnStatement(path.node.body)]); | ||
} | ||
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, []))); // The second call is around the function itself. | ||
// This is used to associate a type with a signature. | ||
if (path.parent.type === 'VariableDeclarator') { | ||
let insertAfterPath = null; | ||
path.find(p => { | ||
if (p.parentPath.isBlock()) { | ||
insertAfterPath = p; | ||
return true; | ||
} | ||
"ArrowFunctionExpression|FunctionExpression": { | ||
exit: function (path) { | ||
var node = path.node, | ||
signature = getHookCallsSignature(node); | ||
if (null !== signature && !seenForSignature.has(node)) { | ||
seenForSignature.add(node); | ||
var sigCallID = path.scope.generateUidIdentifier("_s"); | ||
path.scope.parent.push({ | ||
id: sigCallID, | ||
init: t.callExpression(refreshSig, []) | ||
}); | ||
if (insertAfterPath === null) { | ||
return; | ||
} // Special case when a function would get an inferred name: | ||
// let Foo = () => {} | ||
// let Foo = function() {} | ||
// We'll add signature it on next line so that | ||
// we don't mess up the inferred 'Foo' function name. | ||
insertAfterPath.insertAfter(t.expressionStatement(t.callExpression(sigCallID, createArgumentsForSignature(path.parent.id, signature, insertAfterPath.scope)))); // Result: let Foo = () => {}; __signature(Foo, ...); | ||
} else { | ||
// let Foo = hoc(() => {}) | ||
const paths = [path].concat(findHOCCallPathsAbove(path)); | ||
paths.forEach(p => { | ||
p.replaceWith(t.callExpression(sigCallID, createArgumentsForSignature(p.node, signature, p.scope))); | ||
}); // Result: let Foo = __signature(hoc(__signature(() => {}, ...)), ...) | ||
"BlockStatement" !== path.node.body.type && | ||
(path.node.body = t.blockStatement([ | ||
t.returnStatement(path.node.body) | ||
])); | ||
path | ||
.get("body") | ||
.unshiftContainer( | ||
"body", | ||
t.expressionStatement(t.callExpression(sigCallID, [])) | ||
); | ||
if ("VariableDeclarator" === path.parent.type) { | ||
var insertAfterPath = null; | ||
path.find(function (p) { | ||
if (p.parentPath.isBlock()) return (insertAfterPath = p), !0; | ||
}); | ||
null !== insertAfterPath && | ||
insertAfterPath.insertAfter( | ||
t.expressionStatement( | ||
t.callExpression( | ||
sigCallID, | ||
createArgumentsForSignature( | ||
path.parent.id, | ||
signature, | ||
insertAfterPath.scope | ||
) | ||
) | ||
) | ||
); | ||
} else | ||
[path].concat(findHOCCallPathsAbove(path)).forEach(function (p) { | ||
p.replaceWith( | ||
t.callExpression( | ||
sigCallID, | ||
createArgumentsForSignature(p.node, signature, p.scope) | ||
) | ||
); | ||
}); | ||
} | ||
} | ||
}, | ||
VariableDeclaration(path) { | ||
const node = path.node; | ||
let programPath; | ||
let insertAfterPath; | ||
let modulePrefix = ''; | ||
VariableDeclaration: function (path) { | ||
var node = path.node, | ||
modulePrefix = ""; | ||
switch (path.parent.type) { | ||
case 'Program': | ||
insertAfterPath = path; | ||
programPath = path.parentPath; | ||
case "Program": | ||
var insertAfterPath = path; | ||
var programPath = path.parentPath; | ||
break; | ||
case 'TSModuleBlock': | ||
case "TSModuleBlock": | ||
insertAfterPath = path; | ||
programPath = insertAfterPath.parentPath.parentPath; | ||
break; | ||
case 'ExportNamedDeclaration': | ||
case "ExportNamedDeclaration": | ||
insertAfterPath = path.parentPath; | ||
programPath = insertAfterPath.parentPath; | ||
break; | ||
case 'ExportDefaultDeclaration': | ||
case "ExportDefaultDeclaration": | ||
insertAfterPath = path.parentPath; | ||
programPath = insertAfterPath.parentPath; | ||
break; | ||
default: | ||
return; | ||
} // These types can be nested in typescript namespace | ||
// We need to find the export chain | ||
// Or return if it stays local | ||
if (path.parent.type === 'TSModuleBlock' || path.parent.type === 'ExportNamedDeclaration') { | ||
while (programPath.type !== 'Program') { | ||
if (programPath.type === 'TSModuleDeclaration') { | ||
if (programPath.parentPath.type !== 'Program' && programPath.parentPath.type !== 'ExportNamedDeclaration') { | ||
} | ||
if ( | ||
"TSModuleBlock" === path.parent.type || | ||
"ExportNamedDeclaration" === path.parent.type | ||
) | ||
for (; "Program" !== programPath.type; ) { | ||
if ("TSModuleDeclaration" === programPath.type) { | ||
if ( | ||
"Program" !== programPath.parentPath.type && | ||
"ExportNamedDeclaration" !== programPath.parentPath.type | ||
) | ||
return; | ||
} | ||
modulePrefix = programPath.node.id.name + '$' + modulePrefix; | ||
modulePrefix = programPath.node.id.name + "$" + modulePrefix; | ||
} | ||
programPath = programPath.parentPath; | ||
} | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
if (seenForRegistration.has(node)) { | ||
return; | ||
if ( | ||
!seenForRegistration.has(node) && | ||
(seenForRegistration.add(node), | ||
(path = path.get("declarations")), | ||
1 === path.length) | ||
) { | ||
var declPath = path[0]; | ||
findInnerComponents( | ||
modulePrefix + declPath.node.id.name, | ||
declPath, | ||
function (persistentID, targetExpr, targetPath) { | ||
null !== targetPath && | ||
((persistentID = createRegistration(programPath, persistentID)), | ||
"VariableDeclarator" === targetPath.parent.type | ||
? insertAfterPath.insertAfter( | ||
t.expressionStatement( | ||
t.assignmentExpression( | ||
"=", | ||
persistentID, | ||
declPath.node.id | ||
) | ||
) | ||
) | ||
: targetPath.replaceWith( | ||
t.assignmentExpression("=", persistentID, targetExpr) | ||
)); | ||
} | ||
); | ||
} | ||
seenForRegistration.add(node); // Don't mutate the tree above this point. | ||
const declPaths = path.get('declarations'); | ||
if (declPaths.length !== 1) { | ||
return; | ||
} | ||
const declPath = declPaths[0]; | ||
const inferredName = declPath.node.id.name; | ||
const innerName = modulePrefix + inferredName; | ||
findInnerComponents(innerName, declPath, (persistentID, targetExpr, targetPath) => { | ||
if (targetPath === null) { | ||
// For case like: | ||
// export const Something = hoc(Foo) | ||
// we don't want to wrap Foo inside the call. | ||
// Instead we assume it's registered at definition. | ||
return; | ||
} | ||
const handle = createRegistration(programPath, persistentID); | ||
if (targetPath.parent.type === 'VariableDeclarator') { | ||
// Special case when a variable would get an inferred name: | ||
// let Foo = () => {} | ||
// let Foo = function() {} | ||
// let Foo = styled.div``; | ||
// We'll register it on next line so that | ||
// we don't mess up the inferred 'Foo' function name. | ||
// (eg: with @babel/plugin-transform-react-display-name or | ||
// babel-plugin-styled-components) | ||
insertAfterPath.insertAfter(t.expressionStatement(t.assignmentExpression('=', handle, declPath.node.id))); // Result: let Foo = () => {}; _c1 = Foo; | ||
} else { | ||
// let Foo = hoc(() => {}) | ||
targetPath.replaceWith(t.assignmentExpression('=', handle, targetExpr)); // Result: let Foo = hoc(_c1 = () => {}) | ||
} | ||
}); | ||
}, | ||
Program: { | ||
enter(path) { | ||
// This is a separate early visitor because we need to collect Hook calls | ||
// and "const [foo, setFoo] = ..." signatures before the destructuring | ||
// transform mangles them. This extra traversal is not ideal for perf, | ||
// but it's the best we can do until we stop transpiling destructuring. | ||
enter: function (path) { | ||
path.traverse(HookCallsVisitor); | ||
}, | ||
exit(path) { | ||
const registrations = registrationsByProgramPath.get(path); | ||
if (registrations === undefined) { | ||
return; | ||
} // Make sure we're not mutating the same tree twice. | ||
// This can happen if another Babel plugin replaces parents. | ||
const node = path.node; | ||
if (seenForOutro.has(node)) { | ||
return; | ||
exit: function (path) { | ||
var registrations = registrationsByProgramPath.get(path); | ||
if (void 0 !== registrations) { | ||
var node = path.node; | ||
if (!seenForOutro.has(node)) { | ||
seenForOutro.add(node); | ||
registrationsByProgramPath.delete(path); | ||
var declarators = []; | ||
path.pushContainer( | ||
"body", | ||
t.variableDeclaration("var", declarators) | ||
); | ||
registrations.forEach(function (_ref) { | ||
var handle = _ref.handle; | ||
path.pushContainer( | ||
"body", | ||
t.expressionStatement( | ||
t.callExpression(refreshReg, [ | ||
handle, | ||
t.stringLiteral(_ref.persistentID) | ||
]) | ||
) | ||
); | ||
declarators.push(t.variableDeclarator(handle)); | ||
}); | ||
} | ||
} | ||
seenForOutro.add(node); // Don't mutate the tree above this point. | ||
registrationsByProgramPath.delete(path); | ||
const declarators = []; | ||
path.pushContainer('body', t.variableDeclaration('var', declarators)); | ||
registrations.forEach((_ref) => { | ||
let handle = _ref.handle, | ||
persistentID = _ref.persistentID; | ||
path.pushContainer('body', t.expressionStatement(t.callExpression(refreshReg, [handle, t.stringLiteral(persistentID)]))); | ||
declarators.push(t.variableDeclarator(handle)); | ||
}); | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
module.exports = ReactFreshBabelPlugin; | ||
}; |
@@ -17,3 +17,2 @@ /** | ||
// ATTENTION | ||
var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref'); | ||
@@ -20,0 +19,0 @@ var REACT_MEMO_TYPE = Symbol.for('react.memo'); |
/** | ||
* @license React | ||
* react-refresh-runtime.production.min.js | ||
* react-refresh-runtime.production.js | ||
* | ||
@@ -11,105 +11,5 @@ * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
'use strict'; | ||
{ | ||
throw new Error('React Refresh runtime should not be included in the production bundle.'); | ||
} // In old environments, we'll leak previous types after every edit. | ||
function performReactRefresh() { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function register(type, id) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function setSignature(type, key) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} // This is lazily called during first render for a type. | ||
// It captures Hook list at that time so inline requires don't break comparisons. | ||
function collectCustomHooksForSignature(type) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function getFamilyByID(id) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function getFamilyByType(type) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function findAffectedHostInstances(families) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function injectIntoGlobalHook(globalObject) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function hasUnrecoverableErrors() { | ||
// TODO: delete this after removing dependency in RN. | ||
return false; | ||
} // Exposed for testing. | ||
function _getMountedRootCount() { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} // This is a wrapper over more primitive functions for setting signature. | ||
// Signatures let us decide whether the Hook order has changed on refresh. | ||
// | ||
// This function is intended to be used as a transform target, e.g.: | ||
// var _s = createSignatureFunctionForTransform() | ||
// | ||
// function Hello() { | ||
// const [foo, setFoo] = useState(0); | ||
// const value = useCustomHook(); | ||
// _s(); /* Call without arguments triggers collecting the custom Hook list. | ||
// * This doesn't happen during the module evaluation because we | ||
// * don't want to change the module order with inline requires. | ||
// * Next calls are noops. */ | ||
// return <h1>Hi</h1>; | ||
// } | ||
// | ||
// /* Call with arguments attaches the signature to the type: */ | ||
// _s( | ||
// Hello, | ||
// 'useState{[foo, setFoo]}(0)', | ||
// () => [useCustomHook], /* Lazy to avoid triggering inline requires */ | ||
// ); | ||
function createSignatureFunctionForTransform() { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
function isLikelyComponentType(type) { | ||
{ | ||
throw new Error('Unexpected call to React Refresh in a production environment.'); | ||
} | ||
} | ||
exports._getMountedRootCount = _getMountedRootCount; | ||
exports.collectCustomHooksForSignature = collectCustomHooksForSignature; | ||
exports.createSignatureFunctionForTransform = createSignatureFunctionForTransform; | ||
exports.findAffectedHostInstances = findAffectedHostInstances; | ||
exports.getFamilyByID = getFamilyByID; | ||
exports.getFamilyByType = getFamilyByType; | ||
exports.hasUnrecoverableErrors = hasUnrecoverableErrors; | ||
exports.injectIntoGlobalHook = injectIntoGlobalHook; | ||
exports.isLikelyComponentType = isLikelyComponentType; | ||
exports.performReactRefresh = performReactRefresh; | ||
exports.register = register; | ||
exports.setSignature = setSignature; | ||
"use strict"; | ||
throw Error( | ||
"React Refresh runtime should not be included in the production bundle." | ||
); |
@@ -7,3 +7,3 @@ { | ||
], | ||
"version": "0.16.0-canary-fd0da3eef-20240404", | ||
"version": "0.16.0-rc-38e3b23483-20240529", | ||
"homepage": "https://react.dev/", | ||
@@ -17,4 +17,3 @@ "bugs": "https://github.com/facebook/react/issues", | ||
"runtime.js", | ||
"cjs/", | ||
"umd/" | ||
"cjs/" | ||
], | ||
@@ -21,0 +20,0 @@ "main": "runtime.js", |
'use strict'; | ||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('./cjs/react-refresh-runtime.production.min.js'); | ||
module.exports = require('./cjs/react-refresh-runtime.production.js'); | ||
} else { | ||
module.exports = require('./cjs/react-refresh-runtime.development.js'); | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1
71747
9
1840