Skip to content

Commit

Permalink
Merge pull request #405 from heap/develop
Browse files Browse the repository at this point in the history
Cut 0.22.4 release
  • Loading branch information
bnickel authored Sep 5, 2023
2 parents 614c6e2 + 22bf5f2 commit 9344fa5
Show file tree
Hide file tree
Showing 22 changed files with 255 additions and 112 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.22.4] - 2023-09-05

### Fixed

- Fixed `<Switch>` change event capture on React Native 0.66 and later.

## [0.22.3] - 2023-06-29

### Fixed
Expand Down Expand Up @@ -276,7 +282,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ability to use Heap's identity APIs from React Native code.
- Instructions for install and use.

[unreleased]: https://github.com/heap/react-native-heap/compare/0.22.3...HEAD
[unreleased]: https://github.com/heap/react-native-heap/compare/0.22.4...HEAD
[0.22.4]: https://github.com/heap/react-native-heap/compare/0.22.3...0.22.4
[0.22.3]: https://github.com/heap/react-native-heap/compare/0.22.2...0.22.3
[0.22.2]: https://github.com/heap/react-native-heap/compare/0.22.1...0.22.2
[0.22.1]: https://github.com/heap/react-native-heap/compare/0.22.0...0.22.1
Expand Down
36 changes: 36 additions & 0 deletions instrumentor/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ const buildHeapImport = template(`(
}
)`);

const buildDisplayNameAssignment = template(`(function (Component, displayName) {
if (Component && displayName) {
Component.displayName = displayName;
}
return Component;
})(COMPONENT_DEFINITION, DISPLAY_NAME)`);

const buildInstrumentationHoc = template(`
const COMPONENT_ID = HOC_CALL_EXPRESSION;
`);
Expand Down Expand Up @@ -397,6 +404,34 @@ const instrumentPressableHoc = path => {
path.get('init').replaceWith(autotrackExpression);
};

const instrumentSwitchHoc = path => {
// 'SwitchWithForwardedRef' is the component that gets exported from 'Switch.js' in the react-native library. The whole component is
// defined inside a `React.forwardRef` call.
// See https://github.com/facebook/react-native/blob/4deb29ae1bf71d8da1a18b1a930883854b519949/packages/react-native/Libraries/Components/Switch/Switch.js#L134-L139.
if (!path.node.id || path.node.id.name !== 'SwitchWithForwardedRef') {
return;
}

const hocIdentifier = t.identifier('withHeapSwitchAutocapture');

const heapImport = buildHeapImport({
HOC_IDENTIFIER: hocIdentifier,
}).expression;

// Special to "Switch", the component doesn't have a display name. Per a suggestion in another comment, I'm fixing this up in Switch.js.
const initWithDisplayName = buildDisplayNameAssignment({
COMPONENT_DEFINITION: path.node.init,
DISPLAY_NAME: t.stringLiteral('Switch'),
}).expression;

const autotrackExpression = t.callExpression(
t.memberExpression(heapImport, hocIdentifier),
[initWithDisplayName]
);

path.get('init').replaceWith(autotrackExpression);
};

function transform(babel) {
return {
visitor: {
Expand All @@ -417,6 +452,7 @@ function transform(babel) {
},
VariableDeclarator(path) {
instrumentPressableHoc(path);
instrumentSwitchHoc(path);
},
},
};
Expand Down
25 changes: 25 additions & 0 deletions instrumentor/test/fixtures/is-switch-pre-0-66/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

class Switch extends React.Component<Props> {
_handleChange = (event: SwitchChangeEvent) => {
if (this._nativeSwitchRef == null) {
return;
}

// Force value of native switch in order to control it.
const value = this.props.value === true;
if (Platform.OS === 'android') {
this._nativeSwitchRef.setNativeProps({on: value});
} else {
this._nativeSwitchRef.setNativeProps({value});
}

if (this.props.onChange != null) {
this.props.onChange(event);
}

if (this.props.onValueChange != null) {
this.props.onValueChange(event.nativeEvent.value);
}
};
}
49 changes: 49 additions & 0 deletions instrumentor/test/fixtures/is-switch-pre-0-66/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var Switch = function (_React$Component) {
(0, _inherits2["default"])(Switch, _React$Component);
var _super = _createSuper(Switch);
function Switch() {
var _this;
(0, _classCallCheck2["default"])(this, Switch);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _super.call.apply(_super, [this].concat(args));
_this._handleChange = function (e) {
var Heap = require('@heap/react-native-heap')["default"];
Heap.autotrackSwitchChange("change", _this, e);
(function (event) {
if (_this._nativeSwitchRef == null) {
return;
}
var value = _this.props.value === true;
if (Platform.OS === 'android') {
_this._nativeSwitchRef.setNativeProps({
on: value
});
} else {
_this._nativeSwitchRef.setNativeProps({
value: value
});
}
if (_this.props.onChange != null) {
_this.props.onChange(event);
}
if (_this.props.onValueChange != null) {
_this.props.onValueChange(event.nativeEvent.value);
}
}).call(_this, e);
};
return _this;
}
return (0, _createClass2["default"])(Switch);
}(React.Component);
31 changes: 6 additions & 25 deletions instrumentor/test/fixtures/is-switch/code.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
'use strict';

class Switch extends React.Component<Props> {
_handleChange = (event: SwitchChangeEvent) => {
if (this._nativeSwitchRef == null) {
return;
}

// Force value of native switch in order to control it.
const value = this.props.value === true;
if (Platform.OS === 'android') {
this._nativeSwitchRef.setNativeProps({on: value});
} else {
this._nativeSwitchRef.setNativeProps({value});
}

if (this.props.onChange != null) {
this.props.onChange(event);
}

if (this.props.onValueChange != null) {
this.props.onValueChange(event.nativeEvent.value);
}
};
}
const SwitchWithForwardedRef: React.AbstractComponent<
Props,
React.ElementRef<
typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent,
>,
> = React.forwardRef(function Switch(props, forwardedRef): React.Node {});
57 changes: 10 additions & 47 deletions instrumentor/test/fixtures/is-switch/output.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,12 @@
'use strict';
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var Switch = function (_React$Component) {
(0, _inherits2["default"])(Switch, _React$Component);
var _super = _createSuper(Switch);
function Switch() {
var _this;
(0, _classCallCheck2["default"])(this, Switch);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _super.call.apply(_super, [this].concat(args));
_this._handleChange = function (e) {
var Heap = require('@heap/react-native-heap')["default"];
Heap.autotrackSwitchChange("change", _this, e);
(function (event) {
if (_this._nativeSwitchRef == null) {
return;
}
var value = _this.props.value === true;
if (Platform.OS === 'android') {
_this._nativeSwitchRef.setNativeProps({
on: value
});
} else {
_this._nativeSwitchRef.setNativeProps({
value: value
});
}
if (_this.props.onChange != null) {
_this.props.onChange(event);
}
if (_this.props.onValueChange != null) {
_this.props.onValueChange(event.nativeEvent.value);
}
}).call(_this, e);
};
return _this;
var SwitchWithForwardedRef = (require('@heap/react-native-heap')["default"] || {
withHeapSwitchAutocapture: function withHeapSwitchAutocapture(Component) {
return Component;
}
return (0, _createClass2["default"])(Switch);
}(React.Component);
}).withHeapSwitchAutocapture(function (Component, displayName) {
if (Component && displayName) {
Component.displayName = displayName;
}
return Component;
}(React.forwardRef(function Switch(props, forwardedRef) {}), "Switch"));
6 changes: 6 additions & 0 deletions instrumentor/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ describe('autotrack instrumentor plugin', () => {
assert.equal(actual, expected);
});

it('switch should be instrumented (pre-0.66)', () => {
var actual = getActualTransformedFile('is-switch-pre-0-66');
var expected = getExpectedTransformedFile('is-switch-pre-0-66');
assert.equal(actual, expected);
});

it('switch should be instrumented', () => {
var actual = getActualTransformedFile('is-switch');
var expected = getExpectedTransformedFile('is-switch');
Expand Down
16 changes: 10 additions & 6 deletions integration-tests/drivers/TestDriver063/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'add-react-displayname',
'./node_modules/@heap/react-native-heap/instrumentor/src/index.js',
],
module.exports = (api) => {
api.cache(false);

return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'add-react-displayname',
'./node_modules/@heap/react-native-heap/instrumentor/src/index.js',
],
};
};
4 changes: 2 additions & 2 deletions integration-tests/drivers/TestDriver063/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ PODS:
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsinspector (0.63.5)
- react-native-heap (0.22.3):
- react-native-heap (0.22.4):
- Heap (~> 9.0)
- React
- react-native-safe-area-context (3.3.2):
Expand Down Expand Up @@ -381,7 +381,7 @@ SPEC CHECKSUMS:
React-jsi: 7d908b17758178b076a05a254523f1a4227b53d2
React-jsiexecutor: e06a32e42affb2bd89e4c8369349b5fcf787710c
React-jsinspector: fdbc08866b34ae8e1b788ea1cbd9f9d1ca2aa3d6
react-native-heap: da918ba329898d671d6c536d34772017e35b5afe
react-native-heap: f179319f2bff9c601dad23115ade6cee24f96e7d
react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
React-RCTActionSheet: e911b99f0d6fa7711ffc2f62d236b12a32771835
React-RCTAnimation: ad8b853170a059faf31d6add34f67d22391bbe01
Expand Down
12 changes: 6 additions & 6 deletions integration-tests/drivers/TestDriver063/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion integration-tests/drivers/TestDriver063/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"postinstall": "patch-package"
},
"dependencies": {
"@heap/react-native-heap": "file:../../heap-react-native-heap-0.22.3.tgz",
"@heap/react-native-heap": "file:../../heap-react-native-heap-0.22.4.tgz",
"@react-native-community/masked-view": "^0.1.10",
"@react-navigation/bottom-tabs": "^5.7.3",
"@react-navigation/native": "^5.7.2",
Expand Down
16 changes: 10 additions & 6 deletions integration-tests/drivers/TestDriver066/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'add-react-displayname',
'./node_modules/@heap/react-native-heap/instrumentor/src/index.js',
],
module.exports = api => {
api.cache(false);

return {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'add-react-displayname',
'./node_modules/@heap/react-native-heap/instrumentor/src/index.js',
],
};
};
4 changes: 2 additions & 2 deletions integration-tests/drivers/TestDriver066/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ PODS:
- React-jsinspector (0.66.5)
- React-logger (0.66.5):
- glog
- react-native-heap (0.22.3):
- react-native-heap (0.22.4):
- Heap (~> 9.0)
- React
- react-native-safe-area-context (3.3.2):
Expand Down Expand Up @@ -535,7 +535,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 50a73168582868421112609d2fb155e607e34ec8
React-jsinspector: 953260b8580780a6e81f2a6d319a8d42fd5028d8
React-logger: fa4ff1e9c7e115648f7c5dafb7c20822ab4f7a7e
react-native-heap: 09f2b37f1ef8dd0a5b9cad25b9f9fb323d994a7f
react-native-heap: ad93c14f7c9ef03d676e68abe6a2d1f358228e3e
react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
React-perflogger: 169fb34f60c5fd793b370002ee9c916eba9bc4ae
React-RCTActionSheet: 2355539e02ad5cd4b1328682ab046487e1e1e920
Expand Down
Loading

0 comments on commit 9344fa5

Please sign in to comment.