diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 55317e45..c331bbc2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,14 +16,20 @@ jobs: runs-on: ubuntu-latest name: "Release a new version" steps: + - name: Get auth token + id: token + uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + with: + app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} + private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - uses: actions/checkout@v4 with: - token: ${{ secrets.GH_RELEASE_PAT }} + token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release uses: getsentry/action-prepare-release@v1 env: - GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} + GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: version: ${{ github.event.inputs.version }} force: ${{ github.event.inputs.force }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a1c41e..7b8c4cdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ - "You know what they say β€˜Fool me once, strike one, but fool me twice… strike three.’" β€” Michael Scott +## 2.23.0 + +- chore(deps): bump nanoid from 3.3.6 to 3.3.8 (#641) +- feat(core): Detect Railway release name (#639) +- feat(core): Write module injections to `globalThis` (#636) +- feat(react-component-annotate): Allow skipping annotations on specified components (#617) +- ref(core): Rename release management plugin name (#647) + +Work in this release contributed by @conor-ob. Thank you for your contribution! + ## 2.22.7 - deps: Bump `@sentry/cli` to `2.39.1` and require specific version (#632) diff --git a/lerna.json b/lerna.json index b6246f4c..d9394f95 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "2.22.7", + "version": "2.23.0", "npmClient": "yarn", "useWorkspaces": true } diff --git a/packages/babel-plugin-component-annotate/README.md b/packages/babel-plugin-component-annotate/README.md index 7d079934..7783c758 100644 --- a/packages/babel-plugin-component-annotate/README.md +++ b/packages/babel-plugin-component-annotate/README.md @@ -47,6 +47,14 @@ Using pnpm: pnpm add @sentry/babel-plugin-component-annotate --save-dev ``` +## Options + +### `ignoredComponents` + +Type: `string[]` + +A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components. + ## Example ```js @@ -57,7 +65,8 @@ pnpm add @sentry/babel-plugin-component-annotate --save-dev plugins: [ // Put this plugin before any other plugins you have that transform JSX code - ['@sentry/babel-plugin-component-annotate'] + // The options are set by providing an object as the second element in the array, but not required + ['@sentry/babel-plugin-component-annotate', {ignoredComponents: ['Foo', 'Bar']}] ], } ``` diff --git a/packages/babel-plugin-component-annotate/package.json b/packages/babel-plugin-component-annotate/package.json index 53e32009..d0aa944c 100644 --- a/packages/babel-plugin-component-annotate/package.json +++ b/packages/babel-plugin-component-annotate/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/babel-plugin-component-annotate", - "version": "2.22.7", + "version": "2.23.0", "description": "A Babel plugin that annotates frontend components with additional data to enrich the experience in Sentry", "repository": "git://github.com/getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/babel-plugin-component-annotate", @@ -56,8 +56,8 @@ "@babel/preset-typescript": "7.17.12", "@rollup/plugin-babel": "5.3.1", "@rollup/plugin-node-resolve": "13.3.0", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/core": "^1.2.205", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", diff --git a/packages/babel-plugin-component-annotate/src/index.ts b/packages/babel-plugin-component-annotate/src/index.ts index 5a3e4e5e..0cd087d9 100644 --- a/packages/babel-plugin-component-annotate/src/index.ts +++ b/packages/babel-plugin-component-annotate/src/index.ts @@ -48,15 +48,13 @@ const nativeSourceFileName = "dataSentrySourceFile"; interface AnnotationOpts { native?: boolean; "annotate-fragments"?: boolean; - ignoreComponents?: IgnoredComponent[]; + ignoredComponents?: string[]; } interface AnnotationPluginPass extends PluginPass { opts: AnnotationOpts; } -type IgnoredComponent = [file: string, component: string, element: string]; - type AnnotationPlugin = PluginObj; // We must export the plugin as default, otherwise the Babel loader will not be able to resolve it when configured using its string identifier @@ -78,7 +76,7 @@ export default function componentNameAnnotatePlugin({ types: t }: typeof Babel): path.node.id.name, sourceFileNameFromState(state), attributeNamesFromState(state), - state.opts.ignoreComponents ?? [] + state.opts.ignoredComponents ?? [] ); }, ArrowFunctionExpression(path, state) { @@ -106,7 +104,7 @@ export default function componentNameAnnotatePlugin({ types: t }: typeof Babel): parent.id.name, sourceFileNameFromState(state), attributeNamesFromState(state), - state.opts.ignoreComponents ?? [] + state.opts.ignoredComponents ?? [] ); }, ClassDeclaration(path, state) { @@ -120,7 +118,7 @@ export default function componentNameAnnotatePlugin({ types: t }: typeof Babel): return; } - const ignoredComponents = state.opts.ignoreComponents ?? []; + const ignoredComponents = state.opts.ignoredComponents ?? []; render.traverse({ ReturnStatement(returnStatement) { @@ -153,7 +151,7 @@ function functionBodyPushAttributes( componentName: string, sourceFileName: string | undefined, attributeNames: string[], - ignoredComponents: IgnoredComponent[] + ignoredComponents: string[] ) { let jsxNode: Babel.NodePath; @@ -249,7 +247,7 @@ function processJSX( componentName: string | null, sourceFileName: string | undefined, attributeNames: string[], - ignoredComponents: IgnoredComponent[] + ignoredComponents: string[] ) { if (!jsxNode) { return; @@ -324,7 +322,7 @@ function applyAttributes( componentName: string | null, sourceFileName: string | undefined, attributeNames: string[], - ignoredComponents: IgnoredComponent[] + ignoredComponents: string[] ) { const [componentAttributeName, elementAttributeName, sourceFileAttributeName] = attributeNames; @@ -340,10 +338,7 @@ function applyAttributes( const elementName = getPathName(t, openingElement); const isAnIgnoredComponent = ignoredComponents.some( - (ignoredComponent) => - matchesIgnoreRule(ignoredComponent[0], sourceFileName) && - matchesIgnoreRule(ignoredComponent[1], componentName) && - matchesIgnoreRule(ignoredComponent[2], elementName) + (ignoredComponent) => ignoredComponent === componentName || ignoredComponent === elementName ); // Add a stable attribute for the element name but only for non-DOM names @@ -501,10 +496,6 @@ function isReactFragment(t: typeof Babel.types, openingElement: Babel.NodePath): return false; } -function matchesIgnoreRule(rule: string, name: string | undefined | null) { - return rule === "*" || rule === name; -} - function hasAttributeWithName( openingElement: Babel.NodePath, name: string | undefined | null diff --git a/packages/babel-plugin-component-annotate/test/test-plugin.test.ts b/packages/babel-plugin-component-annotate/test/test-plugin.test.ts index edb581e0..7dce87ad 100644 --- a/packages/babel-plugin-component-annotate/test/test-plugin.test.ts +++ b/packages/babel-plugin-component-annotate/test/test-plugin.test.ts @@ -1051,856 +1051,15 @@ export default PureComponentName; expect(result?.code).toMatchSnapshot(); }); -it("Bananas ignore components dataSentrySourceFile=nomatch dataSentryComponent=nomatch dataSentryElement=nomatch snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "nomatch", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("ignore components dataSentrySourceFile=* dataSentryComponent=nomatch dataSentryElement=nomatch snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["*", "nomatch", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("Bananas ignore components dataSentrySourceFile=nomatch dataSentryComponent=* dataSentryElement=nomatch snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "*", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("Bananas ignore components dataSentrySourceFile=nomatch dataSentryComponent=nomatch dataSentryElement=* snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "nomatch", "*"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("Bananas ignore components dataSentrySourceFile=* dataSentryComponent=* dataSentryElement=nomatch snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "nomatch", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("Bananas ignore components dataSentrySourceFile=* dataSentryComponent=nomatch dataSentryElement=* snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "nomatch", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -it("Bananas ignore components dataSentrySourceFile=nomatch dataSentryComponent=* dataSentryElement=* snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "nomatch", "nomatch"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - }" - `); -}); - -// This tests out matching only `dataSentryElement`, with * for the others -it("Bananas ignore components dataSentrySourceFile=* dataSentryComponent=* dataSentryElement=match snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["*", "*", "Image"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - }" - `); -}); - -// This tests out matching only `dataSentryElement` and `dataSentryComponent`, with * for `dataSentrySourceFile` -it("Bananas ignore components dataSentrySourceFile=* dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["*", "Bananas", "Image"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - }" - `); -}); - -// This tests out matching on all 3 of our ignore list values -it("Bananas ignore components dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [ - [plugin, { native: true, ignoreComponents: [["filename-test.js", "Bananas", "Image"]] }], - ], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - }" - `); -}); - -// This tests out matching on all 3 of our ignore list values via * -it("Bananas/Pizza/App ignore components dataSentrySourceFile=* dataSentryComponent=* dataSentryElement=* snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["*", "*", "*"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - } - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - } - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - } - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, null), /*#__PURE__*/React.createElement(PizzaTranslator, null)); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -// This tests out matching on all 3 of our ignore list values -it("Bananas/Pizza/App ignore components dataSentrySourceFile=nomatch dataSentryComponent=* dataSentryElement=* snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true, ignoreComponents: [["nomatch.js", "*", "*"]] }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - }, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"App\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, { - dataSentryElement: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(PizzaTranslator, { - dataSentryElement: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - })); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -it("Bananas/Pizza/App only Bananas dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Pizza - ["filename-test.js", "PizzaTranslator", "View"], - // App - ["filename-test.js", "App", "View"], - ], - }, - ], - ], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - } - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, { - dataSentryElement: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(PizzaTranslator, { - dataSentryElement: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - })); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -it("Bananas/Pizza/App only Pizza dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Bananas - ["filename-test.js", "Bananas", "Image"], - // App - ["filename-test.js", "App", "View"], - ], - }, - ], - ], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - }, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, { - dataSentryElement: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(PizzaTranslator, { - dataSentryElement: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - })); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -it("Bananas/Pizza/App only App dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Bananas - ["filename-test.js", "Bananas", "Image"], - // Pizza - ["filename-test.js", "PizzaTranslator", "View"], - ], - }, - ], - ], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - } - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"App\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, { - dataSentryElement: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(PizzaTranslator, { - dataSentryElement: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - })); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -it("Bananas/Pizza/App No Pizza Elements dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, +it("Bananas incompatible plugin @react-navigation source snapshot matches", () => { + const result = transform(BananasStandardInput, { + filename: "test/node_modules/@react-navigation/core/filename-test.js", presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Pizza Element - ["filename-test.js", null, "PizzaTranslator"], - ], - }, - ], - ], + plugins: [[plugin, { native: true }]], }); expect(result?.code).toMatchInlineSnapshot(` "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; + import { Image } from 'react-native'; class Bananas extends Component { render() { let pic = { @@ -1913,101 +1072,19 @@ it("Bananas/Pizza/App No Pizza Elements dataSentrySourceFile=match dataSentryCom height: 110, marginTop: 10 }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" + fsClass: \\"test-class\\" }); } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - }, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"App\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, { - dataSentryElement: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(PizzaTranslator, null)); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" + }" `); }); -it("Bananas/Pizza/App No Bananas Elements dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { +it("skips components marked in ignoredComponents", () => { const result = transform(BananasPizzaAppStandardInput, { filename: "/filename-test.js", - configFile: false, presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Bananas Element - ["filename-test.js", null, "Bananas"], - ], - }, - ], - ], + plugins: [[plugin, { native: true, ignoredComponents: ["Bananas"] }]], }); - expect(result?.code).toMatchInlineSnapshot(` "import React, { Component } from 'react'; import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; @@ -2024,10 +1101,7 @@ it("Bananas/Pizza/App No Bananas Elements dataSentrySourceFile=match dataSentryC height: 110, marginTop: 10 }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" + fsClass: \\"test-class\\" }); } } @@ -2100,143 +1174,6 @@ it("Bananas/Pizza/App No Bananas Elements dataSentrySourceFile=match dataSentryC `); }); -it("Bananas/Pizza/App No Bananas/Pizza Elements dataSentrySourceFile=match dataSentryComponent=match dataSentryElement=match snapshot matches", () => { - const result = transform(BananasPizzaAppStandardInput, { - filename: "/filename-test.js", - configFile: false, - presets: ["@babel/preset-react"], - plugins: [ - [ - plugin, - { - native: true, - ignoreComponents: [ - // Bananas Element - ["filename-test.js", null, "Bananas"], - // Pizza Element - ["filename-test.js", null, "PizzaTranslator"], - ], - }, - ], - ], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { StyleSheet, Text, TextInput, View, Image, UIManager } from 'react-native'; - UIManager.getViewManagerConfig('RCTView').NativeProps.fsClass = \\"String\\"; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\", - dataSentryElement: \\"Image\\", - dataSentryComponent: \\"Bananas\\", - dataSentrySourceFile: \\"filename-test.js\\" - }); - } - } - class PizzaTranslator extends Component { - constructor(props) { - super(props); - this.state = { - text: '' - }; - } - render() { - return /*#__PURE__*/React.createElement(View, { - style: { - padding: 10 - }, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"PizzaTranslator\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(TextInput, { - style: { - backgroundColor: '#000', - color: '#eee', - padding: 8 - }, - placeholder: \\"Type here to translate!\\" // not supported on iOS - , - onChangeText: text => this.setState({ - text - }), - value: this.state.text, - dataSentryElement: \\"TextInput\\", - dataSentrySourceFile: \\"filename-test.js\\" - }), /*#__PURE__*/React.createElement(Text, { - style: { - padding: 10, - fontSize: 42 - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, this.state.text.split(' ').map(word => word && 'πŸ•').join(' '))); - } - } - export default function App() { - return /*#__PURE__*/React.createElement(View, { - style: styles.container, - dataSentryElement: \\"View\\", - dataSentryComponent: \\"App\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, /*#__PURE__*/React.createElement(Text, { - style: { - color: '#eee' - }, - dataSentryElement: \\"Text\\", - dataSentrySourceFile: \\"filename-test.js\\" - }, \\"FullStory ReactNative testing app\\"), /*#__PURE__*/React.createElement(Bananas, null), /*#__PURE__*/React.createElement(PizzaTranslator, null)); - } - const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#222', - alignItems: 'center', - justifyContent: 'center' - } - });" - `); -}); - -it("Bananas incompatible plugin @react-navigation source snapshot matches", () => { - const result = transform(BananasStandardInput, { - filename: "test/node_modules/@react-navigation/core/filename-test.js", - presets: ["@babel/preset-react"], - plugins: [[plugin, { native: true }]], - }); - expect(result?.code).toMatchInlineSnapshot(` - "import React, { Component } from 'react'; - import { Image } from 'react-native'; - class Bananas extends Component { - render() { - let pic = { - uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' - }; - return /*#__PURE__*/React.createElement(Image, { - source: pic, - style: { - width: 193, - height: 110, - marginTop: 10 - }, - fsClass: \\"test-class\\" - }); - } - }" - `); -}); - it("handles ternary operation returned by function body", () => { const result = transform( `const maybeTrue = Math.random() > 0.5; diff --git a/packages/bundler-plugin-core/package.json b/packages/bundler-plugin-core/package.json index 3d47a19c..5befe9e5 100644 --- a/packages/bundler-plugin-core/package.json +++ b/packages/bundler-plugin-core/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/bundler-plugin-core", - "version": "2.22.7", + "version": "2.23.0", "description": "Sentry Bundler Plugin Core", "repository": "git://github.com/getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/bundler-plugin-core", @@ -53,7 +53,7 @@ }, "dependencies": { "@babel/core": "^7.18.5", - "@sentry/babel-plugin-component-annotate": "2.22.7", + "@sentry/babel-plugin-component-annotate": "2.23.0", "@sentry/cli": "2.39.1", "dotenv": "^16.3.1", "find-up": "^5.0.0", @@ -68,8 +68,8 @@ "@rollup/plugin-json": "4.1.0", "@rollup/plugin-node-resolve": "13.3.0", "@rollup/plugin-replace": "^4.0.0", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@sentry/core": "8.30.0", "@sentry/types": "8.30.0", "@sentry/utils": "8.30.0", diff --git a/packages/bundler-plugin-core/sentry-esbuild-debugid-injection-file.js b/packages/bundler-plugin-core/sentry-esbuild-debugid-injection-file.js index 6135fac3..ac913e2e 100644 --- a/packages/bundler-plugin-core/sentry-esbuild-debugid-injection-file.js +++ b/packages/bundler-plugin-core/sentry-esbuild-debugid-injection-file.js @@ -4,6 +4,8 @@ try { ? window : "undefined" != typeof global ? global + : "undefined" != typeof globalThis + ? global : "undefined" != typeof self ? self : {}; diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index e03e7bee..dc7006dc 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -30,7 +30,7 @@ import { closeSession, DEFAULT_ENVIRONMENT, makeSession } from "@sentry/core"; interface SentryUnpluginFactoryOptions { releaseInjectionPlugin: (injectionCode: string) => UnpluginOptions; - componentNameAnnotatePlugin?: () => UnpluginOptions; + componentNameAnnotatePlugin?: (ignoredComponents?: string[]) => UnpluginOptions; moduleMetadataInjectionPlugin: (injectionCode: string) => UnpluginOptions; debugIdInjectionPlugin: (logger: Logger) => UnpluginOptions; debugIdUploadPlugin: (upload: (buildArtifacts: string[]) => Promise) => UnpluginOptions; @@ -423,7 +423,10 @@ export function sentryUnpluginFactory({ "The component name annotate plugin is currently not supported by '@sentry/esbuild-plugin'" ); } else { - componentNameAnnotatePlugin && plugins.push(componentNameAnnotatePlugin()); + componentNameAnnotatePlugin && + plugins.push( + componentNameAnnotatePlugin(options.reactComponentAnnotation.ignoredComponents) + ); } } @@ -645,7 +648,7 @@ export function createRollupDebugIdUploadHooks( }; } -export function createComponentNameAnnotateHooks() { +export function createComponentNameAnnotateHooks(ignoredComponents?: string[]) { type ParserPlugins = NonNullable< NonNullable[1]>["parserOpts"] >["plugins"]; @@ -673,7 +676,7 @@ export function createComponentNameAnnotateHooks() { try { const result = await transformAsync(code, { - plugins: [[componentNameAnnotatePlugin]], + plugins: [[componentNameAnnotatePlugin, { ignoredComponents }]], filename: id, parserOpts: { sourceType: "module", @@ -700,7 +703,7 @@ export function createComponentNameAnnotateHooks() { } export function getDebugIdSnippet(debugId: string): string { - return `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();`; + return `;!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="${debugId}",e._sentryDebugIdIdentifier="sentry-dbid-${debugId}")}catch(e){}}();`; } export { stringToUUID, replaceBooleanFlagsInCode } from "./utils"; diff --git a/packages/bundler-plugin-core/src/plugins/release-management.ts b/packages/bundler-plugin-core/src/plugins/release-management.ts index b84999a7..e3f2cabf 100644 --- a/packages/bundler-plugin-core/src/plugins/release-management.ts +++ b/packages/bundler-plugin-core/src/plugins/release-management.ts @@ -31,6 +31,11 @@ interface ReleaseManagementPluginOptions { createDependencyOnSourcemapFiles: () => () => void; } +/** + * Creates a plugin that creates releases, sets commits, deploys and finalizes releases. + * + * Additionally, if legacy upload options are set, it uploads source maps in the legacy (non-debugId) way. + */ export function releaseManagementPlugin({ releaseName, include, @@ -47,7 +52,7 @@ export function releaseManagementPlugin({ }: ReleaseManagementPluginOptions): UnpluginOptions { const freeGlobalDependencyOnSourcemapFiles = createDependencyOnSourcemapFiles(); return { - name: "sentry-debug-id-upload-plugin", + name: "sentry-release-management-plugin", async writeBundle() { // It is possible that this writeBundle hook is called multiple times in one build (for example when reusing the plugin, or when using build tooling like `@vitejs/plugin-legacy`) // Therefore we need to actually register the execution of this hook as dependency on the sourcemap files. diff --git a/packages/bundler-plugin-core/src/types.ts b/packages/bundler-plugin-core/src/types.ts index c42e5b10..b6b5052e 100644 --- a/packages/bundler-plugin-core/src/types.ts +++ b/packages/bundler-plugin-core/src/types.ts @@ -319,6 +319,10 @@ export interface Options { * Whether the component name annotate plugin should be enabled or not. */ enabled?: boolean; + /** + * A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components. + */ + ignoredComponents?: string[]; }; /** diff --git a/packages/bundler-plugin-core/src/utils.ts b/packages/bundler-plugin-core/src/utils.ts index 3c8a92fa..6e7a09b4 100644 --- a/packages/bundler-plugin-core/src/utils.ts +++ b/packages/bundler-plugin-core/src/utils.ts @@ -259,6 +259,8 @@ export function determineReleaseName(): string | undefined { process.env["HEROKU_TEST_RUN_COMMIT_VERSION"] || // Heroku #2 https://docs.sentry.io/product/integrations/deployment/heroku/#configure-releases process.env["HEROKU_SLUG_COMMIT"] || + // Railway - https://docs.railway.app/reference/variables#git-variables + process.env["RAILWAY_GIT_COMMIT_SHA"] || // Render - https://render.com/docs/environment-variables process.env["RENDER_GIT_COMMIT"] || // Semaphore CI - https://docs.semaphoreci.com/ci-cd-environment/environment-variables @@ -318,9 +320,11 @@ export function generateGlobalInjectorCode({ window : typeof global !== 'undefined' ? global : - typeof self !== 'undefined' ? - self : - {}; + typeof globalThis !== 'undefined' ? + globalThis : + typeof self !== 'undefined' ? + self : + {}; _global.SENTRY_RELEASE={id:${JSON.stringify(release)}};`; @@ -345,6 +349,8 @@ export function generateModuleMetadataInjectorCode(metadata: any) { ? window : typeof global !== "undefined" ? global + : typeof globalThis !== "undefined" + ? globalThis : typeof self !== "undefined" ? self : {}; diff --git a/packages/bundler-plugin-core/test/index.test.ts b/packages/bundler-plugin-core/test/index.test.ts index 51d0fd57..71ad97bb 100644 --- a/packages/bundler-plugin-core/test/index.test.ts +++ b/packages/bundler-plugin-core/test/index.test.ts @@ -4,7 +4,7 @@ describe("getDebugIdSnippet", () => { it("returns the debugId injection snippet for a passed debugId", () => { const snippet = getDebugIdSnippet("1234"); expect(snippet).toMatchInlineSnapshot( - `";!function(){try{var e=\\"undefined\\"!=typeof window?window:\\"undefined\\"!=typeof global?global:\\"undefined\\"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]=\\"1234\\",e._sentryDebugIdIdentifier=\\"sentry-dbid-1234\\")}catch(e){}}();"` + `";!function(){try{var e=\\"undefined\\"!=typeof window?window:\\"undefined\\"!=typeof global?global:\\"undefined\\"!=typeof globalThis?globalThis:\\"undefined\\"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]=\\"1234\\",e._sentryDebugIdIdentifier=\\"sentry-dbid-1234\\")}catch(e){}}();"` ); }); }); diff --git a/packages/bundler-plugin-core/test/utils.test.ts b/packages/bundler-plugin-core/test/utils.test.ts index 3819e39c..b996a47c 100644 --- a/packages/bundler-plugin-core/test/utils.test.ts +++ b/packages/bundler-plugin-core/test/utils.test.ts @@ -226,6 +226,8 @@ describe("generateModuleMetadataInjectorCode", () => { ? window : typeof global !== \\"undefined\\" ? global + : typeof globalThis !== \\"undefined\\" + ? globalThis : typeof self !== \\"undefined\\" ? self : {}; @@ -259,6 +261,8 @@ describe("generateModuleMetadataInjectorCode", () => { ? window : typeof global !== \\"undefined\\" ? global + : typeof globalThis !== \\"undefined\\" + ? globalThis : typeof self !== \\"undefined\\" ? self : {}; diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0094f20b..698a38d5 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/dev-utils", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true, "files": [ diff --git a/packages/dev-utils/src/generate-documentation-table.ts b/packages/dev-utils/src/generate-documentation-table.ts index d13c8ac3..bd56e487 100644 --- a/packages/dev-utils/src/generate-documentation-table.ts +++ b/packages/dev-utils/src/generate-documentation-table.ts @@ -390,6 +390,13 @@ type IncludeEntry = { fullDescription: "Whether the component name annotate plugin should be enabled or not.", supportedBundlers: ["webpack", "vite", "rollup"], }, + { + name: "ignoredComponents", + type: "string[]", + fullDescription: + "A list of strings representing the names of components to ignore. The plugin will not perform apply `data-sentry` annotations on the DOM element for these components.", + supportedBundlers: ["webpack", "vite", "rollup"], + }, ], }, { diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 5862ce5d..c884a868 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/bundler-plugin-e2e-tests", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true, "scripts": { @@ -15,15 +15,15 @@ "lint": "eslint ." }, "dependencies": { - "@sentry/esbuild-plugin": "2.22.7", - "@sentry/rollup-plugin": "2.22.7", - "@sentry/vite-plugin": "2.22.7", - "@sentry/webpack-plugin": "2.22.7", + "@sentry/esbuild-plugin": "2.23.0", + "@sentry/rollup-plugin": "2.23.0", + "@sentry/vite-plugin": "2.23.0", + "@sentry/webpack-plugin": "2.23.0", "axios": "^1.1.3" }, "devDependencies": { - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/jest": "^0.2.21", "@types/axios": "^0.14.0", "@types/glob": "8.0.0", diff --git a/packages/esbuild-plugin/package.json b/packages/esbuild-plugin/package.json index bc8a0bad..7b2b1a8a 100644 --- a/packages/esbuild-plugin/package.json +++ b/packages/esbuild-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/esbuild-plugin", - "version": "2.22.7", + "version": "2.23.0", "description": "Official Sentry esbuild plugin", "repository": "git@github.com:getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/esbuild-plugin", @@ -48,7 +48,7 @@ "prepack": "ts-node ./src/prepack.ts" }, "dependencies": { - "@sentry/bundler-plugin-core": "2.22.7", + "@sentry/bundler-plugin-core": "2.23.0", "unplugin": "1.0.1", "uuid": "^9.0.0" }, @@ -58,8 +58,8 @@ "@babel/preset-typescript": "7.17.12", "@rollup/plugin-babel": "5.3.1", "@rollup/plugin-node-resolve": "13.3.0", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/core": "^1.2.205", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", diff --git a/packages/esbuild-plugin/test/public-api.test.ts b/packages/esbuild-plugin/test/public-api.test.ts index 0721ef7c..7cad2e0a 100644 --- a/packages/esbuild-plugin/test/public-api.test.ts +++ b/packages/esbuild-plugin/test/public-api.test.ts @@ -1,6 +1,20 @@ +import { EsbuildPlugin } from "unplugin"; import { sentryEsbuildPlugin } from "../src"; test("Esbuild plugin should exist", () => { expect(sentryEsbuildPlugin).toBeDefined(); expect(typeof sentryEsbuildPlugin).toBe("function"); }); + +describe("sentryEsbuildPlugin", () => { + it("returns an esbuild plugin", () => { + const plugins = sentryEsbuildPlugin({ + authToken: "test-token", + org: "test-org", + project: "test-project", + }) as EsbuildPlugin; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + expect(plugins).toEqual({ name: "unplugin-host-0", setup: expect.any(Function) }); + }); +}); diff --git a/packages/eslint-configs/package.json b/packages/eslint-configs/package.json index bbd7d625..27afaf0d 100644 --- a/packages/eslint-configs/package.json +++ b/packages/eslint-configs/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/eslint-config", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true, "peerDependencies": { diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 9c98fad1..09f01b21 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/integration-tests", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true, "scripts": { @@ -19,13 +19,13 @@ "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", - "@sentry/bundler-plugin-core": "2.22.7", - "@sentry/esbuild-plugin": "2.22.7", - "@sentry/rollup-plugin": "2.22.7", - "@sentry/vite-plugin": "2.22.7", - "@sentry/webpack-plugin": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", + "@sentry/bundler-plugin-core": "2.23.0", + "@sentry/esbuild-plugin": "2.23.0", + "@sentry/rollup-plugin": "2.23.0", + "@sentry/vite-plugin": "2.23.0", + "@sentry/webpack-plugin": "2.23.0", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", "@types/react": "^18.2.0", diff --git a/packages/playground/package.json b/packages/playground/package.json index 1c4968d6..c2c414ff 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/bundler-plugin-playground", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true, "scripts": { @@ -18,7 +18,7 @@ "start:proxyLogger": "ts-node scripts/request-logger-proxy.ts" }, "dependencies": { - "@sentry/bundler-plugin-core": "2.22.7", + "@sentry/bundler-plugin-core": "2.23.0", "@sentry/integrations": "7.50", "@sentry/node": "7.50", "@types/express": "^4.17.13", diff --git a/packages/rollup-plugin/package.json b/packages/rollup-plugin/package.json index 1de5a5a9..285fab69 100644 --- a/packages/rollup-plugin/package.json +++ b/packages/rollup-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/rollup-plugin", - "version": "2.22.7", + "version": "2.23.0", "description": "Official Sentry Rollup plugin", "repository": "git://github.com/getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/rollup-plugin", @@ -49,7 +49,7 @@ "prepack": "ts-node ./src/prepack.ts" }, "dependencies": { - "@sentry/bundler-plugin-core": "2.22.7", + "@sentry/bundler-plugin-core": "2.23.0", "unplugin": "1.0.1" }, "peerDependencies": { @@ -61,8 +61,8 @@ "@babel/preset-typescript": "7.17.12", "@rollup/plugin-babel": "5.3.1", "@rollup/plugin-node-resolve": "13.3.0", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/core": "^1.2.205", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index dbdd63b8..de29484f 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -18,10 +18,10 @@ function rollupReleaseInjectionPlugin(injectionCode: string): UnpluginOptions { }; } -function rollupComponentNameAnnotatePlugin(): UnpluginOptions { +function rollupComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions { return { name: "sentry-rollup-component-name-annotate-plugin", - rollup: createComponentNameAnnotateHooks(), + rollup: createComponentNameAnnotateHooks(ignoredComponents), }; } diff --git a/packages/rollup-plugin/test/public-api.test.ts b/packages/rollup-plugin/test/public-api.test.ts index 900e101e..c143ef91 100644 --- a/packages/rollup-plugin/test/public-api.test.ts +++ b/packages/rollup-plugin/test/public-api.test.ts @@ -1,6 +1,30 @@ +import { Plugin } from "rollup"; import { sentryRollupPlugin } from "../src"; test("Rollup plugin should exist", () => { expect(sentryRollupPlugin).toBeDefined(); expect(typeof sentryRollupPlugin).toBe("function"); }); + +describe("sentryRollupPlugin", () => { + it("returns an array of rollup plugins", () => { + const plugins = sentryRollupPlugin({ + authToken: "test-token", + org: "test-org", + project: "test-project", + }) as Plugin[]; + + expect(Array.isArray(plugins)).toBe(true); + + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toEqual([ + "sentry-telemetry-plugin", + "sentry-rollup-release-injection-plugin", + "sentry-release-management-plugin", + "sentry-rollup-debug-id-injection-plugin", + "sentry-rollup-debug-id-upload-plugin", + "sentry-file-deletion-plugin", + ]); + }); +}); diff --git a/packages/tsconfigs/package.json b/packages/tsconfigs/package.json index b102bd6f..58a992fc 100644 --- a/packages/tsconfigs/package.json +++ b/packages/tsconfigs/package.json @@ -1,6 +1,6 @@ { "name": "@sentry-internal/sentry-bundler-plugin-tsconfig", - "version": "2.22.7", + "version": "2.23.0", "license": "MIT", "private": true } diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json index 6bfe405f..7a04e23d 100644 --- a/packages/vite-plugin/package.json +++ b/packages/vite-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/vite-plugin", - "version": "2.22.7", + "version": "2.23.0", "description": "Official Sentry Vite plugin", "repository": "git://github.com/getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/vite-plugin", @@ -48,7 +48,7 @@ "prepack": "ts-node ./src/prepack.ts" }, "dependencies": { - "@sentry/bundler-plugin-core": "2.22.7", + "@sentry/bundler-plugin-core": "2.23.0", "unplugin": "1.0.1" }, "devDependencies": { @@ -57,8 +57,8 @@ "@babel/preset-typescript": "7.17.12", "@rollup/plugin-babel": "5.3.1", "@rollup/plugin-node-resolve": "13.3.0", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/core": "^1.2.205", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 9aa1ee34..11c77f00 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -21,11 +21,11 @@ function viteReleaseInjectionPlugin(injectionCode: string): UnpluginOptions { }; } -function viteComponentNameAnnotatePlugin(): UnpluginOptions { +function viteComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions { return { name: "sentry-vite-component-name-annotate-plugin", enforce: "pre" as const, - vite: createComponentNameAnnotateHooks(), + vite: createComponentNameAnnotateHooks(ignoredComponents), }; } diff --git a/packages/vite-plugin/test/public-api.test.ts b/packages/vite-plugin/test/public-api.test.ts index cfa848ac..a15fc336 100644 --- a/packages/vite-plugin/test/public-api.test.ts +++ b/packages/vite-plugin/test/public-api.test.ts @@ -1,6 +1,30 @@ +import { VitePlugin } from "unplugin"; import { sentryVitePlugin } from "../src"; test("Vite plugin should exist", () => { expect(sentryVitePlugin).toBeDefined(); expect(typeof sentryVitePlugin).toBe("function"); }); + +describe("sentryVitePlugin", () => { + it("returns an array of Vite plugins", () => { + const plugins = sentryVitePlugin({ + authToken: "test-token", + org: "test-org", + project: "test-project", + }) as VitePlugin[]; + + expect(Array.isArray(plugins)).toBe(true); + + const pluginNames = plugins.map((plugin) => plugin.name); + + expect(pluginNames).toEqual([ + "sentry-telemetry-plugin", + "sentry-vite-release-injection-plugin", + "sentry-release-management-plugin", + "sentry-vite-debug-id-injection-plugin", + "sentry-vite-debug-id-upload-plugin", + "sentry-file-deletion-plugin", + ]); + }); +}); diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 2b32d0b4..d28a31b5 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/webpack-plugin", - "version": "2.22.7", + "version": "2.23.0", "description": "Official Sentry Webpack plugin", "repository": "git://github.com/getsentry/sentry-javascript-bundler-plugins.git", "homepage": "https://github.com/getsentry/sentry-javascript-bundler-plugins/tree/main/packages/webpack-plugin", @@ -48,7 +48,7 @@ "prepack": "ts-node ./src/prepack.ts" }, "dependencies": { - "@sentry/bundler-plugin-core": "2.22.7", + "@sentry/bundler-plugin-core": "2.23.0", "unplugin": "1.0.1", "uuid": "^9.0.0" }, @@ -58,8 +58,8 @@ "@babel/preset-typescript": "7.17.12", "@rollup/plugin-babel": "5.3.1", "@rollup/plugin-commonjs": "22.0.1", - "@sentry-internal/eslint-config": "2.22.7", - "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.22.7", + "@sentry-internal/eslint-config": "2.23.0", + "@sentry-internal/sentry-bundler-plugin-tsconfig": "2.23.0", "@swc/core": "^1.2.205", "@swc/jest": "^0.2.21", "@types/jest": "^28.1.3", diff --git a/packages/webpack-plugin/src/index.ts b/packages/webpack-plugin/src/index.ts index 66790c34..f215630c 100644 --- a/packages/webpack-plugin/src/index.ts +++ b/packages/webpack-plugin/src/index.ts @@ -47,7 +47,7 @@ function webpackReleaseInjectionPlugin(injectionCode: string): UnpluginOptions { }; } -function webpackComponentNameAnnotatePlugin(): UnpluginOptions { +function webpackComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions { return { name: "sentry-webpack-component-name-annotate-plugin", enforce: "pre", @@ -55,7 +55,7 @@ function webpackComponentNameAnnotatePlugin(): UnpluginOptions { transformInclude(id) { return id.endsWith(".tsx") || id.endsWith(".jsx"); }, - transform: createComponentNameAnnotateHooks().transform, + transform: createComponentNameAnnotateHooks(ignoredComponents).transform, }; } diff --git a/packages/webpack-plugin/test/public-api.test.ts b/packages/webpack-plugin/test/public-api.test.ts index a27f454d..3340b2f1 100644 --- a/packages/webpack-plugin/test/public-api.test.ts +++ b/packages/webpack-plugin/test/public-api.test.ts @@ -1,6 +1,20 @@ +import { Plugin } from "webpack"; import { sentryWebpackPlugin } from "../src"; test("Webpack plugin should exist", () => { expect(sentryWebpackPlugin).toBeDefined(); expect(typeof sentryWebpackPlugin).toBe("function"); }); + +describe("sentryWebpackPlugin", () => { + it("returns a webpack plugin", () => { + const plugin = sentryWebpackPlugin({ + authToken: "test-token", + org: "test-org", + project: "test-project", + }) as Plugin; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + expect(plugin).toEqual({ apply: expect.any(Function) }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 474cfb66..90844ff8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3328,7 +3328,19 @@ "@types/source-list-map" "*" source-map "^0.7.3" -"@types/webpack4@npm:@types/webpack@^4", "@types/webpack@npm:@types/webpack@^4": +"@types/webpack4@npm:@types/webpack@^4": + version "4.41.33" + resolved "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz#16164845a5be6a306bcbe554a8e67f9cac215ffc" + integrity sha512-PPajH64Ft2vWevkerISMtnZ8rTs4YmRbs+23c402J0INmxDKCrhZNvwZYtzx96gY2wAtXdrK1BS2fiC8MlLr3g== + dependencies: + "@types/node" "*" + "@types/tapable" "^1" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + anymatch "^3.0.0" + source-map "^0.6.0" + +"@types/webpack@npm:@types/webpack@^4": version "4.41.33" resolved "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz#16164845a5be6a306bcbe554a8e67f9cac215ffc" integrity sha512-PPajH64Ft2vWevkerISMtnZ8rTs4YmRbs+23c402J0INmxDKCrhZNvwZYtzx96gY2wAtXdrK1BS2fiC8MlLr3g== @@ -9811,9 +9823,9 @@ nan@^2.12.1: integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + version "3.3.8" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== nanomatch@^1.2.9: version "1.2.13" @@ -12059,7 +12071,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12141,7 +12162,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13054,7 +13082,7 @@ webpack-virtual-modules@^0.5.0: resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== -"webpack4@npm:webpack@4.46.0", "webpack4@npm:webpack@^4", "webpack@npm:webpack@^4": +"webpack4@npm:webpack@4.46.0", "webpack4@npm:webpack@^4": version "4.46.0" resolved "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== @@ -13143,6 +13171,35 @@ webpack-virtual-modules@^0.5.0: watchpack "^2.4.0" webpack-sources "^3.2.3" +"webpack@npm:webpack@^4": + version "4.46.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" + integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/wasm-edit" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + acorn "^6.4.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" + enhanced-resolve "^4.5.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.3" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.3" + watchpack "^1.7.4" + webpack-sources "^1.4.1" + whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" @@ -13240,7 +13297,16 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==