Skip to content

Commit 0c11784

Browse files
committed
Support RxJS 7
- Detect RxJS 7 correctly - Patch Observable of RxJS >=7.2.0 correctly - Runs integration tests with multiple RxJS versions Closes #52
1 parent 8553c1c commit 0c11784

File tree

7 files changed

+72
-9
lines changed

7 files changed

+72
-9
lines changed

.github/workflows/build.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,17 @@ jobs:
6767
- unit-test
6868
- lint
6969
strategy:
70+
fail-fast: false
7071
matrix:
7172
os:
7273
- macos-latest
7374
# - ubuntu-latest TODO Why still timeouts?
7475
# - windows-latest TODO Why still timeouts?
76+
rxjs:
77+
- '6.6.7' # Last 6.x
78+
- '7.0.1' # Latest 7.0.x
79+
- '7.2.0' # First Release that changed how operators are imported https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#720-2021-07-05
80+
- '7.4.0' # Latest and greatest
7581
runs-on: ${{ matrix.os }}
7682
steps:
7783
- name: Checkout
@@ -90,8 +96,11 @@ jobs:
9096
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
9197
restore-keys: |
9298
${{ runner.os }}-yarn-
99+
- name: Use RxJS ${{ matrix.rxjs }} for Test
100+
run: |
101+
sed -i '' 's/\"rxjs\":.*/\"rxjs\": \"${{ matrix.rxjs }}\"\,/' packages/*/package.json
93102
- name: Install Dependencies
94-
run: yarn --pure-lockfile
103+
run: yarn
95104
- name: Test on Linux System
96105
if: runner.os == 'Linux'
97106
run: xvfb-run -a yarn nx run extension-integrationtest:integrationtest --configuration=test

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
## Next
4+
5+
- Feature: Support RxJS 7 [#52](https://github.com/swissmanu/rxjs-debugging-for-vscode/issues/52)
6+
37
## 0.9.0
48

59
- Feature: Support Debugging of Browser-based Applications [#43](https://github.com/swissmanu/rxjs-debugging-for-vscode/issues/43)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Add non-intrusive debugging capabilities for [RxJS](https://rxjs.dev/) applicati
1111
## Features
1212

1313
- RxJS debugging, fully integrated with Visual Studio Code
14-
- Works with RxJS 6
14+
- Works with RxJS 6.6.7 and newer
1515
- Support for:
1616
- NodeJS-based RxJS applications
1717
- browser-based RxJS applications
@@ -40,7 +40,7 @@ You can toggle the display of recommended log points via the command palette.
4040

4141
- [Visual Studio Code 1.61](https://code.visualstudio.com/) or newer
4242
- [TypeScript 4.2](https://www.typescriptlang.org/) or newer
43-
- [RxJS 6](https://rxjs.dev/)
43+
- [RxJS 6.6.7](https://rxjs.dev/) or newer
4444
- To debug NodeJS-based applications: [NodeJS 12](https://nodejs.org/) or newer
4545
- To debug web applications:
4646
- [Webpack 5.60.0](https://webpack.js.org/) or newer

packages/runtime-nodejs/src/index.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import {
66
import operatorLogPointInstrumentation from '@rxjs-debugging/runtime/out/instrumentation/operatorLogPoint';
77
import patchObservable from '@rxjs-debugging/runtime/out/instrumentation/operatorLogPoint/patchObservable';
88
import TelemetryBridge from '@rxjs-debugging/runtime/out/telemetryBridge';
9+
import isRxJSImport from '@rxjs-debugging/runtime/out/utils/isRxJSImport';
910
import waitForCDPBindings from '@rxjs-debugging/runtime/out/utils/waitForCDPBindings';
1011
import { TelemetryEvent } from '@rxjs-debugging/telemetry';
1112
import serializeTelemetryEvent from '@rxjs-debugging/telemetry/out/serialize';
1213
import * as Module from 'module';
14+
import type { Subscriber as SubscriberType } from 'rxjs';
1315

1416
const programPath = process.env[RUNTIME_PROGRAM_ENV_VAR];
1517
const programModule = Module.createRequire(programPath);
16-
const createWrapOperatorFunction = operatorLogPointInstrumentation(programModule('rxjs').Subscriber);
18+
const Subscriber = getSubscriber(programModule);
19+
const createWrapOperatorFunction = operatorLogPointInstrumentation(Subscriber);
1720

18-
const observableRegex = /rxjs\/(_esm5\/)?internal\/Observable/g;
1921
const originalRequire = Module.prototype.require;
2022
let patchedCache = null;
2123

@@ -28,7 +30,7 @@ const patchedRequire: NodeJS.Require = function (id) {
2830
this
2931
);
3032

31-
if (observableRegex.exec(filename) !== null) {
33+
if (isRxJSImport(filename)) {
3234
if (patchedCache) {
3335
return patchedCache;
3436
}
@@ -52,6 +54,18 @@ function defaultSend(event: TelemetryEvent): void {
5254
global[CDP_BINDING_NAME_SEND_TELEMETRY](message); // global.sendRxJsDebuggerTelemetry will be provided via CDP Runtime.addBinding eventually:
5355
}
5456

57+
function getSubscriber(
58+
customRequire: (module: string) => { Subscriber: typeof SubscriberType }
59+
): typeof SubscriberType {
60+
try {
61+
// Try access Subscriber via /internal first. This works for RxJS >=7.2.0.
62+
return customRequire('rxjs/internal/Subscriber').Subscriber;
63+
} catch (_) {
64+
// If the first attempt failed, fall back to a plain root import:
65+
return customRequire('rxjs').Subscriber;
66+
}
67+
}
68+
5569
global[RUNTIME_TELEMETRY_BRIDGE] = telemetryBridge;
5670

5771
waitForCDPBindings('nodejs');

packages/runtime-webpack/src/RxJSDebuggingPlugin.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import isRxJSImport from '@rxjs-debugging/runtime/out/utils/isRxJSImport';
12
import * as path from 'path';
23
import type { Compiler } from 'webpack';
34
import { NormalModule } from 'webpack';
@@ -6,8 +7,6 @@ const PLUGIN_NAME = 'RxJSDebuggingPlugin';
67
const loaderPath = require.resolve('./loader.js');
78
const here = path.dirname(loaderPath);
89

9-
const observableRegex = /rxjs\/(_esm5\/)?internal\/Observable(\.js)?$/g;
10-
1110
export default class RxJSDebuggingPlugin {
1211
apply(compiler: Compiler): void {
1312
if (compiler.options.mode === 'production') {
@@ -22,7 +21,7 @@ export default class RxJSDebuggingPlugin {
2221
}
2322

2423
const { userRequest = '' } = normalModule;
25-
if (observableRegex.exec(userRequest) !== null) {
24+
if (isRxJSImport(userRequest)) {
2625
loaders.push({
2726
loader: loaderPath,
2827
options: {},
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import isRxJSImport from './isRxJSImport';
2+
3+
describe('Runtime', () => {
4+
describe('isRxJSImport()', () => {
5+
test.each([
6+
[true, '/node_modules/rxjs/dist/esm5/internal/Observable.js'],
7+
[true, '/node_modules/rxjs/dist/esm5/internal/Observable'],
8+
[true, '/node_modules/rxjs/esm5/internal/Observable.js'],
9+
[true, '/node_modules/rxjs/esm5/internal/Observable'],
10+
[true, '/node_modules/rxjs/_esm5/internal/Observable.js'],
11+
[true, '/node_modules/rxjs/_esm5/internal/Observable'],
12+
[true, '/node_modules/rxjs/_esm2015/internal/Observable.js'],
13+
[true, '/node_modules/rxjs/_esm2015/internal/Observable'],
14+
[true, '/node_modules/rxjs/internal/Observable.js'],
15+
[true, '/node_modules/rxjs/internal/Observable'],
16+
[true, 'rxjs/internal/Observable'],
17+
[false, 'rxjs'],
18+
[false, 'rxjs/Observable'],
19+
[false, 'Observable'],
20+
[false, ''],
21+
])('returns %s for %s', (expected, path) => {
22+
expect(isRxJSImport(path)).toBe(expected);
23+
});
24+
});
25+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const OBSERVABLE_MODULE_REGEX = /rxjs\/(dist\/|esm\/|esm5\/|_esm5\/|_esm2015\/|cjs\/)*internal\/Observable(\.js)?$/;
2+
3+
/**
4+
* Tests if a given path is leads to RxJS' `Observable.js` file.
5+
*
6+
* @param path
7+
* @returns
8+
*/
9+
export default function isRxJSImport(path: string): boolean {
10+
const match = OBSERVABLE_MODULE_REGEX.exec(path);
11+
return match !== null;
12+
}

0 commit comments

Comments
 (0)