Skip to content

Commit d743f9f

Browse files
committed
STASH polyfills in dev-utils
1 parent 3da1afa commit d743f9f

33 files changed

+314
-60
lines changed

packages/dev-utils/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!test/jsPolyfills/originals.d.ts

packages/dev-utils/jest.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
module.exports = require('../../jest/jest.config.js');
1+
const baseConfig = require('../../jest/jest.config.js');
2+
3+
module.exports = {
4+
...baseConfig,
5+
transform: {
6+
'^.+\\.ts$': 'ts-jest',
7+
'^.+\\.js$': 'ts-jest',
8+
},
9+
};

packages/dev-utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"build:dev": "run-s build",
2626
"build:es5": "yarn build:cjs # *** backwards compatibility - remove in v7 ***",
2727
"build:esm": "tsc -p tsconfig.esm.json",
28-
"build:rollup": "rollup -c rollup.npm.config.js",
28+
"build:rollup": "yarn rollup -c rollup.npm.config.js && cp src/jsPolyfills/README.md build/cjs/jsPolyfills && cp src/jsPolyfills/README.md build/esm/jsPolyfills",
2929
"build:types": "tsc -p tsconfig.types.json",
3030
"build:watch": "run-p build:cjs:watch build:esm:watch build:types:watch",
3131
"build:cjs:watch": "tsc -p tsconfig.cjs.json --watch",

packages/dev-utils/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
export * as jsPolyfills from './jsPolyfills';
2+
13
// empty placeholder
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { RequireResult } from './types';
2+
/**
3+
* Adds a `default` property to CJS modules which aren't the result of transpilation from ESM modules.
4+
*
5+
* Adapted from Rollup (https://github.com/rollup/rollup)
6+
*
7+
* @param requireResult The result of calling `require` on a module
8+
* @returns Either `requireResult` or a copy of `requireResult` with an added self-referential `default` property
9+
*/
10+
export function _interopNamespace(requireResult: RequireResult): RequireResult {
11+
return requireResult.__esModule ? requireResult : { ...requireResult, default: requireResult };
12+
}
13+
14+
// Rollup version (with `output.externalLiveBindings` and `output.freeze` both set to false)
15+
// function _interopNamespace(e) {
16+
// if (e && e.__esModule) return e;
17+
// var n = Object.create(null);
18+
// if (e) {
19+
// for (var k in e) {
20+
// n[k] = e[k];
21+
// }
22+
// }
23+
// n["default"] = e;
24+
// return n;
25+
// }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Polyfill for the nullish coalescing operator (`??`).
3+
*
4+
* Note that the RHS is wrapped in a function so that if it's a computed value, that evaluation won't happen unless the
5+
* LHS evaluates to a nullish value, to mimic the operator's short-circuiting behavior.
6+
*
7+
* Adapted from Sucrase (https://github.com/alangpierce/sucrase)
8+
*
9+
* @param lhs The value of the expression to the left of the `??`
10+
* @param rhsFn A function returning the value of the expression to the right of the `??`
11+
* @returns The LHS value, unless it's `null` or `undefined`, in which case, the RHS value
12+
*/
13+
export function _nullishCoalesce(lhs: unknown, rhsFn: () => unknown): unknown {
14+
// by checking for loose equality to `null`, we catch both `null` and `undefined`
15+
return lhs != null ? lhs : rhsFn();
16+
}
17+
18+
// Sucrase version:
19+
// function _nullishCoalesce(lhs, rhsFn) {
20+
// if (lhs != null) {
21+
// return lhs;
22+
// } else {
23+
// return rhsFn();
24+
// }
25+
// }

rollup/jsPolyfills/_optionalChain.js renamed to packages/dev-utils/src/jsPolyfills/_optionalChain.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// adapted from Sucrase (https://github.com/alangpierce/sucrase)
22

3-
export function _optionalChain(ops) {
4-
let lastAccessLHS = undefined;
3+
/**
4+
*
5+
*
6+
* @param ops
7+
* @returns
8+
*/
9+
export function _optionalChain(ops: any[]): any {
10+
let lastAccessLHS: any = undefined;
511
let value = ops[0];
612
let i = 1;
713
while (i < ops.length) {
@@ -17,7 +23,9 @@ export function _optionalChain(ops) {
1723
lastAccessLHS = value;
1824
value = fn(value);
1925
} else if (op in ['call', 'optionalCall']) {
20-
value = fn((...args) => value.call(lastAccessLHS, ...args));
26+
// TODO !!!!!!!!
27+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
28+
value = fn((...args: unknown[]) => value.call(lastAccessLHS, ...args));
2129
lastAccessLHS = undefined;
2230
}
2331
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export type { RequireResult } from './types';
2+
3+
// export { _asyncNullishCoalesce } from './_asyncNullishCoalesce';
4+
// export { _asyncOptionalChain } from './_asyncOptionalChain';
5+
// export { _asyncOptionalChainDelete } from './_asyncOptionalChainDelete';
6+
// export { _createNamedExportFrom } from './_createNamedExportFrom';
7+
// export { _createStarExport } from './_createStarExport';
8+
// export { _interopDefault } from './_interopDefault';
9+
export { _interopNamespace } from './_interopNamespace';
10+
// export { _interopRequireDefault } from './_interopRequireDefault';
11+
// export { _interopRequireWildcard } from './_interopRequireWildcard';
12+
export { _nullishCoalesce } from './_nullishCoalesce';
13+
export { _optionalChain } from './_optionalChain';
14+
// export { _optionalChainDelete } from './_optionalChainDelete';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// export type RequireResult = Record<string, unknown> | (((...args: unknown[]) => unknown) & Record<string, unknown>);
2+
type GenericObject = { [key: string]: unknown };
3+
type GenericFunction = (...args: unknown[]) => unknown;
4+
5+
export type RequireResult = GenericObject | (GenericFunction & GenericObject);
6+
// export type RequireResult = GenericObject | GenericFunction | (GenericFunction & GenericObject);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { _interopNamespace, RequireResult } from '../../src/jsPolyfills';
2+
import { _interopNamespace as _interopNamespaceOrig } from './originals';
3+
4+
describe('_interopNamespace', () => {
5+
it('returns the same result as the original', () => {
6+
const withESModuleFlag = { __esModule: true, charlie: 'goofy', maisey: 'silly' };
7+
const namedExports = { charlie: 'goofy', maisey: 'silly' };
8+
const withNonEnumerableProp = { charlie: 'goofy', maisey: 'silly' };
9+
Object.defineProperty(withNonEnumerableProp, 'hiddenProp', {
10+
value: 'shhhhhhhh',
11+
// this is the default, but including it here anyway for clarity
12+
enumerable: false,
13+
});
14+
const withDefaultExport = { default: () => 'dogs are great', charlie: 'goofy', maisey: 'silly' };
15+
const withOnlyDefaultExport = { default: () => 'dogs are great' };
16+
const exportsEquals = () => 'dogs are great';
17+
const exportsEqualsWithDefault = () => 'dogs are great';
18+
exportsEqualsWithDefault.default = exportsEqualsWithDefault;
19+
20+
expect(_interopNamespace(withESModuleFlag)).toEqual(_interopNamespaceOrig(withESModuleFlag));
21+
expect(_interopNamespace(namedExports)).toEqual(_interopNamespaceOrig(namedExports));
22+
expect(_interopNamespace(withNonEnumerableProp)).toEqual(_interopNamespaceOrig(withNonEnumerableProp));
23+
expect(_interopNamespace(withDefaultExport)).toEqual(_interopNamespaceOrig(withDefaultExport));
24+
expect(_interopNamespace(withOnlyDefaultExport)).toEqual(_interopNamespaceOrig(withOnlyDefaultExport));
25+
expect(_interopNamespace(exportsEquals as RequireResult)).toEqual(_interopNamespaceOrig(exportsEquals));
26+
expect(_interopNamespace(exportsEqualsWithDefault as unknown as RequireResult)).toEqual(
27+
_interopNamespaceOrig(exportsEqualsWithDefault),
28+
);
29+
});
30+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// NOTE: Unlike other types files, this is NOT auto-generated by our build scripts. Since these functions are the
2+
// originals of functions we adapted from Rollup and Sucrase, there's no reason they should ever change, but if they do,
3+
// this file needs to be regenerated, by running
4+
// `yarn tsc --allowJs --skipLibCheck --declaration --emitDeclarationOnly test/jsPolyfills/originals.js`
5+
// (Keep in mind that that will clobber this note, so make sure to undo that part of the change.)
6+
7+
export function _asyncNullishCoalesce(lhs: any, rhsFn: any): Promise<any>;
8+
export function _asyncOptionalChain(ops: any): Promise<any>;
9+
export function _asyncOptionalChainDelete(ops: any): Promise<any>;
10+
export function createNamedExportFrom(obj: any, localName: any, importedName: any): void;
11+
export function _createStarExport(obj: any): void;
12+
export function _interopDefault(e: any): any;
13+
export function _interopNamespace(e: any): any;
14+
export function _interopRequireDefault(obj: any): any;
15+
export function _interopRequireWildcard(obj: any): any;
16+
export function _nullishCoalesce(lhs: any, rhsFn: any): any;
17+
export function _optionalChain(ops: any): any;
18+
export function _optionalChainDelete(ops: any): any;
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Originals of the jsPolyfills from Sucrase and Rollup we use (which we have adapted in various ways), preserved here for testing, to prove that
2+
// the modified versions do the same thing the originals do.
3+
4+
// From Sucrase
5+
export async function _asyncNullishCoalesce(lhs, rhsFn) {
6+
if (lhs != null) {
7+
return lhs;
8+
} else {
9+
return await rhsFn();
10+
}
11+
}
12+
13+
// From Sucrase
14+
export async function _asyncOptionalChain(ops) {
15+
let lastAccessLHS = undefined;
16+
let value = ops[0];
17+
let i = 1;
18+
while (i < ops.length) {
19+
const op = ops[i];
20+
const fn = ops[i + 1];
21+
i += 2;
22+
if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
23+
return undefined;
24+
}
25+
if (op === 'access' || op === 'optionalAccess') {
26+
lastAccessLHS = value;
27+
value = await fn(value);
28+
} else if (op === 'call' || op === 'optionalCall') {
29+
value = await fn((...args) => value.call(lastAccessLHS, ...args));
30+
lastAccessLHS = undefined;
31+
}
32+
}
33+
return value;
34+
}
35+
36+
// From Sucrase
37+
export async function _asyncOptionalChainDelete(ops) {
38+
const result = await _asyncOptionalChain(ops);
39+
// by checking for loose equality to `null`, we catch both `null` and `undefined`
40+
return result == null ? true : result;
41+
}
42+
43+
// From Sucrase
44+
export function createNamedExportFrom(obj, localName, importedName) {
45+
Object.defineProperty(exports, localName, { enumerable: true, get: () => obj[importedName] });
46+
}
47+
48+
// From Sucrase
49+
export function _createStarExport(obj) {
50+
Object.keys(obj)
51+
.filter(key => key !== 'default' && key !== '__esModule')
52+
.forEach(key => {
53+
// eslint-disable-next-line no-prototype-builtins
54+
if (exports.hasOwnProperty(key)) {
55+
return;
56+
}
57+
Object.defineProperty(exports, key, { enumerable: true, get: () => obj[key] });
58+
});
59+
}
60+
61+
// From Rollup
62+
export function _interopDefault(e) {
63+
return e && e.__esModule ? e['default'] : e;
64+
}
65+
66+
// From Rollup
67+
export function _interopNamespace(e) {
68+
if (e && e.__esModule) return e;
69+
var n = Object.create(null);
70+
if (e) {
71+
// eslint-disable-next-line guard-for-in
72+
for (var k in e) {
73+
n[k] = e[k];
74+
}
75+
}
76+
n['default'] = e;
77+
return n;
78+
}
79+
80+
// From Sucrase
81+
export function _interopRequireDefault(obj) {
82+
return obj && obj.__esModule ? obj : { default: obj };
83+
}
84+
85+
// From Sucrase
86+
export function _interopRequireWildcard(obj) {
87+
if (obj && obj.__esModule) {
88+
return obj;
89+
} else {
90+
var newObj = {};
91+
if (obj != null) {
92+
for (var key in obj) {
93+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
94+
newObj[key] = obj[key];
95+
}
96+
}
97+
}
98+
newObj.default = obj;
99+
return newObj;
100+
}
101+
}
102+
103+
// From Sucrase
104+
export function _nullishCoalesce(lhs, rhsFn) {
105+
if (lhs != null) {
106+
return lhs;
107+
} else {
108+
return rhsFn();
109+
}
110+
}
111+
112+
// From Sucrase
113+
export function _optionalChain(ops) {
114+
let lastAccessLHS = undefined;
115+
let value = ops[0];
116+
let i = 1;
117+
while (i < ops.length) {
118+
const op = ops[i];
119+
const fn = ops[i + 1];
120+
i += 2;
121+
if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
122+
return undefined;
123+
}
124+
if (op === 'access' || op === 'optionalAccess') {
125+
lastAccessLHS = value;
126+
value = fn(value);
127+
} else if (op === 'call' || op === 'optionalCall') {
128+
value = fn((...args) => value.call(lastAccessLHS, ...args));
129+
lastAccessLHS = undefined;
130+
}
131+
}
132+
return value;
133+
}
134+
135+
// From Sucrase
136+
export function _optionalChainDelete(ops) {
137+
const result = _optionalChain(ops);
138+
// by checking for loose equality to `null`, we catch both `null` and `undefined`
139+
return result == null ? true : result;
140+
}

packages/dev-utils/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55

66
"compilerOptions": {
77
// package-specific options
8+
"types": ["node"]
89
}
910
}

packages/dev-utils/tsconfig.test.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@
88
"types": ["node", "jest"],
99

1010
// other package-specific, test-specific options
11+
// this is necessary in order to be able to handle the jsPolyfills `originals.js` which is used for testing
12+
"allowJs": true
1113
}
1214
}

packages/integrations/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121
"localforage": "^1.8.1",
2222
"tslib": "^1.9.3"
2323
},
24-
"devDependencies": {
25-
"chai": "^4.1.2"
26-
},
2724
"scripts": {
2825
"build": "run-p build:cjs build:esm build:types build:bundle",
2926
"build:bundle": "bash scripts/buildBundles.sh",

packages/utils/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
## General
2121

2222
Common utilities used by the Sentry JavaScript SDKs. **Warning, only submodule imports are allowed here.** Also note,
23-
this function shouldn't be used externally, we will break them from time to time. This package is not part of our public
24-
API contract, we use them only internally.
23+
these functions shouldn't be used externally, as we may break them from time to time. This package is only meant to be used internally, and as such is not part of our public
24+
API contract and does not follow semver.

packages/utils/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@
1616
"access": "public"
1717
},
1818
"dependencies": {
19+
"@sentry-internal/dev-utils": "7.0.0-beta.0",
1920
"@sentry/types": "7.0.0-beta.0",
2021
"tslib": "^1.9.3"
2122
},
22-
"devDependencies": {
23-
"chai": "^4.1.2"
24-
},
2523
"scripts": {
2624
"build": "run-p build:cjs build:esm build:types",
2725
"build:cjs": "tsc -p tsconfig.cjs.json",
2826
"build:dev": "run-s build",
2927
"build:es5": "yarn build:cjs # *** backwards compatibility - remove in v7 ***",
3028
"build:esm": "tsc -p tsconfig.esm.json",
31-
"build:rollup": "rollup -c rollup.npm.config.js && rollup -c rollup.polyfills.config.js && cp ../../rollup/jsPolyfills/README.md jsPolyfills",
29+
"build:rollup": "yarn rollup -c rollup.npm.config.js && cp ../dev-utils/src/jsPolyfills/README.md build/jsPolyfills && cp -r build/jsPolyfills . && echo \"**Dummy copy of polyfills (copied from \\`build/jsPolyfills\\`) necessary for tests.**\" > jsPolyfills/why-is-this-here?.md",
30+
"build:rollup:code": "rollup -c rollup.npm.config.js",
31+
"build:rollup:polyfills": "yarn rollup -c rollup.polyfills.config.js && cp ../../rollup/jsPolyfills/README.md jsPolyfills && yarn tsc --allowJs --skipLibCheck --declaration --emitDeclarationOnly ../../rollup/jsPolyfills/index.js && yarn tsc --allowJs --skipLibCheck --declaration --emitDeclarationOnly ../../rollup/jsPolyfills/originals.js",
3232
"build:types": "tsc -p tsconfig.types.json",
3333
"build:watch": "run-p build:cjs:watch build:esm:watch build:types:watch",
3434
"build:cjs:watch": "tsc -p tsconfig.cjs.json --watch",

packages/utils/rollup.npm.config.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
import * as path from 'path';
2+
13
import { makeBaseNPMConfig, makeNPMConfigVariants } from '../../rollup/index.js';
24

3-
export default makeNPMConfigVariants(makeBaseNPMConfig());
5+
const jsPolyfillsBaseConfig = makeBaseNPMConfig({ entrypoints: ['src/jsPolyfills.ts'] });
6+
7+
jsPolyfillsBaseConfig.output.dir = path.join(jsPolyfillsBaseConfig.output.dir, 'jsPolyfills');
8+
jsPolyfillsBaseConfig.output.entryFileNames = 'index.js';
9+
10+
export default [
11+
// the standard, import-it-straight-from-the-package-like-normal code
12+
...makeNPMConfigVariants(makeBaseNPMConfig()),
13+
// our tslib-like language and CJS/ESM interop helpers, which get imported from `@sentry/utils/jsPolyfills`
14+
...makeNPMConfigVariants(jsPolyfillsBaseConfig),
15+
];

packages/utils/src/jsPolyfills.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { jsPolyfills } from '@sentry-internal/dev-utils';
2+
3+
module.exports = jsPolyfills;

0 commit comments

Comments
 (0)