@markuplint/ml-config 4.6.2 → 4.7.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/CHANGELOG.md +8 -0
- package/lib/merge-config.d.ts +2 -2
- package/lib/merge-config.js +78 -4
- package/lib/types.d.ts +22 -3
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.7.0](https://github.com/markuplint/markuplint/compare/@markuplint/ml-config@4.6.2...@markuplint/ml-config@4.7.0) (2024-05-28)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **ml-config:** `pretenders` field accepts new structure ([3f9f5e8](https://github.com/markuplint/markuplint/commit/3f9f5e8ffdb7fa2526e842559b871ec6414de190))
|
|
11
|
+
- **ml-config:** add test for merging `pretenders` structure ([fac00d7](https://github.com/markuplint/markuplint/commit/fac00d7ce4c709757097b8ce8c2e40813af0461c))
|
|
12
|
+
- **ml-config:** improve merging for new `pretenders` structure ([fa7d990](https://github.com/markuplint/markuplint/commit/fa7d990c91e7843f6928fd48dc1ff41b7b446402))
|
|
13
|
+
|
|
6
14
|
## [4.6.2](https://github.com/markuplint/markuplint/compare/@markuplint/ml-config@4.6.1...@markuplint/ml-config@4.6.2) (2024-05-12)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @markuplint/ml-config
|
package/lib/merge-config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Config, AnyRule, AnyRuleV2 } from './types.js';
|
|
1
|
+
import type { Config, AnyRule, AnyRuleV2, OptimizedConfig } from './types.js';
|
|
2
2
|
import type { Nullable } from '@markuplint/shared';
|
|
3
|
-
export declare function mergeConfig(a: Config, b
|
|
3
|
+
export declare function mergeConfig(a: Config, b?: Config): OptimizedConfig;
|
|
4
4
|
export declare function mergeRule(a: Nullable<AnyRule | AnyRuleV2>, b: AnyRule | AnyRuleV2): AnyRule;
|
package/lib/merge-config.js
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
import deepmerge from 'deepmerge';
|
|
2
2
|
import { deleteUndefProp, cleanOptions, isRuleConfigValue } from './utils.js';
|
|
3
3
|
export function mergeConfig(a, b) {
|
|
4
|
+
const deleteExtendsProp = !!b;
|
|
5
|
+
b = b ?? {};
|
|
4
6
|
const config = {
|
|
5
7
|
...a,
|
|
6
8
|
...b,
|
|
7
|
-
plugins: concatArray(a.plugins, b.plugins, true, 'name')
|
|
9
|
+
plugins: concatArray(a.plugins, b.plugins, true, 'name')?.map(plugin => {
|
|
10
|
+
if (typeof plugin === 'string') {
|
|
11
|
+
return {
|
|
12
|
+
name: plugin,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return plugin;
|
|
16
|
+
}),
|
|
8
17
|
parser: mergeObject(a.parser, b.parser),
|
|
9
18
|
parserOptions: mergeObject(a.parserOptions, b.parserOptions),
|
|
10
19
|
specs: mergeObject(a.specs, b.specs),
|
|
11
20
|
excludeFiles: concatArray(a.excludeFiles, b.excludeFiles, true),
|
|
21
|
+
pretenders: mergePretenders(a.pretenders, b.pretenders),
|
|
12
22
|
rules: mergeRules(
|
|
13
23
|
// TODO: Deep merge
|
|
14
24
|
a.rules, b.rules),
|
|
15
25
|
nodeRules: concatArray(a.nodeRules, b.nodeRules),
|
|
16
26
|
childNodeRules: concatArray(a.childNodeRules, b.childNodeRules),
|
|
17
27
|
overrideMode: b.overrideMode ?? a.overrideMode,
|
|
18
|
-
overrides:
|
|
19
|
-
|
|
20
|
-
extends: undefined,
|
|
28
|
+
overrides: mergeOverrides(a.overrides, b.overrides),
|
|
29
|
+
extends: concatArray(toReadonlyArray(a.extends), toReadonlyArray(b.extends)),
|
|
21
30
|
};
|
|
31
|
+
if (deleteExtendsProp) {
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
delete config.extends;
|
|
34
|
+
}
|
|
22
35
|
deleteUndefProp(config);
|
|
23
36
|
return config;
|
|
24
37
|
}
|
|
@@ -62,6 +75,47 @@ export function mergeRule(a, b) {
|
|
|
62
75
|
deleteUndefProp(res);
|
|
63
76
|
return res;
|
|
64
77
|
}
|
|
78
|
+
function mergePretenders(a, b) {
|
|
79
|
+
if (!a && !b) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const aDetails = a ? convertPretenersToDetails(a) : undefined;
|
|
83
|
+
const bDetails = b ? convertPretenersToDetails(b) : undefined;
|
|
84
|
+
const details = mergeObject(aDetails, bDetails) ?? {};
|
|
85
|
+
deleteUndefProp(details);
|
|
86
|
+
return details;
|
|
87
|
+
}
|
|
88
|
+
function convertPretenersToDetails(pretenders) {
|
|
89
|
+
if (isReadonlyArray(pretenders)) {
|
|
90
|
+
return {
|
|
91
|
+
data: pretenders,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return pretenders;
|
|
95
|
+
}
|
|
96
|
+
function mergeOverrides(a = {}, b = {}) {
|
|
97
|
+
const keys = new Set();
|
|
98
|
+
for (const key of Object.keys(a))
|
|
99
|
+
keys.add(key);
|
|
100
|
+
for (const key of Object.keys(b))
|
|
101
|
+
keys.add(key);
|
|
102
|
+
if (keys.size === 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const result = {};
|
|
106
|
+
for (const key of keys) {
|
|
107
|
+
const config = mergeConfig(a[key] ?? {}, b[key] ?? {});
|
|
108
|
+
// @ts-ignore
|
|
109
|
+
delete config.$schema;
|
|
110
|
+
// @ts-ignore
|
|
111
|
+
delete config.extends;
|
|
112
|
+
// @ts-ignore
|
|
113
|
+
delete config.overrides;
|
|
114
|
+
deleteUndefProp(config);
|
|
115
|
+
result[key] = config;
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
65
119
|
function mergeObject(a, b) {
|
|
66
120
|
if (a == null) {
|
|
67
121
|
return b ?? undefined;
|
|
@@ -162,3 +216,23 @@ function optimizeRule(rule) {
|
|
|
162
216
|
}
|
|
163
217
|
return cleanOptions(rule);
|
|
164
218
|
}
|
|
219
|
+
function toReadonlyArray(value) {
|
|
220
|
+
if (value == null) {
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
return isReadonlyArray(value) ? value : [value];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Checks if a value is a readonly array.
|
|
227
|
+
*
|
|
228
|
+
* If the array is readonly, it passes the type check.
|
|
229
|
+
* However, it saves the type because using ESLint warns `@typescript-eslint/prefer-readonly-parameter-types`.
|
|
230
|
+
*
|
|
231
|
+
* @param value - The value to check.
|
|
232
|
+
* @returns `true` if the value is a readonly array, `false` otherwise.
|
|
233
|
+
* @template T - The type of elements in the array.
|
|
234
|
+
* @template X - The type of the value if it's not an array.
|
|
235
|
+
*/
|
|
236
|
+
function isReadonlyArray(value) {
|
|
237
|
+
return Array.isArray(value);
|
|
238
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type Config = {
|
|
|
10
10
|
readonly parserOptions?: ParserOptions;
|
|
11
11
|
readonly specs?: SpecConfig;
|
|
12
12
|
readonly excludeFiles?: readonly string[];
|
|
13
|
-
readonly pretenders?: readonly Pretender[];
|
|
13
|
+
readonly pretenders?: readonly Pretender[] | PretenderDetails;
|
|
14
14
|
readonly rules?: Rules;
|
|
15
15
|
readonly nodeRules?: readonly NodeRule[];
|
|
16
16
|
readonly childNodeRules?: readonly ChildNodeRule[];
|
|
@@ -24,10 +24,18 @@ export type PlainData = Nullable<PrimitiveScalar> | readonly PlainData[] | {
|
|
|
24
24
|
export type NonNullablePlainData = PrimitiveScalar | readonly NonNullablePlainData[] | {
|
|
25
25
|
readonly [key: string]: NonNullablePlainData;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
type NoInherit = '$schema' | 'extends' | 'overrideMode' | 'overrides';
|
|
28
|
+
export type OverrideConfig = Omit<Config, NoInherit>;
|
|
29
|
+
export type OptimizedConfig = Omit<Config, '$schema' | 'extends' | 'plugins' | 'pretenders' | 'overrides'> & {
|
|
30
|
+
readonly extends?: readonly string[];
|
|
31
|
+
readonly plugins?: readonly PluginConfig[];
|
|
32
|
+
readonly pretenders?: PretenderDetails;
|
|
33
|
+
readonly overrides?: Readonly<Record<string, OptimizedOverrideConfig>>;
|
|
34
|
+
};
|
|
35
|
+
export type OptimizedOverrideConfig = Omit<OptimizedConfig, NoInherit>;
|
|
28
36
|
export type PluginConfig = {
|
|
29
37
|
readonly name: string;
|
|
30
|
-
readonly settings
|
|
38
|
+
readonly settings?: Readonly<Record<string, NonNullablePlainData>>;
|
|
31
39
|
};
|
|
32
40
|
export type ParserConfig = {
|
|
33
41
|
readonly [extensionPattern: string]: string;
|
|
@@ -35,6 +43,17 @@ export type ParserConfig = {
|
|
|
35
43
|
export type SpecConfig = {
|
|
36
44
|
readonly [extensionPattern: string]: string;
|
|
37
45
|
};
|
|
46
|
+
export type PretenderDetails = {
|
|
47
|
+
/**
|
|
48
|
+
* @experimental
|
|
49
|
+
*/
|
|
50
|
+
readonly files?: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* @experimental
|
|
53
|
+
*/
|
|
54
|
+
readonly imports?: readonly string[];
|
|
55
|
+
readonly data?: readonly Pretender[];
|
|
56
|
+
};
|
|
38
57
|
export type PretenderFileData = {
|
|
39
58
|
readonly version: string;
|
|
40
59
|
readonly data: readonly Pretender[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/ml-config",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.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>",
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"clean": "tsc --build --clean"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@markuplint/ml-ast": "4.
|
|
28
|
-
"@markuplint/selector": "4.6.
|
|
29
|
-
"@markuplint/shared": "4.4.
|
|
27
|
+
"@markuplint/ml-ast": "4.4.0",
|
|
28
|
+
"@markuplint/selector": "4.6.3",
|
|
29
|
+
"@markuplint/shared": "4.4.1",
|
|
30
30
|
"@types/mustache": "4.2.5",
|
|
31
31
|
"deepmerge": "4.3.1",
|
|
32
32
|
"is-plain-object": "5.0.0",
|
|
33
33
|
"mustache": "4.2.0",
|
|
34
|
-
"type-fest": "4.18.
|
|
34
|
+
"type-fest": "4.18.3"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "bf70c41b1d2497e85b73c9ecd5551eb522e6bdfc"
|
|
37
37
|
}
|