@contrast/agentify
Advanced tools
Comparing version 1.24.0 to 1.24.1
@@ -21,5 +21,46 @@ /* | ||
const IS_RETURN_REGEX = /^return\W/; | ||
const METHOD_CONTEXT = 'function _contrast_'; | ||
const FUNCTION_CONTEXT = 'const _contrast_fn = '; | ||
const FUNCTION_DECL = 'function _contrast_'; | ||
const VARIABLE_DECL = 'const _contrast_fn = '; | ||
/** | ||
* Injects some context around a function's toString() to make it syntactically | ||
* valid. The `swc` parser expects input to be a valid `Statement` like one of | ||
* the following: | ||
* ```js | ||
* // (named) function declaration | ||
* function f() {} | ||
* // (named) class declaration | ||
* class C {} | ||
* // variable declaration with an (anonymous?) class or function expression | ||
* const _contrast_fn = function () {}; | ||
* const _contrast_fn = () => {}; | ||
* const _contrast_fn = class {}; | ||
* ``` | ||
* @param {string} code original toString() return value | ||
* @returns {string} the contextualized statement | ||
*/ | ||
function contextualize(code) { | ||
// in case the class is anonymous we need to prepend a variable declaration. | ||
if (IS_CLASS_REGEX.exec(code)) { | ||
return `${VARIABLE_DECL}${code}`; | ||
} | ||
// if the function is a return, we don't need to add context. | ||
if (!IS_RETURN_REGEX.exec(code)) { | ||
const [orig] = code.split('{'); | ||
let lineOne = orig; | ||
// When stringified, class methods look like normal function without the | ||
// `function` keyword. We can normalize this by prepending `function`. | ||
if (!IS_FUNCTION_REGEX.exec(lineOne) && lineOne.indexOf('=>') === -1) { | ||
lineOne = `${FUNCTION_DECL}${lineOne}`; | ||
} | ||
lineOne = `${VARIABLE_DECL}${lineOne}`; | ||
code = code.replace(orig, lineOne); | ||
} | ||
return code; | ||
} | ||
module.exports = function (deps) { | ||
@@ -41,46 +82,14 @@ const { | ||
/** | ||
* Create some code context around a function to make it syntactically valid | ||
* the three general types of syntactic function definitions are: | ||
* - functions (declared with the function keyword) | ||
* - arrow functions | ||
* - class methods | ||
* @param {string} code the user code | ||
* @returns {string} the contextualized function | ||
*/ | ||
functionHooks.contextualizeFunction = (code) => { | ||
// Classes themselves are functions, so we need to exit early to avoid | ||
// clobbering the `class` keyword. | ||
if (IS_CLASS_REGEX.exec(code)) return code; | ||
const [orig] = code.split('{'); | ||
let lineOne = orig; | ||
// if the function is a return, we don't need to add context. | ||
if (!IS_RETURN_REGEX.exec(lineOne)) { | ||
// When stringified, class methods look like normal function without the | ||
// `function` keyword. We can normalize this by prepending `function`. | ||
if (!IS_FUNCTION_REGEX.exec(lineOne) && lineOne.indexOf('=>') === -1) { | ||
lineOne = `${METHOD_CONTEXT}${lineOne}`; | ||
} | ||
lineOne = `${FUNCTION_CONTEXT}${lineOne}`; | ||
code = code.replace(orig, lineOne); | ||
} | ||
return code; | ||
}; | ||
/** | ||
* Returns the rewritten function code. If an error occurs during rewriting, | ||
* we log the error and code information and return the original code string. | ||
* @param {string} code string value of the JavaScript function | ||
* @returns {string} the code rewritten to remove Contrast tokens | ||
* @param {string} code original toString() return value | ||
* @returns {string} the code rewritten to remove Contrast tokens | ||
*/ | ||
functionHooks.unwrite = function (code) { | ||
function unwrite(code) { | ||
// cannot parse lone function expressions that are not part of an assignment. | ||
try { | ||
let unwritten = functionHooks.contextualizeFunction(code); | ||
let unwritten = contextualize(code); | ||
unwritten = rewriter.unwriteSync(unwritten); | ||
unwritten = unwritten.replace(METHOD_CONTEXT, ''); | ||
unwritten = unwritten.replace(FUNCTION_CONTEXT, ''); | ||
unwritten = unwritten.replace(FUNCTION_DECL, ''); | ||
unwritten = unwritten.replace(VARIABLE_DECL, ''); | ||
unwritten = unwritten.replace(/;\s*$/, ''); // removes trailing semicolon/whitespace | ||
@@ -92,3 +101,3 @@ return unwritten; | ||
} | ||
}; | ||
} | ||
@@ -119,3 +128,3 @@ functionHooks.install = function () { | ||
if (code.indexOf('ContrastMethods') > -1) { | ||
const unwritten = functionHooks.unwrite(code); | ||
const unwritten = unwrite(code); | ||
functionHooks.cache.set(data.obj, unwritten); | ||
@@ -122,0 +131,0 @@ result = unwritten; |
@@ -20,2 +20,6 @@ /* | ||
const { IntentionalError } = require('@contrast/common'); | ||
const { | ||
assertValidOpts, | ||
preStartupValidation | ||
} = require('./utils'); | ||
@@ -65,2 +69,5 @@ const ERROR_MESSAGE = 'An error prevented the Contrast agent from installing. The application will be run without instrumentation.'; | ||
core.agentify = async function agentify(callback, opts = {}) { | ||
// options are hardcoded, so if this throws it's going to be in testing/dev situation | ||
assertValidOpts(opts); | ||
_callback = callback; | ||
@@ -129,2 +136,5 @@ _opts = opts; | ||
try { | ||
// check supported Node version and correct preload usage before anything else | ||
preStartupValidation(core); | ||
require('@contrast/core/lib/messages')(core); | ||
@@ -137,3 +147,3 @@ require('@contrast/config')(core); | ||
const errorMessage = 'Contrast agent disabled by configuration (enable: false)'; | ||
console.log(errorMessage); | ||
console.info(errorMessage); | ||
throw new IntentionalError(errorMessage); | ||
@@ -179,3 +189,4 @@ } | ||
} else { | ||
console.error(new Error(ERROR_MESSAGE, { cause: err })); | ||
console.error(err); | ||
console.error(ERROR_MESSAGE); | ||
} | ||
@@ -182,0 +193,0 @@ } |
{ | ||
"name": "@contrast/agentify", | ||
"version": "1.24.0", | ||
"version": "1.24.1", | ||
"description": "Configures Contrast agent services and instrumentation within an application", | ||
@@ -14,3 +14,3 @@ "license": "SEE LICENSE IN LICENSE", | ||
"npm": ">=6.13.7 <7 || >= 8.3.1", | ||
"node": ">= 14.15.0" | ||
"node": ">= 14.18.0" | ||
}, | ||
@@ -21,16 +21,18 @@ "scripts": { | ||
"dependencies": { | ||
"@contrast/common": "1.20.0", | ||
"@contrast/config": "1.27.0", | ||
"@contrast/core": "1.31.0", | ||
"@contrast/deadzones": "1.1.2", | ||
"@contrast/dep-hooks": "1.3.1", | ||
"@contrast/esm-hooks": "2.5.0", | ||
"@contrast/instrumentation": "1.7.0", | ||
"@contrast/logger": "1.8.0", | ||
"@contrast/metrics": "1.7.0", | ||
"@contrast/patcher": "1.7.1", | ||
"@contrast/reporter": "1.26.0", | ||
"@contrast/rewriter": "1.7.0", | ||
"@contrast/scopes": "1.4.0" | ||
"@contrast/common": "1.20.1", | ||
"@contrast/config": "1.27.1", | ||
"@contrast/core": "1.31.1", | ||
"@contrast/deadzones": "1.1.3", | ||
"@contrast/dep-hooks": "1.3.2", | ||
"@contrast/esm-hooks": "2.5.1", | ||
"@contrast/find-package-json": "^1.1.0", | ||
"@contrast/instrumentation": "1.7.1", | ||
"@contrast/logger": "1.8.1", | ||
"@contrast/metrics": "1.7.1", | ||
"@contrast/patcher": "1.7.2", | ||
"@contrast/reporter": "1.26.1", | ||
"@contrast/rewriter": "1.7.1", | ||
"@contrast/scopes": "1.4.1", | ||
"semver": "^7.6.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31516
12
790
15
6
+ Addedsemver@^7.6.0
+ Added@contrast/common@1.20.1(transitive)
+ Added@contrast/config@1.27.1(transitive)
+ Added@contrast/core@1.31.1(transitive)
+ Added@contrast/deadzones@1.1.3(transitive)
+ Added@contrast/dep-hooks@1.3.2(transitive)
+ Added@contrast/esm-hooks@2.5.1(transitive)
+ Added@contrast/instrumentation@1.7.1(transitive)
+ Added@contrast/logger@1.8.1(transitive)
+ Added@contrast/metrics@1.7.1(transitive)
+ Added@contrast/patcher@1.7.2(transitive)
+ Added@contrast/reporter@1.26.1(transitive)
+ Added@contrast/rewriter@1.7.1(transitive)
+ Added@contrast/scopes@1.4.1(transitive)
- Removed@contrast/common@1.20.0(transitive)
- Removed@contrast/config@1.27.0(transitive)
- Removed@contrast/core@1.31.0(transitive)
- Removed@contrast/deadzones@1.1.2(transitive)
- Removed@contrast/dep-hooks@1.3.1(transitive)
- Removed@contrast/esm-hooks@2.5.0(transitive)
- Removed@contrast/instrumentation@1.7.0(transitive)
- Removed@contrast/logger@1.8.0(transitive)
- Removed@contrast/metrics@1.7.0(transitive)
- Removed@contrast/patcher@1.7.1(transitive)
- Removed@contrast/reporter@1.26.0(transitive)
- Removed@contrast/rewriter@1.7.0(transitive)
- Removed@contrast/scopes@1.4.0(transitive)
Updated@contrast/common@1.20.1
Updated@contrast/config@1.27.1
Updated@contrast/core@1.31.1
Updated@contrast/deadzones@1.1.3
Updated@contrast/dep-hooks@1.3.2
Updated@contrast/esm-hooks@2.5.1
Updated@contrast/logger@1.8.1
Updated@contrast/metrics@1.7.1
Updated@contrast/patcher@1.7.2
Updated@contrast/reporter@1.26.1
Updated@contrast/rewriter@1.7.1
Updated@contrast/scopes@1.4.1