Socket
Socket
Sign inDemoInstall

bpmnlint

Package Overview
Dependencies
Maintainers
2
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bpmnlint - npm Package Compare versions

Comparing version 1.0.0-alpha4 to 1.0.0-alpha5

CHANGELOG.md

81

bin/bpmnlint.js
#!/usr/bin/env node
const meow = require("meow");
const fs = require("fs");
const path = require("path");
const { red, yellow, underline } = require("chalk");
const BpmnModdle = require("bpmn-moddle");
const meow = require('meow');
const fs = require('fs');
const path = require('path');
const { red, yellow, underline } = require('chalk');
const BpmnModdle = require('bpmn-moddle');
const { promisify } = require("util");
const { promisify } = require('util');
const readFile = promisify(fs.readFile);
const linter = require("../lib/linter");
const Linter = require('../lib/linter');
const moddle = new BpmnModdle();
const nodeResolver = require('../lib/resolver/nodeResolver');
/**

@@ -19,8 +21,7 @@ * Reads XML form path and return moddle object

*/
async function getModdleRoot(sourcePath) {
const source = await readFile(path.resolve(sourcePath), "utf-8");
function getModdleFromXML(source) {
return new Promise((resolve, reject) => {
moddle.fromXML(source, (err, root) => {
if (err) {
return reject(new Error("failed to parse XML", err));
return reject(new Error('failed to parse XML', err));
}

@@ -38,3 +39,3 @@

console.log(
`${yellow("warning:")} ${underline(warning.id)} ${warning.message}`
`${yellow('warning:')} ${underline(warning.id)} ${warning.message}`
);

@@ -46,3 +47,3 @@

const logError = error =>
console.log(`${red("error:")} ${underline(error.id)} ${error.message}`);
console.log(`${red('error:')} ${underline(error.id)} ${error.message}`);

@@ -69,3 +70,3 @@ /**

$ bpmnlint ./invoice.bpmn
`,

@@ -75,4 +76,4 @@ {

config: {
type: "string",
alias: "c"
type: 'string',
alias: 'c'
}

@@ -86,23 +87,48 @@ }

if (cli.input.length !== 1) {
console.log("Error: bpmn file path missing.");
console.log('Error: bpmn file path missing.');
process.exit(1);
}
function logAndExit(...args) {
console.error(...args);
process.exit(1);
}
async function handleConfig(config) {
let parsedConfig;
try {
const parsedConfig = JSON.parse(config);
const moddleRoot = await getModdleRoot(cli.input[0]);
linter({ moddleRoot, config: parsedConfig })
.then(logReports)
.catch(console.error);
parsedConfig = JSON.parse(config);
} catch (e) {
console.log(`Error parsing the configuration file: ${e}`);
return logAndExit('Error: Could not parse configuration file', e);
}
let diagramXML;
try {
diagramXML = await readFile(path.resolve(cli.input[0]), 'utf-8');
} catch (e) {
return logAndExit(`Error: Failed to read ${cli.input[0]}`, e);
}
try {
const moddleRoot = await getModdleFromXML(diagramXML);
const linter = new Linter({
resolver: nodeResolver
});
const lintResults = await linter.lint(moddleRoot, parsedConfig);
logReports(lintResults);
} catch (e) {
return logAndExit(e);
}
}
if (configFlag) {
fs.readFile(configFlag, "utf-8", (error, config) => {
fs.readFile(configFlag, 'utf-8', (error, config) => {
if (error) {
console.log("Error: couldn't read specified config file.");
process.exit(1);
return logAndExit('Error: Could not read specified config file', error);
}

@@ -113,6 +139,5 @@

} else {
fs.readFile(path.resolve(".bpmnlintrc"), "utf-8", (error, config) => {
fs.readFile(path.resolve('.bpmnlintrc'), 'utf-8', (error, config) => {
if (error) {
console.log("Error: bpmnlint configuration file missing.");
process.exit(1);
return logAndExit('Error: Configuration file missing', error);
}

@@ -119,0 +144,0 @@

@@ -1,58 +0,243 @@

const testRule = require("./testRule");
const utils = require("./utils");
const testRule = require('./testRule');
const utils = require('./utils');
const flagsMap = {
1: "warnings",
2: "errors"
1: 'warnings',
2: 'errors',
warn: 'warnings',
error: 'errors'
};
require("../rules/bpmnlint-label-required");
function Linter(options = {}) {
const {
resolver
} = options;
if (typeof resolver === 'undefined') {
throw new Error('must provide <options.resolver>');
}
this.resolver = resolver;
this.cachedRules = {};
this.cachedConfigs = {};
}
module.exports = Linter;
/**
* Applies a rule on the moddleRoot and adds reports to the finalReport
* @param {*} moddleRoot
* @param {*} ruleName
* @param {*} ruleFlagIdx
*
* @param {ModdleElement} options.moddleRoot
* @param {String|Number} options.ruleFlag
* @param {Rule} options.rule
*
* @return {Object} lint results, keyed by category name
*/
function applyRule({ moddleRoot, ruleFlagIdx, rule }) {
const flagName = flagsMap[ruleFlagIdx];
let reports = [];
Linter.prototype.applyRule = function applyRule({ moddleRoot, ruleFlag, rule, ruleConfig }) {
if (ruleFlagIdx) {
reports = testRule({ moddleRoot, rule });
if (typeof ruleFlag === 'string') {
ruleFlag = ruleFlag.toLowerCase();
}
const flagName = flagsMap[ruleFlag];
if (!flagName) {
return {};
}
const reports = testRule({ moddleRoot, rule, ruleConfig });
return { [flagName]: reports };
}
};
module.exports = async function linter({ moddleRoot, config }) {
// final report that holds all lint reports
const finalReport = { warnings: [], errors: [] };
Object.entries(config).forEach(([ruleName, value]) => {
let rule, ruleFlagIdx;
if (typeof value === "object" && value !== null) {
rule = require(value.path)(utils);
ruleFlagIdx = value.flag;
} else {
try {
rule = require(`../rules/bpmnlint-${ruleName}`)(utils);
} catch (e) {
try {
rule = require(`../../bpmnlint-${ruleName}/index.js`)(utils);
} catch (e) {
console.error(`Couldn't find path to rule ${ruleName}.`);
}
}
ruleFlagIdx = value;
Linter.prototype.resolveRule = function(name) {
const rule = this.cachedRules[name];
if (rule) {
return Promise.resolve(rule);
}
return Promise.resolve(this.resolver.resolveRule(name)).then((ruleFactory) => {
if (!ruleFactory) {
throw new Error(`unknown rule <${name}>`);
}
const [flagName, reports] = Object.entries(
applyRule({ moddleRoot, ruleFlagIdx, rule })
)[0];
const rule = this.cachedRules[name] = ruleFactory(utils);
finalReport[flagName] = (finalReport[flagName] || []).concat(reports);
return rule;
});
};
return finalReport;
Linter.prototype.resolveConfig = function(name) {
const config = this.cachedConfigs[name];
if (config) {
return Promise.resolve(config);
}
return Promise.resolve(this.resolver.resolveConfig(name)).then((config) => {
if (!config) {
throw new Error(`unknown config <${name}>`);
}
const actualConfig = this.cachedConfigs[name] = prefix(config, name);
return actualConfig;
});
};
/**
* Take a linter config and return list of resolved rules.
*
* @param {Object} rulesConfig
*
* @return {Array<RuleDefinition>}
*/
Linter.prototype.resolveRules = function(config) {
return this.resolveConfiguredRules(config).then((rulesConfig) => {
return Promise.all(
Object.entries(rulesConfig).map(([ name, value ]) => {
return this.resolveRule(name).then(function(rule) {
return {
value,
name,
rule
};
});
})
);
});
};
Linter.prototype.resolveConfiguredRules = function(config) {
let parents = config.extends;
if (typeof parents === 'string') {
parents = [ parents ];
}
if (typeof parents === 'undefined') {
parents = [];
}
return Promise.all(
parents.map((configName) => {
return this.resolveConfig(configName).then((config) => {
return this.resolveConfiguredRules(config);
});
})
).then((inheritedRules) => {
const rules = [ ...inheritedRules, config.rules || [] ].reduce((rules, currentRules) => {
return {
...rules,
...currentRules
};
}, {});
return rules;
});
};
/**
* Lint the given model root, using the specified linter config.
*
* @param {ModdleElement} moddleRoot
* @param {Object} config rule config
*
* @return {Object} lint results, keyed by category names
*/
Linter.prototype.lint = function(moddleRoot, config) {
// load rules
return this.resolveRules(config).then((ruleDefinitions) => {
const finalReport = {};
ruleDefinitions.forEach(({ rule, name, value }) => {
const {
ruleFlag,
ruleConfig
} = this.parseRuleValue(value);
const ruleResults = this.applyRule({ moddleRoot, ruleFlag, rule, ruleConfig });
Object.entries(ruleResults).forEach(([category, reports]) => {
finalReport[category] = (finalReport[category] || []).concat(reports);
});
});
return finalReport;
});
};
Linter.prototype.parseRuleValue = function(value) {
let ruleFlag;
let ruleConfig;
if (Array.isArray(value)) {
ruleFlag = value[0];
ruleConfig = value[1];
} else {
ruleFlag = value;
ruleConfig = {};
}
return {
ruleConfig,
ruleFlag
};
};
// helpers ///////////////////////////
function prefix(config, configName) {
let pkg;
if (configName.indexOf('bpmnlint:') === 0) {
pkg = 'bpmnlint';
} else {
pkg = configName.substring('plugin:'.length, configName.indexOf('/'));
}
const rules = config.rules || {};
const prefixedRules = Object.keys(rules).reduce((prefixed, name) => {
const value = rules[name];
// prefix local rule definition
if (name.indexOf('/') === -1) {
name = `${pkg}/${name}`;
}
return {
...prefixed,
[name]: value
};
}, {});
return {
...config,
rules: prefixedRules
};
}

@@ -1,2 +0,2 @@

const traverse = require("./traverse");
const traverse = require('./traverse');

@@ -3,0 +3,0 @@ class Reporter {

@@ -12,3 +12,3 @@ /**

var containedProperties = element.$descriptor.properties.filter(p => {
return !p.isAttr && !p.isReference && p.type !== "String";
return !p.isAttr && !p.isReference && p.type !== 'String';
});

@@ -15,0 +15,0 @@

@@ -1,10 +0,19 @@

function isNodeOfType(node, type) {
/**
* Checks whether node is of specific bpmn type
* @param {*} node
* @param {*} type
*/
return Boolean(
node.$descriptor.allTypes.filter(({ name }) => `bpmn:${type}` === name)
.length
/**
* Checks whether node is of specific bpmn type.
*
* @param {ModdleElement} node
* @param {String} type
*
* @return {Boolean}
*/
function is(node, type) {
if (type.indexOf(':') === -1) {
type = 'bpmn:' + type;
}
return (
(typeof node.$instanceOf === 'function')
? node.$instanceOf(type)
: node.$type === type
);

@@ -14,3 +23,3 @@ }

module.exports = {
isNodeOfType
is
};
{
"name": "bpmnlint",
"version": "1.0.0-alpha4",
"version": "1.0.0-alpha5",
"main": "index.js",
"repository": "https://github.com/siffogh/bpmnlint/",
"keywords": [
"bpmnlint",
"bpmn",
"linter",
"cli",
"validation",
"rules"
],
"repository": {
"type": "git",
"url": "https://github.com/bpmn-io/bpmnlint"
},
"author": "Seif Eddine Ghezala <siffogh3@gmail.com>",
"contributors": [
{
"name": "bpmn.io contributors",
"url": "https://github.com/bpmn-io"
}
],
"license": "MIT",
"scripts": {
"all": "run-s lint test",
"lint": "eslint .",
"dev": "npm test -- --watch",
"test": "mocha -r esm --exclude 'test/integration/cli/**' 'test/**/*.js'"
},
"bin": {

@@ -12,3 +35,3 @@ "bpmnlint": "./bin/bpmnlint.js"

"dependencies": {
"bpmn-moddle": "4.0",
"bpmn-moddle": "^4.0.0",
"chalk": "^2.4.1",

@@ -18,8 +41,11 @@ "meow": "^5.0.0"

"devDependencies": {
"chai": "^4.1.2",
"eslint": "^5.3.0",
"eslint-config-prettier": "^3.0.1",
"eslint-plugin-bpmn-io": "^0.5.4",
"eslint-plugin-prettier": "^2.6.2",
"prettier": "^1.14.2"
"esm": "^3.0.81",
"execa": "^1.0.0",
"install-local": "^0.6.0",
"mocha": "^5.2.0",
"npm-run-all": "^4.1.3"
}
}
# bpmnlint
Linter for BPMN diagrams.
[![Build Status](https://travis-ci.org/bpmn-io/bpmnlint.svg?branch=master)](https://travis-ci.org/bpmn-io/bpmnlint)
Validate and improve your BPMN diagrams.
## Installing

@@ -19,3 +23,3 @@

### As a command line tool
#### Using a local **.bpmnlintrc** configuration file
#### Using a local **.bpmnlintrc** configuration file
- Make sure to have a **.bpmnlintrc** configuration file in the directory where you are running the tool:

@@ -26,5 +30,7 @@

{
"label-required": 1,
"start-event-required": 2,
"end-event-required": 2
"rules": {
"label-required": "warn",
"start-event-required": "error",
"end-event-required": "error"
}
}

@@ -38,10 +44,12 @@ ```

#### Using an explicit configuration file
- e.g.
#### Using an explicit configuration file
- e.g.
```json
// some-config.json file
{
"label-required": 1,
"start-event-required": 2,
"end-event-required": 2
"rules": {
"label-required": "warn",
"start-event-required": "error",
"end-event-required": "error"
}
}

@@ -72,3 +80,3 @@ ```

### Implicit Configuration
If the specified value for a rule is a number, it will hold the rule status flag:
If the specified value for a rule is a number, it will hold the rule status flag:
- 0: the rule is off

@@ -80,7 +88,9 @@ - 1: problems reported by the rule are considered as warnings

{
"label-required": 1
"rules": {
"label-required": "warn"
}
}
```
bpmnlint will then look for the rule first in the built-in rules.
bpmnlint will then look for the rule first in the built-in rules.
If not found, bpmnlint will look for the rule in the npm packages installed as **bpmn-**rule-name (e.g. bpmn-no-implicit-parallel-gateway).

@@ -91,3 +101,3 @@

### Explicit Configuration
If the specified value for a rule is an object, it will hold the following information:
If the specified value for a rule is an object, it will hold the following information:
- path to the the rule.

@@ -98,5 +108,7 @@ - flag: rule status flag

{
"bpmnlint-some-custom-rule": {
"path": "some/local/path/bpmnlint-some-custom-rule",
"flag": 2
"plugins": [
"custom-rules"
],
"rules": {
"custom-rules/some-custom-rule": "error"
}

@@ -106,3 +118,3 @@ }

### Adding Custom Rules
### Adding Custom Rules
> **Important:** The rule needs to have a suffix of 'bpmnlint-'.

@@ -118,5 +130,7 @@

{
"bpmnlint-some-custom-rule": {
"path": "some/local/path/bpmnlint-some-custom-rule",
"flag": 2
"plugins": [
"custom-rules"
],
"rules": {
"custom-rules/some-custom-rule": "error"
}

@@ -123,0 +137,0 @@ }

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