Skip to content

Commit

Permalink
fix: impore how we replace this in third-party code` (#453)
Browse files Browse the repository at this point in the history
* fix: imporove how we replace `this` in third-party code

* stash
  • Loading branch information
molszanski authored Sep 15, 2023
1 parent 05eca46 commit 0cc8e43
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 9 deletions.
47 changes: 40 additions & 7 deletions src/lib/web-worker/worker-exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,50 @@ export const runScriptContent = (
return errorMsg;
};

/**
* Replace some `this` symbols with a new value.
* Still not perfect, but might be better than a more naive regex.
* Check out the tests for examples: tests/unit/worker-exec.spec.ts
*/
export const replaceThisInSource = (scriptContent: string, newThis: string): string => {
// Best for now but not perfect
// Use a more complex regex to match potential preceding character and adjust replacement accordingly
const r0 = /(?<!([a-zA-Z0-9_$\.\'\"\`]))(\.\.\.)?this(?![a-zA-Z0-9_$:])/g;
const r2 = /([a-zA-Z0-9_$\.\'\"\`])?(\.\.\.)?this(?![a-zA-Z0-9_$:])/g;

return scriptContent.replace(r2, (match, p1, p2) => {
// console.log('\n');
// console.log('input: ' + scriptContent);
// console.log('match: ', match);
// console.log('p1: ', p1);
// console.log('p2: ', p2);
// console.log('\n');
if (p1 != null) {
return (p1 || '') + (p2 || '') + 'this';
}
// If there was a preceding character, include it unchanged
// console.log('===', scriptContent, '----', p1, p2);
return (p1 || '') + (p2 || '') + newThis;
});

// 3.5
// const r = /(^|[^a-zA-Z0-9_$.\'\"`])\.\.\.?this(?![a-zA-Z0-9_$:])/g;
// return scriptContent.replace(r, '$1' + newThis);
// const r = /(?<!([a-zA-Z0-9_$\.\'\"\`]))(\.\.\.)?this(?![a-zA-Z0-9_$:])/g;
// return scriptContent.replace(r, '$2' + newThis);
};

export const run = (env: WebWorkerEnvironment, scriptContent: string, scriptUrl?: string) => {
env.$runWindowLoadEvent$ = 1;

// First we want to replace all `this` symbols
let sourceWithReplacedThis = replaceThisInSource(scriptContent, '(thi$(this)?window:this)');

scriptContent =
`with(this){${scriptContent
.replace(/\bthis\b/g, (match, offset, originalStr) =>
offset > 0 && originalStr[offset - 1] !== '$' ? '(thi$(this)?window:this)' : match
)
.replace(/\/\/# so/g, '//Xso')}\n;function thi$(t){return t===this}};${(
webWorkerCtx.$config$.globalFns || []
)
`with(this){${sourceWithReplacedThis.replace(
/\/\/# so/g,
'//Xso'
)}\n;function thi$(t){return t===this}};${(webWorkerCtx.$config$.globalFns || [])
.filter((globalFnName) => /[a-zA-Z_$][0-9a-zA-Z_$]*/.test(globalFnName))
.map((g) => `(typeof ${g}=='function'&&(this.${g}=${g}))`)
.join(';')};` + (scriptUrl ? '\n//# sourceURL=' + scriptUrl : '');
Expand Down
68 changes: 66 additions & 2 deletions tests/unit/worker-exec.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as assert from 'uvu/assert';
import { run } from '../../src/lib/web-worker/worker-exec';
import { run, replaceThisInSource } from '../../src/lib/web-worker/worker-exec';
import { suite } from './utils';

const test = suite();

test('add window id to postMessage() when cross-origin', ({ env, win, winId }) => {
Expand Down Expand Up @@ -93,4 +92,69 @@ test('window is window', ({ env, win }) => {
assert.is(win.result, true);
});

test('We should replace `this` keyword more or less sane', ({ env, win }) => {
const replaceSymbol = '__this';
const r = function (code: string) {
return replaceThisInSource(code, replaceSymbol);
};

// Should replace:
// assert.is(r('`sadly we fail at this simple string`'), '`sadly we fail at this simple string`');
assert.is(r('{this:123}'), '{this:123}');
assert.is(r('a.this'), 'a.this');
assert.is(r('[`kathis`]'), '[`kathis`]');
assert.is(r('{ ...this.opts };'), '{ ...__this.opts };');
assert.is(r('{ ...this.opts };this.lol;'), '{ ...__this.opts };__this.lol;');

const input = `
// Should replace:
{ ...this.opts };this.lol;
this
this.test
log(this.variable)
\`hello \${CONST} is \${this.CONST2}\`
// Should not replace:
['this', "this", \`this\`]
{this:123}
{ this: 123 }
'sadly we fail at this simple string'
"same as this"
\`and this is \${false} too\`;
a.b.this
let _this, This, $this
`;
// const rez = replaceThisInSource(input, `__this`);

const out = `
// Should replace:
{ ...__this.opts };__this.lol;
__this
__this.test
log(__this.variable)
\`hello \${CONST} is \${__this.CONST2}\`
// Should not replace:
['this', "this", \`this\`]
{this:123}
{ this: 123 }
'sadly we fail at __this simple string'
"same as __this"
\`and __this is \${false} too\`;
a.b.this
let _this, This, $this
`;

// assert.is(rez, out);
});

// test('properly replaces this is js window context', ({ env, win }) => {
// const s = `
// let a = { this: 123 };
// window.result = a.this;
// `;
// run(env, s);
// assert.is(win.result, 123);
// });

test.run();

1 comment on commit 0cc8e43

@vercel
Copy link

@vercel vercel bot commented on 0cc8e43 Sep 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.