1- const fs = require ( 'fs' )
2- const helperModuleImports = require ( '@babel/helper-module-imports' )
1+ import type { Node , PluginObj , PluginPass } from '@babel/core'
2+ import * as helperModuleImports from '@babel/helper-module-imports'
3+ import * as fs from 'node:fs'
4+
5+ type Babel = typeof import ( '@babel/core' )
36
47/**
5- * Converts an AST type into a javascript string so that it can be added to the error message lookup.
8+ * Represents the options for the {@linkcode mangleErrorsPlugin}.
9+ *
10+ * @internal
11+ */
12+ export interface MangleErrorsPluginOptions {
13+ /**
14+ * Whether to minify the error messages or not.
15+ * If `true`, the error messages will be replaced with an index
16+ * that maps object lookup.
17+ */
18+ minify : boolean
19+ }
20+
21+ /**
22+ * Converts an AST type into a JavaScript string so that it can be added to the error message lookup.
623 *
724 * Adapted from React (https://github.com/facebook/react/blob/master/scripts/shared/evalToString.js) with some
8- * adjustments
25+ * adjustments.
926 */
10- const evalToString = ast => {
27+ const evalToString = (
28+ ast : Node | { type : 'Literal' ; value : string }
29+ ) : string => {
1130 switch ( ast . type ) {
1231 case 'StringLiteral' :
1332 case 'Literal' : // ESLint
@@ -31,14 +50,14 @@ const evalToString = ast => {
3150}
3251
3352/**
34- * Takes a `throw new error ` statement and transforms it depending on the minify argument. Either option results in a
35- * smaller bundle size in production for consumers .
53+ * Transforms a `throw new Error ` statement based on the ` minify` argument, resulting in a smaller bundle size
54+ * for consumers in production.
3655 *
37- * If minify is enabled, we'll replace the error message with just an index that maps to an arrow object lookup.
56+ * If ` minify` is enabled, the error message will be replaced with an index that maps to an object lookup.
3857 *
39- * If minify is disabled, we'll add in a conditional statement to check the process.env.NODE_ENV which will output a
40- * an error number index in production or the actual error message in development. This allows consumers using webpack
41- * or another build tool to have these messages in development but have just the error index in production.
58+ * If ` minify` is disabled, a conditional statement will be added to check ` process.env.NODE_ENV`, which will output
59+ * an error number index in production or the actual error message in development. This allows consumers using Webpack
60+ * or another build tool to have these messages in development but only the error index in production.
4261 *
4362 * E.g.
4463 * Before:
@@ -49,30 +68,40 @@ const evalToString = ast => {
4968 * throw new Error(0);
5069 * throw new Error(1);
5170 *
52- * After: (without minify):
53- * throw new Error(node. process.NODE_ENV === 'production' ? 0 : "This is my error message.");
54- * throw new Error(node. process.NODE_ENV === 'production' ? 1 : "This is a second error message.");
71+ * After (without minify):
72+ * throw new Error(process.env .NODE_ENV === 'production' ? 0 : "This is my error message.");
73+ * throw new Error(process.env .NODE_ENV === 'production' ? 1 : "This is a second error message.");
5574 */
56- module . exports = babel => {
75+ export const mangleErrorsPlugin = (
76+ babel : Babel ,
77+ options : MangleErrorsPluginOptions
78+ ) : PluginObj < PluginPass & MangleErrorsPluginOptions > => {
5779 const t = babel . types
5880 // When the plugin starts up, we'll load in the existing file. This allows us to continually add to it so that the
5981 // indexes do not change between builds.
6082 let errorsFiles = ''
6183 if ( fs . existsSync ( 'errors.json' ) ) {
6284 errorsFiles = fs . readFileSync ( 'errors.json' ) . toString ( )
6385 }
64- let errors = Object . values ( JSON . parse ( errorsFiles || '{}' ) )
86+ const errors = Object . values ( JSON . parse ( errorsFiles || '{}' ) )
6587 // This variable allows us to skip writing back to the file if the errors array hasn't changed
6688 let changeInArray = false
6789
6890 return {
91+ name : 'mangle-errors-plugin' ,
6992 pre : ( ) => {
7093 changeInArray = false
7194 } ,
7295 visitor : {
73- ThrowStatement ( path , file ) {
96+ ThrowStatement ( path ) {
97+ if (
98+ ! ( 'arguments' in path . node . argument ) ||
99+ ! t . isNewExpression ( path . node . argument )
100+ ) {
101+ return
102+ }
74103 const args = path . node . argument . arguments
75- const minify = file . opts . minify
104+ const { minify } = options
76105
77106 if ( args && args [ 0 ] ) {
78107 // Skip running this logic when certain types come up:
@@ -82,11 +111,15 @@ module.exports = babel => {
82111 path . node . argument . arguments [ 0 ] . type === 'Identifier' ||
83112 path . node . argument . arguments [ 0 ] . type === 'NumericLiteral' ||
84113 path . node . argument . arguments [ 0 ] . type === 'ConditionalExpression' ||
85- path . node . argument . arguments [ 0 ] . type === 'CallExpression'
114+ path . node . argument . arguments [ 0 ] . type === 'CallExpression' ||
115+ ! t . isExpression ( path . node . argument . arguments [ 0 ] ) ||
116+ ! t . isIdentifier ( path . node . argument . callee )
86117 ) {
87118 return
88119 }
89120
121+ const errorName = path . node . argument . callee . name
122+
90123 const errorMsgLiteral = evalToString ( path . node . argument . arguments [ 0 ] )
91124
92125 if ( errorMsgLiteral . includes ( 'Super expression' ) ) {
@@ -106,7 +139,7 @@ module.exports = babel => {
106139 const formatProdErrorMessageIdentifier = helperModuleImports . addNamed (
107140 path ,
108141 'formatProdErrorMessage' ,
109- 'src /utils/formatProdErrorMessage' ,
142+ '@internal /utils/formatProdErrorMessage' ,
110143 { nameHint : 'formatProdErrorMessage' }
111144 )
112145
@@ -119,13 +152,13 @@ module.exports = babel => {
119152 if ( minify ) {
120153 path . replaceWith (
121154 t . throwStatement (
122- t . newExpression ( t . identifier ( 'Error' ) , [ prodMessage ] )
155+ t . newExpression ( t . identifier ( errorName ) , [ prodMessage ] )
123156 )
124157 )
125158 } else {
126159 path . replaceWith (
127160 t . throwStatement (
128- t . newExpression ( t . identifier ( 'Error' ) , [
161+ t . newExpression ( t . identifier ( errorName ) , [
129162 t . conditionalExpression (
130163 t . binaryExpression (
131164 '===' ,
@@ -150,3 +183,5 @@ module.exports = babel => {
150183 }
151184 }
152185}
186+
187+ export default mangleErrorsPlugin
0 commit comments