bpmnlint 11.15.0 → 12.0.0

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.
@@ -1,48 +1 @@
1
- /**
2
- * @typedef { import('../types.js').RuleFactory } RuleFactory
3
- * @typedef { import('../types.js').Config } Config
4
- */
5
-
6
-
7
- /**
8
- * A resolver that resolves rules and packages from a static cache.
9
- *
10
- * @param { any } cache
11
- */
12
- function StaticResolver(cache) {
13
- this.cache = cache;
14
- }
15
-
16
- module.exports = StaticResolver;
17
-
18
- /**
19
- * @param { string } pkg
20
- * @param { string } ruleName
21
- *
22
- * @return { RuleFactory }
23
- */
24
- StaticResolver.prototype.resolveRule = function(pkg, ruleName) {
25
- return /** @type { RuleFactory } */ (this.resolve('rule', pkg, ruleName));
26
- };
27
-
28
- /**
29
- * @param { string } pkg
30
- * @param { string } configName
31
- *
32
- * @return { Config }
33
- */
34
- StaticResolver.prototype.resolveConfig = function(pkg, configName) {
35
- return /** @type { Config } */ (this.resolve('config', pkg, configName));
36
- };
37
-
38
- StaticResolver.prototype.resolve = function(type, pkg, name) {
39
- const id = `${pkg}/${name}`;
40
-
41
- const resolved = this.cache[`${type}:${id}`];
42
-
43
- if (!resolved) {
44
- throw new Error(`unknown ${type} <${id}>`);
45
- }
46
-
47
- return resolved;
48
- };
1
+ module.exports = require('@bpmn-io/lint-core/lib/resolver/static-resolver');
@@ -1,201 +1,6 @@
1
- const path = require('path');
1
+ const { createCompileConfig } = require('@bpmn-io/lint-core/lib/support/compile-config');
2
2
 
3
- const { isString } = require('min-dash');
4
-
5
- const Linter = require('../linter');
6
-
7
- const NodeResolver = require('../resolver/node-resolver');
8
-
9
- /**
10
- * Compile the bpmnlint configuration to a JavaScript file that exports
11
- * a { config, resolver } bundle, resolving all enabled rules.
12
- *
13
- * @param {Object} config the parsed bpmnlint configuration
14
- * @param {NodeResolver} [resolver]
15
- * @return {Promise<String>} the configuration compiled to a JS file
16
- */
17
- async function compileConfig(config, resolver) {
18
-
19
- resolver = resolver || new NodeResolver();
20
-
21
- const linter = new Linter({
22
- resolver
23
- });
24
-
25
- const resolvedRules = await linter.resolveConfiguredRules(config);
26
-
27
- // only process and serialize enabled rules
28
- const rules = Object.keys(resolvedRules).reduce(function(rules, key) {
29
- const value = resolvedRules[key];
30
-
31
- const { category } = linter.parseRuleValue(value);
32
-
33
- if (category === 'off') {
34
- rules[key] = 0;
35
- } else {
36
- rules[key] = value;
37
- }
38
-
39
- return rules;
40
- }, {});
41
-
42
- const serializedRules = JSON.stringify(rules, null, ' ');
43
-
44
- const preambleCode = `
45
- const cache = {};
46
-
47
- /**
48
- * A resolver that caches rules and configuration as part of the bundle,
49
- * making them accessible in the browser.
50
- *
51
- * @param {Object} cache
52
- */
53
- function Resolver() {}
54
-
55
- Resolver.prototype.resolveRule = function(pkg, ruleName) {
56
-
57
- const rule = cache[pkg + '/' + ruleName];
58
-
59
- if (!rule) {
60
- throw new Error('cannot resolve rule <' + pkg + '/' + ruleName + '>: not bundled');
61
- }
62
-
63
- return rule;
64
- };
65
-
66
- Resolver.prototype.resolveConfig = function(pkg, configName) {
67
- throw new Error(
68
- 'cannot resolve config <' + configName + '> in <' + pkg +'>: not bundled'
69
- );
70
- };
71
-
72
- const resolver = new Resolver();
73
-
74
- const rules = ${serializedRules};
75
-
76
- const config = {
77
- rules: rules
78
- };
79
-
80
- const moddleExtensions = {};
81
-
82
- const bundle = {
83
- resolver: resolver,
84
- config: config,
85
- moddleExtensions: moddleExtensions
86
- };
87
-
88
- export { resolver, config, moddleExtensions };
89
-
90
- export default bundle;
91
- `;
92
-
93
- const ruleImportCode = Object.entries(rules).map(([ key, value ], idx) => {
94
-
95
- if (!value) {
96
- return null;
97
- }
98
-
99
- const {
100
- pkg, ruleName
101
- } = linter.parseRuleName(key);
102
-
103
- return createRuleImportStatement(pkg, ruleName, idx, resolver);
104
- }).filter(e => e).join('\n');
105
-
106
- const moddleExtensionsImportCode = Object.entries(config.moddleExtensions || {}).map(([ key, importPath ], idx) => {
107
-
108
- if (typeof importPath !== 'string') {
109
- throw new Error(`illegal value for moddle-extension ${key}: expected <string>`);
110
- }
111
-
112
- return createModdleExtensionStatement(key, importPath, idx);
113
- }).filter(e => e).join('\n');
114
-
115
- return `${preambleCode}${ruleImportCode}\n${moddleExtensionsImportCode}`;
116
- }
117
-
118
- module.exports = compileConfig;
119
-
120
- function requirePkg(resolver, pkg) {
121
- try {
122
- return resolver.require(pkg);
123
- } catch (err) {
124
- return null;
125
- }
126
- }
127
-
128
- function createRuleImportStatement(pkg, ruleName, idx, resolver) {
129
- const originalPkg = pkg;
130
-
131
- pkg = resolver.normalizePkg(pkg);
132
-
133
- const pkgExport = requirePkg(resolver, pkg);
134
-
135
- // (1) try resolving rule via $PKG.rules[$NAME]
136
- if (pkgExport && pkgExport.rules) {
137
- const rules = pkgExport.rules;
138
-
139
- if (ruleName in rules) {
140
- const rule = rules[ruleName];
141
-
142
- if (!isString(rule)) {
143
- throw new Error(
144
- `failed to bundle rule <${ruleName}> from <${ pkg }>: illegal rule export (expected path reference)`
145
- );
146
- }
147
-
148
- const rulePath = computeRuleImport(resolver, pkg, originalPkg, rule);
149
-
150
- return `
151
- import rule_${ idx } from '${rulePath}';
152
-
153
- cache['${ originalPkg }/${ ruleName }'] = rule_${ idx };`;
154
-
155
- }
156
- }
157
-
158
- // (2) resolve rule via $PKG/rules/$NAME
159
- return `
160
- import rule_${ idx } from '${ pkg }/rules/${ ruleName }';
161
-
162
- cache['${ originalPkg }/${ ruleName }'] = rule_${ idx };`;
163
- }
164
-
165
-
166
- /**
167
- * @param {string} key
168
- * @param {string} importPath
169
- * @param {number} idx
170
- *
171
- * @return {string}
172
- */
173
- function createModdleExtensionStatement(key, importPath, idx) {
174
-
175
- // (2) resolve rule via $PKG/rules/$NAME
176
- return `
177
- import moddle_extension_${ idx } from '${ importPath }';
178
-
179
- moddleExtensions['${key}'] = moddle_extension_${ idx };`;
180
- }
181
-
182
- function computeRuleImport(resolver, pkg, originalPkg, rule) {
183
-
184
- // local reference, resolved relative to pkg location
185
- if (rule.startsWith('.')) {
186
- const pkgJsonPath = resolver.require.resolve(`${ pkg }/package.json`);
187
-
188
- const pkgMainPath = resolver.require.resolve(pkg);
189
-
190
- const relativePkgMainPath = path.relative(
191
- path.dirname(pkgJsonPath),
192
- path.dirname(pkgMainPath)
193
- );
194
-
195
- return path.posix.normalize(`${ originalPkg }/${ relativePkgMainPath }/${ rule }`);
196
- } else {
197
-
198
- // absolute reference
199
- return path.posix.normalize(rule);
200
- }
201
- }
3
+ module.exports = createCompileConfig({
4
+ Linter: require('../linter'),
5
+ NodeResolver: require('../resolver/node-resolver')
6
+ });
package/lib/test-rule.js CHANGED
@@ -1,107 +1 @@
1
- const traverse = require('./traverse');
2
-
3
- const {
4
- isArray,
5
- isObject,
6
- isFunction
7
- } = require('min-dash');
8
-
9
-
10
- /**
11
- * @typedef { import('./types.js').EnterFn } EnterFn
12
- * @typedef { import('./types.js').ModdleElement } ModdleElement
13
- * @typedef { import('./types.js').RuleDefinition } RuleDefinition
14
- * @typedef { import('./types.js').Report } Report
15
- */
16
-
17
-
18
- class Reporter {
19
-
20
- /**
21
- * @param { {
22
- * moddleRoot: ModdleElement,
23
- * rule: RuleDefinition
24
- * } } options
25
- */
26
- constructor({ moddleRoot, rule }) {
27
- this.rule = rule;
28
- this.moddleRoot = moddleRoot;
29
-
30
- /**
31
- * @type { Report[] }
32
- */
33
- this.messages = [];
34
-
35
- this.report = this.report.bind(this);
36
- }
37
-
38
- /**
39
- * @param { string } id
40
- * @param { string } message
41
- * @param { string[] | { path?: string[], [key: string]: any } } [path]
42
- *
43
- * @example
44
- *
45
- * ```javascript
46
- * reporter.report('foo', 'Foo error', [ 'foo', 'bar', 'baz' ]);
47
- *
48
- * reporter.report('foo', 'Foo error', {
49
- * path: [ 'foo', 'bar', 'baz' ],
50
- * foo: 'foo'
51
- * });
52
- * ```
53
- */
54
- report(id, message, path) {
55
- let report = {
56
- id,
57
- message
58
- };
59
-
60
- if (path && isArray(path)) {
61
- report = {
62
- ...report,
63
- path
64
- };
65
- }
66
-
67
- if (path && isObject(path)) {
68
- report = {
69
- ...report,
70
- ...path
71
- };
72
- }
73
-
74
- this.messages.push(report);
75
- }
76
- }
77
-
78
- /**
79
- * @param { {
80
- * moddleRoot: ModdleElement,
81
- * rule: RuleDefinition,
82
- * config: any
83
- * } } options
84
- *
85
- * @return { Report[] } lint reports
86
- */
87
- module.exports = function testRule({ moddleRoot, rule }) {
88
- const reporter = new Reporter({ rule, moddleRoot });
89
-
90
- const check = rule.check || {};
91
-
92
- const leave = 'leave' in check ? check.leave : undefined;
93
- const enter = 'enter' in check ? check.enter : (
94
- isFunction(check) ? check : undefined
95
- );
96
-
97
- if (!enter && !leave) {
98
- throw new Error('no check implemented');
99
- }
100
-
101
- traverse(moddleRoot, {
102
- enter: enter ? (node) => enter(node, reporter) : undefined,
103
- leave: leave ? (node) => leave(node, reporter) : undefined
104
- });
105
-
106
- return reporter.messages;
107
- };
1
+ module.exports = require('@bpmn-io/lint-core/lib/test-rule');
@@ -1,73 +1,17 @@
1
1
  // @ts-expect-error 'missing <bpmn-moddle> types'
2
2
  const { BpmnModdle } = require('bpmn-moddle');
3
3
 
4
- const { readFileSync } = require('node:fs');
5
-
6
- /**
7
- * @typedef { any } ModdleElement
8
- *
9
- * @typedef { {
10
- * root: ModdleElement,
11
- * moddle: BpmnModdle,
12
- * warnings: any[]
13
- * } } CreatedModdle
14
- */
15
-
16
- /**
17
- * Create moddle instance.
18
- *
19
- * @param {string} xml the XML string
20
- * @param {string} [elementType]
21
- * @param {Object} [moddleExtensions]
22
- *
23
- * @return {Promise<CreatedModdle>}
24
- */
25
- async function createModdle(xml, elementType = 'bpmn:Definitions', moddleExtensions) {
26
-
27
- if (typeof elementType !== 'string') {
28
- moddleExtensions = elementType;
29
- elementType = undefined;
30
- }
31
-
32
- if (typeof elementType === 'undefined') {
33
- elementType = 'bpmn:Definitions';
34
- }
35
-
36
- const moddle = new BpmnModdle(moddleExtensions);
37
-
38
- const {
39
- rootElement: root,
40
- warnings = []
41
- } = await moddle.fromXML(xml, elementType, { lax: true });
42
-
43
- return {
44
- root,
45
- moddle,
46
-
47
- // @ts-ignore-next-line "legacy"
48
- context: {
49
- warnings
50
- },
51
- warnings
52
- };
53
- }
54
-
55
- module.exports.createModdle = createModdle;
56
-
57
-
58
- /**
59
- * Return moddle instance, read from the given file.
60
- *
61
- * @param {string|URL} filePath
62
- * @param {string} [elementType]
63
- * @param {Object} [moddleExtensions]
64
- *
65
- * @return {Promise<CreatedModdle>}
66
- */
67
- function readModdle(filePath, elementType, moddleExtensions) {
68
- const contents = readFileSync(filePath, 'utf8');
69
-
70
- return createModdle(contents, elementType, moddleExtensions);
71
- }
72
-
73
- module.exports.readModdle = readModdle;
4
+ const { createModdleHelper } = require('@bpmn-io/lint-core/lib/testers/helper');
5
+
6
+ const {
7
+ createModdle,
8
+ readModdle
9
+ } = createModdleHelper({
10
+ Moddle: BpmnModdle,
11
+ rootType: 'bpmn:Definitions'
12
+ });
13
+
14
+ module.exports = {
15
+ createModdle,
16
+ readModdle
17
+ };
@@ -1,31 +1,13 @@
1
- export type TestFn = (...any) => any;
1
+ import type { RuleTests } from '@bpmn-io/lint-core/lib/testers/rule-tester';
2
2
 
3
- export type ModdleElement = any;
4
-
5
- export type ValidRuleTest = {
6
- config?: any,
7
- it?: TestFn,
8
- moddleElement: ModdleElement,
9
- name?: string
10
- };
11
-
12
- export type InvalidReport = {
13
- id: string,
14
- message: string
15
- };
16
-
17
- export type InvalidRuleTest = {
18
- config?: any,
19
- it?: TestFn,
20
- moddleElement: ModdleElement,
21
- name?: string,
22
- report: InvalidReport | InvalidReport[]
23
- };
24
-
25
- export type RuleTests = {
26
- valid?: ValidRuleTest[],
27
- invalid?: InvalidRuleTest[]
28
- };
3
+ export type {
4
+ TestFn,
5
+ ModdleElement,
6
+ ValidRuleTest,
7
+ InvalidReport,
8
+ InvalidRuleTest,
9
+ RuleTests
10
+ } from '@bpmn-io/lint-core/lib/testers/rule-tester';
29
11
 
30
12
  /**
31
13
  * Verify a rule.
@@ -34,4 +16,4 @@ export type RuleTests = {
34
16
  * @param rule the rule implementation
35
17
  * @param tests the tests to verify
36
18
  */
37
- export function verify(ruleName: string, rule: any, tests: RuleTests): void;
19
+ export function verify(ruleName: string, rule: any, tests: RuleTests): void;
@@ -1,147 +1,17 @@
1
- /* global it, describe, beforeEach */
1
+ const { createRuleTester } = require('@bpmn-io/lint-core/lib/testers/rule-tester');
2
2
 
3
- const assert = require('assert');
4
-
5
- const Linter = require('../linter');
6
-
7
- function createResolver(rule) {
8
-
9
- return {
10
- resolveRule: () => Promise.resolve(rule),
11
-
12
- resolveConfig: () => {
13
- throw new Error('not implemented');
14
- }
15
- };
16
- }
17
-
18
- function expectEqual(a, b) {
19
- assert.deepStrictEqual(JSON.stringify(a, replacer, 2), JSON.stringify(b, replacer, 2));
20
- }
21
-
22
- function verify(ruleName, rule, testCases) {
23
- function createLinterConfig(config = {}) {
24
- return {
25
- rules: { [ruleName]: [ 2, config ] }
26
- };
27
- }
28
-
29
- describe(`rules/${ruleName}`, function() {
30
-
31
- let linter;
32
-
33
- beforeEach(function() {
34
- linter = new Linter({
35
- resolver: createResolver(rule)
36
- });
37
- });
38
-
39
-
40
- describe('should lint valid', function() {
41
-
42
- testCases.valid.forEach(({ config = {}, it: _it, moddleElement, name }, idx) => (
43
-
44
- (_it || it)(getTitle(idx, name), function() {
45
- return (
46
- Promise.resolve(moddleElement)
47
- .then(moddleRoot => {
48
- return linter.lint(moddleRoot.root, createLinterConfig(config));
49
- })
50
- .then(lintResults => {
51
- expectEqual(lintResults, {});
52
- })
53
- );
54
- })
55
-
56
- ));
57
-
58
- });
59
-
60
-
61
- describe('should lint invalid', function() {
62
-
63
- testCases.invalid.forEach(({ config = {}, it: _it, moddleElement, name, report }, idx) => (
64
-
65
- (_it || it)(getTitle(idx, name), async function() {
66
-
67
- if (!Array.isArray(report)) {
68
- report = [
69
- report
70
- ];
71
- }
72
-
73
- const {
74
- meta
75
- } = await linter.resolveRule(name, config);
76
-
77
- const expectedResults = report.map(report => {
78
- return {
79
- ...report,
80
- meta,
81
- category: 'error'
82
- };
83
- });
84
-
85
- const expectedLintResults = {
86
- [ruleName]: expectedResults
87
- };
88
-
89
- return (
90
- Promise.resolve(moddleElement)
91
- .then(moddleRoot => {
92
- return linter.lint(moddleRoot.root, createLinterConfig(config));
93
- })
94
- .then(lintResults => {
95
- expectEqual(lintResults, expectedLintResults);
96
- })
97
- );
98
- })
99
-
100
- ));
101
-
102
- });
103
-
104
- });
105
-
106
- }
107
-
108
- function getTitle(idx, name) {
109
- return `test case #${ idx + 1 }${ name ? ` ${ name }` : '' }`;
110
- }
111
-
112
- function replacer(_, value) {
113
- if (!value) {
114
- return value;
115
- }
116
-
117
- const { $type } = value;
118
-
119
- if ($type) {
120
- const { $descriptor } = value;
121
-
122
- const { idProperty } = $descriptor;
123
-
124
- if (idProperty) {
125
- const { name } = idProperty;
126
-
127
- const id = value.get(name);
128
-
129
- if (id) {
130
- return id;
131
- } else {
132
- return $type;
133
- }
134
- } else {
135
- return $type;
136
- }
137
- }
138
-
139
- return value;
140
- }
3
+ const {
4
+ expectEqual,
5
+ verify,
6
+ getTitle,
7
+ replacer
8
+ } = createRuleTester({
9
+ Linter: require('../linter')
10
+ });
141
11
 
142
12
  module.exports = {
143
13
  expectEqual,
144
14
  verify,
145
15
  getTitle,
146
16
  replacer
147
- };
17
+ };
package/lib/traverse.js CHANGED
@@ -1,56 +1 @@
1
- /**
2
- * @typedef { import('./types.js').ModdleElement } ModdleElement
3
- *
4
- * @typedef { (element: ModdleElement) => boolean | void } EnterFn
5
- * @typedef { (element: ModdleElement) => void } LeaveFn
6
- */
7
-
8
- /**
9
- * Check if a type is simple, primitive.
10
- *
11
- * @param {string} type
12
- * @return {boolean}
13
- */
14
- function isSimpleType(type) {
15
- return [ 'String', 'Boolean', 'Integer', 'Real' ].includes(type);
16
- }
17
-
18
- /**
19
- * Traverse a moddle tree, depth first from top to bottom
20
- * and call the passed visitor fn.
21
- *
22
- * @param { ModdleElement } element
23
- * @param { { enter?: EnterFn; leave?: LeaveFn } } options
24
- */
25
- module.exports = function traverse(element, options) {
26
-
27
- const enter = options.enter;
28
- const leave = options.leave;
29
-
30
- const enterSubTree = enter && enter(element);
31
-
32
- const descriptor = element.$descriptor;
33
-
34
- if (enterSubTree !== false && !descriptor.isGeneric) {
35
-
36
- const containedProperties = descriptor.properties.filter(p => {
37
- return !p.isAttr && !p.isReference && !isSimpleType(p.type);
38
- });
39
-
40
- containedProperties.forEach(p => {
41
- if (p.name in element) {
42
- const propertyValue = element[p.name];
43
-
44
- if (p.isMany) {
45
- propertyValue.forEach(child => {
46
- traverse(child, options);
47
- });
48
- } else {
49
- traverse(propertyValue, options);
50
- }
51
- }
52
- });
53
- }
54
-
55
- leave && leave(element);
56
- };
1
+ module.exports = require('@bpmn-io/lint-core/lib/traverse');