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.
package/lib/linter.js CHANGED
@@ -1,543 +1,3 @@
1
- const testRule = require('./test-rule');
1
+ const { createLinter } = require('@bpmn-io/lint-core/lib/linter');
2
2
 
3
-
4
- /**
5
- * @typedef { import('./types.js').ModdleElement } ModdleElement
6
- *
7
- * @typedef { import('./types.js').ReportingCategory } ReportingCategory
8
- * @typedef { import('./types.js').ReportingCategoryMap } ReportingCategoryMap
9
- * @typedef { import('./types.js').RuleErrorCategory } RuleErrorCategory
10
- *
11
- * @typedef { import('./types.js').Resolver } Resolver
12
- * @typedef { import('./types.js').Config } Config
13
- *
14
- * @typedef { import('./types.js').RuleFactory } RuleFactory
15
- *
16
- * @typedef { import('./types.js').RuleDefinition } RuleDefinition
17
- * @typedef { import('./types.js').RuleConfigs } RuleConfigs
18
- * @typedef { import('./types.js').RuleConfig } RuleConfig
19
- *
20
- * @typedef { {
21
- * name: string,
22
- * rule: RuleDefinition,
23
- * config: any,
24
- * category: ReportingCategory
25
- * } } ResolvedRuleDefinition
26
- *
27
- * @typedef { import('./types.js').Report } Report
28
- * @typedef { Report & Pick<RuleDefinition, 'meta'> & {
29
- * category: ReportingCategory | RuleErrorCategory
30
- * } } AnnotatedReport
31
- *
32
- * @typedef { import('./types.js').TransformRuleFn } TransformRuleFn
33
- *
34
- * @typedef { Record<string, AnnotatedReport[]> } LintResults
35
- */
36
-
37
-
38
- /**
39
- * Transform a rule after it is loaded.
40
- *
41
- * @param { RuleDefinition } rule
42
- * @param { { pkg: string, ruleName: string } } options
43
- */
44
- const noopTransformRule = (rule, options) => {
45
- return rule;
46
- };
47
-
48
-
49
- /**
50
- * @typeof { ReportingCategoryMap }
51
- */
52
- const categoryMap = {
53
- 0: 'off',
54
- 1: 'warn',
55
- 2: 'error',
56
- 3: 'info'
57
- };
58
-
59
- /**
60
- * @type { RuleErrorCategory }
61
- */
62
- const ruleErrorCategory = 'rule-error';
63
-
64
- /**
65
- * @param { {
66
- * config?: Config,
67
- * resolver: Resolver,
68
- * transformRule?: TransformRuleFn
69
- * } } options
70
- */
71
- function Linter(options) {
72
-
73
- const {
74
- config = {},
75
- resolver,
76
- transformRule = noopTransformRule
77
- } = options || {};
78
-
79
- if (typeof resolver === 'undefined') {
80
- throw new Error('must provide <options.resolver>');
81
- }
82
-
83
- this.config = config;
84
- this.resolver = resolver;
85
-
86
- this.transformRule = transformRule;
87
-
88
- /**
89
- * @type { Record<string, RuleDefinition> }
90
- */
91
- this.cachedRules = {};
92
-
93
- /**
94
- * @type { Record<string, Config> }
95
- */
96
- this.cachedConfigs = {};
97
- }
98
-
99
-
100
- module.exports = Linter;
101
-
102
- /**
103
- * Applies a rule on the moddleRoot and adds reports to the finalReport
104
- *
105
- * @param { ModdleElement } moddleRoot
106
- *
107
- * @param { ResolvedRuleDefinition } ruleDefinition
108
- *
109
- * @return { AnnotatedReport[] } reports
110
- */
111
- Linter.prototype.applyRule = function applyRule(moddleRoot, ruleDefinition) {
112
-
113
- const {
114
- config,
115
- rule,
116
- category,
117
- name
118
- } = ruleDefinition;
119
-
120
- try {
121
-
122
- const reports = testRule({
123
- moddleRoot,
124
- rule,
125
- config
126
- });
127
-
128
- return reports.map(function(report) {
129
- return {
130
- ...report,
131
- meta: rule.meta,
132
- category
133
- };
134
- });
135
- } catch (e) {
136
- console.error('rule <' + name + '> failed with error: ', e);
137
-
138
- return [
139
- {
140
- message: /** @type { Error } */ (e).message,
141
- category: ruleErrorCategory
142
- }
143
- ];
144
- }
145
-
146
- };
147
-
148
-
149
- /**
150
- * @param { string } name
151
- * @param { RuleConfig } config
152
- *
153
- * @return { Promise<RuleDefinition> }
154
- */
155
- Linter.prototype.resolveRule = function(name, config) {
156
-
157
- const {
158
- pkg,
159
- ruleName
160
- } = this.parseRuleName(name);
161
-
162
- const id = `${pkg}-${ruleName}`;
163
-
164
- const rule = this.cachedRules[id];
165
-
166
- if (rule) {
167
- return Promise.resolve(rule);
168
- }
169
-
170
- return Promise.resolve(this.resolver.resolveRule(pkg, ruleName)).then((ruleFactory) => {
171
-
172
- if (!ruleFactory) {
173
- throw new Error(`unknown rule <${name}>`);
174
- }
175
-
176
- const rule = this.cachedRules[id] = this.transformRule(ruleFactory(config), { pkg, ruleName });
177
-
178
- return rule;
179
- });
180
- };
181
-
182
- /**
183
- * @param {string} name
184
- *
185
- * @return {Promise<Config>}
186
- */
187
- Linter.prototype.resolveConfig = function(name) {
188
-
189
- const {
190
- pkg,
191
- configName
192
- } = this.parseConfigName(name);
193
-
194
- const id = `${pkg}-${configName}`;
195
-
196
- const config = this.cachedConfigs[id];
197
-
198
- if (config) {
199
- return Promise.resolve(config);
200
- }
201
-
202
- return Promise.resolve(this.resolver.resolveConfig(pkg, configName)).then((config) => {
203
-
204
- if (!config) {
205
- throw new Error(`unknown config <${name}>`);
206
- }
207
-
208
- const actualConfig = this.cachedConfigs[id] = this.normalizeConfig(config, pkg);
209
-
210
- return actualConfig;
211
- });
212
- };
213
-
214
- /**
215
- * Take a linter config and return list of resolved rules.
216
- *
217
- * @param { Config } config
218
- *
219
- * @return { Promise<ResolvedRuleDefinition[]> }
220
- */
221
- Linter.prototype.resolveRules = function(config) {
222
-
223
- return this.resolveConfiguredRules(config).then((rulesConfig) => {
224
-
225
- // parse rule values
226
- const parsedRules = Object.entries(rulesConfig).map(([ name, value ]) => {
227
- const {
228
- category,
229
- config
230
- } = this.parseRuleValue(value);
231
-
232
- return {
233
- name,
234
- category,
235
- config
236
- };
237
- });
238
-
239
- // filter only for enabled rules
240
- const enabledRules = parsedRules.filter(definition => definition.category !== 'off');
241
-
242
- // load enabled rules
243
- const loaders = enabledRules.map((definition) => {
244
-
245
- const {
246
- name,
247
- config
248
- } = definition;
249
-
250
- return this.resolveRule(name, config).then(function(rule) {
251
- return {
252
- ...definition,
253
- rule
254
- };
255
- });
256
- });
257
-
258
- return Promise.all(loaders);
259
- });
260
- };
261
-
262
- /**
263
- * @param { Config } config
264
- *
265
- * @return { Promise<RuleConfigs> }
266
- */
267
- Linter.prototype.resolveConfiguredRules = function(config) {
268
-
269
- let parents = config.extends;
270
-
271
- if (typeof parents === 'string') {
272
- parents = [ parents ];
273
- }
274
-
275
- if (typeof parents === 'undefined') {
276
- parents = [];
277
- }
278
-
279
- return Promise.all(
280
- parents.map((configName) => {
281
- return this.resolveConfig(configName).then((config) => {
282
- return this.resolveConfiguredRules(config);
283
- });
284
- })
285
- ).then((inheritedRules) => {
286
-
287
- const overrideRules = this.normalizeConfig(config, 'bpmnlint').rules;
288
-
289
- const rules = [ ...inheritedRules, overrideRules ].reduce((rules, currentRules) => {
290
- return {
291
- ...rules,
292
- ...currentRules
293
- };
294
- }, {});
295
-
296
- return rules;
297
- });
298
- };
299
-
300
-
301
- /**
302
- * Lint the given model root, using the specified linter config.
303
- *
304
- * @param { ModdleElement } moddleRoot
305
- * @param { Config } [config] the bpmnlint configuration to use
306
- *
307
- * @return { Promise<LintResults> } lint results, keyed by rule names
308
- */
309
- Linter.prototype.lint = function(moddleRoot, config) {
310
-
311
- config = config || this.config;
312
-
313
- // load rules
314
- return this.resolveRules(config).then((ruleDefinitions) => {
315
-
316
- /**
317
- * @type { LintResults }
318
- */
319
- const allReports = {};
320
-
321
- ruleDefinitions.forEach((ruleDefinition) => {
322
-
323
- const {
324
- name
325
- } = ruleDefinition;
326
-
327
- const reports = this.applyRule(moddleRoot, ruleDefinition);
328
-
329
- if (reports.length) {
330
- allReports[name] = reports;
331
- }
332
- });
333
-
334
- return allReports;
335
- });
336
- };
337
-
338
- /**
339
- * @param { import('./types.js').RuleConfig } value
340
- *
341
- * @return { { config: any, category: ReportingCategory } }
342
- */
343
- Linter.prototype.parseRuleValue = function(value) {
344
-
345
- let category;
346
- let config;
347
-
348
- if (Array.isArray(value)) {
349
- category = value[0];
350
- config = value[1];
351
- } else {
352
- category = value;
353
- config = {};
354
- }
355
-
356
- // normalize rule flag to <error> and <warn> which
357
- // may be upper case or a number at this point
358
- if (typeof category === 'string') {
359
- category = category.toLowerCase();
360
- }
361
-
362
- category = categoryMap[category] || category;
363
-
364
- return {
365
- config,
366
- category
367
- };
368
- };
369
-
370
- Linter.prototype.parseRuleName = function(name, localPackage = 'bpmnlint') {
371
-
372
- /**
373
- * We recognize the following rule name patterns:
374
- *
375
- * {RULE_NAME} => PKG = 'bpmnlint'
376
- * bpmnlint/{RULE_NAME} => PKG = 'bpmnlint'
377
- * {PACKAGE_SHORTCUT}/{RULE_NAME} => PKG = 'bpmnlint-plugin-{PACKAGE_SHORTCUT}'
378
- * bpmnlint-plugin-{PACKAGE_SHORTCUT}/{RULE_NAME} => PKG = 'bpmnlint-plugin-{PACKAGE_SHORTCUT}'
379
- * @scope/{PACKAGE_SHORTCUT}/{RULE_NAME} => PKG = '@scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}'
380
- * @scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}/{RULE_NAME} => PKG = '@scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}'
381
- */
382
-
383
- const match = /^(?:(?:(@[^/]+)\/)?([^@]{1}[^/]*)\/)?([^/]+)$/.exec(name);
384
-
385
- if (!match) {
386
- throw new Error(`unparseable rule name <${name}>`);
387
- }
388
-
389
- const [
390
- _,
391
- ns,
392
- packageName,
393
- ruleName
394
- ] = match;
395
-
396
- if (!packageName) {
397
- return {
398
- pkg: localPackage,
399
- ruleName
400
- };
401
- }
402
-
403
- const pkg = `${ns ? ns + '/' : '' }${prefixPackage(packageName)}`;
404
-
405
- return {
406
- pkg,
407
- ruleName
408
- };
409
- };
410
-
411
-
412
- Linter.prototype.parseConfigName = function(name) {
413
-
414
- /**
415
- * We recognize the following config name patterns:
416
- *
417
- * bpmnlint:{CONFIG_NAME} => PKG = 'bpmnlint'
418
- * plugin:{PACKAGE_SHORTCUT}/{CONFIG_NAME} => PKG = 'bpmnlint-plugin-{PACKAGE_SHORTCUT}'
419
- * plugin:bpmnlint-plugin-{PACKAGE_SHORTCUT}/{CONFIG_NAME} => PKG = 'bpmnlint-plugin-{PACKAGE_SHORTCUT}'
420
- * plugin:@scope/{PACKAGE_SHORTCUT}/{CONFIG_NAME} => PKG = '@scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}'
421
- * plugin:@scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}/{CONFIG_NAME} => PKG = '@scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}'
422
- */
423
-
424
- const match = /^(?:(?:plugin:(?:(@[^/]+)\/)?([^@]{1}[^/]*)\/)|bpmnlint:)([^/]+)$/.exec(name);
425
-
426
- if (!match) {
427
- throw new Error(`unparseable config name <${name}>`);
428
- }
429
-
430
- const [
431
- _,
432
- ns,
433
- packageName,
434
- configName
435
- ] = match;
436
-
437
- if (!packageName) {
438
- return {
439
- pkg: 'bpmnlint',
440
- configName
441
- };
442
- }
443
-
444
- const pkg = `${ns ? ns + '/' : '' }${prefixPackage(packageName)}`;
445
-
446
- return {
447
- pkg,
448
- configName
449
- };
450
- };
451
-
452
-
453
- Linter.prototype.getSimplePackageName = function(name) {
454
-
455
- /**
456
- * We recognize the following package name patterns:
457
- *
458
- * bpmnlint => PKG = 'bpmnlint'
459
- * {PACKAGE_SHORTCUT} => PKG = PACKAGE_SHORTCUT
460
- * bpmnlint-plugin-{PACKAGE_SHORTCUT}' => PKG = PACKAGE_SHORTCUT
461
- * @scope/{PACKAGE_SHORTCUT} => PKG = '@scope/{PACKAGE_SHORTCUT}'
462
- * @scope/bpmnlint-plugin-{PACKAGE_SHORTCUT}' => PKG = '@scope/PACKAGE_SHORTCUT'
463
- */
464
-
465
- const match = /^(?:(@[^/]+)\/)?([^/]+)$/.exec(name);
466
-
467
- if (!match) {
468
- throw new Error(`unparseable package name <${name}>`);
469
- }
470
-
471
- const [
472
- _,
473
- ns,
474
- packageName
475
- ] = match;
476
-
477
- return `${ns ? ns + '/' : '' }${unprefixPackage(packageName)}`;
478
- };
479
-
480
-
481
- /**
482
- * Validate and return validated config.
483
- *
484
- * @param {Object} config
485
- * @param {String} localPackage
486
- *
487
- * @return {Object} validated config
488
- */
489
- Linter.prototype.normalizeConfig = function(config, localPackage) {
490
-
491
- const rules = config.rules || {};
492
-
493
- const validatedRules = Object.keys(rules).reduce((normalizedRules, name) => {
494
-
495
- const value = rules[name];
496
-
497
- const {
498
- pkg,
499
- ruleName
500
- } = this.parseRuleName(name, localPackage);
501
-
502
- const normalizedName = (
503
- pkg === 'bpmnlint'
504
- ? ruleName
505
- : `${this.getSimplePackageName(pkg)}/${ruleName}`
506
- );
507
-
508
- normalizedRules[normalizedName] = value;
509
-
510
- return normalizedRules;
511
- }, {});
512
-
513
- return {
514
- ...config,
515
- rules: validatedRules
516
- };
517
- };
518
-
519
-
520
- // helpers ///////////////////////////
521
-
522
- function prefixPackage(pkg) {
523
-
524
- if (pkg === 'bpmnlint') {
525
- return 'bpmnlint';
526
- }
527
-
528
- if (pkg.startsWith('bpmnlint-plugin-')) {
529
- return pkg;
530
- }
531
-
532
- return `bpmnlint-plugin-${pkg}`;
533
- }
534
-
535
-
536
- function unprefixPackage(pkg) {
537
-
538
- if (pkg.startsWith('bpmnlint-plugin-')) {
539
- return pkg.substring('bpmnlint-plugin-'.length);
540
- }
541
-
542
- return pkg;
543
- }
3
+ module.exports = createLinter(require('./product'));
package/lib/product.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @type { import('@bpmn-io/lint-core/lib/types').Product }
3
+ */
4
+ module.exports = {
5
+ name: 'bpmnlint'
6
+ };
@@ -1,12 +1 @@
1
- const Module = require('node:module');
2
- const path = require('node:path');
3
-
4
- /**
5
- * Create require function for a given path.
6
- *
7
- * @param {string} cwd
8
- * @returns {NodeRequire}
9
- */
10
- module.exports.createScopedRequire = function(cwd) {
11
- return Module.createRequire(path.join(cwd, '__placeholder__.js'));
12
- };
1
+ module.exports = require('@bpmn-io/lint-core/lib/resolver/helper');
@@ -1,136 +1,7 @@
1
- const path = require('node:path');
2
- const { cwd } = require('node:process');
1
+ const { createNodeResolver } = require('@bpmn-io/lint-core/lib/resolver/node-resolver');
3
2
 
4
- const { isString } = require('min-dash');
5
-
6
- /**
7
- * @typedef { import('../types.js').RuleFactory } RuleFactory
8
- * @typedef { import('../types.js').Config } Config
9
- */
10
-
11
- const { createScopedRequire } = require('./helper');
12
-
13
- /**
14
- * A resolver that locates rules and configurations
15
- * using node module resolution.
16
- *
17
- * @param { { require?: NodeRequire, requireLocal?: NodeRequire } } [options]
18
- */
19
- function NodeResolver(options) {
20
- this.require = options && options.require || createScopedRequire(cwd());
21
-
22
- this.requireLocal = options && options.requireLocal || require;
23
-
24
- try {
25
- this.pkg = this.require('./package.json').name;
26
- } catch (err) {
27
- this.pkg = '__unknown';
28
- }
29
- }
30
-
31
- module.exports = NodeResolver;
32
-
33
-
34
- /**
35
- * @param { string } pkg
36
- * @param { string } ruleName
37
- *
38
- * @return { RuleFactory }
39
- */
40
- NodeResolver.prototype.resolveRule = function(pkg, ruleName) {
41
-
42
- const originalPkg = pkg;
43
-
44
- pkg = this.normalizePkg(pkg);
45
-
46
- let pkgInstance;
47
-
48
- // (1) try resolving rule via $PKG.rules[$NAME]
49
- try {
50
- pkgInstance = this.require(pkg);
51
- } catch (err) {
52
-
53
- /* ignore */
54
- }
55
-
56
- if (pkgInstance) {
57
- const rules = pkgInstance.rules || {};
58
-
59
- if (ruleName in rules) {
60
- const rule = rules[ruleName];
61
-
62
- if (!isString(rule)) {
63
- throw new Error('cannot resolve rule <' + ruleName + '> from <' + originalPkg + '>: illegal rule export (expected path reference)');
64
- }
65
-
66
- // local reference, resolved relative to pkg location
67
- if (rule.startsWith('.')) {
68
- const pkgDir = path.dirname(this.require.resolve(pkg));
69
-
70
- return this.require(path.posix.normalize(`${ pkgDir }/${ rule }`));
71
- }
72
-
73
- // absolute reference
74
- return this.require(rule);
75
- }
76
- }
77
-
78
- // (2) try resolving rule via $PKG/rules/$NAME
79
- try {
80
- if (pkg === 'bpmnlint') {
81
- return this.requireLocal(`../../rules/${ruleName}`);
82
- } else {
83
- return this.require(`${pkg}/rules/${ruleName}`);
84
- }
85
- } catch (err) { /* ignore */ }
86
-
87
- throw new Error('cannot resolve rule <' + ruleName + '> from <' + originalPkg + '>');
88
- };
89
-
90
- /**
91
- * @param { string } pkg
92
- * @param { string } configName
93
- *
94
- * @return { Config }
95
- */
96
- NodeResolver.prototype.resolveConfig = function(pkg, configName) {
97
-
98
- const originalPkg = pkg;
99
-
100
- pkg = this.normalizePkg(pkg);
101
-
102
- // (1) try resolving config via $PKG.configs[$NAME]
103
- try {
104
- const instance = this.require(pkg);
105
-
106
- const configs = instance.configs || {};
107
-
108
- if (configName in configs) {
109
- return configs[configName];
110
- }
111
- } catch (err) {
112
-
113
- /* ignore */
114
- }
115
-
116
- // (2) try resolving config via $PKG/config/$NAME
117
- try {
118
- if (pkg === 'bpmnlint') {
119
- return this.requireLocal(`../../config/${configName}`);
120
- } else {
121
- return this.require(`${pkg}/config/${configName}`);
122
- }
123
- } catch (err) { /* ignore */ }
124
-
125
- throw new Error(
126
- 'cannot resolve config <' + configName + '> from <' + originalPkg + '>'
127
- );
128
- };
129
-
130
- NodeResolver.prototype.normalizePkg = function(pkg) {
131
- if (pkg !== 'bpmnlint' && pkg === this.pkg) {
132
- pkg = '.';
133
- }
134
-
135
- return pkg;
136
- };
3
+ // rules and configs of this package are resolved relative to this file,
4
+ // i.e. via ../../rules/* and ../../config/*
5
+ module.exports = createNodeResolver(require('../product'), {
6
+ requireLocal: require
7
+ });