Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed May 9, 2023
1 parent ce4ace5 commit dd5e7a9
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 1 deletion.
20 changes: 20 additions & 0 deletions packages/forgetti/src/core/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,23 @@ export function isNestedExpression(node: t.Node): node is NestedExpression {
return false;
}
}

/** Check whether a Node is CallExpression and a React Hook call */
export function isCallExpressionAndHook(ctx: StateContext, node: t.Node): node is t.CallExpression {
if (node.type !== 'CallExpression') {
return false;
}

// A simple check to see if "node.callee" is an Identifier
// TypeScript is able to infer the type of "node.callee" to Identifier or V8IntrinsicIdentifier
if (!('name' in node.callee)) {
return false;
}

// Check if callee is a react hook
if (!ctx.filters.hook) {
return false;
}

return ctx.filters.hook.test(node.callee.name);
}
8 changes: 7 additions & 1 deletion packages/forgetti/src/core/optimizer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
import type * as babel from '@babel/core';
import * as t from '@babel/types';
import { isNestedExpression, isPathValid } from './checks';
import { isCallExpressionAndHook, isNestedExpression, isPathValid } from './checks';
import getForeignBindings, { isForeignBinding } from './get-foreign-bindings';
import getImportIdentifier from './get-import-identifier';
import { RUNTIME_EQUALS } from './imports';
Expand Down Expand Up @@ -517,6 +517,7 @@ export default class Optimizer {
// Check if callee is potentially a namespace import
}
const trueMember = unwrapNode(calleePath.node, t.isMemberExpression);

if (
trueMember
&& !trueMember.computed
Expand Down Expand Up @@ -561,7 +562,12 @@ export default class Optimizer {
for (let i = 0, len = argumentsPath.length; i < len; i++) {
argument = argumentsPath[i];
if (isPathValid(argument, t.isExpression)) {
if (isCallExpressionAndHook(this.ctx, argument.node)) {
continue;
}

const optimized = this.createDependency(argument);

if (optimized) {
mergeDependencies(dependencies, optimized.deps);
path.node.arguments[i] = optimized.expr;
Expand Down
9 changes: 9 additions & 0 deletions packages/forgetti/test/__snapshots__/hooks.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
// Vitest Snapshot v1

exports[`hooks > should correct transform nested hooks call (issue #14) 1`] = `
"import { useDeferredValue } from 'react';
import { useAtomValue } from 'jotai';
import { stateAtom } from 'whatever';
function Example(props) {
return useDeferredValue(useAtomValue(stateAtom));
}"
`;

exports[`hooks > should optimize useCallback 1`] = `
"import { useMemo as _useMemo } from \\"react\\";
import { $$cache as _$$cache } from \\"forgetti/runtime\\";
Expand Down
11 changes: 11 additions & 0 deletions packages/forgetti/test/hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ import { useEffect } from 'react';
function Example(props) {
useEffect(() => props.value());
}
`;
expect(await compile(code)).toMatchSnapshot();
});
it('should correct transform nested hooks call (issue #14)', async () => {
const code = `
import { useDeferredValue } from 'react';
import { useAtomValue } from 'jotai';
import { stateAtom } from 'whatever';
function Example(props) {
return useDeferredValue(useAtomValue(stateAtom));
}
`;
expect(await compile(code)).toMatchSnapshot();
});
Expand Down

0 comments on commit dd5e7a9

Please sign in to comment.