Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@scandipwa/eslint-plugin-scandipwa-guidelines

Package Overview
Dependencies
Maintainers
3
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@scandipwa/eslint-plugin-scandipwa-guidelines - npm Package Compare versions

Comparing version 1.10.2 to 2.0.0

lib/rules/no-duplicate-namespaces.js

3

lib/rules/create-config-files.js

@@ -5,2 +5,3 @@ /**

*/
const path = require('path');

@@ -37,3 +38,3 @@ const extractDeclaration = (declarationOrExport) => {

const filePath = context.getFilename();
const exploded = filePath.split('/');
const exploded = filePath.split(path.sep);
const [fileName, postfix] = exploded[exploded.length - 1].split('.');

@@ -40,0 +41,0 @@

@@ -5,4 +5,5 @@ /**

*/
const path = require('path');
function capitalize(word) {
const capitalize = (word) => {
return word.charAt(0).toUpperCase() + word.slice(1);

@@ -24,16 +25,17 @@ }

const filePath = context.getFilename();
const exploded = filePath.split('/');
const [fileName, postfix] = exploded[exploded.length - 1].split('.');
if (fileName === 'index' && postfix === 'js') {
const exploded = filePath.split(path.sep);
const [filename, postfix] = exploded[exploded.length - 1].split('.');
if (filename === 'index' || postfix.length <= 3) {
// Ignore index files, they could have anything in them
// Ignore files without postfix, AKA postfix is a file extension
return;
}
const expectedClassName = capitalize(fileName)
+ (['js', 'component'].includes(postfix)
? ''
: capitalize(postfix));
const actualClassName = node.id.name;
const expectedClassName = capitalize(filename) + capitalize(postfix);
if (expectedClassName !== actualClassName) {
if (expectedClassName !== node.id.name) {
// Check if expected class name does match the node class name
const { id: { loc } } = node;
context.report({

@@ -40,0 +42,0 @@ loc,

@@ -6,2 +6,4 @@ /**

const path = require('path');
/* eslint-disable max-len */

@@ -113,3 +115,3 @@ /* eslint-disable no-magic-numbers */

const relativeToApp = filePath.slice(filePath.indexOf(pathKey) + pathKey.length + 1);
const exploded = relativeToApp.split('/');
const exploded = relativeToApp.split(path.sep);

@@ -116,0 +118,0 @@ if (!([

@@ -6,2 +6,4 @@ /**

const path = require('path');
module.exports = {

@@ -19,3 +21,3 @@ meta: {

const filePath = context.getFilename();
const exploded = filePath.split('/');
const exploded = filePath.split(path.sep);
const [, postfix] = exploded[exploded.length - 1].split('.');

@@ -41,2 +43,2 @@

})
}
}

@@ -7,2 +7,16 @@ /**

const hasNamespace = (node, context) => {
const nodeToProcess = node.parent.type === 'ExportNamedDeclaration'
? node.parent
: node;
const leadingComments = context.getSourceCode().getCommentsBefore(nodeToProcess);
const namespaceComment = leadingComments.find(
({ value }) => value.match(/@namespace/)
);
return !!namespaceComment;
};
module.exports = {

@@ -21,6 +35,3 @@ meta: {

MethodDefinition(node) {
if (
node.key.name === 'constructor' &&
node.parent.parent.superClass.name.match(/^Extensible\w+/)
) {
if (node.key.name === 'constructor' && hasNamespace(node.parent.parent, context)) {
context.report({

@@ -40,6 +51,8 @@ node,

const fixes = [fixer.replaceText(node.key, '__construct')];
const fixes = [fixer.replaceText(node.key, '__construct')]
if (superNode) {
fixes.push(fixer.replaceText(superNode, 'super.__construct();'))
}
fixes.push(fixer.replaceText(superNode, `super.__construct(${
superNode.expression.arguments.map(arg => arg.name).join(', ')
});`))
}

@@ -46,0 +59,0 @@ return fixes;

@@ -6,2 +6,4 @@ /**

const path = require('path');
const { getPackageJson } = require('@scandipwa/scandipwa-dev-utils/package-json');
const fixNamespaceLack = require('../util/fix-namespace-lack.js');

@@ -23,13 +25,19 @@

isExportedClass: node => node.type === 'ClassDeclaration'
&& node.parent.type === 'ExportNamedDeclaration',
&& node.parent.type === 'ExportNamedDeclaration',
isExportedArrowFunction: node => node.type === 'ArrowFunctionExpression'
&& node.parent.type === 'VariableDeclarator'
&& node.parent.parent.type === 'VariableDeclaration'
&& node.parent.parent.parent.type === 'ExportNamedDeclaration',
&& node.parent.type === 'VariableDeclarator'
&& node.parent.parent.type === 'VariableDeclaration'
&& node.parent.parent.parent.type === 'ExportNamedDeclaration',
PromiseHandlerArrowFunction: [
"CallExpression[callee.type='MemberExpression']".concat(
":matches([callee.property.name='then'], [callee.property.name='catch'])"
),
[
"CallExpression",
"[callee.type='MemberExpression']",
"[callee.object.name!=/.+Dispatcher/]",
":matches(",
"[callee.property.name='then'], ",
"[callee.property.name='catch']",
")",
].join(''),
'ArrowFunctionExpression'

@@ -44,5 +52,6 @@ ].join(' > '),

node.type === 'ArrowFunctionExpression'
&& parent.type === 'CallExpression'
&& parent.callee.type === 'MemberExpression'
&& promiseHandlerNames.includes(parent.callee.property.name)
&& parent.type === 'CallExpression'
&& parent.callee.type === 'MemberExpression'
&& !(parent.callee.object.name || "").endsWith('Dispatcher')
&& promiseHandlerNames.includes(parent.callee.property.name)
);

@@ -52,3 +61,3 @@ },

isHandleableArrowFunction: node => types.isExportedArrowFunction(node)
|| types.isPromiseHandlerArrowFunction(node),
|| types.isPromiseHandlerArrowFunction(node),

@@ -76,3 +85,3 @@ detectType: node => {

const getNamespaceForNode = (node) => {
const getNamespaceCommentForNode = (node, sourceCode) => {
const getNamespaceFromComments = (comments = []) => comments.find(

@@ -83,90 +92,94 @@ comment => comment.value.includes('@namespace')

return getNamespaceFromComments(
getProperParentNode(node).leadingComments
sourceCode.getCommentsBefore(getProperParentNode(node))
);
};
const collectFunctionNamespace = (node, stack) => {
if (node.type === 'CallExpression') {
if (node.callee.type === 'MemberExpression') {
stack.push(node.callee.property.name);
collectFunctionNamespace(node.callee.object, stack);
} else if (node.callee.type === 'Identifier') {
stack.push(node.callee.name);
}
}
}
const generateNamespace = (node, context) => {
const capitalise = word => word.charAt(0).toUpperCase() + word.slice(1);
const generateBaseNamespace = () => {
const splitReverseFilePath = context.getFilename().split('/').reverse();
const postfix = capitalise(splitReverseFilePath[0].split('.')[1]);
const getNodeNamespace = (node) => {
const stack = [];
const generatePluginPart = () => {
const pluginRootIndex = context.getFilename().indexOf('/src/scandipwa/');
if (pluginRootIndex === -1) {
return '';
}
if (node.parent.type === 'VariableDeclarator') {
stack.push(node.parent.id.name)
} else if (node.type === 'ClassDeclaration') {
stack.push(node.id.name);
} else {
collectFunctionNamespace(node.parent, stack);
}
return context.getFilename()
.slice(0, pluginRootIndex)
.split('/')
.reverse()
.slice(0, 2)
.reverse()
.join('/')
.concat('/');
}
return stack.reverse().join(path.sep);
}
return generatePluginPart().concat(
splitReverseFilePath.slice(1).reduce(
(acc, cur, _, array) => {
if (cur === 'app' || cur === 'sw') {
// Mutate the initial array to break cycle
array.splice(1);
return acc;
}
const prepareFilePath = (pathname) => {
const {
name: filename,
dir
} = path.parse(pathname);
return [capitalise(cur), acc].filter(Boolean).join('/');
},
['JS', 'QUERY'].includes(postfix.toUpperCase()) ? '' : postfix
)
);
};
const [name, postfix = ''] = filename.split('.');
const toCamelCase = (...args) => {
const decapitalise = word => word.charAt(0).toLowerCase() + word.slice(1);
return path.join(
dir,
// If dir name === file name without postfix => do not repeat it
new RegExp(`${path.sep}${name}$`).test(dir) ? '' : name,
postfix
);
}
return args.slice(1).reduce(
(acc, cur) => {
acc = acc.concat(capitalise(cur));
const preparePackageName = (packageName) => {
const [org, name] = packageName.split(path.sep);
return acc;
},
decapitalise(args[0])
)
};
if (org === '@scandipwa') {
// Legacy support
if (name === 'scandipwa') {
return '';
}
if (node.type === 'ClassDeclaration') {
return generateBaseNamespace();
return name;
}
let stack = [];
const collect = (node, namespaceContainer) => {
if (node.type === 'CallExpression') {
if (node.callee.type === 'MemberExpression') {
stack.push(node.callee.property.name);
collect(node.callee.object);
} else if (node.callee.type === 'Identifier') {
stack.push(node.callee.name);
}
}
}
return path.join(org.slice(1), name);
};
if (node.parent.type === 'VariableDeclarator') {
stack.push(node.parent.id.name)
} else if (node.type === 'ClassDeclaration') {
stack.push(node.id.name);
} else {
collect(node.parent);
}
return [generateBaseNamespace(), toCamelCase(...stack.reverse())].join('/');
}
const generateNamespace = (node, context) => {
const filename = context.getFilename();
const splitted = filename.split('src');
const toFile = splitted.pop();
const toPackage = path.normalize(splitted.join('src'));
const { name: packageName } = getPackageJson(toPackage);
const isPlugin = (node) => {
return node &&
node.id &&
node.id.name &&
node.id.name.match(/[P|p]lugin/);
const pathname = path.join(
// remove @ from organization, support @scandipwa legacy namespaces
preparePackageName(packageName),
// trim post-fixes if they are not present
prepareFilePath(toFile)
).replace(
// Convert to pascal-case, and trim "-"
/\b[a-z](?=[a-z]{2})/g,
(letter) => letter.toUpperCase()
).replace('-', '');
// do not transform code to uppercase / lowercase it should be written alright
return path.join(pathname, getNodeNamespace(node));
}
const extractNamespaceFromComment = ({ value: comment = '' }) => {
const {
groups: {
namespace
} = {}
} = comment.match(/@namespace +(?<namespace>[^ ]+)/) || {};
return namespace;
};
module.exports = {

@@ -188,16 +201,37 @@ meta: {

].join(',')](node) {
const namespace = getNamespaceForNode(node);
const namespaceComment = getNamespaceCommentForNode(node, context.getSourceCode());
if (!namespace && !isPlugin(node)) {
const namespace = extractNamespaceFromComment(namespaceComment);
const generatedNamespace = generateNamespace(node, context);
if (!namespaceComment) {
context.report({
node,
message: `Provide namespace for ${types.detectType(node)} by using @namespace magic comment`,
fix: fixer => fixNamespaceLack(
fixer,
getProperParentNode(node),
context,
generatedNamespace
) || []
});
} else if (generatedNamespace !== namespaceComment) {
context.report({
node,
message: `Namespace for this node is not valid! Consider changing it to ${generatedNamespace}`,
fix: fixer => {
const newNamespace = generateNamespace(node, context);
return [fixNamespaceLack(fixer, getProperParentNode(node), context, newNamespace)].filter(value => value)
}
const newNamespaceCommentContent = namespaceComment.value.replace(namespace, generatedNamespace);
const newNamespaceComment = namespaceComment.type === 'Block'
? `/*${newNamespaceCommentContent}*/`
: `// ${newNamespaceCommentContent}`;
return fixer.replaceText(
namespaceComment,
newNamespaceComment
)
}
});
}
}
}
})
};

@@ -9,3 +9,5 @@ /**

module.exports = (fixer, node, context, namespace) => {
const { leadingComments = [] } = node;
const sourceCode = context.getSourceCode();
const leadingComments = sourceCode.getLeadingComments(node);
if (leadingComments.find(comment => comment.value.includes('@namespace'))) {

@@ -12,0 +14,0 @@ return null;

{
"name": "@scandipwa/eslint-plugin-scandipwa-guidelines",
"version": "1.10.2",
"version": "2.0.0",
"description": "Eslint rules for ScandiPWA",

@@ -29,3 +29,3 @@ "keywords": [

},
"gitHead": "9a20d82ccff47f83fbea315370d30806848ccddb"
"gitHead": "6bf68e8fe01d38fd577df8059e86156b297999f3"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc