This commit is contained in:
2025-06-16 13:37:14 +02:00
parent ac273655e6
commit a8b82208f7
5100 changed files with 737524 additions and 2 deletions

65
node_modules/@prefresh/babel-plugin/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,65 @@
# @prefresh/babel-plugin
## 0.5.1
### Patch Changes
- [`7e47061`](https://github.com/preactjs/prefresh/commit/7e470614e70915e994937e97245df9914806be86) [#524](https://github.com/preactjs/prefresh/pull/524) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Ensure we accoutn for the filename when hashing
## 0.5.0
### Minor Changes
- [`e641c69`](https://github.com/preactjs/prefresh/commit/e641c69c610c3adeeb5dcb9e912d030a6fbb5229) [#499](https://github.com/preactjs/prefresh/pull/499) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Publish automatically with npm provenance enabled
* [`35e18f7`](https://github.com/preactjs/prefresh/commit/35e18f719cf17415e33cd2ac0ed83031b1f62b44) [#488](https://github.com/preactjs/prefresh/pull/488) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Transform createContext calls that we find within a closure to make them unique
## 0.4.4
### Patch Changes
- [`01bf615`](https://github.com/preactjs/prefresh/commit/01bf615f99f8615d892883c6e47d4f0c94822e89) [#477](https://github.com/preactjs/prefresh/pull/477) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Support contexts nested in an object
## 0.4.2
### Patch Changes
- [`eb9aa93`](https://github.com/preactjs/prefresh/commit/eb9aa932fc2a01fed3ecb662e195422986529419) [#425](https://github.com/preactjs/prefresh/pull/425) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix import paths for newer node versions
* [`f39ab40`](https://github.com/preactjs/prefresh/commit/f39ab409a46a7a06f8e892920e407be728fcefa1) [#432](https://github.com/preactjs/prefresh/pull/432) Thanks [@jvdsande](https://github.com/jvdsande)! - Allow curried HOC and any parameter order for HOC
## 0.4.1
### Patch Changes
- [`010f21b`](https://github.com/preactjs/prefresh/commit/010f21b947d0cdee59fac6af6a17d10cb6a696b5) [#287](https://github.com/preactjs/prefresh/pull/287) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix createContext detection in React-Preact/compat
## 0.4.0
### Minor Changes
- [`21f8c43`](https://github.com/preactjs/prefresh/commit/21f8c4330a29edcb5d4493cda5465e6556a5f92c) [#243](https://github.com/preactjs/prefresh/pull/243) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Invalidate useEffect/useLayoutEffect/useMemo/useCallback without resetting hook-state aggressively, now hook-state will only be reset for stateful hooks.
## 0.3.0
### Minor Changes
- [`c0835d5`](https://github.com/preactjs/prefresh/commit/c0835d5c5820809563ec768296a610b45d7dc0c0) [#233](https://github.com/preactjs/prefresh/pull/233) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Calculate hashes for useEffect and useLayoutEffect
## 0.2.2
### Patch Changes
- [`39c60c5`](https://github.com/preactjs/prefresh/commit/39c60c5862adef106fed1ca59a968f40cdacdd10) [#195](https://github.com/preactjs/prefresh/pull/195) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix syntax issue preventing babel from correctly assigning defaultValues
## 0.2.1
### Patch Changes
- [`53e79a8`](https://github.com/preactjs/prefresh/commit/53e79a8bcdf5ef3a9387e46307cfd0ce1a2a3186) [#193](https://github.com/preactjs/prefresh/pull/193) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix bug where a TSAsExpression would make our transform behave funky
## 0.2.0
### Minor Changes
- [`430fe2c`](https://github.com/preactjs/prefresh/commit/430fe2c2b281b1973a74c542a38c1bb5be2a6559) [#185](https://github.com/preactjs/prefresh/pull/185) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add support for registering class components

22
node_modules/@prefresh/babel-plugin/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2020-2021 Jovi De Croock
Copyright (c) 2021-Present Preact Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
node_modules/@prefresh/babel-plugin/README.md generated vendored Normal file
View File

@@ -0,0 +1,6 @@
# Prefresh-babel
[![npm version](https://badgen.net/npm/v/@prefresh/babel-plugin)](https://www.npmjs.com/package/@prefresh/babel-plugin)
This is a forked equivalent of [the react-refresh babel plugin](https://github.com/facebook/react/blob/master/packages/react-refresh/src/ReactFreshBabelPlugin.js)
difference being that we need a way to memoize createContext between HMR.

924
node_modules/@prefresh/babel-plugin/dist/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,924 @@
function hash(str) {
let hash = 5381,
i = str.length;
while (i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
return (hash >>> 0).toString(36);
}
/**
*
* Majority copied from https://github.com/facebook/react/blob/master/packages/react-refresh/src/ReactFreshBabelPlugin.js
*/
module.exports=function (babel, opts = {}) {
if (typeof babel.env === 'function') {
const env = babel.env();
if (env !== 'development' && !opts.skipEnvCheck) {
throw new Error(
'Prefresh 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 { types: t, template } = babel;
const refreshReg = t.identifier(opts.refreshReg || '$RefreshReg$');
const refreshSig = t.identifier(opts.refreshSig || '$RefreshSig$');
const registrationsByProgramPath = new Map();
function createRegistration(programPath, persistentID) {
const handle = programPath.scope.generateUidIdentifier('c');
if (!registrationsByProgramPath.has(programPath)) {
registrationsByProgramPath.set(programPath, []);
}
const registrations = registrationsByProgramPath.get(programPath);
registrations.push({
handle,
persistentID,
});
return handle;
}
function isComponentishName(name) {
return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z';
}
function findInnerComponents(inferredName, path, callback) {
const 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 'FunctionDeclaration': {
// function Foo() {}
// function Foo() {}
// module.exports=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 'CallExpression':
case 'MemberExpression':
case 'Identifier': {
const calleeSource = calleePath.getSource().split('(')[0];
const innerName = inferredName + '$' + calleeSource;
const foundInside = argsPath.some(argPath =>
findInnerComponents(innerName, argPath, 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.
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 if (calleeType === 'MemberExpression') {
// Could be something like React.forwardRef(...)
// Pass through.
}
break;
}
case 'TaggedTemplateExpression':
// Maybe something like styled.div`...`
break;
default:
return false;
}
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;
}
switch (fnName) {
case 'createElement':
case 'jsx':
case 'jsxDEV':
case 'jsxs':
isLikelyUsedAsType = true;
break;
}
}
if (isLikelyUsedAsType) {
// const X = ... + later <X />
callback(inferredName, init, initPath);
return true;
}
}
}
}
return false;
}
function isBuiltinHook(hookName) {
switch (hookName) {
case 'useErrorBoundary':
case 'React.useErrorBoundary':
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 'useImperativeMethods':
case 'React.useImperativeMethods':
case 'useDebugValue':
case 'React.useDebugValue':
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)),
};
}
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;
break;
}
}
hasForceResetCommentByFile.set(file, hasForceReset);
return hasForceReset;
}
function createArgumentsForSignature(node, signature, scope) {
const { key, customHooks } = signature;
let forceReset = hasForceResetComment(scope.path);
const customHooksInScope = [];
customHooks.forEach(callee => {
// Check if a corresponding binding exists where we emit the signature.
let bindingName;
switch (callee.type) {
case 'MemberExpression':
if (callee.object.type === 'Identifier') {
bindingName = callee.object.name;
}
break;
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;
}
});
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;
}
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;
}
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 first 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,
});
},
};
const createContextTemplate = template(
`
Object.assign((CREATECONTEXT[IDENT] || (CREATECONTEXT[IDENT]=CREATECONTEXT(VALUE))), {__:VALUE});
`,
{ placeholderPattern: /^[A-Z]+$/ }
);
const emptyTemplate = template(`
(CREATECONTEXT[IDENT] || (CREATECONTEXT[IDENT]=CREATECONTEXT()));
`);
const getFirstNonTsExpression = expression =>
expression.type === 'TSAsExpression'
? getFirstNonTsExpression(expression.expression)
: expression;
return {
visitor: {
ClassDeclaration: {
enter(path) {
const node = path.node;
let programPath;
let insertAfterPath;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
return;
}
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 handle = createRegistration(programPath, inferredName);
insertAfterPath.insertAfter(
t.expressionStatement(
t.assignmentExpression('=', handle, path.node.id)
)
);
},
},
CallExpression(path, state) {
if (
!path.get('callee').referencesImport('preact', 'createContext') &&
!path.get('callee').referencesImport('react', 'createContext') &&
!path.get('callee').referencesImport('preact/compat', 'createContext')
)
return;
let id = '';
if (t.isObjectProperty(path.parentPath)) {
id += '__' + path.parent.key.name;
} else if (t.isVariableDeclarator(path.parentPath)) {
id += '$' + path.parent.id.name;
} else if (t.isAssignmentExpression(path.parentPath)) {
if (t.isIdentifier(path.parent.left)) {
id += '_' + path.parent.left.name;
} else {
id += '_' + hash(path.parentPath.get('left').getSource());
}
}
const getFirstParent = parentPath => {
if (
t.isProgram(parentPath) ||
t.isFunctionDeclaration(parentPath) ||
t.isArrowFunctionExpression(parentPath)
)
return parentPath;
return getFirstParent(parentPath.parentPath);
};
const closestClosurePath = getFirstParent(path.parentPath);
const contexts = state.get('contexts');
let counter = (contexts.get(id) || -1) + 1;
contexts.set(id, counter);
if (counter) id += counter;
id = '_' + state.get('filehash') + id;
path.skip();
if (!t.isProgram(closestClosurePath)) {
const params = closestClosurePath.node.params;
params.forEach(param => {
if (t.isIdentifier(param)) {
id += '_PARAM' + param.name;
}
});
}
// TODO: maybe wrap with JSON.stringify
if (path.node.arguments[0]) {
const [quasi, ...expressions] = id.split('_PARAM');
const first = t.templateElement({ raw: quasi, cooked: '' });
const expr = expressions.map(x => t.identifier(x.replace('}', '')));
path.replaceWith(
createContextTemplate({
CREATECONTEXT: path.get('callee').node,
IDENT: t.templateLiteral(
[
first,
...expressions.map(() =>
t.templateElement({ raw: '', cooked: '' }, true)
),
],
expr
),
VALUE: t.clone(getFirstNonTsExpression(path.node.arguments[0])),
})
);
} else {
const [quasi, ...expressions] = id.split('_PARAM');
const first = t.templateElement({ raw: quasi, cooked: '' });
const expr = expressions.map(x => t.identifier(x.replace('}', '')));
path.replaceWith(
emptyTemplate({
CREATECONTEXT: path.get('callee').node,
IDENT: t.templateLiteral(
[
first,
...expressions.map(() =>
t.templateElement({ raw: '', cooked: '' }, true)
),
],
expr
),
})
);
}
},
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 module.exports=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;
}
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;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
return;
}
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.
// function Named() {}
// function Named() {}
findInnerComponents(
inferredName,
path,
(persistentID, targetExpr) => {
const handle = createRegistration(programPath, persistentID);
insertAfterPath.insertAfter(
t.expressionStatement(
t.assignmentExpression('=', handle, 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;
}
});
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;
}
});
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(() => {})
path.replaceWith(
t.callExpression(
sigCallID,
createArgumentsForSignature(node, signature, path.scope)
)
);
// Result: let Foo = hoc(__signature(() => {}, ...))
}
},
},
VariableDeclaration(path) {
const node = path.node;
let programPath;
let insertAfterPath;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
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 declPaths = path.get('declarations');
if (declPaths.length !== 1) {
return;
}
const declPath = declPaths[0];
const inferredName = declPath.node.id.name;
findInnerComponents(
inferredName,
declPath,
(persistentID, targetExpr, targetPath) => {
if (targetPath === null) {
// For case like:
// 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, state) {
state.set(
'filehash',
hash(
path.hub.file.opts.filename ||
path.hub.file.opts.sourceFileName ||
path.hub.file.opts.generatorOpts?.sourceFileName ||
'unnamed'
)
);
state.set('contexts', new Map());
// 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.
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;
}
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(({ handle, persistentID }) => {
path.pushContainer(
'body',
t.expressionStatement(
t.callExpression(refreshReg, [
handle,
t.stringLiteral(persistentID),
])
)
);
declarators.push(t.variableDeclarator(handle));
});
},
},
},
};
}

33
node_modules/@prefresh/babel-plugin/package.json generated vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "@prefresh/babel-plugin",
"version": "0.5.1",
"main": "dist/src/index.js",
"module": "src/index.mjs",
"exports": {
".": {
"import": "./src/index.mjs",
"require": "./dist/src/index.js"
},
"./package.json": "./package.json"
},
"repository": {
"type": "git",
"url": "git+https://github.com/preactjs/prefresh.git",
"directory": "packages/babel"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/preactjs/prefresh/issues"
},
"homepage": "https://github.com/preactjs/prefresh#readme",
"devDependencies": {
"cjyes": "0.3.1"
},
"publishConfig": {
"provenance": true
},
"scripts": {
"build": "cjyes src/index.mjs",
"lint": "eslint src"
}
}

924
node_modules/@prefresh/babel-plugin/src/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,924 @@
function hash(str) {
let hash = 5381,
i = str.length;
while (i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
return (hash >>> 0).toString(36);
}
/**
*
* Majority copied from https://github.com/facebook/react/blob/master/packages/react-refresh/src/ReactFreshBabelPlugin.js
*/
export default function (babel, opts = {}) {
if (typeof babel.env === 'function') {
const env = babel.env();
if (env !== 'development' && !opts.skipEnvCheck) {
throw new Error(
'Prefresh 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 { types: t, template } = babel;
const refreshReg = t.identifier(opts.refreshReg || '$RefreshReg$');
const refreshSig = t.identifier(opts.refreshSig || '$RefreshSig$');
const registrationsByProgramPath = new Map();
function createRegistration(programPath, persistentID) {
const handle = programPath.scope.generateUidIdentifier('c');
if (!registrationsByProgramPath.has(programPath)) {
registrationsByProgramPath.set(programPath, []);
}
const registrations = registrationsByProgramPath.get(programPath);
registrations.push({
handle,
persistentID,
});
return handle;
}
function isComponentishName(name) {
return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z';
}
function findInnerComponents(inferredName, path, callback) {
const 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 '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 'CallExpression':
case 'MemberExpression':
case 'Identifier': {
const calleeSource = calleePath.getSource().split('(')[0];
const innerName = inferredName + '$' + calleeSource;
const foundInside = argsPath.some(argPath =>
findInnerComponents(innerName, argPath, 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.
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 if (calleeType === 'MemberExpression') {
// Could be something like React.forwardRef(...)
// Pass through.
}
break;
}
case 'TaggedTemplateExpression':
// Maybe something like styled.div`...`
break;
default:
return false;
}
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;
}
switch (fnName) {
case 'createElement':
case 'jsx':
case 'jsxDEV':
case 'jsxs':
isLikelyUsedAsType = true;
break;
}
}
if (isLikelyUsedAsType) {
// const X = ... + later <X />
callback(inferredName, init, initPath);
return true;
}
}
}
}
return false;
}
function isBuiltinHook(hookName) {
switch (hookName) {
case 'useErrorBoundary':
case 'React.useErrorBoundary':
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 'useImperativeMethods':
case 'React.useImperativeMethods':
case 'useDebugValue':
case 'React.useDebugValue':
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)),
};
}
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;
break;
}
}
hasForceResetCommentByFile.set(file, hasForceReset);
return hasForceReset;
}
function createArgumentsForSignature(node, signature, scope) {
const { key, customHooks } = signature;
let forceReset = hasForceResetComment(scope.path);
const customHooksInScope = [];
customHooks.forEach(callee => {
// Check if a corresponding binding exists where we emit the signature.
let bindingName;
switch (callee.type) {
case 'MemberExpression':
if (callee.object.type === 'Identifier') {
bindingName = callee.object.name;
}
break;
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;
}
});
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;
}
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;
}
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 first 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,
});
},
};
const createContextTemplate = template(
`
Object.assign((CREATECONTEXT[IDENT] || (CREATECONTEXT[IDENT]=CREATECONTEXT(VALUE))), {__:VALUE});
`,
{ placeholderPattern: /^[A-Z]+$/ }
);
const emptyTemplate = template(`
(CREATECONTEXT[IDENT] || (CREATECONTEXT[IDENT]=CREATECONTEXT()));
`);
const getFirstNonTsExpression = expression =>
expression.type === 'TSAsExpression'
? getFirstNonTsExpression(expression.expression)
: expression;
return {
visitor: {
ClassDeclaration: {
enter(path) {
const node = path.node;
let programPath;
let insertAfterPath;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
return;
}
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 handle = createRegistration(programPath, inferredName);
insertAfterPath.insertAfter(
t.expressionStatement(
t.assignmentExpression('=', handle, path.node.id)
)
);
},
},
CallExpression(path, state) {
if (
!path.get('callee').referencesImport('preact', 'createContext') &&
!path.get('callee').referencesImport('react', 'createContext') &&
!path.get('callee').referencesImport('preact/compat', 'createContext')
)
return;
let id = '';
if (t.isObjectProperty(path.parentPath)) {
id += '__' + path.parent.key.name;
} else if (t.isVariableDeclarator(path.parentPath)) {
id += '$' + path.parent.id.name;
} else if (t.isAssignmentExpression(path.parentPath)) {
if (t.isIdentifier(path.parent.left)) {
id += '_' + path.parent.left.name;
} else {
id += '_' + hash(path.parentPath.get('left').getSource());
}
}
const getFirstParent = parentPath => {
if (
t.isProgram(parentPath) ||
t.isFunctionDeclaration(parentPath) ||
t.isArrowFunctionExpression(parentPath)
)
return parentPath;
return getFirstParent(parentPath.parentPath);
};
const closestClosurePath = getFirstParent(path.parentPath);
const contexts = state.get('contexts');
let counter = (contexts.get(id) || -1) + 1;
contexts.set(id, counter);
if (counter) id += counter;
id = '_' + state.get('filehash') + id;
path.skip();
if (!t.isProgram(closestClosurePath)) {
const params = closestClosurePath.node.params;
params.forEach(param => {
if (t.isIdentifier(param)) {
id += '_PARAM' + param.name;
}
});
}
// TODO: maybe wrap with JSON.stringify
if (path.node.arguments[0]) {
const [quasi, ...expressions] = id.split('_PARAM');
const first = t.templateElement({ raw: quasi, cooked: '' });
const expr = expressions.map(x => t.identifier(x.replace('}', '')));
path.replaceWith(
createContextTemplate({
CREATECONTEXT: path.get('callee').node,
IDENT: t.templateLiteral(
[
first,
...expressions.map(() =>
t.templateElement({ raw: '', cooked: '' }, true)
),
],
expr
),
VALUE: t.clone(getFirstNonTsExpression(path.node.arguments[0])),
})
);
} else {
const [quasi, ...expressions] = id.split('_PARAM');
const first = t.templateElement({ raw: quasi, cooked: '' });
const expr = expressions.map(x => t.identifier(x.replace('}', '')));
path.replaceWith(
emptyTemplate({
CREATECONTEXT: path.get('callee').node,
IDENT: t.templateLiteral(
[
first,
...expressions.map(() =>
t.templateElement({ raw: '', cooked: '' }, true)
),
],
expr
),
})
);
}
},
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;
}
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;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
return;
}
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.
// export function Named() {}
// function Named() {}
findInnerComponents(
inferredName,
path,
(persistentID, targetExpr) => {
const handle = createRegistration(programPath, persistentID);
insertAfterPath.insertAfter(
t.expressionStatement(
t.assignmentExpression('=', handle, 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;
}
});
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;
}
});
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(() => {})
path.replaceWith(
t.callExpression(
sigCallID,
createArgumentsForSignature(node, signature, path.scope)
)
);
// Result: let Foo = hoc(__signature(() => {}, ...))
}
},
},
VariableDeclaration(path) {
const node = path.node;
let programPath;
let insertAfterPath;
switch (path.parent.type) {
case 'Program':
insertAfterPath = path;
programPath = path.parentPath;
break;
case 'ExportNamedDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
case 'ExportDefaultDeclaration':
insertAfterPath = path.parentPath;
programPath = insertAfterPath.parentPath;
break;
default:
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 declPaths = path.get('declarations');
if (declPaths.length !== 1) {
return;
}
const declPath = declPaths[0];
const inferredName = declPath.node.id.name;
findInnerComponents(
inferredName,
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, state) {
state.set(
'filehash',
hash(
path.hub.file.opts.filename ||
path.hub.file.opts.sourceFileName ||
path.hub.file.opts.generatorOpts?.sourceFileName ||
'unnamed'
)
);
state.set('contexts', new Map());
// 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.
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;
}
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(({ handle, persistentID }) => {
path.pushContainer(
'body',
t.expressionStatement(
t.callExpression(refreshReg, [
handle,
t.stringLiteral(persistentID),
])
)
);
declarators.push(t.variableDeclarator(handle));
});
},
},
},
};
}

158
node_modules/@prefresh/core/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,158 @@
# @prefresh/core
## 1.5.3
### Patch Changes
- [`06f97ac`](https://github.com/preactjs/prefresh/commit/06f97ac8dfa17492bab9a1f9d711fba2069d0f48) [#559](https://github.com/preactjs/prefresh/pull/559) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Avoid memory leak by not registering built-in types
## 1.5.2
### Patch Changes
- [`1101d1f`](https://github.com/preactjs/prefresh/commit/1101d1f34c31c58196ffcaa044b9c80625a4ed81) [#514](https://github.com/preactjs/prefresh/pull/514) Thanks [@antran22](https://github.com/antran22)! - add guard for undefined component before accessing parentDom
## 1.5.1
### Patch Changes
- [`9ad0839`](https://github.com/preactjs/prefresh/commit/9ad083939801a5eae6fbb78ec94f58b357667ece) [#505](https://github.com/preactjs/prefresh/pull/505) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Stop invoking setState on unmounted vnodes
* [`9ad0839`](https://github.com/preactjs/prefresh/commit/9ad083939801a5eae6fbb78ec94f58b357667ece) [#505](https://github.com/preactjs/prefresh/pull/505) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix case where a repeatedly called upon component would have a lot of entries in the vnodesForComponent
## 1.5.0
### Minor Changes
- [`e641c69`](https://github.com/preactjs/prefresh/commit/e641c69c610c3adeeb5dcb9e912d030a6fbb5229) [#499](https://github.com/preactjs/prefresh/pull/499) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Publish automatically with npm provenance enabled
## 1.4.1
### Patch Changes
- [`a4f25c2`](https://github.com/preactjs/prefresh/commit/a4f25c25ccec53df522aa9b506a4b2dee973af7d) [#471](https://github.com/preactjs/prefresh/pull/471) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - update signal handling to not dispose all state
## 1.4.0
### Minor Changes
- [`1121bae`](https://github.com/preactjs/prefresh/commit/1121baecfaf9d2206a216f7c7cb2d2ea260540d7) [#470](https://github.com/preactjs/prefresh/pull/470) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Support signals that are globally defined
## 1.3.4
### Patch Changes
- [`f89017d`](https://github.com/preactjs/prefresh/commit/f89017df1d9194468dbde4241c6d8431d77d0377) [#447](https://github.com/preactjs/prefresh/pull/447) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - remove async component check
## 1.3.3
### Patch Changes
- [`eb9aa93`](https://github.com/preactjs/prefresh/commit/eb9aa932fc2a01fed3ecb662e195422986529419) [#425](https://github.com/preactjs/prefresh/pull/425) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix import paths for newer node versions
## 1.3.2
### Patch Changes
- [`0121873`](https://github.com/preactjs/prefresh/commit/01218735288c380a1d7ad6909f5b94bff4c77ead) [#325](https://github.com/preactjs/prefresh/pull/325) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Forward thirth prop for catchError
## 1.3.1
### Patch Changes
- [`c256066`](https://github.com/preactjs/prefresh/commit/c2560664e794bbd50f26d10953b0d63fb563b26c) [#296](https://github.com/preactjs/prefresh/pull/296) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Skip registration of non-function nodes
## 1.3.0
### Minor Changes
- [`21f8c43`](https://github.com/preactjs/prefresh/commit/21f8c4330a29edcb5d4493cda5465e6556a5f92c) [#243](https://github.com/preactjs/prefresh/pull/243) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Invalidate useEffect/useLayoutEffect/useMemo/useCallback without resetting hook-state aggressively, now hook-state will only be reset for stateful hooks.
## 1.2.0
### Minor Changes
- [`bcd6113`](https://github.com/preactjs/prefresh/commit/bcd61138872ca0494b9b480f4b153458997071a0) [#236](https://github.com/preactjs/prefresh/pull/236) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Update oldVnodeTypes in place with newer equivalents
## 1.1.1
### Patch Changes
- [`b8678d0`](https://github.com/preactjs/prefresh/commit/b8678d036cb02c7b3b9901b2057ba04a4f4c1041) [#206](https://github.com/preactjs/prefresh/pull/206) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Improve cleanup detection
## 1.1.0
### Minor Changes
- [`ac7c5d1`](https://github.com/preactjs/prefresh/commit/ac7c5d150bcbb9cea40060549b31a2ed06fcc5dc) [#202](https://github.com/preactjs/prefresh/pull/202) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Cleanup effects when resetting hooks state
## 1.0.0
### Major Changes
- [`b075a8e`](https://github.com/preactjs/prefresh/commit/b075a8ebb7c613b8ce41844d82532803fd61f710) [#190](https://github.com/preactjs/prefresh/pull/190) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Remove export registration
## 0.8.1
### Patch Changes
- [`9e34c74`](https://github.com/preactjs/prefresh/commit/9e34c7408a5307f270681f2c7029180908a5538a) [#143](https://github.com/preactjs/prefresh/pull/143) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Cleanup utils and core code
## 0.8.0
### Minor Changes
- [`32b7a6e`](https://github.com/preactjs/prefresh/commit/32b7a6e86036efd7363ae599317f3d3770a0a1bb) [#131](https://github.com/preactjs/prefresh/pull/131) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Handle non-exported components correctly
## 0.7.4
### Patch Changes
- [`ff43e20`](https://github.com/preactjs/prefresh/commit/ff43e2029f88fd2bc3103539b7d0a50bde42ce25) [#132](https://github.com/preactjs/prefresh/pull/132) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix mistake where the signature for custom hooks would always override itself
## 0.7.3
### Patch Changes
- [`f645aaa`](https://github.com/preactjs/prefresh/commit/f645aaa8da7ec8b1596ec537059a78a8fc630e00) [#128](https://github.com/preactjs/prefresh/pull/128) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Perform initial registration in core to avoid type without a signature
## 0.7.2
### Patch Changes
- [`23bdb37`](https://github.com/preactjs/prefresh/commit/23bdb376c9d20d986f669599c19a98bf991f290e) [#115](https://github.com/preactjs/prefresh/pull/115) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add .npmignore removing example
## 0.7.1
### Patch Changes
- [`501d8f6`](https://github.com/preactjs/prefresh/commit/501d8f6e62db87099846b80fc4d22185c2e3dad2) [#72](https://github.com/preactjs/prefresh/pull/72) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add "default" to the export map to support CJS modules requiring core
## 0.7.0
### Minor Changes
- [`520acd7`](https://github.com/preactjs/prefresh/commit/520acd75ea2a1414ccf8a614049f7b159f448a90) [#69](https://github.com/preactjs/prefresh/pull/69) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add export maps for Node 13/14
### Patch Changes
- [`9948be5`](https://github.com/preactjs/prefresh/commit/9948be52120d03992a183f24e9f4ef53a9a27629) [#67](https://github.com/preactjs/prefresh/pull/67) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Handle async errors in nested components
## 0.6.2
### Patch Changes
- [`ee56105`](https://github.com/preactjs/prefresh/commit/ee5610575228663c08d40eed17a46064089d0075) [#57](https://github.com/preactjs/prefresh/pull/57) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Graciously handle errors with Preact options
- Some performance refactors
## 0.6.1
- Remove invalid `webpack` peerDependency
## 0.6.0
- Added `computeKey` and `register` to the window payload
- `computeKey` will calculate a hash for `functional components` and `custom hooks` this will allow you to derive the need for resetting state or not.
- `register` is a noop that might be used later
- Added a third parameter to `replaceComponent` allowing the user to specify whether or not the stat has to be reset.

22
node_modules/@prefresh/core/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2020-2021 Jovi De Croock
Copyright (c) 2021-Present Preact Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

19
node_modules/@prefresh/core/README.md generated vendored Normal file
View File

@@ -0,0 +1,19 @@
# Prefresh-core
[![npm version](https://badgen.net/npm/v/@prefresh/core)](https://www.npmjs.com/package/@prefresh/core)
We are still fleshing out the details on how to go about this approach best for [Preact](https://github.com/preactjs/preact), we'd
love to give you the best reloading experience possible.
Note that now the refreshing component will dispose of its `hookState` to reload in case of added hook, ... this to ensure consistency.
## How to use
This plugin will set up a series of hooks onto the webpack instance, so the first thing
to do is ensure that this package is part of your entries.
This will add a method on the window `window.__PREFRESH__.replaceComponent`, this function
expects two arguments. The first being the old `class/function` and the second the new one.
This will go over all vnodes it knows for the `oldType` and rerender them according to the
`NewType`.

34
node_modules/@prefresh/core/package.json generated vendored Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "@prefresh/core",
"version": "1.5.3",
"main": "src/index.js",
"exports": {
".": {
"import": "./src/index.js",
"default": "./src/index.js"
},
"./package.json": "./package.json"
},
"repository": {
"type": "git",
"url": "git+https://github.com/preactjs/prefresh.git",
"directory": "packages/core"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/preactjs/prefresh/issues"
},
"homepage": "https://github.com/preactjs/prefresh#readme",
"devDependencies": {
"preact": "^10.15.1"
},
"peerDependencies": {
"preact": "^10.0.0"
},
"publishConfig": {
"provenance": true
},
"scripts": {
"lint": "eslint src"
}
}

36
node_modules/@prefresh/core/src/computeKey.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
import { signaturesForType } from './runtime/signaturesForType';
/**
*
* This part has been vendored from "react-refresh"
* https://github.com/facebook/react/blob/master/packages/react-refresh/src/ReactFreshRuntime.js#L83
*/
export const computeKey = signature => {
let fullKey = signature.key;
let hooks;
try {
hooks = signature.getCustomHooks();
} catch (err) {
signature.forceReset = true;
return fullKey;
}
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i];
if (typeof hook !== 'function') {
signature.forceReset = true;
return fullKey;
}
const nestedHookSignature = signaturesForType.get(hook);
if (nestedHookSignature === undefined) continue;
const nestedHookKey = computeKey(nestedHookSignature);
if (nestedHookSignature.forceReset) signature.forceReset = true;
fullKey += '\n---\n' + nestedHookKey;
}
return fullKey;
};

13
node_modules/@prefresh/core/src/constants.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
export const VNODE_COMPONENT = '__c';
export const NAMESPACE = '__PREFRESH__';
export const COMPONENT_HOOKS = '__H';
export const HOOKS_LIST = '__';
export const EFFECTS_LIST = '__h';
export const RERENDER_COUNT = '__r';
export const CATCH_ERROR_OPTION = '__e';
export const COMPONENT_DIRTY = '__d';
export const VNODE_DOM = '__e';
export const VNODE_CHILDREN = '__k';
export const HOOK_VALUE = '__';
export const HOOK_ARGS = '__H';
export const HOOK_CLEANUP = '__c';

208
node_modules/@prefresh/core/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,208 @@
// Options for Preact.
import './runtime/catchError';
import './runtime/debounceRendering';
import './runtime/vnode';
import './runtime/unmount';
import { Component } from 'preact';
import {
VNODE_COMPONENT,
NAMESPACE,
HOOKS_LIST,
EFFECTS_LIST,
COMPONENT_HOOKS,
HOOK_ARGS,
HOOK_VALUE,
HOOK_CLEANUP,
} from './constants';
import { computeKey } from './computeKey';
import { vnodesForComponent, mappedVNodes } from './runtime/vnodesForComponent';
import { signaturesForType } from './runtime/signaturesForType';
let typesById = new Map();
let pendingUpdates = [];
function sign(type, key, forceReset, getCustomHooks, status) {
if (type) {
let signature = signaturesForType.get(type);
if (status === 'begin') {
signaturesForType.set(type, {
type,
key,
forceReset,
getCustomHooks: getCustomHooks || (() => []),
});
return 'needsHooks';
} else if (status === 'needsHooks') {
signature.fullKey = computeKey(signature);
}
}
}
function replaceComponent(OldType, NewType, resetHookState) {
const vnodes = vnodesForComponent.get(OldType);
if (!vnodes) return;
// migrate the list to our new constructor reference
vnodesForComponent.delete(OldType);
vnodesForComponent.set(NewType, vnodes);
mappedVNodes.set(OldType, NewType);
pendingUpdates = pendingUpdates.filter(p => p[0] !== OldType);
vnodes.forEach(vnode => {
if (!vnode.__c || !vnode.__c.__P) return;
// update the type in-place to reference the new component
vnode.type = NewType;
if (vnode[VNODE_COMPONENT]) {
vnode[VNODE_COMPONENT].constructor = vnode.type;
try {
if (vnode[VNODE_COMPONENT] instanceof OldType) {
const oldInst = vnode[VNODE_COMPONENT];
const newInst = new NewType(
vnode[VNODE_COMPONENT].props,
vnode[VNODE_COMPONENT].context
);
vnode[VNODE_COMPONENT] = newInst;
// copy old properties onto the new instance.
// - Objects (including refs) in the new instance are updated with their old values
// - Missing or null properties are restored to their old values
// - Updated Functions are not reverted
// - Scalars are copied
for (let i in oldInst) {
const type = typeof oldInst[i];
if (!(i in newInst)) {
newInst[i] = oldInst[i];
} else if (type !== 'function' && typeof newInst[i] === type) {
if (
type === 'object' &&
newInst[i] != null &&
newInst[i].constructor === oldInst[i].constructor
) {
Object.assign(newInst[i], oldInst[i]);
} else {
newInst[i] = oldInst[i];
}
}
}
}
} catch (e) {
/* Functional component */
vnode[VNODE_COMPONENT].constructor = NewType;
}
if (resetHookState) {
if (
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].length
) {
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(
possibleEffect => {
if (
possibleEffect[HOOK_CLEANUP] &&
typeof possibleEffect[HOOK_CLEANUP] === 'function'
) {
possibleEffect[HOOK_CLEANUP]();
possibleEffect[HOOK_CLEANUP] = undefined;
} else if (
possibleEffect[HOOK_ARGS] &&
possibleEffect[HOOK_VALUE] &&
Object.keys(possibleEffect).length === 3
) {
const cleanupKey = Object.keys(possibleEffect).find(
key => key !== HOOK_ARGS && key !== HOOK_VALUE
);
if (
cleanupKey &&
typeof possibleEffect[cleanupKey] == 'function'
) {
possibleEffect[cleanupKey]();
possibleEffect[cleanupKey] = undefined;
}
}
}
);
}
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] = {
[HOOKS_LIST]: [],
[EFFECTS_LIST]: [],
};
} else if (
vnode[VNODE_COMPONENT][COMPONENT_HOOKS] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST] &&
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].length
) {
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(
possibleEffect => {
if (
possibleEffect[HOOK_CLEANUP] &&
typeof possibleEffect[HOOK_CLEANUP] === 'function'
) {
possibleEffect[HOOK_CLEANUP]();
possibleEffect[HOOK_CLEANUP] = undefined;
} else if (
possibleEffect[HOOK_ARGS] &&
possibleEffect[HOOK_VALUE] &&
Object.keys(possibleEffect).length === 3
) {
const cleanupKey = Object.keys(possibleEffect).find(
key => key !== HOOK_ARGS && key !== HOOK_VALUE
);
if (cleanupKey && typeof possibleEffect[cleanupKey] == 'function')
possibleEffect[cleanupKey]();
possibleEffect[cleanupKey] = undefined;
}
}
);
vnode[VNODE_COMPONENT][COMPONENT_HOOKS][HOOKS_LIST].forEach(hook => {
if (hook.__H && Array.isArray(hook.__H)) {
hook.__H = undefined;
}
});
}
Component.prototype.forceUpdate.call(vnode[VNODE_COMPONENT]);
}
});
}
self[NAMESPACE] = {
getSignature: type => signaturesForType.get(type),
register: (type, id) => {
if (typeof type !== 'function') return;
if (typesById.has(id)) {
const existing = typesById.get(id);
if (existing !== type) {
pendingUpdates.push([existing, type]);
typesById.set(id, type);
}
} else {
typesById.set(id, type);
}
if (!signaturesForType.has(type)) {
signaturesForType.set(type, {
getCustomHooks: () => [],
type,
});
}
},
getPendingUpdates: () => pendingUpdates,
flush: () => {
pendingUpdates = [];
},
replaceComponent,
sign,
computeKey,
};

15
node_modules/@prefresh/core/src/runtime/catchError.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { options } from 'preact';
import {
CATCH_ERROR_OPTION,
COMPONENT_DIRTY,
VNODE_COMPONENT,
} from '../constants';
const oldCatchError = options[CATCH_ERROR_OPTION];
options[CATCH_ERROR_OPTION] = (error, vnode, oldVNode) => {
if (vnode[VNODE_COMPONENT] && vnode[VNODE_COMPONENT][COMPONENT_DIRTY]) {
vnode[VNODE_COMPONENT][COMPONENT_DIRTY] = false;
}
if (oldCatchError) oldCatchError(error, vnode, oldVNode);
};

View File

@@ -0,0 +1,19 @@
import { options } from 'preact';
import { RERENDER_COUNT } from '../constants';
const defer =
typeof Promise == 'function'
? Promise.prototype.then.bind(Promise.resolve())
: setTimeout;
options.debounceRendering = process => {
defer(() => {
try {
process();
} catch (e) {
process[RERENDER_COUNT] = 0;
throw e;
}
});
};

View File

@@ -0,0 +1,2 @@
// Signatures for functional components and custom hooks.
export const signaturesForType = new WeakMap();

18
node_modules/@prefresh/core/src/runtime/unmount.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
import { options } from 'preact';
import { vnodesForComponent } from './vnodesForComponent';
const oldUnmount = options.unmount;
options.unmount = vnode => {
const type = (vnode || {}).type;
if (typeof type === 'function' && vnodesForComponent.has(type)) {
const vnodes = vnodesForComponent.get(type);
if (vnodes) {
const index = vnodes.indexOf(vnode);
if (index !== -1) {
vnodes.splice(index, 1);
}
}
}
if (oldUnmount) oldUnmount(vnode);
};

66
node_modules/@prefresh/core/src/runtime/vnode.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import { options } from 'preact';
import { vnodesForComponent, mappedVNodes } from './vnodesForComponent';
import { VNODE_COMPONENT } from '../constants';
const getMappedVnode = type => {
if (mappedVNodes.has(type)) {
return getMappedVnode(mappedVNodes.get(type));
}
return type;
};
const BUILT_IN_COMPONENTS = ['Fragment', 'Suspense', 'SuspenseList'];
const isBuiltIn = type => {
return BUILT_IN_COMPONENTS.includes(type.name)
}
const oldVnode = options.vnode;
options.vnode = vnode => {
if (vnode && typeof vnode.type === 'function' && !isBuiltIn(vnode.type)) {
const vnodes = vnodesForComponent.get(vnode.type);
if (!vnodes) {
vnodesForComponent.set(vnode.type, [vnode]);
} else {
vnodes.push(vnode);
}
const foundType = getMappedVnode(vnode.type);
if (foundType !== vnode.type) {
const vnodes = vnodesForComponent.get(foundType);
if (!vnodes) {
vnodesForComponent.set(foundType, [vnode]);
} else {
vnodes.push(vnode);
}
}
vnode.type = foundType;
if (
vnode[VNODE_COMPONENT] &&
'prototype' in vnode.type &&
vnode.type.prototype.render
) {
vnode[VNODE_COMPONENT].constructor = vnode.type;
}
}
if (oldVnode) oldVnode(vnode);
};
const oldDiffed = options.diffed;
options.diffed = vnode => {
if (vnode && typeof vnode.type === 'function') {
const vnodes = vnodesForComponent.get(vnode.type);
if (vnodes) {
const matchingDom = vnodes.filter(p => p.__c === vnode.__c);
if (matchingDom.length > 1) {
const i = vnodes.findIndex(p => p === matchingDom[0]);
vnodes.splice(i, 1);
}
}
}
if (oldDiffed) oldDiffed(vnode);
};

View File

@@ -0,0 +1,3 @@
// all vnodes referencing a given constructor
export const vnodesForComponent = new WeakMap();
export const mappedVNodes = new WeakMap();

63
node_modules/@prefresh/utils/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,63 @@
# @prefresh/utils
## 1.2.0
### Minor Changes
- [`e641c69`](https://github.com/preactjs/prefresh/commit/e641c69c610c3adeeb5dcb9e912d030a6fbb5229) [#499](https://github.com/preactjs/prefresh/pull/499) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Publish automatically with npm provenance enabled
## 1.1.2
### Patch Changes
- [`eb9aa93`](https://github.com/preactjs/prefresh/commit/eb9aa932fc2a01fed3ecb662e195422986529419) [#425](https://github.com/preactjs/prefresh/pull/425) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Fix import paths for newer node versions
## 1.1.1
### Patch Changes
- [`5d23ebc`](https://github.com/preactjs/prefresh/commit/5d23ebc771fd2da7e86e5b3a9479f97692c47e9d) [#240](https://github.com/preactjs/prefresh/pull/240) Thanks [@sidujjain](https://github.com/sidujjain)! - Fix exception in isComponent when exportValue is undefined
## 1.1.0
### Minor Changes
- [`39bcf44`](https://github.com/preactjs/prefresh/commit/39bcf44604c377ca493db9ebce1d75071107704b) [#238](https://github.com/preactjs/prefresh/pull/238) Thanks [@sidujjain](https://github.com/sidujjain)! - Add prototype-check to `@prefresh/utils` isComponent check and utilize this in nollup & webpack
## 1.0.0
### Major Changes
- [`25c683c`](https://github.com/preactjs/prefresh/commit/25c683cf47484ee1612ff0fcd677f788b00d8860) [#191](https://github.com/preactjs/prefresh/pull/191) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Trim the utils down to only used methods
## 0.3.1
### Patch Changes
- [`9e34c74`](https://github.com/preactjs/prefresh/commit/9e34c7408a5307f270681f2c7029180908a5538a) [#143](https://github.com/preactjs/prefresh/pull/143) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Cleanup utils and core code
## 0.3.0
### Minor Changes
- [`32b7a6e`](https://github.com/preactjs/prefresh/commit/32b7a6e86036efd7363ae599317f3d3770a0a1bb) [#131](https://github.com/preactjs/prefresh/pull/131) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Handle non-exported components correctly
## 0.2.1
### Patch Changes
- [`23bdb37`](https://github.com/preactjs/prefresh/commit/23bdb376c9d20d986f669599c19a98bf991f290e) [#115](https://github.com/preactjs/prefresh/pull/115) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add .npmignore removing example
## 0.2.0
### Minor Changes
- [`520acd7`](https://github.com/preactjs/prefresh/commit/520acd75ea2a1414ccf8a614049f7b159f448a90) [#69](https://github.com/preactjs/prefresh/pull/69) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add export maps for Node 13/14
## 0.1.2
### Patch Changes
- [`846eec0`](https://github.com/preactjs/prefresh/commit/846eec0a77ba8f9b8e1ea36bfc0dd6a6ad7ba94c) [#44](https://github.com/preactjs/prefresh/pull/44) Thanks [@JoviDeCroock](https://github.com/JoviDeCroock)! - Add esm + CJS exports
- Add ESM export

22
node_modules/@prefresh/utils/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2020-2021 Jovi De Croock
Copyright (c) 2021-Present Preact Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
node_modules/@prefresh/utils/README.md generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Prefresh-utils
[![npm version](https://badgen.net/npm/v/@prefresh/utils)](https://www.npmjs.com/package/@prefresh/utils)

46
node_modules/@prefresh/utils/dist/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,46 @@
const compareSignatures = (prev, next) => {
const prevSignature = self.__PREFRESH__.getSignature(prev) || {};
const nextSignature = self.__PREFRESH__.getSignature(next) || {};
if (
prevSignature.key !== nextSignature.key ||
self.__PREFRESH__.computeKey(prevSignature) !==
self.__PREFRESH__.computeKey(nextSignature) ||
nextSignature.forceReset
) {
self.__PREFRESH__.replaceComponent(prev, next, true);
} else {
self.__PREFRESH__.replaceComponent(prev, next, false);
}
};
const flush = () => {
const pending = [...self.__PREFRESH__.getPendingUpdates()];
self.__PREFRESH__.flush();
if (pending.length > 0) {
pending.forEach(([prev, next]) => {
compareSignatures(prev, next);
});
}
};
const isComponent = exportValue => {
if (typeof exportValue === 'function') {
if (
exportValue.prototype != null &&
exportValue.prototype.isReactComponent
) {
return true;
}
const name = exportValue.name || exportValue.displayName;
return (
typeof name === 'string' && name[0] && name[0] == name[0].toUpperCase()
);
}
return false;
};
exports.flush=flush;
exports.isComponent=isComponent;

33
node_modules/@prefresh/utils/package.json generated vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "@prefresh/utils",
"version": "1.2.0",
"module": "src/index.js",
"main": "dist/src/index.js",
"exports": {
".": {
"import": "./src/index.js",
"require": "./dist/src/index.js"
},
"./package.json": "./package.json"
},
"repository": {
"type": "git",
"url": "git+https://github.com/preactjs/prefresh.git",
"directory": "packages/utils"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/preactjs/prefresh/issues"
},
"homepage": "https://github.com/preactjs/prefresh#readme",
"devDependencies": {
"cjyes": "0.3.1"
},
"publishConfig": {
"provenance": true
},
"scripts": {
"build": "cjyes src/index.js",
"lint": "eslint src"
}
}

43
node_modules/@prefresh/utils/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
const compareSignatures = (prev, next) => {
const prevSignature = self.__PREFRESH__.getSignature(prev) || {};
const nextSignature = self.__PREFRESH__.getSignature(next) || {};
if (
prevSignature.key !== nextSignature.key ||
self.__PREFRESH__.computeKey(prevSignature) !==
self.__PREFRESH__.computeKey(nextSignature) ||
nextSignature.forceReset
) {
self.__PREFRESH__.replaceComponent(prev, next, true);
} else {
self.__PREFRESH__.replaceComponent(prev, next, false);
}
};
export const flush = () => {
const pending = [...self.__PREFRESH__.getPendingUpdates()];
self.__PREFRESH__.flush();
if (pending.length > 0) {
pending.forEach(([prev, next]) => {
compareSignatures(prev, next);
});
}
};
export const isComponent = exportValue => {
if (typeof exportValue === 'function') {
if (
exportValue.prototype != null &&
exportValue.prototype.isReactComponent
) {
return true;
}
const name = exportValue.name || exportValue.displayName;
return (
typeof name === 'string' && name[0] && name[0] == name[0].toUpperCase()
);
}
return false;
};

22
node_modules/@prefresh/vite/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2020-2021 Jovi De Croock
Copyright (c) 2021-Present Preact Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

56
node_modules/@prefresh/vite/README.md generated vendored Normal file
View File

@@ -0,0 +1,56 @@
# Prefresh-vite
[![npm version](https://badgen.net/npm/v/@prefresh/vite)](https://www.npmjs.com/package/@prefresh/vite)
## Setup
```
npm i -s @prefresh/vite
## OR
yarn add @prefresh/vite
```
Then add it to your `vite.config.js` config:
```js
import prefresh from '@prefresh/vite';
export default {
plugins: [prefresh()],
};
```
## Options
The plugin accepts two options `include` & `exclude` which are used in the [`@rollup/pluginutils.createFilter`](https://github.com/rollup/plugins/tree/master/packages/pluginutils#createfilter) to filter out files or include them.
The plugin also accepts the addition of [`parserPlugins`](https://babeljs.io/docs/en/babel-parser#plugins)
## Best practices
### Recognition
We need to be able to recognise your components, this means that components should
start with a capital letter and hook should start with `use` followed by a capital letter.
This allows the Babel plugin to effectively recognise these.
Do note that a component as seen below is not named.
```jsx
export default () => {
return <p>Want to refresh</p>;
};
```
Instead do:
```jsx
const Refresh = () => {
return <p>Want to refresh</p>;
};
export default Refresh;
```
When you are working with HOC's be sure to lift up the `displayName` so we can
recognise it as a component.

12
node_modules/@prefresh/vite/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import { FilterPattern } from '@rollup/pluginutils';
import { Plugin } from 'vite';
interface Options {
parserPlugins?: readonly string[];
include?: FilterPattern;
exclude?: FilterPattern;
}
declare const prefreshPlugin: (options?: Options) => Plugin;
export = prefreshPlugin;

55
node_modules/@prefresh/vite/package.json generated vendored Normal file
View File

@@ -0,0 +1,55 @@
{
"name": "@prefresh/vite",
"version": "2.4.7",
"main": "src/index.js",
"types": "index.d.ts",
"exports": {
".": {
"types": "./index.d.ts",
"require": "./src/index.js",
"import": "./src/index.js"
},
"./package.json": "./package.json"
},
"modes": {
"default": "src/index.js"
},
"files": [
"dist",
"runtime",
"utils",
"index.d.ts"
],
"repository": {
"type": "git",
"url": "git+https://github.com/preactjs/prefresh.git",
"directory": "packages/vite"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/preactjs/prefresh/issues"
},
"homepage": "https://github.com/preactjs/prefresh#readme",
"dependencies": {
"@babel/core": "^7.22.1",
"@prefresh/babel-plugin": "0.5.1",
"@prefresh/core": "^1.5.1",
"@prefresh/utils": "^1.2.0",
"@rollup/pluginutils": "^4.2.1"
},
"devDependencies": {
"preact": "^10.15.1",
"vite": "^5.0.13"
},
"peerDependencies": {
"preact": "^10.4.0",
"vite": ">=2.0.0"
},
"publishConfig": {
"provenance": true
},
"scripts": {
"lint": "eslint src",
"test": "jest --clearCache && jest --runInBand --forceExit --detectOpenHandles"
}
}

117
node_modules/@prefresh/vite/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,117 @@
const { transformSync } = require('@babel/core');
const { createFilter } = require('@rollup/pluginutils');
const prefreshBabelPlugin = require('@prefresh/babel-plugin');
/** @returns {import('vite').Plugin} */
module.exports = function prefreshPlugin(options = {}) {
let shouldSkip = false;
const filter = createFilter(options.include, options.exclude);
return {
name: 'prefresh',
configResolved(config) {
shouldSkip = config.isProduction || config.command === 'build' || config.server.hmr === false;
},
async transform(code, id, options) {
const ssr =
typeof options === 'boolean'
? options
: options && options.ssr === true;
if (
shouldSkip ||
!/\.(c|m)?(t|j)sx?$/.test(id) ||
id.includes('node_modules') ||
id.includes('?worker') ||
!filter(id) ||
ssr
)
return;
const parserPlugins = [
'jsx',
'classProperties',
'classPrivateProperties',
'classPrivateMethods',
/\.tsx?$/.test(id) && 'typescript',
...((options && options.parserPlugins) || []),
].filter(Boolean);
const result = transform(code, id, parserPlugins);
const hasReg = /\$RefreshReg\$\(/.test(result.code);
const hasSig = /\$RefreshSig\$\(/.test(result.code);
if (!hasSig && !hasReg) return code;
const prefreshCore = await this.resolve('@prefresh/core', __filename);
const prefreshUtils = await this.resolve('@prefresh/utils', __filename);
const prelude = `
${'import'} ${JSON.stringify(prefreshCore.id)};
${'import'} { flush as flushUpdates } from ${JSON.stringify(
prefreshUtils.id
)};
let prevRefreshReg;
let prevRefreshSig;
if (import.meta.hot) {
prevRefreshReg = self.$RefreshReg$ || (() => {});
prevRefreshSig = self.$RefreshSig$ || (() => (type) => type);
self.$RefreshReg$ = (type, id) => {
self.__PREFRESH__.register(type, ${JSON.stringify(id)} + " " + id);
};
self.$RefreshSig$ = () => {
let status = 'begin';
let savedType;
return (type, key, forceReset, getCustomHooks) => {
if (!savedType) savedType = type;
status = self.__PREFRESH__.sign(type || savedType, key, forceReset, getCustomHooks, status);
return type;
};
};
}
`.replace(/[\n]+/gm, '');
if (hasSig && !hasReg) {
return {
code: `${prelude}${result.code}`,
map: result.map,
};
}
return {
code: `${prelude}${result.code}
if (import.meta.hot) {
self.$RefreshReg$ = prevRefreshReg;
self.$RefreshSig$ = prevRefreshSig;
import.meta.hot.accept((m) => {
try {
flushUpdates();
} catch (e) {
self.location.reload();
}
});
}
`,
map: result.map,
};
},
};
};
const transform = (code, path, plugins) =>
transformSync(code, {
plugins: [[prefreshBabelPlugin, { skipEnvCheck: true }]],
parserOpts: {
plugins,
},
ast: false,
sourceMaps: true,
filename: path,
sourceFileName: path,
configFile: false,
babelrc: false,
});