@fullstory/babel-plugin-annotate-react
Advanced tools
Comparing version 2.1.2 to 2.2.0
# Changelog | ||
## 2.2.0 | ||
- Added the ability to skip annotating certain elements. See the README for usage. | ||
## 2.1.2 | ||
@@ -4,0 +8,0 @@ |
84
index.js
@@ -11,5 +11,9 @@ const webComponentName = 'data-component'; | ||
const annotateFragmentsOptionName = 'annotate-fragments' | ||
const ignoreComponentsOptionName = 'ignoreComponents' | ||
module.exports = function({ types: t }) { | ||
return { | ||
pre() { | ||
this.ignoreComponentsFromOption = this.opts[ignoreComponentsOptionName] || []; | ||
}, | ||
visitor: { | ||
@@ -24,3 +28,4 @@ FunctionDeclaration(path, state) { | ||
sourceFileNameFromState(state), | ||
...attributeNamesFromState(state) | ||
attributeNamesFromState(state), | ||
this.ignoreComponentsFromOption, | ||
) | ||
@@ -36,3 +41,4 @@ }, | ||
sourceFileNameFromState(state), | ||
...attributeNamesFromState(state) | ||
attributeNamesFromState(state), | ||
this.ignoreComponentsFromOption, | ||
) | ||
@@ -51,2 +57,4 @@ }, | ||
const ignoreComponentsFromOption = this.ignoreComponentsFromOption; | ||
render.traverse({ | ||
@@ -62,3 +70,4 @@ ReturnStatement(returnStatement) { | ||
sourceFileNameFromState(state), | ||
...attributeNamesFromState(state) | ||
attributeNamesFromState(state), | ||
ignoreComponentsFromOption | ||
) | ||
@@ -114,3 +123,4 @@ } | ||
function applyAttributes(t, openingElement, componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName) { | ||
function applyAttributes(t, openingElement, componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) { | ||
const [componentAttributeName, elementAttributeName, sourceFileAttributeName] = attributeNames; | ||
if (!openingElement | ||
@@ -125,10 +135,17 @@ || isReactFragment(openingElement) | ||
const elementName = openingElement.node.name.name || 'unknown' | ||
const ignoredComponentFromOptions = ignoreComponentsFromOption && !!ignoreComponentsFromOption.find(component => | ||
matchesIgnoreRule(component[0], sourceFileName) && | ||
matchesIgnoreRule(component[1], componentName) && | ||
matchesIgnoreRule(component[2], elementName) | ||
) | ||
let ignoredElement = false | ||
// Add a stable attribute for the element name but only for non-DOM names | ||
if(openingElement.node.attributes.find(node => { | ||
if (!node.name) return | ||
return node.name.name === elementAttributeName | ||
}) == null){ | ||
const name = openingElement.node.name.name || 'unknown' | ||
if (ignoredElements.includes(name)) { | ||
if ( | ||
!ignoredComponentFromOptions && | ||
!hasNodeNamed(openingElement, componentAttributeName) | ||
) { | ||
if (defaultIgnoredElements.includes(elementName)) { | ||
ignoredElement = true | ||
@@ -139,3 +156,3 @@ } else { | ||
t.jSXIdentifier(elementAttributeName), | ||
t.stringLiteral(name) | ||
t.stringLiteral(elementName) | ||
) | ||
@@ -147,6 +164,6 @@ ) | ||
// Add a stable attribute for the component name (absent for non-root elements) | ||
if(componentName && (openingElement.node.attributes.find(node => { | ||
if (!node.name) return | ||
return node.name.name === componentAttributeName | ||
}) == null)){ | ||
if ( | ||
componentName | ||
&& !ignoredComponentFromOptions | ||
&& !hasNodeNamed(openingElement, componentAttributeName)) { | ||
openingElement.node.attributes.push( | ||
@@ -161,10 +178,8 @@ t.jSXAttribute( | ||
// Add a stable attribute for the source file name (absent for non-root elements) | ||
if( | ||
if ( | ||
sourceFileName | ||
&& !ignoredComponentFromOptions | ||
&& (componentName || ignoredElement === false) | ||
&& openingElement.node.attributes.find(node => { | ||
if (!node.name) return | ||
return node.name.name === sourceFileAttributeName | ||
} | ||
) == null){ | ||
&& !hasNodeNamed(openingElement, sourceFileAttributeName) | ||
) { | ||
openingElement.node.attributes.push( | ||
@@ -179,3 +194,3 @@ t.jSXAttribute( | ||
function processJSXElement(annotateFragments, t, jsxElement, componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName) { | ||
function processJSXElement(annotateFragments, t, jsxElement, componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) { | ||
if (!jsxElement) { | ||
@@ -186,3 +201,3 @@ return | ||
applyAttributes(t, openingElement, componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName) | ||
applyAttributes(t, openingElement, componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) | ||
@@ -196,5 +211,5 @@ const children = jsxElement.get('children') | ||
shouldSetComponentName = false | ||
processJSXElement(annotateFragments, t, children[i], componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName, annotateFragments) | ||
processJSXElement(annotateFragments, t, children[i], componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) | ||
} else { | ||
processJSXElement(annotateFragments, t, children[i], null, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName, annotateFragments) | ||
processJSXElement(annotateFragments, t, children[i], null, sourceFileName, attributeNames, ignoreComponentsFromOption) | ||
} | ||
@@ -205,3 +220,3 @@ } | ||
function functionBodyPushAttributes(annotateFragments, t, path, componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName) { | ||
function functionBodyPushAttributes(annotateFragments, t, path, componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) { | ||
let jsxElement = null | ||
@@ -229,7 +244,18 @@ const functionBody = path.get('body').get('body') | ||
if (!jsxElement) return | ||
processJSXElement(annotateFragments, t, jsxElement, componentName, sourceFileName, componentAttributeName, elementAttributeName, sourceFileAttributeName) | ||
processJSXElement(annotateFragments, t, jsxElement, componentName, sourceFileName, attributeNames, ignoreComponentsFromOption) | ||
} | ||
function matchesIgnoreRule(rule, name) { | ||
return rule === '*' || rule === name; | ||
} | ||
function hasNodeNamed(openingElement, name) { | ||
return openingElement.node.attributes.find(node => { | ||
if (!node.name) return | ||
return node.name.name === name | ||
}) | ||
} | ||
// We don't write data-element attributes for these names | ||
const ignoredElements = [ | ||
const defaultIgnoredElements = [ | ||
'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', | ||
@@ -254,2 +280,2 @@ 'b', 'base', 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button', | ||
'wbr' | ||
] | ||
] |
{ | ||
"name": "@fullstory/babel-plugin-annotate-react", | ||
"version": "2.1.2", | ||
"version": "2.2.0", | ||
"description": "A Babel plugin that annotates React components, making them easier to target with FullStory search", | ||
@@ -24,4 +24,4 @@ "main": "index.js", | ||
"babel-core": "^7.0.0-0", | ||
"jest": "^26.0.1" | ||
"jest": "^27.2.4" | ||
} | ||
} |
@@ -71,2 +71,22 @@ # Babel Plugin: Annotate React | ||
If you would like the plugin to skip the annotation for certain components, use the `ignoreComponents` option: | ||
```javascript | ||
plugins: [ | ||
[ | ||
'../..', | ||
{ | ||
ignoreComponents:[ | ||
// each item must be a string array containing three items: file name, component name, element name | ||
// corresponding to the values for data-source-file, data-component, data-element | ||
// use wild card (*) to match anything | ||
["myBoxComponent.jsx","MyBox","Box"], | ||
["App.jsx", "*", "ThemeProvider"], // use wild-card to match anything | ||
["App.jsx", "App", "*"], | ||
] | ||
} | ||
], | ||
] | ||
``` | ||
We have a few samples to demonstrate this plugin: | ||
@@ -73,0 +93,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
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
14822
241
98