@markuplint/ml-config 3.4.0 → 3.6.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,3 +1,4 @@
1
- import type { Config, Nullable, AnyRule, AnyRuleV2 } from './types';
1
+ import type { Config, AnyRule, AnyRuleV2 } from './types';
2
+ import type { Nullable } from '@markuplint/shared';
2
3
  export declare function mergeConfig(a: Config, b: Config): Config;
3
4
  export declare function mergeRule(a: Nullable<AnyRule | AnyRuleV2>, b: AnyRule | AnyRuleV2): AnyRule;
@@ -49,7 +49,7 @@ function mergeRule(a, b) {
49
49
  }
50
50
  return oB;
51
51
  }
52
- const value = Array.isArray(oA.value) && Array.isArray(b) ? [...oA.value, oB] : oB;
52
+ const value = Array.isArray(oA.value) && Array.isArray(oB) ? [...oA.value, ...oB] : oB;
53
53
  const res = (0, utils_1.cleanOptions)({ ...oA, value });
54
54
  (0, utils_1.deleteUndefProp)(res);
55
55
  return res;
@@ -70,10 +70,10 @@ function mergeRule(a, b) {
70
70
  exports.mergeRule = mergeRule;
71
71
  function mergeObject(a, b) {
72
72
  if (a == null) {
73
- return b || undefined;
73
+ return b !== null && b !== void 0 ? b : undefined;
74
74
  }
75
75
  if (b == null) {
76
- return a || undefined;
76
+ return a !== null && a !== void 0 ? a : undefined;
77
77
  }
78
78
  const res = (0, deepmerge_1.default)(a, b);
79
79
  (0, utils_1.deleteUndefProp)(res);
@@ -135,7 +135,7 @@ function mergeRules(a, b) {
135
135
  return b && optimizeRules(b);
136
136
  }
137
137
  if (b == null) {
138
- return a && optimizeRules(a);
138
+ return optimizeRules(a);
139
139
  }
140
140
  const res = optimizeRules(a);
141
141
  for (const [key, rule] of Object.entries(b)) {
@@ -145,7 +145,7 @@ function mergeRules(a, b) {
145
145
  }
146
146
  }
147
147
  (0, utils_1.deleteUndefProp)(res);
148
- return res;
148
+ return Object.freeze(res);
149
149
  }
150
150
  function optimizeRules(rules) {
151
151
  const res = {};
package/lib/types.d.ts CHANGED
@@ -1,35 +1,50 @@
1
1
  import type { ParserOptions } from '@markuplint/ml-ast';
2
2
  import type { RegexSelector } from '@markuplint/selector';
3
+ import type { Nullable } from '@markuplint/shared';
3
4
  export type { RegexSelector } from '@markuplint/selector';
4
- export interface Config {
5
- $schema?: string;
6
- extends?: string | string[];
7
- plugins?: (PluginConfig | string)[];
8
- parser?: ParserConfig;
9
- parserOptions?: ParserOptions;
10
- specs?: SpecConfig;
11
- excludeFiles?: string[];
12
- pretenders?: Pretender[];
13
- rules?: Rules;
14
- nodeRules?: NodeRule[];
15
- childNodeRules?: ChildNodeRule[];
16
- overrides?: Record<string, Omit<Config, '$schema' | 'extends' | 'overrides'>>;
17
- }
5
+ export type Config = {
6
+ readonly $schema?: string;
7
+ readonly extends?: string | readonly string[];
8
+ readonly plugins?: readonly (PluginConfig | string)[];
9
+ readonly parser?: ParserConfig;
10
+ readonly parserOptions?: ParserOptions;
11
+ readonly specs?: SpecConfig;
12
+ readonly excludeFiles?: readonly string[];
13
+ readonly pretenders?: readonly Pretender[];
14
+ readonly rules?: Rules;
15
+ readonly nodeRules?: readonly NodeRule[];
16
+ readonly childNodeRules?: readonly ChildNodeRule[];
17
+ readonly overrides?: Readonly<Record<string, OverrideConfig>>;
18
+ };
19
+ export type PrimitiveScalar = string | number | boolean;
20
+ export type PlainData =
21
+ | Nullable<PrimitiveScalar>
22
+ | readonly PlainData[]
23
+ | {
24
+ readonly [key: string]: PlainData | any;
25
+ };
26
+ export type NonNullablePlainData =
27
+ | PrimitiveScalar
28
+ | readonly NonNullablePlainData[]
29
+ | {
30
+ readonly [key: string]: NonNullablePlainData;
31
+ };
32
+ export type OverrideConfig = Omit<Config, '$schema' | 'extends' | 'overrides'>;
18
33
  export type PluginConfig = {
19
- name: string;
20
- settings: Record<string, any>;
34
+ readonly name: string;
35
+ readonly settings: Readonly<Record<string, NonNullablePlainData>>;
36
+ };
37
+ export type ParserConfig = {
38
+ readonly [extensionPattern: string]: string;
21
39
  };
22
- export interface ParserConfig {
23
- [extensionPattern: string]: string;
24
- }
25
40
  export type SpecConfig = {
26
- [extensionPattern: string]: string;
41
+ readonly [extensionPattern: string]: string;
27
42
  };
28
43
  export type Pretender = {
29
44
  /**
30
45
  * Target node selectors
31
46
  */
32
- selector: string;
47
+ readonly selector: string;
33
48
  /**
34
49
  * If it is a string, it is resolved as an element name.
35
50
  * An element has the same attributes as the pretended custom element
@@ -37,45 +52,45 @@ export type Pretender = {
37
52
  *
38
53
  * If it is an Object, It creates the element by that.
39
54
  */
40
- as: string | OriginalNode;
55
+ readonly as: string | OriginalNode;
41
56
  };
42
57
  export type OriginalNode = {
43
58
  /**
44
59
  * Element name
45
60
  */
46
- element: string;
61
+ readonly element: string;
47
62
  /**
48
63
  * Namespace
49
64
  *
50
65
  * Supports `"svg"` and `undefined` only.
51
66
  * If it is `undefined`, the namespace is HTML.
52
67
  */
53
- namespace?: 'svg';
68
+ readonly namespace?: 'svg';
54
69
  /**
55
70
  * Attributes
56
71
  */
57
- attrs?: {
72
+ readonly attrs?: readonly {
58
73
  /**
59
74
  * Attribute name
60
75
  */
61
- name: string;
76
+ readonly name: string;
62
77
  /**
63
78
  * If it omits this property, the attribute is resolved as a boolean.
64
79
  */
65
- value?:
80
+ readonly value?:
66
81
  | string
67
82
  | {
68
- fromAttr: string;
83
+ readonly fromAttr: string;
69
84
  };
70
85
  }[];
71
86
  /**
72
87
  * To have attributes the defined element has.
73
88
  */
74
- inheritAttrs?: boolean;
89
+ readonly inheritAttrs?: boolean;
75
90
  /**
76
91
  * ARIA properties
77
92
  */
78
- aria?: PretenderARIA;
93
+ readonly aria?: PretenderARIA;
79
94
  };
80
95
  /**
81
96
  * Pretender Node ARIA properties
@@ -87,97 +102,102 @@ export type PretenderARIA = {
87
102
  * - If it is `true`, it assumes the element has any text on its accessible name.
88
103
  * - If it specifies `fromAttr` property, it assumes the accessible name refers to the value of the attribute.
89
104
  */
90
- name?:
105
+ readonly name?:
91
106
  | boolean
92
107
  | {
93
- fromAttr: string;
108
+ readonly fromAttr: string;
94
109
  };
95
110
  };
96
- export type Rule<T extends RuleConfigValue, O = void> = RuleConfig<T, O> | T | boolean;
111
+ export type Rule<T extends RuleConfigValue, O extends PlainData = undefined> = RuleConfig<T, O> | Readonly<T> | boolean;
97
112
  /**
98
113
  * @deprecated
99
114
  */
100
- export type RuleV2<T extends RuleConfigValue, O = void> = RuleConfigV2<T, O> | T | boolean;
101
- export type AnyRule = Rule<RuleConfigValue, unknown>;
115
+ export type RuleV2<T extends RuleConfigValue, O extends PlainData = undefined> =
116
+ | RuleConfigV2<T, O>
117
+ | Readonly<T>
118
+ | boolean;
119
+ export type AnyRule = Rule<RuleConfigValue, PlainData>;
102
120
  /**
103
121
  * @deprecated
104
122
  */
105
- export type AnyRuleV2 = RuleV2<RuleConfigValue, unknown>;
106
- export interface Rules {
107
- [ruleName: string]: AnyRule;
108
- }
109
- export type RuleConfig<T extends RuleConfigValue, O = void> = {
110
- severity?: Severity;
111
- value?: T;
112
- options?: O;
113
- reason?: string;
123
+ export type AnyRuleV2 = RuleV2<RuleConfigValue, PlainData>;
124
+ export type Rules = {
125
+ readonly [ruleName: string]: AnyRule;
126
+ };
127
+ export type RuleConfig<T extends RuleConfigValue, O extends PlainData = undefined> = {
128
+ readonly severity?: Severity;
129
+ readonly value?: Readonly<T>;
130
+ readonly options?: Readonly<O>;
131
+ readonly reason?: string;
114
132
  };
115
133
  /**
116
134
  * @deprecated
117
135
  */
118
- export type RuleConfigV2<T extends RuleConfigValue, O = void> = {
119
- severity?: Severity;
120
- value?: T;
121
- reason?: string;
136
+ export type RuleConfigV2<T extends RuleConfigValue, O extends PlainData = undefined> = {
137
+ readonly severity?: Severity;
138
+ readonly value?: Readonly<T>;
139
+ readonly reason?: string;
122
140
  /**
123
141
  * Old property
124
142
  *
125
143
  * @deprecated
126
144
  * @see {this.options}
127
145
  */
128
- option?: O;
146
+ readonly option?: Readonly<O>;
129
147
  };
130
148
  export type Severity = 'error' | 'warning' | 'info';
131
- export type RuleConfigValue = string | number | boolean | any[] | null;
132
- export interface NodeRule {
133
- selector?: string;
134
- regexSelector?: RegexSelector;
135
- categories?: string[];
136
- roles?: string[];
137
- obsolete?: boolean;
138
- rules?: Rules;
139
- }
140
- export interface ChildNodeRule {
141
- selector?: string;
142
- regexSelector?: RegexSelector;
143
- inheritance?: boolean;
144
- rules?: Rules;
145
- }
146
- export type Report<T extends RuleConfigValue, O = null> = Report1<T, O> | Report2 | (Report1<T, O> & Report2);
147
- export type Report1<T extends RuleConfigValue, O = null> = {
148
- message: string;
149
- scope: Scope<T, O>;
149
+ export type RuleConfigValue = PrimitiveScalar | readonly (PrimitiveScalar | Readonly<Record<string, any>>)[] | null;
150
+ export type NodeRule = {
151
+ readonly selector?: string;
152
+ readonly regexSelector?: RegexSelector;
153
+ readonly categories?: readonly string[];
154
+ readonly roles?: readonly string[];
155
+ readonly obsolete?: boolean;
156
+ readonly rules?: Rules;
157
+ };
158
+ export type ChildNodeRule = {
159
+ readonly selector?: string;
160
+ readonly regexSelector?: RegexSelector;
161
+ readonly inheritance?: boolean;
162
+ readonly rules?: Rules;
163
+ };
164
+ export type Report<T extends RuleConfigValue, O extends PlainData = undefined> =
165
+ | Report1<T, O>
166
+ | Report2
167
+ | (Report1<T, O> & Report2);
168
+ export type Report1<T extends RuleConfigValue, O extends PlainData = undefined> = {
169
+ readonly message: string;
170
+ readonly scope: Scope<T, O>;
150
171
  };
151
172
  export type Report2 = {
152
- message: string;
153
- line: number;
154
- col: number;
155
- raw: string;
156
- };
157
- export type Scope<T extends RuleConfigValue, O = null> = {
158
- rule: RuleInfo<T, O>;
159
- startLine: number;
160
- startCol: number;
161
- raw: string;
162
- };
163
- export interface Violation {
164
- ruleId: string;
165
- severity: Severity;
166
- message: string;
167
- reason?: string;
168
- line: number;
169
- col: number;
170
- raw: string;
171
- }
172
- export interface RuleInfo<T extends RuleConfigValue, O = null> {
173
- disabled: boolean;
174
- severity: Severity;
175
- value: T;
176
- options: O;
177
- reason?: string;
178
- }
179
- export type GlobalRuleInfo<T extends RuleConfigValue, O = null> = RuleInfo<T, O> & {
173
+ readonly message: string;
174
+ readonly line: number;
175
+ readonly col: number;
176
+ readonly raw: string;
177
+ };
178
+ export type Scope<T extends RuleConfigValue, O extends PlainData = undefined> = {
179
+ readonly rule: RuleInfo<T, O>;
180
+ readonly startLine: number;
181
+ readonly startCol: number;
182
+ readonly raw: string;
183
+ };
184
+ export type Violation = {
185
+ readonly ruleId: string;
186
+ readonly severity: Severity;
187
+ readonly message: string;
188
+ readonly reason?: string;
189
+ readonly line: number;
190
+ readonly col: number;
191
+ readonly raw: string;
192
+ };
193
+ export type RuleInfo<T extends RuleConfigValue, O extends PlainData = undefined> = {
194
+ readonly disabled: boolean;
195
+ readonly severity: Severity;
196
+ readonly value: Readonly<T>;
197
+ readonly options: Readonly<O>;
198
+ readonly reason?: string;
199
+ };
200
+ export type GlobalRuleInfo<T extends RuleConfigValue, O extends PlainData = undefined> = RuleInfo<T, O> & {
180
201
  nodeRules: RuleInfo<T, O>[];
181
202
  childNodeRules: RuleInfo<T, O>[];
182
203
  };
183
- export type Nullable<T> = T | null | undefined;
package/lib/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AnyRule, AnyRuleV2, RuleConfig, RuleConfigV2, RuleConfigValue } from './types';
1
+ import type { AnyRule, AnyRuleV2, PlainData, RuleConfig, RuleConfigV2, RuleConfigValue } from './types';
2
2
  /**
3
3
  * Return undefined if the template doesn't include the variable that is set as a property in data.
4
4
  * But return template string without changes if it doesn't have a variable.
@@ -6,14 +6,14 @@ import type { AnyRule, AnyRuleV2, RuleConfig, RuleConfigV2, RuleConfigValue } fr
6
6
  * @param template Mustache template string
7
7
  * @param data Captured string for replacement
8
8
  */
9
- export declare function provideValue(template: string, data: Record<string, string>): string | undefined;
9
+ export declare function provideValue(template: string, data: Readonly<Record<string, string>>): string | undefined;
10
10
  export declare function exchangeValueOnRule(
11
11
  rule: AnyRule | AnyRuleV2,
12
- data: Record<string, string>,
12
+ data: Readonly<Record<string, string>>,
13
13
  ): AnyRule | undefined;
14
14
  export declare function cleanOptions(
15
- rule: RuleConfig<RuleConfigValue, unknown> | RuleConfigV2<RuleConfigValue, unknown>,
16
- ): RuleConfig<RuleConfigValue, unknown>;
15
+ rule: RuleConfig<RuleConfigValue, PlainData> | RuleConfigV2<RuleConfigValue, PlainData>,
16
+ ): RuleConfig<RuleConfigValue, PlainData>;
17
17
  export declare function isRuleConfigValue(v: any): v is RuleConfigValue;
18
18
  /**
19
19
  *
package/lib/utils.js CHANGED
@@ -39,17 +39,22 @@ function exchangeValueOnRule(rule, data) {
39
39
  };
40
40
  }
41
41
  const options = extractOptions(result);
42
- if (options) {
42
+ if (options != null && options !== '' && options !== 0) {
43
+ const newOptions = exchangeOption(options, data);
43
44
  result = {
44
45
  ...result,
45
- options: exchangeOption(options, data),
46
+ ...(newOptions == null
47
+ ? undefined
48
+ : {
49
+ options: newOptions,
50
+ }),
46
51
  };
47
52
  }
48
53
  if (result.reason != null) {
49
54
  const exchangedValue = exchangeValue(result.reason, data);
50
55
  result = {
51
56
  ...result,
52
- reason: exchangedValue ? `${exchangedValue}` : undefined,
57
+ reason: exchangedValue != null ? `${exchangedValue}` : undefined,
53
58
  };
54
59
  }
55
60
  deleteUndefProp(result);
@@ -104,10 +109,10 @@ exports.deleteUndefProp = deleteUndefProp;
104
109
  * @returns
105
110
  */
106
111
  function extractOptions(rule) {
107
- if ('options' in rule && rule.options) {
112
+ if ('options' in rule && rule.options != null) {
108
113
  return rule.options;
109
114
  }
110
- if ('option' in rule && rule.option) {
115
+ if ('option' in rule && rule.option != null) {
111
116
  return rule.option;
112
117
  }
113
118
  }
@@ -126,8 +131,8 @@ function exchangeValue(rule, data) {
126
131
  }
127
132
  return val;
128
133
  })
129
- .filter(item => item !== undefined);
130
- return ruleArray.length ? ruleArray : undefined;
134
+ .filter((item) => item !== undefined);
135
+ return ruleArray.length > 0 ? ruleArray : undefined;
131
136
  }
132
137
  return rule;
133
138
  }
@@ -141,7 +146,7 @@ function exchangeOption(optionValue, data) {
141
146
  if (typeof optionValue === 'string') {
142
147
  return provideValue(optionValue, data);
143
148
  }
144
- if (Array.isArray(optionValue)) {
149
+ if (isArray(optionValue)) {
145
150
  return optionValue.map(v => exchangeOption(v, data));
146
151
  }
147
152
  const result = {};
@@ -150,3 +155,16 @@ function exchangeOption(optionValue, data) {
150
155
  });
151
156
  return result;
152
157
  }
158
+ /**
159
+ * Array.isArray for ReadonlyArray
160
+ *
161
+ * > Array.isArray type narrows to any[] for ReadonlyArray<T>
162
+ *
163
+ * @see https://github.com/microsoft/TypeScript/issues/17002
164
+ *
165
+ * @param value
166
+ * @returns
167
+ */
168
+ function isArray(value) {
169
+ return Array.isArray(value);
170
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/ml-config",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "description": "JSON Schema and TypeScript types of markuplint configure JSON",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -19,14 +19,16 @@
19
19
  "clean": "tsc --build --clean"
20
20
  },
21
21
  "devDependencies": {
22
- "@markuplint/ml-ast": "3.0.0",
22
+ "@markuplint/ml-ast": "3.1.0",
23
+ "@markuplint/shared": "3.5.0",
23
24
  "@types/mustache": "^4.2.2"
24
25
  },
25
26
  "dependencies": {
26
- "@markuplint/selector": "3.4.0",
27
+ "@markuplint/selector": "3.6.0",
27
28
  "deepmerge": "^4.2.2",
28
29
  "is-plain-object": "^5.0.0",
29
- "mustache": "^4.2.0"
30
+ "mustache": "^4.2.0",
31
+ "type-fest": "^3.6.1"
30
32
  },
31
- "gitHead": "a83e0f5f214a9bbcc0286b9e269074ddca6189e7"
33
+ "gitHead": "715dd53d3b1064a9bcf616c1533921cad9e3b187"
32
34
  }