@markuplint/rules 3.0.0-rc.5 → 3.0.1

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/debug.js CHANGED
@@ -3,4 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.log = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const debug_1 = tslib_1.__importDefault(require("debug"));
6
- exports.log = (0, debug_1.default)('markuplint-rules');
6
+ exports.log = (0, debug_1.default)('ml-rules');
@@ -1,14 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.choice = void 0;
4
+ const debug_1 = require("./debug");
4
5
  const order_1 = require("./order");
5
6
  const utils_1 = require("./utils");
7
+ const indexes = new WeakMap();
6
8
  function choice(pattern, elements, specs, options, depth) {
9
+ const choiceLog = debug_1.cmLog.extend(`choice#${depth}`);
7
10
  const collection = new utils_1.Collection(elements);
8
11
  const unmatchedResults = [];
12
+ let i = 0;
9
13
  for (const some of pattern.choice) {
14
+ choiceLog('Patterns[%s]: %s', i, (0, utils_1.modelLog)(some, ''));
10
15
  const result = (0, order_1.order)(some, collection.unmatched, specs, options, depth + 1);
11
16
  if (result.type === 'UNEXPECTED_EXTRA_NODE' || result.type === 'MATCHED' || result.type === 'MATCHED_ZERO') {
17
+ choiceLog('Results[%s]: %s', i, choiceLogString(pattern.choice, i));
12
18
  collection.addMatched(result.matched);
13
19
  return {
14
20
  type: result.type,
@@ -20,11 +26,27 @@ function choice(pattern, elements, specs, options, depth) {
20
26
  };
21
27
  }
22
28
  unmatchedResults.push(result);
29
+ indexes.set(result, i);
30
+ i++;
23
31
  }
24
- const barelyMatchedResult = unmatchedResults.sort((a, b) => b.matched.length - a.matched.length)[0];
32
+ const barelyMatchedResult = unmatchedResults.sort((a, b) => {
33
+ var _c, _d, _e, _f;
34
+ const computed1 = b.matched.length - a.matched.length;
35
+ if (computed1 !== 0) {
36
+ return computed1;
37
+ }
38
+ const _a = (_d = (_c = a.hint.missing) === null || _c === void 0 ? void 0 : _c.barelyMatchedElements) !== null && _d !== void 0 ? _d : 0;
39
+ const _b = (_f = (_e = b.hint.missing) === null || _e === void 0 ? void 0 : _e.barelyMatchedElements) !== null && _f !== void 0 ? _f : 0;
40
+ const computed2 = _b - _a;
41
+ return computed2;
42
+ })[0];
25
43
  if (!barelyMatchedResult) {
26
44
  throw new Error('Unreachable code');
27
45
  }
46
+ const index = indexes.get(barelyMatchedResult);
47
+ if (index != null) {
48
+ choiceLog('Results[%s]: %s', index, choiceLogString(pattern.choice, index, true));
49
+ }
28
50
  return {
29
51
  type: barelyMatchedResult.type,
30
52
  matched: collection.matched,
@@ -35,3 +57,14 @@ function choice(pattern, elements, specs, options, depth) {
35
57
  };
36
58
  }
37
59
  exports.choice = choice;
60
+ function choiceLogString(choice, index, barely = false) {
61
+ const colorFn = barely ? debug_1.bgBlue : debug_1.bgGreen;
62
+ return choice
63
+ .map((pattern, i) => {
64
+ if (i === index) {
65
+ return colorFn((0, utils_1.modelLog)(pattern, ''));
66
+ }
67
+ return (0, utils_1.modelLog)(pattern, '');
68
+ })
69
+ .join(', ');
70
+ }
@@ -15,94 +15,72 @@ const utils_1 = require("./utils");
15
15
  * @returns
16
16
  */
17
17
  function countPattern(pattern, elements, specs, options, depth) {
18
- var _a, _b, _c, _d, _e;
19
18
  const ptLog = debug_1.cmLog.extend(`countPattern#${depth}`);
20
19
  const collection = new utils_1.Collection(elements);
21
- let min;
22
- let max;
23
- let model;
24
- let type;
25
- let _type;
26
- if ((0, utils_1.isRequire)(pattern)) {
27
- min = (_a = pattern.min) !== null && _a !== void 0 ? _a : 1;
28
- max = Math.max((_b = pattern.max) !== null && _b !== void 0 ? _b : 1, min);
29
- model = pattern.require;
30
- type = 'MISSING_NODE_REQUIRED';
31
- _type = 'require';
32
- }
33
- else if ((0, utils_1.isOptional)(pattern)) {
34
- min = 0;
35
- max = Math.max((_c = pattern.max) !== null && _c !== void 0 ? _c : 1, 1);
36
- model = pattern.optional;
37
- _type = 'optional';
38
- }
39
- else if ((0, utils_1.isOneOrMore)(pattern)) {
40
- min = 1;
41
- max = Math.max((_d = pattern.max) !== null && _d !== void 0 ? _d : Infinity, 1);
42
- model = pattern.oneOrMore;
43
- type = 'MISSING_NODE_ONE_OR_MORE';
44
- _type = 'one or more';
45
- }
46
- else if ((0, utils_1.isZeroOrMore)(pattern)) {
47
- min = 0;
48
- max = Math.max((_e = pattern.max) !== null && _e !== void 0 ? _e : Infinity, 1);
49
- model = pattern.zeroOrMore;
50
- _type = 'zero or more';
51
- }
52
- else {
53
- throw new Error('Unreachable code');
54
- }
55
- ptLog('%s: %o', _type, model);
20
+ const { model, min, max, repeat, missingType } = (0, utils_1.normalizeModel)(pattern);
21
+ ptLog('Model:\n RegEx: %s\n Schema: %o', (0, utils_1.modelLog)(model, repeat), pattern);
56
22
  let prevResult = null;
23
+ let barelyResult = null;
24
+ let loopCount = 0;
57
25
  // eslint-disable-next-line no-constant-condition
58
26
  while (true) {
59
- ptLog('%s', collection);
27
+ loopCount++;
28
+ ptLog('Check#%s: %s', loopCount, collection);
60
29
  const result = (0, recursive_branch_1.recursiveBranch)(model, collection.unmatched, specs, options, depth);
61
30
  const added = collection.addMatched(result.matched);
31
+ const { matchedCount } = collection;
62
32
  if (result.type === 'UNMATCHED_SELECTOR_BUT_MAY_EMPTY') {
63
- ptLog('MATCHED_ZERO: %s', result.query);
64
- return {
33
+ ptLog('MATCHED_ZERO:\n model: %s\n max: %s\n collection: %s\n matched element: %s', (0, utils_1.modelLog)(model, repeat), max, collection, matchedCount);
34
+ return compereResult({
65
35
  type: 'MATCHED_ZERO',
66
36
  matched: collection.matched,
67
37
  unmatched: collection.unmatched,
68
38
  zeroMatch: true,
69
39
  query: result.query,
70
40
  hint: result.hint,
71
- };
41
+ }, barelyResult);
72
42
  }
73
43
  if (max < collection.matchedCount) {
74
44
  collection.max(max);
75
- ptLog('UNEXPECTED_EXTRA_NODE (max: %s): %s', max, result.query);
76
- return {
45
+ ptLog('UNEXPECTED_EXTRA_NODE:\n model: %s\n max: %s\n collection: %s\n matched element: %s', (0, utils_1.modelLog)(model, repeat), max, collection, matchedCount);
46
+ return compereResult({
77
47
  type: 'UNEXPECTED_EXTRA_NODE',
78
48
  matched: collection.matched,
79
49
  unmatched: collection.unmatched,
80
50
  zeroMatch: result.zeroMatch,
81
51
  query: result.query,
82
- hint: {
83
- ...result.hint,
84
- max,
85
- },
86
- };
52
+ hint: (0, utils_1.mergeHints)(result.hint, { max }),
53
+ }, barelyResult);
87
54
  }
88
55
  if (prevResult) {
89
56
  if (result.type === 'MISSING_NODE_ONE_OR_MORE' ||
90
57
  result.type === 'MISSING_NODE_REQUIRED' ||
91
58
  result.type === 'TRANSPARENT_MODEL_DISALLOWS') {
92
- ptLog('%s(continued): %s', result.type, collection);
93
- return {
59
+ ptLog('%s(continued): %s; Needs', result.type, collection, result.query);
60
+ return compereResult({
94
61
  type: result.type,
95
62
  matched: collection.matched,
96
63
  unmatched: collection.unmatched,
97
64
  zeroMatch: result.zeroMatch,
98
65
  query: result.query,
99
66
  hint: result.hint,
100
- };
67
+ }, barelyResult);
101
68
  }
102
69
  ptLog('%s(continued): %s', prevResult.type, collection);
103
- return prevResult;
70
+ return compereResult(prevResult, barelyResult);
104
71
  }
105
72
  if (added && collection.unmatched.length > 0) {
73
+ if (result.type !== 'MISSING_NODE' && result.type !== 'UNMATCHED_SELECTORS') {
74
+ barelyResult = {
75
+ type: result.type,
76
+ matched: collection.matched,
77
+ unmatched: collection.unmatched,
78
+ zeroMatch: result.zeroMatch,
79
+ query: result.query,
80
+ hint: result.hint,
81
+ };
82
+ }
83
+ ptLog('continue⤴️');
106
84
  continue;
107
85
  }
108
86
  if (collection.matchedCount + (result.zeroMatch ? 1 : 0) < min) {
@@ -110,16 +88,21 @@ function countPattern(pattern, elements, specs, options, depth) {
110
88
  result.type === 'MISSING_NODE_ONE_OR_MORE' ||
111
89
  result.type === 'TRANSPARENT_MODEL_DISALLOWS'
112
90
  ? result.type
113
- : type !== null && type !== void 0 ? type : 'MISSING_NODE_REQUIRED';
114
- ptLog('%s(in %s): %s', resultType, type, result.query);
115
- return {
91
+ : missingType !== null && missingType !== void 0 ? missingType : 'MISSING_NODE_REQUIRED';
92
+ ptLog('%s(in %s); Needs %s', resultType, missingType, result.query);
93
+ return compereResult({
116
94
  type: resultType,
117
95
  matched: collection.matched,
118
96
  unmatched: collection.unmatched,
119
97
  zeroMatch: result.zeroMatch,
120
98
  query: result.query,
121
- hint: result.hint,
122
- };
99
+ hint: (0, utils_1.mergeHints)(result.hint, {
100
+ missing: {
101
+ barelyMatchedElements: collection.matched.length,
102
+ need: result.query,
103
+ },
104
+ }),
105
+ }, barelyResult);
123
106
  }
124
107
  const resultType = collection.matched.length === 0 ? 'MATCHED_ZERO' : 'MATCHED';
125
108
  const zeroMatch = result.zeroMatch || min === 0 || resultType === 'MATCHED_ZERO';
@@ -129,27 +112,44 @@ function countPattern(pattern, elements, specs, options, depth) {
129
112
  unmatched: collection.unmatched,
130
113
  zeroMatch,
131
114
  query: result.query,
132
- hint: result.hint,
115
+ hint: (0, utils_1.mergeHints)(result.hint, {
116
+ missing: {
117
+ barelyMatchedElements: collection.matched.length,
118
+ need: result.query,
119
+ },
120
+ }),
133
121
  };
134
122
  if (!prevResult && collection.unmatched.length) {
135
- ptLog('continue checking');
136
123
  prevResult = matchedResult;
124
+ ptLog('continue⤴️ (add prev)');
137
125
  continue;
138
126
  }
139
- ptLog('%s: %s', resultType, collection);
127
+ ptLog('%s:\n model: %s\n max: %s\n collection: %s\n matched element: %s', resultType, (0, utils_1.modelLog)(model, repeat), max, collection, matchedCount);
140
128
  if (result.type === 'MISSING_NODE_REQUIRED' ||
141
129
  result.type === 'MISSING_NODE_ONE_OR_MORE' ||
142
130
  result.type === 'TRANSPARENT_MODEL_DISALLOWS') {
143
- return {
131
+ return compereResult({
144
132
  type: result.type,
145
133
  matched: collection.matched,
146
134
  unmatched: collection.unmatched,
147
135
  zeroMatch: result.zeroMatch,
148
136
  query: result.query,
149
137
  hint: result.hint,
150
- };
138
+ }, barelyResult);
151
139
  }
152
- return matchedResult;
140
+ return compereResult(matchedResult, barelyResult);
153
141
  }
154
142
  }
155
143
  exports.countPattern = countPattern;
144
+ const cLog = debug_1.cmLog.extend('countCompereResult');
145
+ function compereResult(a, b) {
146
+ cLog('current: %s %O\nbarely: %s %O', a.type, a.hint, b === null || b === void 0 ? void 0 : b.type, b === null || b === void 0 ? void 0 : b.hint);
147
+ if (b == null) {
148
+ return a;
149
+ }
150
+ if (a.type === 'MATCHED' || a.type === 'MATCHED_ZERO' || a.type === 'UNEXPECTED_EXTRA_NODE') {
151
+ return a;
152
+ }
153
+ const result = [a, b].sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = b.hint.missing) === null || _a === void 0 ? void 0 : _a.barelyMatchedElements) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = a.hint.missing) === null || _c === void 0 ? void 0 : _c.barelyMatchedElements) !== null && _d !== void 0 ? _d : 0); })[0];
154
+ return result;
155
+ }
@@ -103,9 +103,9 @@ function matchesSelector(query, node, specs, options, depth) {
103
103
  unmatched: [node],
104
104
  zeroMatch: true,
105
105
  query,
106
- hint: {
106
+ hint: (0, utils_1.cleanObject)({
107
107
  not: result.not,
108
- },
108
+ }),
109
109
  };
110
110
  }
111
111
  return {
@@ -114,9 +114,9 @@ function matchesSelector(query, node, specs, options, depth) {
114
114
  unmatched: [node],
115
115
  zeroMatch: false,
116
116
  query,
117
- hint: {
117
+ hint: (0, utils_1.cleanObject)({
118
118
  not: result.not,
119
- },
119
+ }),
120
120
  };
121
121
  }
122
122
  return {
@@ -16,11 +16,12 @@ const utils_1 = require("./utils");
16
16
  * @returns
17
17
  */
18
18
  function order(contents, nodes, specs, options, depth) {
19
- var _a, _b, _c, _d;
19
+ var _a, _b, _c, _d, _e;
20
20
  const orderLog = debug_1.cmLog.extend(`order#${depth}`);
21
21
  const btLog = debug_1.cmLog.extend(`backtrack#${depth}`);
22
22
  const patterns = (0, helpers_1.deepCopy)(contents);
23
23
  const collection = new utils_1.Collection(nodes);
24
+ orderLog('Model:\n RegEx: %s\n Schema: %o', (0, utils_1.modelLog)(patterns, ''), patterns);
24
25
  orderLog('Starts: %s', collection);
25
26
  let result = undefined;
26
27
  let backtrackMode = false;
@@ -29,28 +30,34 @@ function order(contents, nodes, specs, options, depth) {
29
30
  while (patterns.length) {
30
31
  result = (0, complex_branch_1.complexBranch)(patterns[0], collection.unmatched, specs, options, depth);
31
32
  collection.addMatched(result.matched);
32
- orderLog('stack: %s', collection);
33
33
  if (result.type !== 'UNEXPECTED_EXTRA_NODE' && result.type !== 'MATCHED' && result.type !== 'MATCHED_ZERO') {
34
34
  unmatchedResults.push(result);
35
35
  if (backtrackMode) {
36
36
  collection.back();
37
- btLog('🔙');
37
+ btLog('🔙◀BACK');
38
38
  backtrackMode = false;
39
39
  afterBacktrack = true;
40
40
  continue;
41
41
  }
42
- orderLog('conformed (%s): %s', result.type, collection.toString(true));
43
42
  const barelyMatchedResult = unmatchedResults.sort((a, b) => b.matched.length - a.matched.length)[0];
44
43
  if (!barelyMatchedResult) {
45
44
  throw new Error('Unreachable code');
46
45
  }
46
+ orderLog('Result (%s): %s%s', result.type, collection.toString(true), ((_a = barelyMatchedResult.hint.missing) === null || _a === void 0 ? void 0 : _a.barelyMatchedElements)
47
+ ? `; But ${barelyMatchedResult.hint.missing.barelyMatchedElements} elements hit out of pattern`
48
+ : '');
47
49
  return {
48
50
  type: barelyMatchedResult.type,
49
51
  matched: collection.matched,
50
52
  unmatched: collection.unmatched,
51
53
  zeroMatch: barelyMatchedResult.zeroMatch,
52
54
  query: barelyMatchedResult.query,
53
- hint: barelyMatchedResult.hint,
55
+ hint: (0, utils_1.mergeHints)(barelyMatchedResult.hint, {
56
+ missing: {
57
+ barelyMatchedElements: collection.matched.length,
58
+ need: barelyMatchedResult.query,
59
+ },
60
+ }),
54
61
  };
55
62
  }
56
63
  if (afterBacktrack) {
@@ -66,24 +73,25 @@ function order(contents, nodes, specs, options, depth) {
66
73
  patterns.shift();
67
74
  }
68
75
  if (collection.unmatched.length) {
69
- orderLog('Conformed (UNEXPECTED_EXTRA_NODE): %s', collection.toString(true));
76
+ orderLog('Result (UNEXPECTED_EXTRA_NODE): %s', collection.toString(true));
70
77
  return {
71
78
  type: 'UNEXPECTED_EXTRA_NODE',
72
79
  matched: collection.matched,
73
80
  unmatched: collection.unmatched,
74
81
  zeroMatch: false,
75
- query: (_a = result === null || result === void 0 ? void 0 : result.query) !== null && _a !== void 0 ? _a : 'N/A',
76
- hint: (_b = result === null || result === void 0 ? void 0 : result.hint) !== null && _b !== void 0 ? _b : {},
82
+ query: (_b = result === null || result === void 0 ? void 0 : result.query) !== null && _b !== void 0 ? _b : 'N/A',
83
+ hint: (_c = result === null || result === void 0 ? void 0 : result.hint) !== null && _c !== void 0 ? _c : {},
77
84
  };
78
85
  }
79
- orderLog('Conformed: %s', collection);
86
+ const resultType = collection.matched.length ? 'MATCHED' : 'MATCHED_ZERO';
87
+ orderLog('Result (%s): %s', resultType, collection.toString(true));
80
88
  return {
81
- type: collection.matched.length ? 'MATCHED' : 'MATCHED_ZERO',
89
+ type: resultType,
82
90
  matched: collection.matched,
83
91
  unmatched: collection.unmatched,
84
92
  zeroMatch: false,
85
- query: (_c = result === null || result === void 0 ? void 0 : result.query) !== null && _c !== void 0 ? _c : 'N/A',
86
- hint: (_d = result === null || result === void 0 ? void 0 : result.hint) !== null && _d !== void 0 ? _d : {},
93
+ query: (_d = result === null || result === void 0 ? void 0 : result.query) !== null && _d !== void 0 ? _d : 'N/A',
94
+ hint: (_e = result === null || result === void 0 ? void 0 : result.hint) !== null && _e !== void 0 ? _e : {},
87
95
  };
88
96
  }
89
97
  exports.order = order;
@@ -24,15 +24,21 @@ export type Result<T extends string = MatchedReason> = {
24
24
  unmatched: ChildNode[];
25
25
  zeroMatch: boolean;
26
26
  query: string;
27
- hint: {
28
- max?: number;
29
- not?: ChildNode;
30
- transparent?: Element;
27
+ hint: Hints;
28
+ };
29
+ export type Hints = {
30
+ max?: number;
31
+ not?: ChildNode;
32
+ transparent?: Element;
33
+ missing?: {
34
+ barelyMatchedElements?: number;
35
+ need?: string;
31
36
  };
32
37
  };
33
38
  export type MatchedReason = 'MATCHED' | 'MATCHED_ZERO';
34
39
  export type UnmatchedReason = 'NOTHING' | 'UNEXPECTED_EXTRA_NODE' | 'TRANSPARENT_MODEL_DISALLOWS' | MissingNodeReason;
35
40
  export type MissingNodeReason = 'MISSING_NODE_REQUIRED' | 'MISSING_NODE_ONE_OR_MORE';
41
+ export type RepeatSign = '' | '?' | '+' | '*' | `{${number},${number}}`;
36
42
  export type TransparentModel = {
37
43
  el: Element;
38
44
  additionalCondition: string;
@@ -1,4 +1,4 @@
1
- import type { ChildNode, Element, Specs } from './types';
1
+ import type { ChildNode, Element, Hints, MissingNodeReason, RepeatSign, Specs } from './types';
2
2
  import type { PermittedContentPattern, PermittedContentChoice, PermittedContentOneOrMore, PermittedContentOptional, PermittedContentRequire, PermittedContentTransparent, PermittedContentZeroOrMore, Model } from '@markuplint/ml-spec';
3
3
  export declare function getChildNodesWithoutWhitespaces(el: Element): ChildNode[];
4
4
  export declare function isModel(model: Model | PermittedContentPattern[]): model is Model;
@@ -15,6 +15,23 @@ export declare function isOneOrMore(content: PermittedContentPattern): content i
15
15
  export declare function isZeroOrMore(content: PermittedContentPattern): content is PermittedContentZeroOrMore;
16
16
  export declare function isChoice(content: PermittedContentPattern): content is PermittedContentChoice;
17
17
  export declare function isTransparent(content: PermittedContentPattern): content is PermittedContentTransparent;
18
+ export declare function normalizeModel(pattern: PermittedContentRequire | PermittedContentOptional | PermittedContentOneOrMore | PermittedContentZeroOrMore): {
19
+ model: PermittedContentPattern[] | Model;
20
+ min: number;
21
+ max: number;
22
+ repeat: RepeatSign;
23
+ missingType: MissingNodeReason | undefined;
24
+ };
25
+ export declare function mergeHints(a: Hints, b: Hints): Partial<{
26
+ missing: Partial<{
27
+ barelyMatchedElements?: number | undefined;
28
+ need?: string | undefined;
29
+ }> | undefined;
30
+ max?: number | undefined;
31
+ not?: import("packages/@markuplint/ml-core/lib").DocumentType<import("./types").TagRule[], import("./types").Options> | import("packages/@markuplint/ml-core/lib/ml-dom/node/character-data").MLCharacterData<import("./types").TagRule[], import("./types").Options, import("packages/@markuplint/ml-ast/lib").MLASTAbstractNode> | import("packages/@markuplint/ml-core/lib").Element<import("./types").TagRule[], import("./types").Options> | import("packages/@markuplint/ml-core/lib").Block<import("./types").TagRule[], import("./types").Options> | undefined;
32
+ transparent?: Element | undefined;
33
+ }>;
34
+ export declare function cleanObject<T extends Object>(object: T): Partial<T>;
18
35
  export declare class Collection {
19
36
  #private;
20
37
  constructor(origin: readonly ChildNode[]);
@@ -30,3 +47,4 @@ export declare class Collection {
30
47
  }
31
48
  export declare class UnsupportedError extends Error {
32
49
  }
50
+ export declare function modelLog(model: Model | PermittedContentPattern[], repeat: RepeatSign): string;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _Collection_locked, _Collection_matched, _Collection_nodes, _Collection_origin;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.UnsupportedError = exports.Collection = exports.isTransparent = exports.isChoice = exports.isZeroOrMore = exports.isOneOrMore = exports.isOptional = exports.isRequire = exports.matches = exports.isModel = exports.getChildNodesWithoutWhitespaces = void 0;
4
+ exports.modelLog = exports.UnsupportedError = exports.Collection = exports.cleanObject = exports.mergeHints = exports.normalizeModel = exports.isTransparent = exports.isChoice = exports.isZeroOrMore = exports.isOneOrMore = exports.isOptional = exports.isRequire = exports.matches = exports.isModel = exports.getChildNodesWithoutWhitespaces = void 0;
5
5
  const tslib_1 = require("tslib");
6
6
  const selector_1 = require("@markuplint/selector");
7
7
  const debug_1 = require("./debug");
@@ -95,6 +95,81 @@ function isTransparent(content) {
95
95
  return 'transparent' in content;
96
96
  }
97
97
  exports.isTransparent = isTransparent;
98
+ function normalizeModel(pattern) {
99
+ var _a, _b, _c, _d, _e;
100
+ let model;
101
+ let min;
102
+ let max;
103
+ let repeat;
104
+ let missingType;
105
+ if (isRequire(pattern)) {
106
+ model = pattern.require;
107
+ min = (_a = pattern.min) !== null && _a !== void 0 ? _a : 1;
108
+ max = Math.max((_b = pattern.max) !== null && _b !== void 0 ? _b : 1, min);
109
+ missingType = 'MISSING_NODE_REQUIRED';
110
+ }
111
+ else if (isOptional(pattern)) {
112
+ model = pattern.optional;
113
+ min = 0;
114
+ max = Math.max((_c = pattern.max) !== null && _c !== void 0 ? _c : 1, 1);
115
+ }
116
+ else if (isOneOrMore(pattern)) {
117
+ model = pattern.oneOrMore;
118
+ min = 1;
119
+ max = Math.max((_d = pattern.max) !== null && _d !== void 0 ? _d : Infinity, 1);
120
+ missingType = 'MISSING_NODE_ONE_OR_MORE';
121
+ }
122
+ else if (isZeroOrMore(pattern)) {
123
+ model = pattern.zeroOrMore;
124
+ min = 0;
125
+ max = Math.max((_e = pattern.max) !== null && _e !== void 0 ? _e : Infinity, 1);
126
+ }
127
+ else {
128
+ throw new Error('Unreachable code');
129
+ }
130
+ if (min === 0 && max === 1) {
131
+ repeat = '?';
132
+ }
133
+ else if (min === 0 && !Number.isFinite(max)) {
134
+ repeat = '*';
135
+ }
136
+ else if (min === 1 && max === 1) {
137
+ repeat = '';
138
+ }
139
+ else if (min === 1 && !Number.isFinite(max)) {
140
+ repeat = '+';
141
+ }
142
+ else {
143
+ repeat = `{${min},${max}}`;
144
+ }
145
+ return {
146
+ model,
147
+ min,
148
+ max,
149
+ repeat,
150
+ missingType,
151
+ };
152
+ }
153
+ exports.normalizeModel = normalizeModel;
154
+ function mergeHints(a, b) {
155
+ const missing = [a.missing, b.missing].sort((a, b) => { var _a, _b; return ((_a = b === null || b === void 0 ? void 0 : b.barelyMatchedElements) !== null && _a !== void 0 ? _a : 0) - ((_b = a === null || a === void 0 ? void 0 : a.barelyMatchedElements) !== null && _b !== void 0 ? _b : 0); })[0];
156
+ return cleanObject({
157
+ ...a,
158
+ ...b,
159
+ missing: missing && cleanObject(missing),
160
+ });
161
+ }
162
+ exports.mergeHints = mergeHints;
163
+ function cleanObject(object) {
164
+ const newObject = {};
165
+ Object.entries(object).forEach(([key, value]) => {
166
+ if (value !== undefined) {
167
+ newObject[key] = value;
168
+ }
169
+ });
170
+ return newObject;
171
+ }
172
+ exports.cleanObject = cleanObject;
98
173
  class Collection {
99
174
  constructor(origin) {
100
175
  _Collection_locked.set(this, new Set());
@@ -182,3 +257,32 @@ _Collection_locked = new WeakMap(), _Collection_matched = new WeakMap(), _Collec
182
257
  class UnsupportedError extends Error {
183
258
  }
184
259
  exports.UnsupportedError = UnsupportedError;
260
+ function modelLog(model, repeat) {
261
+ if (!isModel(model)) {
262
+ return orderLog(model, repeat);
263
+ }
264
+ if (typeof model === 'string') {
265
+ return `<${model}>${repeat}`;
266
+ }
267
+ return `(<${model.join('>|<')}>)${repeat}`;
268
+ }
269
+ exports.modelLog = modelLog;
270
+ function orderLog(order, repeat) {
271
+ return order.length === 1
272
+ ? markRepeat(patternLog(order[0]), repeat)
273
+ : markRepeat(order.map(pattern => patternLog(pattern)).join(''), repeat);
274
+ }
275
+ function patternLog(pattern) {
276
+ if (isTransparent(pattern)) {
277
+ // 適当
278
+ return `:transparent(${modelLog(pattern.transparent, '')})`;
279
+ }
280
+ if (isChoice(pattern)) {
281
+ return `(${pattern.choice.map(candidate => orderLog(candidate, '')).join('|')})`;
282
+ }
283
+ const { model, repeat } = normalizeModel(pattern);
284
+ return modelLog(model, repeat);
285
+ }
286
+ function markRepeat(pattern, repeat) {
287
+ return repeat ? `(${pattern})${repeat}` : pattern;
288
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/rules",
3
- "version": "3.0.0-rc.5",
3
+ "version": "3.0.1",
4
4
  "description": "Built-in rules of markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -20,10 +20,10 @@
20
20
  "./lib/permitted-contents/debug.js": "./lib/permitted-contents/debug.browser.js"
21
21
  },
22
22
  "dependencies": {
23
- "@markuplint/html-spec": "3.0.0-rc.5",
24
- "@markuplint/ml-core": "3.0.0-rc.5",
25
- "@markuplint/ml-spec": "3.0.0-rc.5",
26
- "@markuplint/types": "3.0.0-rc.5",
23
+ "@markuplint/html-spec": "3.0.1",
24
+ "@markuplint/ml-core": "3.0.1",
25
+ "@markuplint/ml-spec": "3.0.1",
26
+ "@markuplint/types": "3.0.0",
27
27
  "@ungap/structured-clone": "^1.0.1",
28
28
  "debug": "^4.3.4",
29
29
  "html-entities": "^2.3.3",
@@ -32,5 +32,5 @@
32
32
  "devDependencies": {
33
33
  "@types/debug": "^4.1.7"
34
34
  },
35
- "gitHead": "fb0cde3550b1c9df1279da8019146f9a495216e7"
35
+ "gitHead": "4ade31aab89b4bcc3527d4b00bcbfa3dbd6eb032"
36
36
  }