@wyw-in-js/transform 0.5.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/esm/cache.js +17 -0
  2. package/esm/cache.js.map +1 -1
  3. package/esm/plugins/dynamic-import.js +6 -1
  4. package/esm/plugins/dynamic-import.js.map +1 -1
  5. package/esm/plugins/preeval.js +1 -1
  6. package/esm/plugins/preeval.js.map +1 -1
  7. package/esm/transform/BaseEntrypoint.js +3 -1
  8. package/esm/transform/BaseEntrypoint.js.map +1 -1
  9. package/esm/transform/Entrypoint.js +3 -3
  10. package/esm/transform/Entrypoint.js.map +1 -1
  11. package/esm/transform/EvaluatedEntrypoint.js.map +1 -1
  12. package/esm/transform/generators/extract.js.map +1 -1
  13. package/esm/types.js.map +1 -1
  14. package/esm/utils/removeDangerousCode.js +113 -1
  15. package/esm/utils/removeDangerousCode.js.map +1 -1
  16. package/lib/cache.js +19 -0
  17. package/lib/cache.js.map +1 -1
  18. package/lib/plugins/dynamic-import.js +6 -1
  19. package/lib/plugins/dynamic-import.js.map +1 -1
  20. package/lib/plugins/preeval.js +1 -1
  21. package/lib/plugins/preeval.js.map +1 -1
  22. package/lib/transform/BaseEntrypoint.js +3 -1
  23. package/lib/transform/BaseEntrypoint.js.map +1 -1
  24. package/lib/transform/Entrypoint.js +3 -3
  25. package/lib/transform/Entrypoint.js.map +1 -1
  26. package/lib/transform/EvaluatedEntrypoint.js.map +1 -1
  27. package/lib/transform/generators/extract.js.map +1 -1
  28. package/lib/types.js.map +1 -1
  29. package/lib/utils/removeDangerousCode.js +114 -1
  30. package/lib/utils/removeDangerousCode.js.map +1 -1
  31. package/package.json +7 -7
  32. package/types/cache.d.ts +13 -7
  33. package/types/cache.js +19 -0
  34. package/types/plugins/dynamic-import.js +9 -1
  35. package/types/plugins/preeval.d.ts +1 -1
  36. package/types/plugins/preeval.js +1 -1
  37. package/types/transform/BaseEntrypoint.d.ts +3 -1
  38. package/types/transform/BaseEntrypoint.js +4 -1
  39. package/types/transform/Entrypoint.d.ts +1 -1
  40. package/types/transform/Entrypoint.js +3 -5
  41. package/types/transform/EvaluatedEntrypoint.d.ts +2 -0
  42. package/types/types.d.ts +1 -0
  43. package/types/utils/removeDangerousCode.d.ts +2 -1
  44. package/types/utils/removeDangerousCode.js +142 -1
@@ -4,10 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.removeDangerousCode = void 0;
7
+ var _core = require("@babel/core");
7
8
  var _findIdentifiers = require("./findIdentifiers");
8
9
  var _isUnnecessaryReactCall = require("./isUnnecessaryReactCall");
9
10
  var _scopeHelpers = require("./scopeHelpers");
10
11
  var _JSXElementsRemover = require("./visitors/JSXElementsRemover");
12
+ var _collectExportsAndImports = require("./collectExportsAndImports");
11
13
  const isGlobal = id => {
12
14
  if (!(0, _findIdentifiers.nonType)(id)) {
13
15
  return false;
@@ -37,7 +39,107 @@ const getPropertyName = path => {
37
39
  }
38
40
  return null;
39
41
  };
40
- const removeDangerousCode = programPath => {
42
+ const getImport = path => {
43
+ const programPath = path.findParent(p => p.isProgram());
44
+ if (!programPath) {
45
+ return undefined;
46
+ }
47
+ const {
48
+ imports
49
+ } = (0, _collectExportsAndImports.collectExportsAndImports)(programPath);
50
+ if (path.isIdentifier()) {
51
+ const binding = path.scope.getBinding(path.node.name);
52
+ const matched = binding && imports.find(imp => imp.imported !== 'side-effect' && binding.path.isAncestor(imp.local));
53
+ if (matched) {
54
+ return [matched.source, matched.imported];
55
+ }
56
+ }
57
+ if (path.isMemberExpression()) {
58
+ const leftPath = path.get('object');
59
+ if (!leftPath.isIdentifier()) {
60
+ // Nested member expression. Not supported yet.
61
+ return undefined;
62
+ }
63
+ const rightPath = path.get('property');
64
+ if (!rightPath.isIdentifier()) {
65
+ return undefined;
66
+ }
67
+ const binding = path.scope.getBinding(leftPath.node.name);
68
+ const matched = binding && imports.find(imp => imp.imported !== 'side-effect' && binding.path.isAncestor(imp.local));
69
+ if (matched) {
70
+ return [matched.source, rightPath.node.name];
71
+ }
72
+ }
73
+ return undefined;
74
+ };
75
+ const getTypeImport = path => {
76
+ // We are looking for either Identifier or TSQualifiedName in path
77
+ if (path.isIdentifier()) {
78
+ const binding = path.scope.getBinding(path.node.name);
79
+ if (!binding) {
80
+ return undefined;
81
+ }
82
+ if (!binding.path.isImportSpecifier() || !binding.path.parentPath.isImportDeclaration()) {
83
+ return undefined;
84
+ }
85
+ const importDeclaration = binding.path.parentPath;
86
+ const imported = binding.path.get('imported');
87
+ const source = importDeclaration.node.source.value;
88
+ const importedNode = imported.node;
89
+ return [source, _core.types.isIdentifier(importedNode) ? importedNode.name : importedNode.value];
90
+ }
91
+ if (path.isTSQualifiedName()) {
92
+ const leftPath = path.get('left');
93
+ if (!leftPath.isIdentifier()) {
94
+ // Nested type. Not supported yet.
95
+ return undefined;
96
+ }
97
+ const rightPath = path.get('right');
98
+ const binding = path.scope.getBinding(leftPath.node.name);
99
+ if (!binding) {
100
+ return undefined;
101
+ }
102
+ if (!binding.path.isImportDefaultSpecifier() && !binding.path.isImportNamespaceSpecifier() || !binding.path.parentPath.isImportDeclaration()) {
103
+ return undefined;
104
+ }
105
+ return [binding.path.parentPath.node.source.value, rightPath.node.name];
106
+ }
107
+ return undefined;
108
+ };
109
+ const isTypeMatch = (id, types) => {
110
+ const typeAnnotation = id.get('typeAnnotation');
111
+ if (!typeAnnotation.isTSTypeAnnotation()) {
112
+ return false;
113
+ }
114
+ const typeReference = typeAnnotation.get('typeAnnotation');
115
+ if (!typeReference.isTSTypeReference()) {
116
+ return false;
117
+ }
118
+ const typeName = typeReference.get('typeName');
119
+ const matchedImport = getTypeImport(typeName);
120
+ return matchedImport !== undefined && matchedImport[0] in types && types[matchedImport[0]].includes(matchedImport[1]);
121
+ };
122
+ const isHOC = (path, hocs) => {
123
+ let calleePath = path;
124
+ while (calleePath.isCallExpression()) {
125
+ calleePath = calleePath.get('callee');
126
+ }
127
+ const matchedImport = getImport(calleePath);
128
+ return matchedImport !== undefined && matchedImport[0] in hocs && hocs[matchedImport[0]].includes(matchedImport[1]);
129
+ };
130
+ const defaultPlaceholder = '...';
131
+ const defaultReactComponentTypes = ['ExoticComponent', 'FC', 'ForwardRefExoticComponent', 'FunctionComponent', 'LazyExoticComponent', 'MemoExoticComponent', 'NamedExoticComponent'];
132
+ const removeDangerousCode = (programPath, options) => {
133
+ var _options$hocs, _options$componentTyp;
134
+ const hocs = (_options$hocs = options === null || options === void 0 ? void 0 : options.hocs) !== null && _options$hocs !== void 0 ? _options$hocs : {};
135
+ const componentTypes = (_options$componentTyp = options === null || options === void 0 ? void 0 : options.componentTypes) !== null && _options$componentTyp !== void 0 ? _options$componentTyp : {
136
+ react: [defaultPlaceholder]
137
+ };
138
+ if (Array.isArray(componentTypes.react) && componentTypes.react.includes(defaultPlaceholder)) {
139
+ const idx = componentTypes.react.indexOf(defaultPlaceholder);
140
+ componentTypes.react = [...componentTypes.react];
141
+ componentTypes.react.splice(idx, 1, ...defaultReactComponentTypes);
142
+ }
41
143
  programPath.traverse({
42
144
  // JSX can be replaced with a dummy value,
43
145
  // but we have to do it after we processed template tags.
@@ -46,6 +148,9 @@ const removeDangerousCode = programPath => {
46
148
  if ((0, _isUnnecessaryReactCall.isUnnecessaryReactCall)(p)) {
47
149
  (0, _JSXElementsRemover.JSXElementsRemover)(p);
48
150
  }
151
+ if (isHOC(p, hocs)) {
152
+ (0, _scopeHelpers.applyAction)(['replace', p, _core.types.arrowFunctionExpression([], _core.types.nullLiteral())]);
153
+ }
49
154
  }
50
155
  },
51
156
  JSXElement: {
@@ -124,6 +229,14 @@ const removeDangerousCode = programPath => {
124
229
  type: 'StringLiteral',
125
230
  value: 'undefined'
126
231
  }]);
232
+ },
233
+ VariableDeclarator(p) {
234
+ const id = p.get('id');
235
+ const init = p.get('init');
236
+ if (id.isIdentifier() && isTypeMatch(id, componentTypes) && init.isExpression()) {
237
+ // Variable is typed as a React component. We can replace its value with a null-function.
238
+ (0, _scopeHelpers.applyAction)(['replace', init, _core.types.arrowFunctionExpression([], _core.types.nullLiteral())]);
239
+ }
127
240
  }
128
241
  }, {
129
242
  globals: [],
@@ -1 +1 @@
1
- {"version":3,"file":"removeDangerousCode.js","names":["_findIdentifiers","require","_isUnnecessaryReactCall","_scopeHelpers","_JSXElementsRemover","isGlobal","id","nonType","scope","name","node","hasBinding","hasGlobal","ssrCheckFields","Set","forbiddenGlobals","isBrowserGlobal","has","isSSRCheckField","getPropertyName","path","isIdentifier","isStringLiteral","value","removeDangerousCode","programPath","traverse","CallExpression","enter","p","isUnnecessaryReactCall","JSXElementsRemover","JSXElement","JSXFragment","MemberExpression","state","obj","get","prop","windowScoped","add","globals","filter","removeWithRelated","MetaProperty","Identifier","find","parent","isTSTypeReference","parentPath","isUnaryExpression","operator","isTSTypeQuery","isClassProperty","isMemberExpression","key","push","UnaryExpression","arg","applyAction","type","exports"],"sources":["../../src/utils/removeDangerousCode.ts"],"sourcesContent":["import type { NodePath } from '@babel/core';\nimport type { Identifier, Program } from '@babel/types';\n\nimport { nonType } from './findIdentifiers';\nimport { isUnnecessaryReactCall } from './isUnnecessaryReactCall';\nimport { applyAction, removeWithRelated } from './scopeHelpers';\nimport { JSXElementsRemover } from './visitors/JSXElementsRemover';\n\nconst isGlobal = (id: NodePath<Identifier>): boolean => {\n if (!nonType(id)) {\n return false;\n }\n\n const { scope } = id;\n const { name } = id.node;\n return !scope.hasBinding(name) && scope.hasGlobal(name);\n};\n\nconst ssrCheckFields = new Set([\n 'document',\n 'location',\n 'navigator',\n 'sessionStorage',\n 'localStorage',\n 'window',\n]);\n\nconst forbiddenGlobals = new Set([\n ...ssrCheckFields,\n '$RefreshReg$',\n 'XMLHttpRequest',\n 'clearImmediate',\n 'clearInterval',\n 'clearTimeout',\n 'fetch',\n 'navigator',\n 'setImmediate',\n 'setInterval',\n 'setTimeout',\n]);\n\nconst isBrowserGlobal = (id: NodePath<Identifier>) => {\n return forbiddenGlobals.has(id.node.name) && isGlobal(id);\n};\n\nconst isSSRCheckField = (id: NodePath<Identifier>) => {\n return ssrCheckFields.has(id.node.name) && isGlobal(id);\n};\n\nconst getPropertyName = (path: NodePath): string | null => {\n if (path.isIdentifier()) {\n return path.node.name;\n }\n\n if (path.isStringLiteral()) {\n return path.node.value;\n }\n\n return null;\n};\n\nexport const removeDangerousCode = (programPath: NodePath<Program>) => {\n programPath.traverse(\n {\n // JSX can be replaced with a dummy value,\n // but we have to do it after we processed template tags.\n CallExpression: {\n enter(p) {\n if (isUnnecessaryReactCall(p)) {\n JSXElementsRemover(p);\n }\n },\n },\n JSXElement: {\n enter: JSXElementsRemover,\n },\n JSXFragment: {\n enter: JSXElementsRemover,\n },\n MemberExpression(p, state) {\n const obj = p.get('object');\n const prop = p.get('property');\n if (!obj.isIdentifier({ name: 'window' })) {\n return;\n }\n\n const name = getPropertyName(prop);\n if (!name) {\n return;\n }\n\n state.windowScoped.add(name);\n // eslint-disable-next-line no-param-reassign\n state.globals = state.globals.filter((id) => {\n if (id.node.name === name) {\n removeWithRelated([id]);\n return false;\n }\n\n return true;\n });\n },\n MetaProperty(p) {\n // Remove all references to `import.meta`\n removeWithRelated([p]);\n },\n Identifier(p, state) {\n if (p.find((parent) => parent.isTSTypeReference())) {\n // don't mess with TS type references\n return;\n }\n if (isBrowserGlobal(p)) {\n if (\n p.find(\n (parentPath) =>\n parentPath.isUnaryExpression({ operator: 'typeof' }) ||\n parentPath.isTSTypeQuery()\n )\n ) {\n // Ignore `typeof window` expressions\n return;\n }\n\n if (p.parentPath.isClassProperty()) {\n // ignore class property decls\n return;\n }\n if (p.parentPath.isMemberExpression() && p.key === 'property') {\n // ignore e.g this.fetch()\n // window.fetch will be handled by the windowScoped block below\n return;\n }\n\n removeWithRelated([p]);\n\n return;\n }\n\n if (state.windowScoped.has(p.node.name)) {\n removeWithRelated([p]);\n } else if (isGlobal(p)) {\n state.globals.push(p);\n }\n },\n\n // Since we can use happy-dom, typical SSR checks may not work as expected.\n // We need to detect them and replace with an \"undefined\" literal.\n UnaryExpression(p) {\n if (p.node.operator !== 'typeof') {\n return;\n }\n const arg = p.get('argument');\n if (!arg.isIdentifier() || !isSSRCheckField(arg)) {\n return;\n }\n\n applyAction([\n 'replace',\n p,\n { type: 'StringLiteral', value: 'undefined' },\n ]);\n },\n },\n {\n globals: [] as NodePath<Identifier>[],\n windowScoped: new Set<string>(),\n }\n );\n};\n"],"mappings":";;;;;;AAGA,IAAAA,gBAAA,GAAAC,OAAA;AACA,IAAAC,uBAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAF,OAAA;AACA,IAAAG,mBAAA,GAAAH,OAAA;AAEA,MAAMI,QAAQ,GAAIC,EAAwB,IAAc;EACtD,IAAI,CAAC,IAAAC,wBAAO,EAACD,EAAE,CAAC,EAAE;IAChB,OAAO,KAAK;EACd;EAEA,MAAM;IAAEE;EAAM,CAAC,GAAGF,EAAE;EACpB,MAAM;IAAEG;EAAK,CAAC,GAAGH,EAAE,CAACI,IAAI;EACxB,OAAO,CAACF,KAAK,CAACG,UAAU,CAACF,IAAI,CAAC,IAAID,KAAK,CAACI,SAAS,CAACH,IAAI,CAAC;AACzD,CAAC;AAED,MAAMI,cAAc,GAAG,IAAIC,GAAG,CAAC,CAC7B,UAAU,EACV,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,QAAQ,CACT,CAAC;AAEF,MAAMC,gBAAgB,GAAG,IAAID,GAAG,CAAC,CAC/B,GAAGD,cAAc,EACjB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,OAAO,EACP,WAAW,EACX,cAAc,EACd,aAAa,EACb,YAAY,CACb,CAAC;AAEF,MAAMG,eAAe,GAAIV,EAAwB,IAAK;EACpD,OAAOS,gBAAgB,CAACE,GAAG,CAACX,EAAE,CAACI,IAAI,CAACD,IAAI,CAAC,IAAIJ,QAAQ,CAACC,EAAE,CAAC;AAC3D,CAAC;AAED,MAAMY,eAAe,GAAIZ,EAAwB,IAAK;EACpD,OAAOO,cAAc,CAACI,GAAG,CAACX,EAAE,CAACI,IAAI,CAACD,IAAI,CAAC,IAAIJ,QAAQ,CAACC,EAAE,CAAC;AACzD,CAAC;AAED,MAAMa,eAAe,GAAIC,IAAc,IAAoB;EACzD,IAAIA,IAAI,CAACC,YAAY,CAAC,CAAC,EAAE;IACvB,OAAOD,IAAI,CAACV,IAAI,CAACD,IAAI;EACvB;EAEA,IAAIW,IAAI,CAACE,eAAe,CAAC,CAAC,EAAE;IAC1B,OAAOF,IAAI,CAACV,IAAI,CAACa,KAAK;EACxB;EAEA,OAAO,IAAI;AACb,CAAC;AAEM,MAAMC,mBAAmB,GAAIC,WAA8B,IAAK;EACrEA,WAAW,CAACC,QAAQ,CAClB;IACE;IACA;IACAC,cAAc,EAAE;MACdC,KAAKA,CAACC,CAAC,EAAE;QACP,IAAI,IAAAC,8CAAsB,EAACD,CAAC,CAAC,EAAE;UAC7B,IAAAE,sCAAkB,EAACF,CAAC,CAAC;QACvB;MACF;IACF,CAAC;IACDG,UAAU,EAAE;MACVJ,KAAK,EAAEG;IACT,CAAC;IACDE,WAAW,EAAE;MACXL,KAAK,EAAEG;IACT,CAAC;IACDG,gBAAgBA,CAACL,CAAC,EAAEM,KAAK,EAAE;MACzB,MAAMC,GAAG,GAAGP,CAAC,CAACQ,GAAG,CAAC,QAAQ,CAAC;MAC3B,MAAMC,IAAI,GAAGT,CAAC,CAACQ,GAAG,CAAC,UAAU,CAAC;MAC9B,IAAI,CAACD,GAAG,CAACf,YAAY,CAAC;QAAEZ,IAAI,EAAE;MAAS,CAAC,CAAC,EAAE;QACzC;MACF;MAEA,MAAMA,IAAI,GAAGU,eAAe,CAACmB,IAAI,CAAC;MAClC,IAAI,CAAC7B,IAAI,EAAE;QACT;MACF;MAEA0B,KAAK,CAACI,YAAY,CAACC,GAAG,CAAC/B,IAAI,CAAC;MAC5B;MACA0B,KAAK,CAACM,OAAO,GAAGN,KAAK,CAACM,OAAO,CAACC,MAAM,CAAEpC,EAAE,IAAK;QAC3C,IAAIA,EAAE,CAACI,IAAI,CAACD,IAAI,KAAKA,IAAI,EAAE;UACzB,IAAAkC,+BAAiB,EAAC,CAACrC,EAAE,CAAC,CAAC;UACvB,OAAO,KAAK;QACd;QAEA,OAAO,IAAI;MACb,CAAC,CAAC;IACJ,CAAC;IACDsC,YAAYA,CAACf,CAAC,EAAE;MACd;MACA,IAAAc,+BAAiB,EAAC,CAACd,CAAC,CAAC,CAAC;IACxB,CAAC;IACDgB,UAAUA,CAAChB,CAAC,EAAEM,KAAK,EAAE;MACnB,IAAIN,CAAC,CAACiB,IAAI,CAAEC,MAAM,IAAKA,MAAM,CAACC,iBAAiB,CAAC,CAAC,CAAC,EAAE;QAClD;QACA;MACF;MACA,IAAIhC,eAAe,CAACa,CAAC,CAAC,EAAE;QACtB,IACEA,CAAC,CAACiB,IAAI,CACHG,UAAU,IACTA,UAAU,CAACC,iBAAiB,CAAC;UAAEC,QAAQ,EAAE;QAAS,CAAC,CAAC,IACpDF,UAAU,CAACG,aAAa,CAAC,CAC7B,CAAC,EACD;UACA;UACA;QACF;QAEA,IAAIvB,CAAC,CAACoB,UAAU,CAACI,eAAe,CAAC,CAAC,EAAE;UAClC;UACA;QACF;QACA,IAAIxB,CAAC,CAACoB,UAAU,CAACK,kBAAkB,CAAC,CAAC,IAAIzB,CAAC,CAAC0B,GAAG,KAAK,UAAU,EAAE;UAC7D;UACA;UACA;QACF;QAEA,IAAAZ,+BAAiB,EAAC,CAACd,CAAC,CAAC,CAAC;QAEtB;MACF;MAEA,IAAIM,KAAK,CAACI,YAAY,CAACtB,GAAG,CAACY,CAAC,CAACnB,IAAI,CAACD,IAAI,CAAC,EAAE;QACvC,IAAAkC,+BAAiB,EAAC,CAACd,CAAC,CAAC,CAAC;MACxB,CAAC,MAAM,IAAIxB,QAAQ,CAACwB,CAAC,CAAC,EAAE;QACtBM,KAAK,CAACM,OAAO,CAACe,IAAI,CAAC3B,CAAC,CAAC;MACvB;IACF,CAAC;IAED;IACA;IACA4B,eAAeA,CAAC5B,CAAC,EAAE;MACjB,IAAIA,CAAC,CAACnB,IAAI,CAACyC,QAAQ,KAAK,QAAQ,EAAE;QAChC;MACF;MACA,MAAMO,GAAG,GAAG7B,CAAC,CAACQ,GAAG,CAAC,UAAU,CAAC;MAC7B,IAAI,CAACqB,GAAG,CAACrC,YAAY,CAAC,CAAC,IAAI,CAACH,eAAe,CAACwC,GAAG,CAAC,EAAE;QAChD;MACF;MAEA,IAAAC,yBAAW,EAAC,CACV,SAAS,EACT9B,CAAC,EACD;QAAE+B,IAAI,EAAE,eAAe;QAAErC,KAAK,EAAE;MAAY,CAAC,CAC9C,CAAC;IACJ;EACF,CAAC,EACD;IACEkB,OAAO,EAAE,EAA4B;IACrCF,YAAY,EAAE,IAAIzB,GAAG,CAAS;EAChC,CACF,CAAC;AACH,CAAC;AAAC+C,OAAA,CAAArC,mBAAA,GAAAA,mBAAA"}
1
+ {"version":3,"file":"removeDangerousCode.js","names":["_core","require","_findIdentifiers","_isUnnecessaryReactCall","_scopeHelpers","_JSXElementsRemover","_collectExportsAndImports","isGlobal","id","nonType","scope","name","node","hasBinding","hasGlobal","ssrCheckFields","Set","forbiddenGlobals","isBrowserGlobal","has","isSSRCheckField","getPropertyName","path","isIdentifier","isStringLiteral","value","getImport","programPath","findParent","p","isProgram","undefined","imports","collectExportsAndImports","binding","getBinding","matched","find","imp","imported","isAncestor","local","source","isMemberExpression","leftPath","get","rightPath","getTypeImport","isImportSpecifier","parentPath","isImportDeclaration","importDeclaration","importedNode","t","isTSQualifiedName","isImportDefaultSpecifier","isImportNamespaceSpecifier","isTypeMatch","types","typeAnnotation","isTSTypeAnnotation","typeReference","isTSTypeReference","typeName","matchedImport","includes","isHOC","hocs","calleePath","isCallExpression","defaultPlaceholder","defaultReactComponentTypes","removeDangerousCode","options","_options$hocs","_options$componentTyp","componentTypes","react","Array","isArray","idx","indexOf","splice","traverse","CallExpression","enter","isUnnecessaryReactCall","JSXElementsRemover","applyAction","arrowFunctionExpression","nullLiteral","JSXElement","JSXFragment","MemberExpression","state","obj","prop","windowScoped","add","globals","filter","removeWithRelated","MetaProperty","Identifier","parent","isUnaryExpression","operator","isTSTypeQuery","isClassProperty","key","push","UnaryExpression","arg","type","VariableDeclarator","init","isExpression","exports"],"sources":["../../src/utils/removeDangerousCode.ts"],"sourcesContent":["import type { NodePath } from '@babel/core';\nimport { types as t } from '@babel/core';\nimport type {\n CallExpression,\n Expression,\n Identifier,\n Program,\n V8IntrinsicIdentifier,\n} from '@babel/types';\n\nimport type { CodeRemoverOptions } from '@wyw-in-js/shared';\nimport { nonType } from './findIdentifiers';\nimport { isUnnecessaryReactCall } from './isUnnecessaryReactCall';\nimport { applyAction, removeWithRelated } from './scopeHelpers';\nimport { JSXElementsRemover } from './visitors/JSXElementsRemover';\nimport type { IImport } from './collectExportsAndImports';\nimport { collectExportsAndImports } from './collectExportsAndImports';\n\nconst isGlobal = (id: NodePath<Identifier>): boolean => {\n if (!nonType(id)) {\n return false;\n }\n\n const { scope } = id;\n const { name } = id.node;\n return !scope.hasBinding(name) && scope.hasGlobal(name);\n};\n\nconst ssrCheckFields = new Set([\n 'document',\n 'location',\n 'navigator',\n 'sessionStorage',\n 'localStorage',\n 'window',\n]);\n\nconst forbiddenGlobals = new Set([\n ...ssrCheckFields,\n '$RefreshReg$',\n 'XMLHttpRequest',\n 'clearImmediate',\n 'clearInterval',\n 'clearTimeout',\n 'fetch',\n 'navigator',\n 'setImmediate',\n 'setInterval',\n 'setTimeout',\n]);\n\nconst isBrowserGlobal = (id: NodePath<Identifier>) => {\n return forbiddenGlobals.has(id.node.name) && isGlobal(id);\n};\n\nconst isSSRCheckField = (id: NodePath<Identifier>) => {\n return ssrCheckFields.has(id.node.name) && isGlobal(id);\n};\n\nconst getPropertyName = (path: NodePath): string | null => {\n if (path.isIdentifier()) {\n return path.node.name;\n }\n\n if (path.isStringLiteral()) {\n return path.node.value;\n }\n\n return null;\n};\n\nconst getImport = (path: NodePath): [string, string] | undefined => {\n const programPath = path.findParent((p) => p.isProgram()) as\n | NodePath<Program>\n | undefined;\n if (!programPath) {\n return undefined;\n }\n\n const { imports } = collectExportsAndImports(programPath);\n\n if (path.isIdentifier()) {\n const binding = path.scope.getBinding(path.node.name);\n const matched =\n binding &&\n imports.find(\n (imp): imp is IImport =>\n imp.imported !== 'side-effect' && binding.path.isAncestor(imp.local)\n );\n\n if (matched) {\n return [matched.source, matched.imported];\n }\n }\n\n if (path.isMemberExpression()) {\n const leftPath = path.get('object');\n if (!leftPath.isIdentifier()) {\n // Nested member expression. Not supported yet.\n return undefined;\n }\n\n const rightPath = path.get('property');\n if (!rightPath.isIdentifier()) {\n return undefined;\n }\n\n const binding = path.scope.getBinding(leftPath.node.name);\n const matched =\n binding &&\n imports.find(\n (imp): imp is IImport =>\n imp.imported !== 'side-effect' && binding.path.isAncestor(imp.local)\n );\n\n if (matched) {\n return [matched.source, rightPath.node.name];\n }\n }\n\n return undefined;\n};\n\nconst getTypeImport = (path: NodePath): [string, string] | undefined => {\n // We are looking for either Identifier or TSQualifiedName in path\n if (path.isIdentifier()) {\n const binding = path.scope.getBinding(path.node.name);\n if (!binding) {\n return undefined;\n }\n\n if (\n !binding.path.isImportSpecifier() ||\n !binding.path.parentPath.isImportDeclaration()\n ) {\n return undefined;\n }\n\n const importDeclaration = binding.path.parentPath;\n const imported = binding.path.get('imported');\n const source = importDeclaration.node.source.value;\n const importedNode = imported.node;\n return [\n source,\n t.isIdentifier(importedNode) ? importedNode.name : importedNode.value,\n ];\n }\n\n if (path.isTSQualifiedName()) {\n const leftPath = path.get('left');\n if (!leftPath.isIdentifier()) {\n // Nested type. Not supported yet.\n return undefined;\n }\n\n const rightPath = path.get('right');\n\n const binding = path.scope.getBinding(leftPath.node.name);\n if (!binding) {\n return undefined;\n }\n\n if (\n (!binding.path.isImportDefaultSpecifier() &&\n !binding.path.isImportNamespaceSpecifier()) ||\n !binding.path.parentPath.isImportDeclaration()\n ) {\n return undefined;\n }\n\n return [binding.path.parentPath.node.source.value, rightPath.node.name];\n }\n\n return undefined;\n};\n\nconst isTypeMatch = (\n id: NodePath<Identifier>,\n types: Record<string, string[]>\n): boolean => {\n const typeAnnotation = id.get('typeAnnotation');\n if (!typeAnnotation.isTSTypeAnnotation()) {\n return false;\n }\n\n const typeReference = typeAnnotation.get('typeAnnotation');\n if (!typeReference.isTSTypeReference()) {\n return false;\n }\n\n const typeName = typeReference.get('typeName');\n const matchedImport = getTypeImport(typeName);\n return (\n matchedImport !== undefined &&\n matchedImport[0] in types &&\n types[matchedImport[0]].includes(matchedImport[1])\n );\n};\n\nconst isHOC = (\n path: NodePath<CallExpression>,\n hocs: Record<string, string[]>\n) => {\n let calleePath: NodePath<V8IntrinsicIdentifier | Expression> = path;\n while (calleePath.isCallExpression()) {\n calleePath = calleePath.get('callee');\n }\n\n const matchedImport = getImport(calleePath);\n return (\n matchedImport !== undefined &&\n matchedImport[0] in hocs &&\n hocs[matchedImport[0]].includes(matchedImport[1])\n );\n};\n\nconst defaultPlaceholder = '...';\n\nconst defaultReactComponentTypes = [\n 'ExoticComponent',\n 'FC',\n 'ForwardRefExoticComponent',\n 'FunctionComponent',\n 'LazyExoticComponent',\n 'MemoExoticComponent',\n 'NamedExoticComponent',\n];\n\nexport const removeDangerousCode = (\n programPath: NodePath<Program>,\n options?: CodeRemoverOptions\n) => {\n const hocs = options?.hocs ?? {};\n\n const componentTypes = options?.componentTypes ?? {\n react: [defaultPlaceholder],\n };\n\n if (\n Array.isArray(componentTypes.react) &&\n componentTypes.react.includes(defaultPlaceholder)\n ) {\n const idx = componentTypes.react.indexOf(defaultPlaceholder);\n componentTypes.react = [...componentTypes.react];\n componentTypes.react.splice(idx, 1, ...defaultReactComponentTypes);\n }\n\n programPath.traverse(\n {\n // JSX can be replaced with a dummy value,\n // but we have to do it after we processed template tags.\n CallExpression: {\n enter(p) {\n if (isUnnecessaryReactCall(p)) {\n JSXElementsRemover(p);\n }\n\n if (isHOC(p, hocs)) {\n applyAction([\n 'replace',\n p,\n t.arrowFunctionExpression([], t.nullLiteral()),\n ]);\n }\n },\n },\n JSXElement: {\n enter: JSXElementsRemover,\n },\n JSXFragment: {\n enter: JSXElementsRemover,\n },\n MemberExpression(p, state) {\n const obj = p.get('object');\n const prop = p.get('property');\n if (!obj.isIdentifier({ name: 'window' })) {\n return;\n }\n\n const name = getPropertyName(prop);\n if (!name) {\n return;\n }\n\n state.windowScoped.add(name);\n // eslint-disable-next-line no-param-reassign\n state.globals = state.globals.filter((id) => {\n if (id.node.name === name) {\n removeWithRelated([id]);\n return false;\n }\n\n return true;\n });\n },\n MetaProperty(p) {\n // Remove all references to `import.meta`\n removeWithRelated([p]);\n },\n Identifier(p, state) {\n if (p.find((parent) => parent.isTSTypeReference())) {\n // don't mess with TS type references\n return;\n }\n if (isBrowserGlobal(p)) {\n if (\n p.find(\n (parentPath) =>\n parentPath.isUnaryExpression({ operator: 'typeof' }) ||\n parentPath.isTSTypeQuery()\n )\n ) {\n // Ignore `typeof window` expressions\n return;\n }\n\n if (p.parentPath.isClassProperty()) {\n // ignore class property decls\n return;\n }\n if (p.parentPath.isMemberExpression() && p.key === 'property') {\n // ignore e.g this.fetch()\n // window.fetch will be handled by the windowScoped block below\n return;\n }\n\n removeWithRelated([p]);\n\n return;\n }\n\n if (state.windowScoped.has(p.node.name)) {\n removeWithRelated([p]);\n } else if (isGlobal(p)) {\n state.globals.push(p);\n }\n },\n\n // Since we can use happy-dom, typical SSR checks may not work as expected.\n // We need to detect them and replace with an \"undefined\" literal.\n UnaryExpression(p) {\n if (p.node.operator !== 'typeof') {\n return;\n }\n const arg = p.get('argument');\n if (!arg.isIdentifier() || !isSSRCheckField(arg)) {\n return;\n }\n\n applyAction([\n 'replace',\n p,\n { type: 'StringLiteral', value: 'undefined' },\n ]);\n },\n VariableDeclarator(p) {\n const id = p.get('id');\n const init = p.get('init');\n if (\n id.isIdentifier() &&\n isTypeMatch(id, componentTypes) &&\n init.isExpression()\n ) {\n // Variable is typed as a React component. We can replace its value with a null-function.\n applyAction([\n 'replace',\n init,\n t.arrowFunctionExpression([], t.nullLiteral()),\n ]);\n }\n },\n },\n {\n globals: [] as NodePath<Identifier>[],\n windowScoped: new Set<string>(),\n }\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyw-in-js/transform",
3
- "version": "0.5.5",
3
+ "version": "0.7.0",
4
4
  "dependencies": {
5
5
  "@babel/core": "^7.23.5",
6
6
  "@babel/generator": "^7.23.5",
@@ -15,8 +15,8 @@
15
15
  "source-map": "^0.7.4",
16
16
  "stylis": "^4.3.0",
17
17
  "ts-invariant": "^0.10.3",
18
- "@wyw-in-js/processor-utils": "0.5.5",
19
- "@wyw-in-js/shared": "0.5.5"
18
+ "@wyw-in-js/processor-utils": "0.7.0",
19
+ "@wyw-in-js/shared": "0.7.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@babel/plugin-syntax-typescript": "^7.23.3",
@@ -37,10 +37,10 @@
37
37
  "glob": "^10.3.10",
38
38
  "strip-ansi": "^5.2.0",
39
39
  "typescript": "^5.2.2",
40
- "@wyw-in-js/babel-config": "0.5.5",
41
- "@wyw-in-js/eslint-config": "0.5.5",
42
- "@wyw-in-js/jest-preset": "0.5.5",
43
- "@wyw-in-js/ts-config": "0.5.5"
40
+ "@wyw-in-js/babel-config": "0.7.0",
41
+ "@wyw-in-js/eslint-config": "0.7.0",
42
+ "@wyw-in-js/jest-preset": "0.7.0",
43
+ "@wyw-in-js/ts-config": "0.7.0"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=16.0.0"
package/types/cache.d.ts CHANGED
@@ -1,21 +1,27 @@
1
1
  import type { Entrypoint } from './transform/Entrypoint';
2
2
  import type { IEvaluatedEntrypoint } from './transform/EvaluatedEntrypoint';
3
- interface ICaches {
4
- entrypoints: Map<string, Entrypoint | IEvaluatedEntrypoint>;
3
+ interface IBaseCachedEntrypoint {
4
+ dependencies: Map<string, {
5
+ resolved: string | null;
6
+ }>;
7
+ initialCode?: string;
8
+ }
9
+ interface ICaches<TEntrypoint extends IBaseCachedEntrypoint> {
10
+ entrypoints: Map<string, TEntrypoint>;
5
11
  exports: Map<string, string[]>;
6
12
  }
7
13
  type MapValue<T> = T extends Map<string, infer V> ? V : never;
8
14
  declare const cacheNames: readonly ["entrypoints", "exports"];
9
15
  type CacheNames = (typeof cacheNames)[number];
10
- export declare class TransformCacheCollection {
11
- readonly entrypoints: Map<string, Entrypoint | IEvaluatedEntrypoint>;
16
+ export declare class TransformCacheCollection<TEntrypoint extends IBaseCachedEntrypoint = Entrypoint | IEvaluatedEntrypoint> {
17
+ readonly entrypoints: Map<string, TEntrypoint>;
12
18
  readonly exports: Map<string, string[]>;
13
19
  private contentHashes;
14
- constructor(caches?: Partial<ICaches>);
15
- add<TCache extends CacheNames, TValue extends MapValue<ICaches[TCache]>>(cacheName: TCache, key: string, value: TValue): void;
20
+ constructor(caches?: Partial<ICaches<TEntrypoint>>);
21
+ add<TCache extends CacheNames, TValue extends MapValue<ICaches<TEntrypoint>[TCache]>>(cacheName: TCache, key: string, value: TValue): void;
16
22
  clear(cacheName: CacheNames | 'all'): void;
17
23
  delete(cacheName: CacheNames, key: string): void;
18
- get<TCache extends CacheNames, TValue extends MapValue<ICaches[TCache]>>(cacheName: TCache, key: string): TValue | undefined;
24
+ get<TCache extends CacheNames, TValue extends MapValue<ICaches<TEntrypoint>[TCache]>>(cacheName: TCache, key: string): TValue | undefined;
19
25
  has(cacheName: CacheNames, key: string): boolean;
20
26
  invalidate(cacheName: CacheNames, key: string): void;
21
27
  invalidateForFile(filename: string): void;
package/types/cache.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.TransformCacheCollection = void 0;
4
7
  const crypto_1 = require("crypto");
8
+ const node_fs_1 = __importDefault(require("node:fs"));
5
9
  const shared_1 = require("@wyw-in-js/shared");
6
10
  const getFileIdx_1 = require("./utils/getFileIdx");
7
11
  function hashContent(content) {
@@ -30,6 +34,9 @@ class TransformCacheCollection {
30
34
  return cache.get(key) === value ? 'unchanged' : 'updated';
31
35
  });
32
36
  cache.set(key, value);
37
+ if ('initialCode' in value) {
38
+ this.contentHashes.set(key, hashContent(value.initialCode ?? ''));
39
+ }
33
40
  }
34
41
  clear(cacheName) {
35
42
  if (cacheName === 'all') {
@@ -71,6 +78,18 @@ class TransformCacheCollection {
71
78
  });
72
79
  }
73
80
  invalidateIfChanged(filename, content) {
81
+ const fileEntrypoint = this.get('entrypoints', filename);
82
+ // We need to check all dependencies of the file
83
+ // because they might have changed as well.
84
+ if (fileEntrypoint) {
85
+ for (const [, dependency] of fileEntrypoint.dependencies) {
86
+ const dependencyFilename = dependency.resolved;
87
+ if (dependencyFilename) {
88
+ const dependencyContent = node_fs_1.default.readFileSync(dependencyFilename, 'utf8');
89
+ this.invalidateIfChanged(dependencyFilename, dependencyContent);
90
+ }
91
+ }
92
+ }
74
93
  const hash = this.contentHashes.get(filename);
75
94
  const newHash = hashContent(content);
76
95
  if (hash !== newHash) {
@@ -23,7 +23,15 @@ function dynamicImport(babel) {
23
23
  ]));
24
24
  return;
25
25
  }
26
- throw new Error('Dynamic import argument must be a string or a template literal');
26
+ // Throw an error if this import will be reached during evaluation
27
+ // throw new Error(
28
+ // 'Dynamic import argument must be a string or a template literal'
29
+ // );
30
+ path.replaceWith(t.callExpression(t.arrowFunctionExpression([], t.blockStatement([
31
+ t.throwStatement(t.newExpression(t.identifier('Error'), [
32
+ t.stringLiteral('Dynamic import argument must be a string or a template literal'),
33
+ ])),
34
+ ])), []));
27
35
  }
28
36
  },
29
37
  },
@@ -7,7 +7,7 @@ import type { StrictOptions } from '@wyw-in-js/shared';
7
7
  import type { Core } from '../babel';
8
8
  import type { IPluginState } from '../types';
9
9
  import { EventEmitter } from '../utils/EventEmitter';
10
- export type PreevalOptions = Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'extensions' | 'evaluate' | 'features' | 'tagResolver'> & {
10
+ export type PreevalOptions = Pick<StrictOptions, 'classNameSlug' | 'codeRemover' | 'displayName' | 'extensions' | 'evaluate' | 'features' | 'tagResolver'> & {
11
11
  eventEmitter?: EventEmitter;
12
12
  };
13
13
  export declare function preeval(babel: Core, options: PreevalOptions): PluginObj<IPluginState & {
@@ -32,7 +32,7 @@ function preeval(babel, options) {
32
32
  });
33
33
  if ((0, shared_1.isFeatureEnabled)(options.features, 'dangerousCodeRemover', filename)) {
34
34
  log('start', 'Strip all JSX and browser related stuff');
35
- eventEmitter.perf('transform:preeval:removeDangerousCode', () => (0, removeDangerousCode_1.removeDangerousCode)(file.path));
35
+ eventEmitter.perf('transform:preeval:removeDangerousCode', () => (0, removeDangerousCode_1.removeDangerousCode)(file.path, options.codeRemover));
36
36
  }
37
37
  },
38
38
  visitor: {},
@@ -2,6 +2,7 @@
2
2
  import type { Debugger } from '@wyw-in-js/shared';
3
3
  import type { ParentEntrypoint } from '../types';
4
4
  import type { Services } from './types';
5
+ import type { IEntrypointDependency } from './Entrypoint.types';
5
6
  export declare const createExports: (log: Debugger) => Record<string | symbol, unknown>;
6
7
  export declare abstract class BaseEntrypoint {
7
8
  #private;
@@ -11,11 +12,12 @@ export declare abstract class BaseEntrypoint {
11
12
  readonly name: string;
12
13
  readonly only: string[];
13
14
  readonly parents: ParentEntrypoint[];
15
+ readonly dependencies: Map<string, IEntrypointDependency>;
14
16
  static createExports: (log: Debugger) => Record<string | symbol, unknown>;
15
17
  readonly idx: string;
16
18
  readonly log: Debugger;
17
19
  readonly seqId: number;
18
- protected constructor(services: Services, evaluatedOnly: string[], exports: Record<string | symbol, unknown> | undefined, generation: number, name: string, only: string[], parents: ParentEntrypoint[]);
20
+ protected constructor(services: Services, evaluatedOnly: string[], exports: Record<string | symbol, unknown> | undefined, generation: number, name: string, only: string[], parents: ParentEntrypoint[], dependencies: Map<string, IEntrypointDependency>);
19
21
  get exports(): Record<string | symbol, unknown>;
20
22
  set exports(value: unknown);
21
23
  get ref(): string;
@@ -115,22 +115,25 @@ class BaseEntrypoint {
115
115
  name;
116
116
  only;
117
117
  parents;
118
+ dependencies;
118
119
  static createExports = exports.createExports;
119
120
  idx;
120
121
  log;
121
122
  // eslint-disable-next-line no-plusplus
122
123
  seqId = entrypointSeqId++;
123
124
  #exports;
124
- constructor(services, evaluatedOnly, exports, generation, name, only, parents) {
125
+ constructor(services, evaluatedOnly, exports, generation, name, only, parents, dependencies) {
125
126
  this.services = services;
126
127
  this.evaluatedOnly = evaluatedOnly;
127
128
  this.generation = generation;
128
129
  this.name = name;
129
130
  this.only = only;
130
131
  this.parents = parents;
132
+ this.dependencies = dependencies;
131
133
  this.idx = (0, getFileIdx_1.getFileIdx)(name);
132
134
  this.log =
133
135
  parents[0]?.log.extend(this.ref, '->') ?? services.log.extend(this.ref);
136
+ this.dependencies = dependencies;
134
137
  let isExportsInherited = false;
135
138
  if (exports) {
136
139
  if (isProxy(exports)) {
@@ -9,7 +9,7 @@ export declare class Entrypoint extends BaseEntrypoint {
9
9
  #private;
10
10
  readonly initialCode: string | undefined;
11
11
  protected readonly resolveTasks: Map<string, Promise<IEntrypointDependency>>;
12
- protected readonly dependencies: Map<string, IEntrypointDependency>;
12
+ readonly dependencies: Map<string, IEntrypointDependency>;
13
13
  readonly evaluated = false;
14
14
  readonly loadedAndParsed: IEntrypointCode | IIgnoredEntrypoint;
15
15
  protected onSupersedeHandlers: Array<(newEntrypoint: Entrypoint) => void>;
@@ -33,7 +33,7 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
33
33
  #supersededWith = null;
34
34
  #transformResultCode = null;
35
35
  constructor(services, parents, initialCode, name, only, exports, evaluatedOnly, loadedAndParsed, resolveTasks = new Map(), dependencies = new Map(), generation = 1) {
36
- super(services, evaluatedOnly, exports, generation, name, only, parents);
36
+ super(services, evaluatedOnly, exports, generation, name, only, parents, dependencies);
37
37
  this.initialCode = initialCode;
38
38
  this.resolveTasks = resolveTasks;
39
39
  this.dependencies = dependencies;
@@ -106,9 +106,7 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
106
106
  }
107
107
  const exports = cached?.exports;
108
108
  const evaluatedOnly = cached?.evaluatedOnly ?? [];
109
- const mergedOnly = !changed && cached?.only
110
- ? (0, Entrypoint_helpers_1.mergeOnly)(cached.only, only).filter((i) => !evaluatedOnly.includes(i))
111
- : only;
109
+ const mergedOnly = cached?.only ? (0, Entrypoint_helpers_1.mergeOnly)(cached.only, only) : only;
112
110
  if (cached?.evaluated) {
113
111
  cached.log('is already evaluated with', cached.evaluatedOnly);
114
112
  }
@@ -177,7 +175,7 @@ class Entrypoint extends BaseEntrypoint_1.BaseEntrypoint {
177
175
  createEvaluated() {
178
176
  const evaluatedOnly = (0, Entrypoint_helpers_1.mergeOnly)(this.evaluatedOnly, this.only);
179
177
  this.log('create EvaluatedEntrypoint for %o', evaluatedOnly);
180
- return new EvaluatedEntrypoint_1.EvaluatedEntrypoint(this.services, evaluatedOnly, this.exportsProxy, this.generation + 1, this.name, this.only, this.parents);
178
+ return new EvaluatedEntrypoint_1.EvaluatedEntrypoint(this.services, evaluatedOnly, this.exportsProxy, this.generation + 1, this.name, this.only, this.parents, this.dependencies);
181
179
  }
182
180
  getDependency(name) {
183
181
  return this.dependencies.get(name);
@@ -1,7 +1,9 @@
1
1
  /// <reference types="debug" />
2
2
  import type { Debugger } from '@wyw-in-js/shared';
3
3
  import { BaseEntrypoint } from './BaseEntrypoint';
4
+ import type { IEntrypointDependency } from './Entrypoint.types';
4
5
  export interface IEvaluatedEntrypoint {
6
+ dependencies: Map<string, IEntrypointDependency>;
5
7
  evaluated: true;
6
8
  evaluatedOnly: string[];
7
9
  exports: Record<string | symbol, unknown>;
package/types/types.d.ts CHANGED
@@ -46,6 +46,7 @@ export type Options = {
46
46
  inputSourceMap?: RawSourceMap;
47
47
  outputFilename?: string;
48
48
  pluginOptions?: Partial<PluginOptions>;
49
+ prefixer?: boolean;
49
50
  preprocessor?: Preprocessor;
50
51
  root?: string;
51
52
  };
@@ -1,3 +1,4 @@
1
1
  import type { NodePath } from '@babel/core';
2
2
  import type { Program } from '@babel/types';
3
- export declare const removeDangerousCode: (programPath: NodePath<Program>) => void;
3
+ import type { CodeRemoverOptions } from '@wyw-in-js/shared';
4
+ export declare const removeDangerousCode: (programPath: NodePath<Program>, options?: CodeRemoverOptions) => void;