@contrast/rewriter 1.4.0 → 1.4.1

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 (2) hide show
  1. package/lib/index.js +37 -8
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
13
  * way not consistent with the End User License Agreement.
14
14
  */
15
+ // @ts-check
15
16
 
16
17
  'use strict';
17
18
 
@@ -21,7 +22,9 @@ const Module = require('module');
21
22
  const rewriterPath = require.resolve('@contrast/agent-swc-plugin');
22
23
  const unwriterPath = require.resolve('@contrast/agent-swc-plugin-unwrite');
23
24
 
25
+ // @ts-expect-error `wrapper` is missing from @types/node
24
26
  const prefix = Module.wrapper[0];
27
+ // @ts-expect-error `wrapper` is missing from @types/node
25
28
  const suffix = Module.wrapper[1].replace(/;$/, '.apply(this, arguments);');
26
29
 
27
30
  /** @typedef {'assess' | 'protect'} Mode */
@@ -42,18 +45,26 @@ const rewriter = {
42
45
  /**
43
46
  * @param {string} content the source code
44
47
  * @param {object} opts
45
- * @param {string} opts.filename e.g. 'index.js'
46
- * @param {boolean} opts.isModule if true, file is parsed as an ES module instead of a CJS script
47
- * @param {boolean} opts.inject if true, injects ContrastMethods on the global object
48
- * @param {boolean} opts.wrap if true, wraps the content with a modified module wrapper IIFE
48
+ * @param {string=} opts.filename e.g. 'index.js'
49
+ * @param {boolean=} opts.isModule if true, file is parsed as an ES module instead of a CJS script
50
+ * @param {boolean=} opts.inject if true, injects ContrastMethods on the global object
51
+ * @param {boolean=} opts.wrap if true, wraps the content with a modified module wrapper IIFE
49
52
  * @returns {import("@swc/core").Output}
50
53
  */
51
54
  rewrite(content, opts = {}) {
55
+ let shebang = '';
56
+
57
+ if (content.charAt(0) === '#') {
58
+ shebang = content.substring(0, content.indexOf('\n') + 1);
59
+ // see the test output: swc doesn't include the commented shebang in the generated code despite including comments otherwise
60
+ content = `//${content}`;
61
+ }
62
+
52
63
  if (opts.wrap) {
53
- content = `${prefix}${content}${suffix}`;
64
+ content = `${shebang}${prefix}${content}${suffix}`;
54
65
  }
55
66
 
56
- return transformSync(content, {
67
+ const result = transformSync(content, {
57
68
  filename: opts.filename,
58
69
  isModule: opts.isModule,
59
70
  jsc: {
@@ -72,6 +83,25 @@ const rewriter = {
72
83
  },
73
84
  sourceMaps: true,
74
85
  });
86
+
87
+ if (!opts.wrap) {
88
+ let carriageReturn = 0;
89
+ // swc always adds a newline, so we only need to check the input
90
+ if (!content.endsWith('\n')) {
91
+ result.code = result.code.substring(0, result.code.length - 1);
92
+ } else if (content.endsWith('\r\n')) {
93
+ // if EOL is \r\n, then we need to account for that when we check the
94
+ // negative index of the last semicolon below
95
+ carriageReturn = 1;
96
+ }
97
+ const resultSemicolonIdx = result.code.lastIndexOf(';');
98
+ const contentSemicolonIdx = content.lastIndexOf(';');
99
+ if (contentSemicolonIdx === -1 || resultSemicolonIdx - result.code.length !== contentSemicolonIdx - content.length + carriageReturn) {
100
+ result.code = result.code.substring(0, resultSemicolonIdx) + result.code.substring(resultSemicolonIdx + 1, result.code.length);
101
+ }
102
+ }
103
+
104
+ return result;
75
105
  },
76
106
 
77
107
  /**
@@ -90,11 +120,10 @@ const rewriter = {
90
120
  },
91
121
  };
92
122
 
93
- /** @typedef {{}} Core */
94
123
  /** @typedef {typeof rewriter} Rewriter */
95
124
 
96
125
  /**
97
- * @param {Core} core
126
+ * @param {{ rewriter: Rewriter }} core
98
127
  * @returns {Rewriter}
99
128
  */
100
129
  module.exports = function init(core) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/rewriter",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "A transpilation tool mainly used for instrumentation",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",