Skip to content

Commit

Permalink
Add opts for relative source location (#3141)
Browse files Browse the repository at this point in the history
## Description

We use react-native-reanimated in a npm package which publishes babel build output.  We want output to be deterministic regardless of builder configuration.

## Changes

Add plugin option that uses relative path for source location.

## Checklist

- [x] Included code example that can be used to test this change
- <s>[ ] Updated TS types</s>
- <s>[ ] Added TS types tests</s>
- <s>[ ] Added unit / integration tests</s>
- [x] Updated documentation
- [x] Ensured that CI passes
  • Loading branch information
jiulongw committed Apr 12, 2022
1 parent f0165b2 commit e4bc507
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 20 deletions.
16 changes: 16 additions & 0 deletions docs/docs/fundamentals/installation.md
Expand Up @@ -30,6 +30,22 @@ Add Reanimated's babel plugin to your `babel.config.js`:
};
```

By default, Reanimated plugin generate source location using absolute path. You can configure to use relative path:

```js {5}
module.exports = {
...
plugins: [
...
[
'react-native-reanimated/plugin', {
relativeSourceLocation: true,
},
]
],
};
```

:::caution

Reanimated plugin has to be listed last.
Expand Down
45 changes: 25 additions & 20 deletions plugin.js
Expand Up @@ -331,7 +331,7 @@ function makeWorkletName(t, fun) {
return '_f'; // fallback for ArrowFunctionExpression and unnamed FunctionExpression
}

function makeWorklet(t, fun, fileName) {
function makeWorklet(t, fun, state) {
// Returns a new FunctionExpression which is a workletized version of provided
// FunctionDeclaration, FunctionExpression, ArrowFunctionExpression or ObjectMethod.

Expand All @@ -358,7 +358,7 @@ function makeWorklet(t, fun, fileName) {
'\n(' + (t.isObjectMethod(fun) ? 'function ' : '') + fun.toString() + '\n)';

const transformed = transformSync(code, {
filename: fileName,
filename: state.file.opts.filename,
presets: ['@babel/preset-typescript'],
plugins: [
'@babel/plugin-transform-shorthand-properties',
Expand Down Expand Up @@ -445,11 +445,17 @@ function makeWorklet(t, fun, fileName) {
);
const workletHash = hash(funString);

let location = state.file.opts.filename;
if (state.opts.relativeSourceLocation) {
const path = require('path');
location = path.relative(state.cwd, location);
}

const loc = fun && fun.node && fun.node.loc && fun.node.loc.start;
if (loc) {
const { line, column } = loc;
if (typeof line === 'number' && typeof column === 'number') {
fileName = `${fileName} (${line}:${column})`;
location = `${location} (${line}:${column})`;
}
}

Expand Down Expand Up @@ -490,7 +496,7 @@ function makeWorklet(t, fun, fileName) {
t.identifier('__location'),
false
),
t.stringLiteral(fileName)
t.stringLiteral(location)
)
),
];
Expand Down Expand Up @@ -518,15 +524,15 @@ function makeWorklet(t, fun, fileName) {
return newFun;
}

function processWorkletFunction(t, fun, fileName) {
function processWorkletFunction(t, fun, state) {
// Replaces FunctionDeclaration, FunctionExpression or ArrowFunctionExpression
// with a workletized version of itself.

if (!t.isFunctionParent(fun)) {
return;
}

const newFun = makeWorklet(t, fun, fileName);
const newFun = makeWorklet(t, fun, state);

const replacement = t.callExpression(newFun, []);

Expand All @@ -546,14 +552,14 @@ function processWorkletFunction(t, fun, fileName) {
);
}

function processWorkletObjectMethod(t, path, fileName) {
function processWorkletObjectMethod(t, path, state) {
// Replaces ObjectMethod with a workletized version of itself.

if (!t.isFunctionParent(path)) {
return;
}

const newFun = makeWorklet(t, path, fileName);
const newFun = makeWorklet(t, path, state);

const replacement = t.objectProperty(
t.identifier(path.node.key.name),
Expand All @@ -563,7 +569,7 @@ function processWorkletObjectMethod(t, path, fileName) {
path.replaceWith(replacement);
}

function processIfWorkletNode(t, fun, fileName) {
function processIfWorkletNode(t, fun, state) {
fun.traverse({
DirectiveLiteral(path) {
const value = path.node.value;
Expand All @@ -581,14 +587,14 @@ function processIfWorkletNode(t, fun, fileName) {
directive.value.value === 'worklet'
)
) {
processWorkletFunction(t, fun, fileName);
processWorkletFunction(t, fun, state);
}
}
},
});
}

function processIfGestureHandlerEventCallbackFunctionNode(t, fun, fileName) {
function processIfGestureHandlerEventCallbackFunctionNode(t, fun, state) {
// Auto-workletizes React Native Gesture Handler callback functions.
// Detects `Gesture.Tap().onEnd(<fun>)` or similar, but skips `something.onEnd(<fun>)`.
// Supports method chaining as well, e.g. `Gesture.Tap().onStart(<fun1>).onUpdate(<fun2>).onEnd(<fun3>)`.
Expand Down Expand Up @@ -641,7 +647,7 @@ function processIfGestureHandlerEventCallbackFunctionNode(t, fun, fileName) {
t.isCallExpression(fun.parent) &&
isGestureObjectEventCallbackMethod(t, fun.parent.callee)
) {
processWorkletFunction(t, fun, fileName);
processWorkletFunction(t, fun, state);
}
}

Expand Down Expand Up @@ -697,7 +703,7 @@ function isGestureObject(t, node) {
);
}

function processWorklets(t, path, fileName) {
function processWorklets(t, path, state) {
const name =
path.node.callee.type === 'MemberExpression'
? path.node.callee.property.name
Expand All @@ -709,17 +715,17 @@ function processWorklets(t, path, fileName) {
const properties = path.get('arguments.0.properties');
for (const property of properties) {
if (t.isObjectMethod(property)) {
processWorkletObjectMethod(t, property, fileName);
processWorkletObjectMethod(t, property, state);
} else {
const value = property.get('value');
processWorkletFunction(t, value, fileName);
processWorkletFunction(t, value, state);
}
}
} else {
const indexes = functionArgsToWorkletize.get(name);
if (Array.isArray(indexes)) {
indexes.forEach((index) => {
processWorkletFunction(t, path.get(`arguments.${index}`), fileName);
processWorkletFunction(t, path.get(`arguments.${index}`), state);
});
}
}
Expand Down Expand Up @@ -764,14 +770,13 @@ module.exports = function ({ types: t }) {
visitor: {
CallExpression: {
enter(path, state) {
processWorklets(t, path, state.file.opts.filename);
processWorklets(t, path, state);
},
},
'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression': {
enter(path, state) {
const fileName = state.file.opts.filename;
processIfWorkletNode(t, path, fileName);
processIfGestureHandlerEventCallbackFunctionNode(t, path, fileName);
processIfWorkletNode(t, path, state);
processIfGestureHandlerEventCallbackFunctionNode(t, path, state);
},
},
},
Expand Down

0 comments on commit e4bc507

Please sign in to comment.