Skip to content

Commit

Permalink
Support RxJS 7
Browse files Browse the repository at this point in the history
- Detect RxJS 7 correctly
- Patch Observable of  RxJS >=7.2.0 correctly
- Runs integration tests with multiple RxJS versions

Closes #52
  • Loading branch information
swissmanu committed Nov 25, 2021
1 parent 8553c1c commit 0c11784
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 9 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,17 @@ jobs:
- unit-test
- lint
strategy:
fail-fast: false
matrix:
os:
- macos-latest
# - ubuntu-latest TODO Why still timeouts?
# - windows-latest TODO Why still timeouts?
rxjs:
- '6.6.7' # Last 6.x
- '7.0.1' # Latest 7.0.x
- '7.2.0' # First Release that changed how operators are imported https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#720-2021-07-05
- '7.4.0' # Latest and greatest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
Expand All @@ -90,8 +96,11 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Use RxJS ${{ matrix.rxjs }} for Test
run: |
sed -i '' 's/\"rxjs\":.*/\"rxjs\": \"${{ matrix.rxjs }}\"\,/' packages/*/package.json
- name: Install Dependencies
run: yarn --pure-lockfile
run: yarn
- name: Test on Linux System
if: runner.os == 'Linux'
run: xvfb-run -a yarn nx run extension-integrationtest:integrationtest --configuration=test
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## Next

- Feature: Support RxJS 7 [#52](https://github.com/swissmanu/rxjs-debugging-for-vscode/issues/52)

## 0.9.0

- Feature: Support Debugging of Browser-based Applications [#43](https://github.com/swissmanu/rxjs-debugging-for-vscode/issues/43)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Add non-intrusive debugging capabilities for [RxJS](https://rxjs.dev/) applicati
## Features

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

- [Visual Studio Code 1.61](https://code.visualstudio.com/) or newer
- [TypeScript 4.2](https://www.typescriptlang.org/) or newer
- [RxJS 6](https://rxjs.dev/)
- [RxJS 6.6.7](https://rxjs.dev/) or newer
- To debug NodeJS-based applications: [NodeJS 12](https://nodejs.org/) or newer
- To debug web applications:
- [Webpack 5.60.0](https://webpack.js.org/) or newer
Expand Down
20 changes: 17 additions & 3 deletions packages/runtime-nodejs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import {
import operatorLogPointInstrumentation from '@rxjs-debugging/runtime/out/instrumentation/operatorLogPoint';
import patchObservable from '@rxjs-debugging/runtime/out/instrumentation/operatorLogPoint/patchObservable';
import TelemetryBridge from '@rxjs-debugging/runtime/out/telemetryBridge';
import isRxJSImport from '@rxjs-debugging/runtime/out/utils/isRxJSImport';
import waitForCDPBindings from '@rxjs-debugging/runtime/out/utils/waitForCDPBindings';
import { TelemetryEvent } from '@rxjs-debugging/telemetry';
import serializeTelemetryEvent from '@rxjs-debugging/telemetry/out/serialize';
import * as Module from 'module';
import type { Subscriber as SubscriberType } from 'rxjs';

const programPath = process.env[RUNTIME_PROGRAM_ENV_VAR];
const programModule = Module.createRequire(programPath);
const createWrapOperatorFunction = operatorLogPointInstrumentation(programModule('rxjs').Subscriber);
const Subscriber = getSubscriber(programModule);
const createWrapOperatorFunction = operatorLogPointInstrumentation(Subscriber);

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

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

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

function getSubscriber(
customRequire: (module: string) => { Subscriber: typeof SubscriberType }
): typeof SubscriberType {
try {
// Try access Subscriber via /internal first. This works for RxJS >=7.2.0.
return customRequire('rxjs/internal/Subscriber').Subscriber;
} catch (_) {
// If the first attempt failed, fall back to a plain root import:
return customRequire('rxjs').Subscriber;
}
}

global[RUNTIME_TELEMETRY_BRIDGE] = telemetryBridge;

waitForCDPBindings('nodejs');
5 changes: 2 additions & 3 deletions packages/runtime-webpack/src/RxJSDebuggingPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import isRxJSImport from '@rxjs-debugging/runtime/out/utils/isRxJSImport';
import * as path from 'path';
import type { Compiler } from 'webpack';
import { NormalModule } from 'webpack';
Expand All @@ -6,8 +7,6 @@ const PLUGIN_NAME = 'RxJSDebuggingPlugin';
const loaderPath = require.resolve('./loader.js');
const here = path.dirname(loaderPath);

const observableRegex = /rxjs\/(_esm5\/)?internal\/Observable(\.js)?$/g;

export default class RxJSDebuggingPlugin {
apply(compiler: Compiler): void {
if (compiler.options.mode === 'production') {
Expand All @@ -22,7 +21,7 @@ export default class RxJSDebuggingPlugin {
}

const { userRequest = '' } = normalModule;
if (observableRegex.exec(userRequest) !== null) {
if (isRxJSImport(userRequest)) {
loaders.push({
loader: loaderPath,
options: {},
Expand Down
25 changes: 25 additions & 0 deletions packages/runtime/src/utils/isRxJSImport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import isRxJSImport from './isRxJSImport';

describe('Runtime', () => {
describe('isRxJSImport()', () => {
test.each([
[true, '/node_modules/rxjs/dist/esm5/internal/Observable.js'],
[true, '/node_modules/rxjs/dist/esm5/internal/Observable'],
[true, '/node_modules/rxjs/esm5/internal/Observable.js'],
[true, '/node_modules/rxjs/esm5/internal/Observable'],
[true, '/node_modules/rxjs/_esm5/internal/Observable.js'],
[true, '/node_modules/rxjs/_esm5/internal/Observable'],
[true, '/node_modules/rxjs/_esm2015/internal/Observable.js'],
[true, '/node_modules/rxjs/_esm2015/internal/Observable'],
[true, '/node_modules/rxjs/internal/Observable.js'],
[true, '/node_modules/rxjs/internal/Observable'],
[true, 'rxjs/internal/Observable'],
[false, 'rxjs'],
[false, 'rxjs/Observable'],
[false, 'Observable'],
[false, ''],
])('returns %s for %s', (expected, path) => {
expect(isRxJSImport(path)).toBe(expected);
});
});
});
12 changes: 12 additions & 0 deletions packages/runtime/src/utils/isRxJSImport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const OBSERVABLE_MODULE_REGEX = /rxjs\/(dist\/|esm\/|esm5\/|_esm5\/|_esm2015\/|cjs\/)*internal\/Observable(\.js)?$/;

/**
* Tests if a given path is leads to RxJS' `Observable.js` file.
*
* @param path
* @returns
*/
export default function isRxJSImport(path: string): boolean {
const match = OBSERVABLE_MODULE_REGEX.exec(path);
return match !== null;
}

0 comments on commit 0c11784

Please sign in to comment.