@markuplint/ml-config
Advanced tools
Comparing version 3.0.0-rc.1 to 3.0.0-rc.2
@@ -1,3 +0,3 @@ | ||
import type { Config, Nullable, AnyRule } from './types'; | ||
import type { Config, Nullable, AnyRule, AnyRuleV2 } from './types'; | ||
export declare function mergeConfig(a: Config, b: Config): Config; | ||
export declare function mergeRule(a: Nullable<AnyRule>, b: AnyRule): AnyRule; | ||
export declare function mergeRule(a: Nullable<AnyRule | AnyRuleV2>, b: AnyRule | AnyRuleV2): AnyRule; |
@@ -6,3 +6,3 @@ "use strict"; | ||
const deepmerge_1 = tslib_1.__importDefault(require("deepmerge")); | ||
const is_plain_object_1 = require("is-plain-object"); | ||
const utils_1 = require("./utils"); | ||
function mergeConfig(a, b) { | ||
@@ -26,3 +26,3 @@ const config = { | ||
}; | ||
deleteUndefProp(config); | ||
(0, utils_1.deleteUndefProp)(config); | ||
return config; | ||
@@ -32,38 +32,40 @@ } | ||
function mergeRule(a, b) { | ||
var _a, _b, _c; | ||
const oA = optimizeRule(a); | ||
const oB = optimizeRule(b); | ||
// Particular behavior: | ||
// | ||
// If the right-side value is false, return false. | ||
// In short; The `false` makes the rule to be disabled absolutely. | ||
if (b === false || (!isRuleConfigValue(b) && b.value === false)) { | ||
if (oB === false || (!(0, utils_1.isRuleConfigValue)(oB) && (oB === null || oB === void 0 ? void 0 : oB.value) === false)) { | ||
return false; | ||
} | ||
if (a === undefined) { | ||
return b; | ||
if (oA === undefined) { | ||
return oB !== null && oB !== void 0 ? oB : {}; | ||
} | ||
if (isRuleConfigValue(b)) { | ||
if (isRuleConfigValue(a)) { | ||
if (Array.isArray(a) && Array.isArray(b)) { | ||
return [...a, ...b]; | ||
if (oB === undefined) { | ||
return oA; | ||
} | ||
if ((0, utils_1.isRuleConfigValue)(oB)) { | ||
if ((0, utils_1.isRuleConfigValue)(oA)) { | ||
if (Array.isArray(oA) && Array.isArray(oB)) { | ||
return [...oA, ...oB]; | ||
} | ||
return b; | ||
return oB; | ||
} | ||
const value = Array.isArray(a.value) && Array.isArray(b) ? [...a.value, b] : b; | ||
const res = { | ||
...a, | ||
value, | ||
}; | ||
deleteUndefProp(res); | ||
const value = Array.isArray(oA.value) && Array.isArray(b) ? [...oA.value, oB] : oB; | ||
const res = (0, utils_1.cleanOptions)({ ...oA, value }); | ||
(0, utils_1.deleteUndefProp)(res); | ||
return res; | ||
} | ||
const severity = b.severity || (!isRuleConfigValue(a) ? a.severity : undefined); | ||
const value = b.value || (isRuleConfigValue(a) ? a : a.value); | ||
const option = mergeObject(!isRuleConfigValue(a) ? a.option : undefined, b.option); | ||
const reason = b.reason || (!isRuleConfigValue(a) ? a.reason : undefined); | ||
const severity = (_a = oB.severity) !== null && _a !== void 0 ? _a : (!(0, utils_1.isRuleConfigValue)(oA) ? oA.severity : undefined); | ||
const value = (_b = oB.value) !== null && _b !== void 0 ? _b : ((0, utils_1.isRuleConfigValue)(oA) ? oA : oA.value); | ||
const options = mergeObject(!(0, utils_1.isRuleConfigValue)(oA) ? oA.options : undefined, oB.options); | ||
const reason = (_c = oB.reason) !== null && _c !== void 0 ? _c : (!(0, utils_1.isRuleConfigValue)(oA) ? oA.reason : undefined); | ||
const res = { | ||
severity, | ||
value, | ||
option, | ||
options, | ||
reason, | ||
}; | ||
deleteUndefProp(res); | ||
(0, utils_1.deleteUndefProp)(res); | ||
return res; | ||
@@ -80,3 +82,3 @@ } | ||
const res = (0, deepmerge_1.default)(a, b); | ||
deleteUndefProp(res); | ||
(0, utils_1.deleteUndefProp)(res); | ||
return res; | ||
@@ -137,8 +139,8 @@ } | ||
if (a == null) { | ||
return b || undefined; | ||
return b && optimizeRules(b); | ||
} | ||
if (b == null) { | ||
return a || undefined; | ||
return a && optimizeRules(a); | ||
} | ||
const res = { ...a }; | ||
const res = optimizeRules(a); | ||
for (const [key, rule] of Object.entries(b)) { | ||
@@ -150,27 +152,23 @@ const merged = mergeRule(res[key], rule); | ||
} | ||
deleteUndefProp(res); | ||
(0, utils_1.deleteUndefProp)(res); | ||
return res; | ||
} | ||
function isRuleConfigValue(v) { | ||
switch (typeof v) { | ||
case 'string': | ||
case 'number': | ||
case 'boolean': { | ||
return true; | ||
function optimizeRules(rules) { | ||
const res = {}; | ||
for (const [key, rule] of Object.entries(rules)) { | ||
const _rule = optimizeRule(rule); | ||
if (_rule != null) { | ||
res[key] = _rule; | ||
} | ||
} | ||
if (v === null) { | ||
return true; | ||
} | ||
return Array.isArray(v); | ||
return res; | ||
} | ||
function deleteUndefProp(obj) { | ||
if (!(0, is_plain_object_1.isPlainObject)(obj)) { | ||
function optimizeRule(rule) { | ||
if (rule === undefined) { | ||
return; | ||
} | ||
for (const key in obj) { | ||
if (obj[key] === undefined) { | ||
delete obj[key]; | ||
} | ||
if ((0, utils_1.isRuleConfigValue)(rule)) { | ||
return rule; | ||
} | ||
return (0, utils_1.cleanOptions)(rule); | ||
} |
@@ -5,76 +5,74 @@ import type { ParserOptions } from '@markuplint/ml-ast'; | ||
export interface Config { | ||
$schema?: string; | ||
extends?: string | string[]; | ||
plugins?: (PluginConfig | string)[]; | ||
parser?: ParserConfig; | ||
parserOptions?: ParserOptions; | ||
specs?: SpecConfig; | ||
excludeFiles?: string[]; | ||
pretenders?: Pretender[]; | ||
rules?: Rules; | ||
nodeRules?: NodeRule[]; | ||
childNodeRules?: ChildNodeRule[]; | ||
overrides?: Record<string, Omit<Config, '$schema' | 'extends' | 'overrides'>>; | ||
$schema?: string; | ||
extends?: string | string[]; | ||
plugins?: (PluginConfig | string)[]; | ||
parser?: ParserConfig; | ||
parserOptions?: ParserOptions; | ||
specs?: SpecConfig; | ||
excludeFiles?: string[]; | ||
pretenders?: Pretender[]; | ||
rules?: Rules; | ||
nodeRules?: NodeRule[]; | ||
childNodeRules?: ChildNodeRule[]; | ||
overrides?: Record<string, Omit<Config, '$schema' | 'extends' | 'overrides'>>; | ||
} | ||
export type PluginConfig = { | ||
name: string; | ||
settings: Record<string, any>; | ||
name: string; | ||
settings: Record<string, any>; | ||
}; | ||
export interface ParserConfig { | ||
[extensionPattern: string]: string; | ||
[extensionPattern: string]: string; | ||
} | ||
export type SpecConfig = { | ||
[extensionPattern: string]: string; | ||
[extensionPattern: string]: string; | ||
}; | ||
export type Pretender = { | ||
/** | ||
* Target node selectors | ||
*/ | ||
selector: string; | ||
/** | ||
* If it is a string, it is resolved as an element name. | ||
* An element has the same attributes as the pretended custom element | ||
* because attributes are just inherited. | ||
* | ||
* If it is an Object, It creates the element by that. | ||
*/ | ||
as: string | OriginalNode; | ||
/** | ||
* Target node selectors | ||
*/ | ||
selector: string; | ||
/** | ||
* If it is a string, it is resolved as an element name. | ||
* An element has the same attributes as the pretended custom element | ||
* because attributes are just inherited. | ||
* | ||
* If it is an Object, It creates the element by that. | ||
*/ | ||
as: string | OriginalNode; | ||
}; | ||
export type OriginalNode = { | ||
/** | ||
* Element name | ||
*/ | ||
element: string; | ||
/** | ||
* Namespace | ||
* | ||
* Supports `"svg"` and `undefined` only. | ||
* If it is `undefined`, the namespace is HTML. | ||
*/ | ||
namespace?: 'svg'; | ||
/** | ||
* Attributes | ||
*/ | ||
attrs?: { | ||
/** | ||
* Attribute name | ||
*/ | ||
name: string; | ||
/** | ||
* If it omits this property, the attribute is resolved as a boolean. | ||
*/ | ||
value?: | ||
| string | ||
| { | ||
fromAttr: string; | ||
}; | ||
}[]; | ||
/** | ||
* To have attributes the defined element has. | ||
*/ | ||
inheritAttrs?: boolean; | ||
/** | ||
* ARIA properties | ||
*/ | ||
aria?: PretenderARIA; | ||
/** | ||
* Element name | ||
*/ | ||
element: string; | ||
/** | ||
* Namespace | ||
* | ||
* Supports `"svg"` and `undefined` only. | ||
* If it is `undefined`, the namespace is HTML. | ||
*/ | ||
namespace?: 'svg'; | ||
/** | ||
* Attributes | ||
*/ | ||
attrs?: { | ||
/** | ||
* Attribute name | ||
*/ | ||
name: string; | ||
/** | ||
* If it omits this property, the attribute is resolved as a boolean. | ||
*/ | ||
value?: string | { | ||
fromAttr: string; | ||
}; | ||
}[]; | ||
/** | ||
* To have attributes the defined element has. | ||
*/ | ||
inheritAttrs?: boolean; | ||
/** | ||
* ARIA properties | ||
*/ | ||
aria?: PretenderARIA; | ||
}; | ||
@@ -85,78 +83,99 @@ /** | ||
export type PretenderARIA = { | ||
/** | ||
* Accessible name | ||
* | ||
* - If it is `true`, it assumes the element has any text on its accessible name. | ||
* - If it specifies `fromAttr` property, it assumes the accessible name refers to the value of the attribute. | ||
*/ | ||
name?: | ||
| boolean | ||
| { | ||
fromAttr: string; | ||
}; | ||
/** | ||
* Accessible name | ||
* | ||
* - If it is `true`, it assumes the element has any text on its accessible name. | ||
* - If it specifies `fromAttr` property, it assumes the accessible name refers to the value of the attribute. | ||
*/ | ||
name?: boolean | { | ||
fromAttr: string; | ||
}; | ||
}; | ||
export type Rule<T extends RuleConfigValue, O = void> = RuleConfig<T, O> | T | boolean; | ||
/** | ||
* @deprecated | ||
*/ | ||
export type RuleV2<T extends RuleConfigValue, O = void> = RuleConfigV2<T, O> | T | boolean; | ||
export type AnyRule = Rule<RuleConfigValue, unknown>; | ||
/** | ||
* @deprecated | ||
*/ | ||
export type AnyRuleV2 = RuleV2<RuleConfigValue, unknown>; | ||
export interface Rules { | ||
[ruleName: string]: AnyRule; | ||
[ruleName: string]: AnyRule; | ||
} | ||
export type RuleConfig<T extends RuleConfigValue, O = void> = { | ||
severity?: Severity; | ||
value?: T; | ||
option?: O; | ||
reason?: string; | ||
severity?: Severity; | ||
value?: T; | ||
options?: O; | ||
reason?: string; | ||
}; | ||
/** | ||
* @deprecated | ||
*/ | ||
export type RuleConfigV2<T extends RuleConfigValue, O = void> = { | ||
severity?: Severity; | ||
value?: T; | ||
reason?: string; | ||
/** | ||
* Old property | ||
* | ||
* @deprecated | ||
* @see {this.options} | ||
*/ | ||
option?: O; | ||
}; | ||
export type Severity = 'error' | 'warning' | 'info'; | ||
export type RuleConfigValue = string | number | boolean | any[] | null; | ||
export interface NodeRule { | ||
selector?: string; | ||
regexSelector?: RegexSelector; | ||
categories?: string[]; | ||
roles?: string[]; | ||
obsolete?: boolean; | ||
rules?: Rules; | ||
selector?: string; | ||
regexSelector?: RegexSelector; | ||
categories?: string[]; | ||
roles?: string[]; | ||
obsolete?: boolean; | ||
rules?: Rules; | ||
} | ||
export interface ChildNodeRule { | ||
selector?: string; | ||
regexSelector?: RegexSelector; | ||
inheritance?: boolean; | ||
rules?: Rules; | ||
selector?: string; | ||
regexSelector?: RegexSelector; | ||
inheritance?: boolean; | ||
rules?: Rules; | ||
} | ||
export type Report<T extends RuleConfigValue, O = null> = Report1<T, O> | Report2 | (Report1<T, O> & Report2); | ||
export type Report1<T extends RuleConfigValue, O = null> = { | ||
message: string; | ||
scope: Scope<T, O>; | ||
message: string; | ||
scope: Scope<T, O>; | ||
}; | ||
export type Report2 = { | ||
message: string; | ||
line: number; | ||
col: number; | ||
raw: string; | ||
message: string; | ||
line: number; | ||
col: number; | ||
raw: string; | ||
}; | ||
export type Scope<T extends RuleConfigValue, O = null> = { | ||
rule: RuleInfo<T, O>; | ||
startLine: number; | ||
startCol: number; | ||
raw: string; | ||
rule: RuleInfo<T, O>; | ||
startLine: number; | ||
startCol: number; | ||
raw: string; | ||
}; | ||
export interface Violation { | ||
ruleId: string; | ||
severity: Severity; | ||
message: string; | ||
reason?: string; | ||
line: number; | ||
col: number; | ||
raw: string; | ||
ruleId: string; | ||
severity: Severity; | ||
message: string; | ||
reason?: string; | ||
line: number; | ||
col: number; | ||
raw: string; | ||
} | ||
export interface RuleInfo<T extends RuleConfigValue, O = null> { | ||
disabled: boolean; | ||
severity: Severity; | ||
value: T; | ||
option: O; | ||
reason?: string; | ||
disabled: boolean; | ||
severity: Severity; | ||
value: T; | ||
options: O; | ||
reason?: string; | ||
} | ||
export type GlobalRuleInfo<T extends RuleConfigValue, O = null> = RuleInfo<T, O> & { | ||
nodeRules: RuleInfo<T, O>[]; | ||
childNodeRules: RuleInfo<T, O>[]; | ||
nodeRules: RuleInfo<T, O>[]; | ||
childNodeRules: RuleInfo<T, O>[]; | ||
}; | ||
export type Nullable<T> = T | null | undefined; |
@@ -1,2 +0,2 @@ | ||
import type { AnyRule } from './types'; | ||
import type { AnyRule, AnyRuleV2, RuleConfig, RuleConfigV2, RuleConfigValue } from './types'; | ||
/** | ||
@@ -10,2 +10,10 @@ * Return undefined if the template doesn't include the variable that is set as a property in data. | ||
export declare function provideValue(template: string, data: Record<string, string>): string | undefined; | ||
export declare function exchangeValueOnRule(rule: AnyRule, data: Record<string, string>): AnyRule | undefined; | ||
export declare function exchangeValueOnRule(rule: AnyRule | AnyRuleV2, data: Record<string, string>): AnyRule | undefined; | ||
export declare function cleanOptions(rule: RuleConfig<RuleConfigValue, unknown> | RuleConfigV2<RuleConfigValue, unknown>): RuleConfig<RuleConfigValue, unknown>; | ||
export declare function isRuleConfigValue(v: any): v is RuleConfigValue; | ||
/** | ||
* | ||
* @param obj | ||
* @returns | ||
*/ | ||
export declare function deleteUndefProp(obj: any): void; |
103
lib/utils.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.exchangeValueOnRule = exports.provideValue = void 0; | ||
exports.deleteUndefProp = exports.isRuleConfigValue = exports.cleanOptions = exports.exchangeValueOnRule = exports.provideValue = void 0; | ||
const tslib_1 = require("tslib"); | ||
const is_plain_object_1 = require("is-plain-object"); | ||
const mustache_1 = tslib_1.__importDefault(require("mustache")); | ||
@@ -29,27 +30,85 @@ /** | ||
function exchangeValueOnRule(rule, data) { | ||
if (rule != null && typeof rule === 'object' && !Array.isArray(rule)) { | ||
if (rule.value != null) { | ||
rule = { | ||
...rule, | ||
value: exchangeValue(rule.value, data), | ||
}; | ||
if (isRuleConfigValue(rule)) { | ||
return exchangeValue(rule, data); | ||
} | ||
let result = cleanOptions(rule); | ||
if (result.value != null) { | ||
result = { | ||
...result, | ||
value: exchangeValue(result.value, data), | ||
}; | ||
} | ||
const options = extractOptions(result); | ||
if (options) { | ||
result = { | ||
...result, | ||
options: exchangeOption(options, data), | ||
}; | ||
} | ||
if (result.reason != null) { | ||
const exchangedValue = exchangeValue(result.reason, data); | ||
result = { | ||
...result, | ||
reason: exchangedValue ? `${exchangedValue}` : undefined, | ||
}; | ||
} | ||
deleteUndefProp(result); | ||
return result; | ||
} | ||
exports.exchangeValueOnRule = exchangeValueOnRule; | ||
function cleanOptions(rule) { | ||
const res = { | ||
severity: rule.severity, | ||
value: rule.value, | ||
options: extractOptions(rule), | ||
reason: rule.reason, | ||
}; | ||
deleteUndefProp(res); | ||
return res; | ||
} | ||
exports.cleanOptions = cleanOptions; | ||
function isRuleConfigValue(v) { | ||
switch (typeof v) { | ||
case 'string': | ||
case 'number': | ||
case 'boolean': { | ||
return true; | ||
} | ||
if (rule.option) { | ||
rule = { | ||
...rule, | ||
option: exchangeOption(rule.option, data), | ||
}; | ||
} | ||
if (v === null) { | ||
return true; | ||
} | ||
return Array.isArray(v); | ||
} | ||
exports.isRuleConfigValue = isRuleConfigValue; | ||
/** | ||
* | ||
* @param obj | ||
* @returns | ||
*/ | ||
function deleteUndefProp(obj) { | ||
if (!(0, is_plain_object_1.isPlainObject)(obj)) { | ||
return; | ||
} | ||
for (const key in obj) { | ||
if (obj[key] === undefined) { | ||
delete obj[key]; | ||
} | ||
if (rule.reason != null) { | ||
const exchangedValue = exchangeValue(rule.reason, data); | ||
rule = { | ||
...rule, | ||
reason: exchangedValue ? `${exchangedValue}` : undefined, | ||
}; | ||
} | ||
return rule; | ||
} | ||
return exchangeValue(rule, data); | ||
} | ||
exports.exchangeValueOnRule = exchangeValueOnRule; | ||
exports.deleteUndefProp = deleteUndefProp; | ||
/** | ||
* Return options from `options` or `option` | ||
* | ||
* @param rule | ||
* @returns | ||
*/ | ||
function extractOptions(rule) { | ||
if ('options' in rule && rule.options) { | ||
return rule.options; | ||
} | ||
if ('option' in rule && rule.option) { | ||
return rule.option; | ||
} | ||
} | ||
function exchangeValue(rule, data) { | ||
@@ -56,0 +115,0 @@ if (rule == null) { |
{ | ||
"name": "@markuplint/ml-config", | ||
"version": "3.0.0-rc.1", | ||
"version": "3.0.0-rc.2", | ||
"description": "JSON Schema and TypeScript types of markuplint configure JSON", | ||
@@ -19,7 +19,7 @@ "repository": "git@github.com:markuplint/markuplint.git", | ||
"devDependencies": { | ||
"@markuplint/ml-ast": "3.0.0-rc.1", | ||
"@markuplint/ml-ast": "3.0.0-rc.2", | ||
"@types/mustache": "^4.2.2" | ||
}, | ||
"dependencies": { | ||
"@markuplint/selector": "3.0.0-rc.1", | ||
"@markuplint/selector": "3.0.0-rc.2", | ||
"deepmerge": "^4.2.2", | ||
@@ -29,3 +29,3 @@ "is-plain-object": "^5.0.0", | ||
}, | ||
"gitHead": "f0d1cd3216c171949c6e6be0d4388a760bd5d37b" | ||
"gitHead": "27a5c8d136f4b0cf8452552cff529dd0a4db6bba" | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82320
542
+ Added@markuplint/selector@3.0.0-rc.2(transitive)
- Removed@markuplint/selector@3.0.0-rc.1(transitive)