jsii 5.9.44 → 5.9.48-dev.3
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/README.md +112 -286
- package/lib/assembler.d.ts +7 -0
- package/lib/assembler.js +24 -1
- package/lib/assembler.js.map +1 -1
- package/lib/compiler.js +2 -2
- package/lib/compiler.js.map +1 -1
- package/lib/main.js +73 -7
- package/lib/main.js.map +1 -1
- package/lib/tsconfig/rule-set-format.d.ts +34 -0
- package/lib/tsconfig/rule-set-format.js +98 -0
- package/lib/tsconfig/rule-set-format.js.map +1 -0
- package/lib/tsconfig/tsconfig-validator.d.ts +39 -0
- package/lib/tsconfig/tsconfig-validator.js +82 -0
- package/lib/tsconfig/tsconfig-validator.js.map +1 -1
- package/lib/tsconfig/validator.d.ts +34 -0
- package/lib/tsconfig/validator.js +39 -0
- package/lib/tsconfig/validator.js.map +1 -1
- package/lib/version.d.ts +2 -2
- package/lib/version.js +2 -2
- package/lib/version.js.map +1 -1
- package/package.json +9 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TypeScriptConfig, TypeScriptConfigValidationRuleSet } from '.';
|
|
2
|
+
import { RuleDescription, RuleSet, Violation } from './validator';
|
|
2
3
|
export declare class TypeScriptConfigValidator {
|
|
3
4
|
ruleSet: TypeScriptConfigValidationRuleSet;
|
|
4
5
|
private readonly validator;
|
|
@@ -13,4 +14,42 @@ export declare class TypeScriptConfigValidator {
|
|
|
13
14
|
*/
|
|
14
15
|
validate(tsconfig: TypeScriptConfig): void;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the `compilerOptions` rule set that backs the given validation setting.
|
|
19
|
+
*
|
|
20
|
+
* These are the substantive, set-specific rules (the top-level rules such as
|
|
21
|
+
* `files`/`include`/`exclude` are identical across all sets). The `off` rule set
|
|
22
|
+
* is empty, as it disables validation.
|
|
23
|
+
*
|
|
24
|
+
* @param ruleSet the validation setting to look up
|
|
25
|
+
* @returns the `RuleSet` applied to `compilerOptions`
|
|
26
|
+
*/
|
|
27
|
+
export declare function getCompilerOptionsRuleSet(ruleSet: TypeScriptConfigValidationRuleSet): RuleSet;
|
|
28
|
+
/**
|
|
29
|
+
* Produces a human-readable description of every `compilerOptions` rule in a rule set.
|
|
30
|
+
*
|
|
31
|
+
* @param ruleSet the validation setting to describe
|
|
32
|
+
* @returns a description for every rule in the set
|
|
33
|
+
*/
|
|
34
|
+
export declare function describeRuleSet(ruleSet: TypeScriptConfigValidationRuleSet): RuleDescription[];
|
|
35
|
+
/**
|
|
36
|
+
* Reads and parses a `tsconfig.json` file from disk into the format expected by
|
|
37
|
+
* the validator. This resolves `extends` and normalizes the options the same way
|
|
38
|
+
* the compiler does, so validation behaves identically to a real compilation.
|
|
39
|
+
*
|
|
40
|
+
* @param configPath the path to the tsconfig file to read
|
|
41
|
+
* @throws {@link JsiiError} if the file cannot be read or parsed
|
|
42
|
+
* @returns the parsed TypeScript configuration
|
|
43
|
+
*/
|
|
44
|
+
export declare function readTypeScriptConfig(configPath: string): TypeScriptConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Reads a `tsconfig.json` file from disk and validates its `compilerOptions`
|
|
47
|
+
* against the given rule set, without running a compilation.
|
|
48
|
+
*
|
|
49
|
+
* @param configPath the path to the tsconfig file to validate
|
|
50
|
+
* @param ruleSet the rule set to validate against
|
|
51
|
+
* @throws {@link JsiiError} if the file cannot be read or parsed
|
|
52
|
+
* @returns the list of rule violations (empty if the config is valid)
|
|
53
|
+
*/
|
|
54
|
+
export declare function validateTypeScriptConfigFile(configPath: string, ruleSet: TypeScriptConfigValidationRuleSet): Violation[];
|
|
16
55
|
//# sourceMappingURL=tsconfig-validator.d.ts.map
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TypeScriptConfigValidator = void 0;
|
|
4
|
+
exports.getCompilerOptionsRuleSet = getCompilerOptionsRuleSet;
|
|
5
|
+
exports.describeRuleSet = describeRuleSet;
|
|
6
|
+
exports.readTypeScriptConfig = readTypeScriptConfig;
|
|
7
|
+
exports.validateTypeScriptConfigFile = validateTypeScriptConfigFile;
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
const ts = require("typescript");
|
|
10
|
+
const compiler_options_1 = require("./compiler-options");
|
|
11
|
+
const utils_1 = require("../utils");
|
|
4
12
|
const generated_public_1 = require("./rulesets/generated.public");
|
|
5
13
|
const minimal_public_1 = require("./rulesets/minimal.public");
|
|
6
14
|
const strict_public_1 = require("./rulesets/strict.public");
|
|
@@ -43,4 +51,78 @@ class TypeScriptConfigValidator {
|
|
|
43
51
|
}
|
|
44
52
|
}
|
|
45
53
|
exports.TypeScriptConfigValidator = TypeScriptConfigValidator;
|
|
54
|
+
/**
|
|
55
|
+
* Returns the `compilerOptions` rule set that backs the given validation setting.
|
|
56
|
+
*
|
|
57
|
+
* These are the substantive, set-specific rules (the top-level rules such as
|
|
58
|
+
* `files`/`include`/`exclude` are identical across all sets). The `off` rule set
|
|
59
|
+
* is empty, as it disables validation.
|
|
60
|
+
*
|
|
61
|
+
* @param ruleSet the validation setting to look up
|
|
62
|
+
* @returns the `RuleSet` applied to `compilerOptions`
|
|
63
|
+
*/
|
|
64
|
+
function getCompilerOptionsRuleSet(ruleSet) {
|
|
65
|
+
return RuleSets[ruleSet];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Produces a human-readable description of every `compilerOptions` rule in a rule set.
|
|
69
|
+
*
|
|
70
|
+
* @param ruleSet the validation setting to describe
|
|
71
|
+
* @returns a description for every rule in the set
|
|
72
|
+
*/
|
|
73
|
+
function describeRuleSet(ruleSet) {
|
|
74
|
+
return getCompilerOptionsRuleSet(ruleSet).describe();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Reads and parses a `tsconfig.json` file from disk into the format expected by
|
|
78
|
+
* the validator. This resolves `extends` and normalizes the options the same way
|
|
79
|
+
* the compiler does, so validation behaves identically to a real compilation.
|
|
80
|
+
*
|
|
81
|
+
* @param configPath the path to the tsconfig file to read
|
|
82
|
+
* @throws {@link JsiiError} if the file cannot be read or parsed
|
|
83
|
+
* @returns the parsed TypeScript configuration
|
|
84
|
+
*/
|
|
85
|
+
function readTypeScriptConfig(configPath) {
|
|
86
|
+
const absolutePath = path.resolve(configPath);
|
|
87
|
+
const { config, error } = ts.readConfigFile(absolutePath, ts.sys.readFile);
|
|
88
|
+
if (error) {
|
|
89
|
+
throw new utils_1.JsiiError(`Failed to read tsconfig at "${configPath}": ${ts.flattenDiagnosticMessageText(error.messageText, '\n')}`);
|
|
90
|
+
}
|
|
91
|
+
const basePath = path.dirname(absolutePath);
|
|
92
|
+
const extended = ts.parseJsonConfigFileContent(config, ts.sys, basePath);
|
|
93
|
+
// the tsconfig parser adds this in, but it is not an expected compilerOption
|
|
94
|
+
delete extended.options.configFilePath;
|
|
95
|
+
return {
|
|
96
|
+
compilerOptions: extended.options,
|
|
97
|
+
watchOptions: extended.watchOptions,
|
|
98
|
+
include: extended.fileNames,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Reads a `tsconfig.json` file from disk and validates its `compilerOptions`
|
|
103
|
+
* against the given rule set, without running a compilation.
|
|
104
|
+
*
|
|
105
|
+
* @param configPath the path to the tsconfig file to validate
|
|
106
|
+
* @param ruleSet the rule set to validate against
|
|
107
|
+
* @throws {@link JsiiError} if the file cannot be read or parsed
|
|
108
|
+
* @returns the list of rule violations (empty if the config is valid)
|
|
109
|
+
*/
|
|
110
|
+
function validateTypeScriptConfigFile(configPath, ruleSet) {
|
|
111
|
+
const config = readTypeScriptConfig(configPath);
|
|
112
|
+
const validator = new TypeScriptConfigValidator(ruleSet);
|
|
113
|
+
try {
|
|
114
|
+
validator.validate({
|
|
115
|
+
...config,
|
|
116
|
+
// convert the internal format to the user format which is what the validator operates on
|
|
117
|
+
compilerOptions: (0, compiler_options_1.convertForJson)(config.compilerOptions),
|
|
118
|
+
});
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (error instanceof validator_1.ValidationError) {
|
|
123
|
+
return error.violations;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
46
128
|
//# sourceMappingURL=tsconfig-validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tsconfig-validator.js","sourceRoot":"","sources":["../../src/tsconfig/tsconfig-validator.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"tsconfig-validator.js","sourceRoot":"","sources":["../../src/tsconfig/tsconfig-validator.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'node:path';\nimport * as ts from 'typescript';\nimport { TypeScriptConfig, TypeScriptConfigValidationRuleSet } from '.';\nimport { convertForJson } from './compiler-options';\nimport { JsiiError } from '../utils';\nimport generated from './rulesets/generated.public';\nimport minimal from './rulesets/minimal.public';\nimport strict from './rulesets/strict.public';\nimport { Match, ObjectValidator, RuleDescription, RuleSet, RuleType, ValidationError, Violation } from './validator';\n\nconst RuleSets: {\n [name in TypeScriptConfigValidationRuleSet]: RuleSet;\n} = {\n generated,\n strict,\n minimal,\n off: new RuleSet(),\n};\n\nexport class TypeScriptConfigValidator {\n private readonly validator: ObjectValidator;\n private readonly compilerOptions: ObjectValidator;\n\n public constructor(public ruleSet: TypeScriptConfigValidationRuleSet) {\n const topLevelRules = new RuleSet({\n unexpectedFields: RuleType.PASS,\n });\n topLevelRules.shouldPass('files', Match.ANY);\n topLevelRules.shouldPass('extends', Match.ANY);\n topLevelRules.shouldPass('include', Match.ANY);\n topLevelRules.shouldPass('exclude', Match.ANY);\n topLevelRules.shouldPass('references', Match.ANY);\n topLevelRules.shouldPass('watchOptions', Match.ANY);\n topLevelRules.shouldPass('typeAcquisition', Match.MISSING);\n\n this.compilerOptions = new ObjectValidator(RuleSets[ruleSet], 'compilerOptions');\n topLevelRules.shouldPass('compilerOptions', (compilerOptions) => {\n this.compilerOptions.validate(compilerOptions);\n return true;\n });\n\n this.validator = new ObjectValidator(topLevelRules, 'tsconfig');\n }\n\n /**\n * Validated the provided config against the set of rules.\n *\n * @throws when the config is invalid\n *\n * @param tsconfig the tsconfig to be validated, this MUST be a tsconfig as a user would have written it in tsconfig.\n */\n public validate(tsconfig: TypeScriptConfig) {\n this.validator.validate(tsconfig);\n }\n}\n\n/**\n * Returns the `compilerOptions` rule set that backs the given validation setting.\n *\n * These are the substantive, set-specific rules (the top-level rules such as\n * `files`/`include`/`exclude` are identical across all sets). The `off` rule set\n * is empty, as it disables validation.\n *\n * @param ruleSet the validation setting to look up\n * @returns the `RuleSet` applied to `compilerOptions`\n */\nexport function getCompilerOptionsRuleSet(ruleSet: TypeScriptConfigValidationRuleSet): RuleSet {\n return RuleSets[ruleSet];\n}\n\n/**\n * Produces a human-readable description of every `compilerOptions` rule in a rule set.\n *\n * @param ruleSet the validation setting to describe\n * @returns a description for every rule in the set\n */\nexport function describeRuleSet(ruleSet: TypeScriptConfigValidationRuleSet): RuleDescription[] {\n return getCompilerOptionsRuleSet(ruleSet).describe();\n}\n\n/**\n * Reads and parses a `tsconfig.json` file from disk into the format expected by\n * the validator. This resolves `extends` and normalizes the options the same way\n * the compiler does, so validation behaves identically to a real compilation.\n *\n * @param configPath the path to the tsconfig file to read\n * @throws {@link JsiiError} if the file cannot be read or parsed\n * @returns the parsed TypeScript configuration\n */\nexport function readTypeScriptConfig(configPath: string): TypeScriptConfig {\n const absolutePath = path.resolve(configPath);\n const { config, error } = ts.readConfigFile(absolutePath, ts.sys.readFile);\n if (error) {\n throw new JsiiError(\n `Failed to read tsconfig at \"${configPath}\": ${ts.flattenDiagnosticMessageText(error.messageText, '\\n')}`,\n );\n }\n\n const basePath = path.dirname(absolutePath);\n const extended = ts.parseJsonConfigFileContent(config, ts.sys, basePath);\n // the tsconfig parser adds this in, but it is not an expected compilerOption\n delete extended.options.configFilePath;\n\n return {\n compilerOptions: extended.options,\n watchOptions: extended.watchOptions,\n include: extended.fileNames,\n };\n}\n\n/**\n * Reads a `tsconfig.json` file from disk and validates its `compilerOptions`\n * against the given rule set, without running a compilation.\n *\n * @param configPath the path to the tsconfig file to validate\n * @param ruleSet the rule set to validate against\n * @throws {@link JsiiError} if the file cannot be read or parsed\n * @returns the list of rule violations (empty if the config is valid)\n */\nexport function validateTypeScriptConfigFile(\n configPath: string,\n ruleSet: TypeScriptConfigValidationRuleSet,\n): Violation[] {\n const config = readTypeScriptConfig(configPath);\n const validator = new TypeScriptConfigValidator(ruleSet);\n try {\n validator.validate({\n ...config,\n // convert the internal format to the user format which is what the validator operates on\n compilerOptions: convertForJson(config.compilerOptions),\n });\n return [];\n } catch (error: unknown) {\n if (error instanceof ValidationError) {\n return error.violations;\n }\n throw error;\n }\n}\n"]}
|
|
@@ -42,6 +42,30 @@ interface Rule {
|
|
|
42
42
|
type: RuleType;
|
|
43
43
|
matcher: Matcher;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* A human-readable description of a single rule.
|
|
47
|
+
* Intended for displaying a rule set to a user, e.g. via the CLI.
|
|
48
|
+
*/
|
|
49
|
+
export interface RuleDescription {
|
|
50
|
+
/**
|
|
51
|
+
* The field (compilerOption) the rule applies to.
|
|
52
|
+
*/
|
|
53
|
+
readonly field: string;
|
|
54
|
+
/**
|
|
55
|
+
* Whether the value must match (`PASS`) or must not match (`FAIL`) the constraint.
|
|
56
|
+
*/
|
|
57
|
+
readonly type: RuleType;
|
|
58
|
+
/**
|
|
59
|
+
* Whether the field is required to be present for the rule to pass.
|
|
60
|
+
*/
|
|
61
|
+
readonly required: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* The values the matcher offered as hints.
|
|
64
|
+
* For `PASS` rules these are allowed values, for `FAIL` rules these are disallowed values.
|
|
65
|
+
* `undefined` when the matcher did not offer any hints (e.g. any value is accepted).
|
|
66
|
+
*/
|
|
67
|
+
readonly values?: any[];
|
|
68
|
+
}
|
|
45
69
|
export declare class RuleSet {
|
|
46
70
|
readonly options: RuleSetOptions;
|
|
47
71
|
private _rules;
|
|
@@ -93,6 +117,16 @@ export declare class RuleSet {
|
|
|
93
117
|
* @returns A record of fields and allowed values
|
|
94
118
|
*/
|
|
95
119
|
getFieldHints(): Record<string, any[]>;
|
|
120
|
+
/**
|
|
121
|
+
* Produces a human-readable description of every rule in the set.
|
|
122
|
+
*
|
|
123
|
+
* This is derived directly from the rules (it does not duplicate them), so it
|
|
124
|
+
* stays in sync as rules are added or changed. It is primarily intended for
|
|
125
|
+
* surfacing a rule set to a user, e.g. via the CLI.
|
|
126
|
+
*
|
|
127
|
+
* @returns A description for every rule, in the order the rules were added.
|
|
128
|
+
*/
|
|
129
|
+
describe(): RuleDescription[];
|
|
96
130
|
}
|
|
97
131
|
export declare class Match {
|
|
98
132
|
/**
|
|
@@ -6,6 +6,12 @@ var RuleType;
|
|
|
6
6
|
RuleType[RuleType["PASS"] = 0] = "PASS";
|
|
7
7
|
RuleType[RuleType["FAIL"] = 1] = "FAIL";
|
|
8
8
|
})(RuleType || (exports.RuleType = RuleType = {}));
|
|
9
|
+
/**
|
|
10
|
+
* A sentinel value used to probe matchers for hints.
|
|
11
|
+
* It is intentionally not `null`/`undefined` so that `Match.optional` delegates
|
|
12
|
+
* to its inner matcher (which is where the hints are recorded).
|
|
13
|
+
*/
|
|
14
|
+
const DESCRIBE_PROBE = Symbol('jsii.tsconfig.describe.probe');
|
|
9
15
|
class RuleSet {
|
|
10
16
|
get rules() {
|
|
11
17
|
return this._rules;
|
|
@@ -116,6 +122,39 @@ class RuleSet {
|
|
|
116
122
|
}
|
|
117
123
|
return fieldHints;
|
|
118
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Produces a human-readable description of every rule in the set.
|
|
127
|
+
*
|
|
128
|
+
* This is derived directly from the rules (it does not duplicate them), so it
|
|
129
|
+
* stays in sync as rules are added or changed. It is primarily intended for
|
|
130
|
+
* surfacing a rule set to a user, e.g. via the CLI.
|
|
131
|
+
*
|
|
132
|
+
* @returns A description for every rule, in the order the rules were added.
|
|
133
|
+
*/
|
|
134
|
+
describe() {
|
|
135
|
+
return this._rules.map((rule) => {
|
|
136
|
+
// Probe the matcher for the values it considers relevant (hints).
|
|
137
|
+
const values = [];
|
|
138
|
+
let hinted = false;
|
|
139
|
+
rule.matcher(DESCRIBE_PROBE, {
|
|
140
|
+
hints: (allowed) => {
|
|
141
|
+
hinted = true;
|
|
142
|
+
if (allowed) {
|
|
143
|
+
values.push(...allowed);
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
// A field is required if the rule is not satisfied when the value is absent.
|
|
148
|
+
const passesWhenAbsent = rule.matcher(undefined);
|
|
149
|
+
const required = rule.type === RuleType.PASS ? !passesWhenAbsent : passesWhenAbsent;
|
|
150
|
+
return {
|
|
151
|
+
field: rule.field,
|
|
152
|
+
type: rule.type,
|
|
153
|
+
required,
|
|
154
|
+
values: hinted ? values : undefined,
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
119
158
|
}
|
|
120
159
|
exports.RuleSet = RuleSet;
|
|
121
160
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/tsconfig/validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A function that receives 3 arguments and validates if the provided value matches.\n * @param value The value to validate\n * @params options Additional options to influence the matcher behavior.\n * @returns true if the value matches\n */\ntype Matcher = (value: any, options?: MatcherOptions) => boolean;\n\ninterface MatcherOptions {\n /**\n * A function that will be called by the matcher with a a violation message.\n * This function is always called, regardless of the outcome of the matcher.\n * It is up to the caller of the matcher to decide if the message should be used or not.\n *\n * @param message The message describing the possible failure.\n */\n reporter?: (message: string) => void;\n /**\n * A function that might receive explicitly allowed values.\n * This can be used to generate synthetics values that would match the matcher.\n * It is not guaranteed that hints are received or that hints are complete.\n *\n * @param allowed The list values that a matcher offers as definitely allowed.\n */\n hints?: (allowed: any[]) => void;\n}\n\nexport enum RuleType {\n PASS,\n FAIL,\n}\n\nexport interface RuleSetOptions {\n /**\n * Defines the behavior for any encountered fields for which no rules are defined.\n * The default is to pass these fields without validation,\n * but this can also be set to fail any unexpected fields.\n *\n * @default RuleType.PASS\n */\n readonly unexpectedFields: RuleType;\n}\n\ninterface Rule {\n field: string;\n type: RuleType;\n matcher: Matcher;\n}\n\nexport class RuleSet {\n private _rules: Array<Rule> = [];\n public get rules(): Array<Rule> {\n return this._rules;\n }\n\n /**\n * Return all fields for which a rule exists\n */\n public get fields(): Array<string> {\n return [...new Set(this._rules.map((r) => r.field))];\n }\n\n /**\n * Return a list of fields that are allowed, or undefined if all are allowed.\n */\n public get allowedFields(): Array<string> | undefined {\n if (this.options.unexpectedFields === RuleType.FAIL) {\n return this.fields;\n }\n\n return undefined;\n }\n\n /**\n * Find all required fields by evaluating every rule in th set against undefined.\n * If the rule fails, the key must be required.\n *\n * @returns A list of keys that must be included or undefined\n */\n public get requiredFields(): Array<string> {\n const required: string[] = [];\n\n for (const rule of this._rules) {\n const key = rule.field;\n const matcherResult = rule.matcher(undefined);\n\n switch (rule.type) {\n case RuleType.PASS:\n if (!matcherResult) {\n required.push(key);\n }\n break;\n case RuleType.FAIL:\n if (matcherResult) {\n required.push(key);\n }\n break;\n default:\n continue;\n }\n }\n\n return required;\n }\n\n public constructor(\n public readonly options: RuleSetOptions = {\n unexpectedFields: RuleType.PASS,\n },\n ) {}\n\n /**\n * Requires the matcher to pass for the given field.\n * Otherwise a violation is detected.\n *\n * @param field The field the rule applies to\n * @param matcher The matcher function\n */\n public shouldPass(field: string, matcher: Matcher) {\n this._rules.push({ field, matcher, type: RuleType.PASS });\n }\n\n /**\n * Detects a violation if the matcher is matching for a certain field.\n *\n * @param field The field the rule applies to\n * @param matcher The matcher function\n */\n public shouldFail(field: string, matcher: Matcher) {\n this._rules.push({ field, matcher, type: RuleType.FAIL });\n }\n\n /**\n * Imports all rules from an other rule set.\n * Note that any options from the other rule set will be ignored.\n *\n * @param other The other rule set to import rules from.\n */\n public import(other: RuleSet) {\n this._rules.push(...other.rules);\n }\n\n /**\n * Records the field hints for the given rule set.\n * Hints are values that are guaranteed to pass the rule.\n * The list of hints is not guaranteed to be complete nor does it guarantee to return any values.\n * This can be used to create synthetic values for testing for error messages.\n *\n * @returns A record of fields and allowed values\n */\n public getFieldHints(): Record<string, any[]> {\n const fieldHints: Record<string, any[]> = {};\n\n for (const rule of this._rules) {\n // We are only interested in PASS rules here.\n // For FAILs we still don't know which values would pass.\n if (rule.type === RuleType.PASS) {\n // run the matcher to record hints\n rule.matcher(undefined, {\n hints: (receivedHints: any[]) => {\n // if we have recorded hints, add them to the map\n if (receivedHints) {\n fieldHints[rule.field] ??= [];\n fieldHints[rule.field].push(...receivedHints);\n }\n },\n });\n }\n }\n\n return fieldHints;\n }\n}\n\n/**\n * Helper to wrap a matcher with error reporting and hints\n */\nfunction wrapMatcher(matcher: Matcher, message: (actual: any) => string, allowed?: any[]): Matcher {\n return (value, options) => {\n options?.reporter?.(message(value));\n if (allowed) {\n options?.hints?.(allowed);\n }\n return matcher(value);\n };\n}\n\n/**\n * Helper to implement loose equality that is safe for any value\n * Needed because there are some values that are equal as object, but not with ==\n * There are also values that cannot be compared using == and will throw\n */\nfunction looseEqual(a: any, b: any): boolean {\n try {\n // if one of the values is an object (or array), but the other isn't - never consider them the same\n if ([typeof a, typeof b].filter((t) => t === 'object').length === 1) {\n return false;\n }\n // if both values are the same object\n // or if both values are loose equal\n return Object.is(a, b) || a == b;\n } catch {\n return false;\n }\n}\n\nexport class Match {\n /**\n * Value is optional, but if present should match\n */\n public static optional(matcher: Matcher): Matcher {\n return (value, options) => {\n if (value == null) {\n return true;\n }\n return matcher(value, options);\n };\n }\n\n /**\n * Value must be one of the allowed options\n */\n public static oneOf(...allowed: Array<string | number>): Matcher {\n return wrapMatcher(\n (actual) => allowed.includes(actual),\n (actual) => `Expected value to be one of ${JSON.stringify(allowed)}, got: ${JSON.stringify(actual)}`,\n allowed,\n );\n }\n\n /**\n * Value must be loosely equal to the expected value\n * Arrays are compared by elements\n */\n public static eq(expected: any): Matcher {\n return (actual, options) => {\n if (Array.isArray(expected)) {\n return Match.arrEq(expected)(actual, options);\n }\n\n options?.hints?.([expected]);\n options?.reporter?.(`Expected value ${JSON.stringify(expected)}, got: ${JSON.stringify(actual)}`);\n return looseEqual(actual, expected);\n };\n }\n\n /**\n * Value must be loosely equal to the expected value\n * Arrays are compared by elements\n */\n public static arrEq(expected: any[]): Matcher {\n return wrapMatcher(\n (actual) => {\n // if both are arrays and of the same length, compare elements\n // if one of them is not, or they are a different length,\n // skip comparing elements as the the equality check later will fail\n if (Array.isArray(expected) && Array.isArray(actual) && expected.length == actual.length) {\n // compare all elements with loose typing\n return expected.every((e) => actual.some((a) => looseEqual(a, e)));\n }\n\n // all other values and arrays of different shape\n return looseEqual(actual, expected);\n },\n (actual) => `Expected array matching ${JSON.stringify(expected)}, got: ${JSON.stringify(actual)}`,\n [expected],\n );\n }\n\n /**\n * Compare strings, allows setting cases sensitivity\n */\n public static strEq(expected: string, caseSensitive = false): Matcher {\n return wrapMatcher(\n (actual) => {\n // case insensitive\n if (!caseSensitive && typeof actual === 'string') {\n return looseEqual(expected.toLowerCase(), actual.toLowerCase());\n }\n\n // case sensitive\n return looseEqual(actual, expected);\n },\n (actual: any) => `Expected string ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,\n [expected],\n );\n }\n\n /**\n * Allows any value\n */\n public static ANY: Matcher = (_val, _options) => true;\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static TRUE: Matcher = Match.eq(true);\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static FALSE: Matcher = Match.eq(false);\n\n /**\n * Missing (undefined) value\n */\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static MISSING = wrapMatcher(\n (actual) => actual === null || actual === undefined,\n (actual) => `Expected value to be present, got ${JSON.stringify(actual)}`,\n [undefined, null],\n );\n}\n\nexport interface Violation {\n field: string;\n message: string;\n}\n\nexport class ValidationError extends Error {\n constructor(public readonly violations: Violation[]) {\n // error message is a list of violations\n super('Data is invalid:\\n' + violations.map((v) => v.field + ': ' + v.message).join('\\n'));\n\n // Set the prototype explicitly.\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class ObjectValidator {\n public constructor(public ruleSet: RuleSet, private readonly dataName: string = 'data') {}\n\n /**\n * Validated the provided data against the set of rules.\n *\n * @throws when the data is invalid\n *\n * @param data the data to be validated\n */\n public validate(data: { [field: string]: any }) {\n // make sure data is an object\n if (!(typeof data === 'object' && !Array.isArray(data) && data !== null)) {\n throw new ValidationError([\n { field: this.dataName, message: 'Provided data must be an object, got: ' + JSON.stringify(data) },\n ]);\n }\n\n const checkedFields = new Set();\n const violations: Violation[] = [];\n\n // first check all defined rules\n for (const rule of this.ruleSet.rules) {\n const value = data[rule.field];\n\n // Use a fallback message, but allow the matcher to report a better arrow\n let violationMessage = 'Value is not allowed, got: ' + JSON.stringify(value);\n const matchResult = rule.matcher(value, {\n reporter: (message: string) => {\n violationMessage = message;\n },\n });\n\n switch (rule.type) {\n case RuleType.PASS:\n if (!matchResult) {\n violations.push({\n field: rule.field,\n message: violationMessage,\n });\n }\n break;\n case RuleType.FAIL:\n if (matchResult) {\n violations.push({\n field: rule.field,\n message: violationMessage,\n });\n }\n break;\n default:\n continue;\n }\n\n checkedFields.add(rule.field);\n }\n\n // finally check fields without any rules if they should fail the validation\n if (this.ruleSet.options.unexpectedFields === RuleType.FAIL) {\n const receivedFields = Object.keys(data);\n for (const field of receivedFields) {\n if (!checkedFields.has(field)) {\n violations.push({ field: field, message: `Unexpected field, got: ${field}` });\n }\n }\n }\n\n // if we have encountered a violation, throw an error\n if (violations.length > 0) {\n throw new ValidationError(violations);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/tsconfig/validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A function that receives 3 arguments and validates if the provided value matches.\n * @param value The value to validate\n * @params options Additional options to influence the matcher behavior.\n * @returns true if the value matches\n */\ntype Matcher = (value: any, options?: MatcherOptions) => boolean;\n\ninterface MatcherOptions {\n /**\n * A function that will be called by the matcher with a a violation message.\n * This function is always called, regardless of the outcome of the matcher.\n * It is up to the caller of the matcher to decide if the message should be used or not.\n *\n * @param message The message describing the possible failure.\n */\n reporter?: (message: string) => void;\n /**\n * A function that might receive explicitly allowed values.\n * This can be used to generate synthetics values that would match the matcher.\n * It is not guaranteed that hints are received or that hints are complete.\n *\n * @param allowed The list values that a matcher offers as definitely allowed.\n */\n hints?: (allowed: any[]) => void;\n}\n\nexport enum RuleType {\n PASS,\n FAIL,\n}\n\nexport interface RuleSetOptions {\n /**\n * Defines the behavior for any encountered fields for which no rules are defined.\n * The default is to pass these fields without validation,\n * but this can also be set to fail any unexpected fields.\n *\n * @default RuleType.PASS\n */\n readonly unexpectedFields: RuleType;\n}\n\ninterface Rule {\n field: string;\n type: RuleType;\n matcher: Matcher;\n}\n\n/**\n * A human-readable description of a single rule.\n * Intended for displaying a rule set to a user, e.g. via the CLI.\n */\nexport interface RuleDescription {\n /**\n * The field (compilerOption) the rule applies to.\n */\n readonly field: string;\n\n /**\n * Whether the value must match (`PASS`) or must not match (`FAIL`) the constraint.\n */\n readonly type: RuleType;\n\n /**\n * Whether the field is required to be present for the rule to pass.\n */\n readonly required: boolean;\n\n /**\n * The values the matcher offered as hints.\n * For `PASS` rules these are allowed values, for `FAIL` rules these are disallowed values.\n * `undefined` when the matcher did not offer any hints (e.g. any value is accepted).\n */\n readonly values?: any[];\n}\n\n/**\n * A sentinel value used to probe matchers for hints.\n * It is intentionally not `null`/`undefined` so that `Match.optional` delegates\n * to its inner matcher (which is where the hints are recorded).\n */\nconst DESCRIBE_PROBE = Symbol('jsii.tsconfig.describe.probe');\n\nexport class RuleSet {\n private _rules: Array<Rule> = [];\n public get rules(): Array<Rule> {\n return this._rules;\n }\n\n /**\n * Return all fields for which a rule exists\n */\n public get fields(): Array<string> {\n return [...new Set(this._rules.map((r) => r.field))];\n }\n\n /**\n * Return a list of fields that are allowed, or undefined if all are allowed.\n */\n public get allowedFields(): Array<string> | undefined {\n if (this.options.unexpectedFields === RuleType.FAIL) {\n return this.fields;\n }\n\n return undefined;\n }\n\n /**\n * Find all required fields by evaluating every rule in th set against undefined.\n * If the rule fails, the key must be required.\n *\n * @returns A list of keys that must be included or undefined\n */\n public get requiredFields(): Array<string> {\n const required: string[] = [];\n\n for (const rule of this._rules) {\n const key = rule.field;\n const matcherResult = rule.matcher(undefined);\n\n switch (rule.type) {\n case RuleType.PASS:\n if (!matcherResult) {\n required.push(key);\n }\n break;\n case RuleType.FAIL:\n if (matcherResult) {\n required.push(key);\n }\n break;\n default:\n continue;\n }\n }\n\n return required;\n }\n\n public constructor(\n public readonly options: RuleSetOptions = {\n unexpectedFields: RuleType.PASS,\n },\n ) {}\n\n /**\n * Requires the matcher to pass for the given field.\n * Otherwise a violation is detected.\n *\n * @param field The field the rule applies to\n * @param matcher The matcher function\n */\n public shouldPass(field: string, matcher: Matcher) {\n this._rules.push({ field, matcher, type: RuleType.PASS });\n }\n\n /**\n * Detects a violation if the matcher is matching for a certain field.\n *\n * @param field The field the rule applies to\n * @param matcher The matcher function\n */\n public shouldFail(field: string, matcher: Matcher) {\n this._rules.push({ field, matcher, type: RuleType.FAIL });\n }\n\n /**\n * Imports all rules from an other rule set.\n * Note that any options from the other rule set will be ignored.\n *\n * @param other The other rule set to import rules from.\n */\n public import(other: RuleSet) {\n this._rules.push(...other.rules);\n }\n\n /**\n * Records the field hints for the given rule set.\n * Hints are values that are guaranteed to pass the rule.\n * The list of hints is not guaranteed to be complete nor does it guarantee to return any values.\n * This can be used to create synthetic values for testing for error messages.\n *\n * @returns A record of fields and allowed values\n */\n public getFieldHints(): Record<string, any[]> {\n const fieldHints: Record<string, any[]> = {};\n\n for (const rule of this._rules) {\n // We are only interested in PASS rules here.\n // For FAILs we still don't know which values would pass.\n if (rule.type === RuleType.PASS) {\n // run the matcher to record hints\n rule.matcher(undefined, {\n hints: (receivedHints: any[]) => {\n // if we have recorded hints, add them to the map\n if (receivedHints) {\n fieldHints[rule.field] ??= [];\n fieldHints[rule.field].push(...receivedHints);\n }\n },\n });\n }\n }\n\n return fieldHints;\n }\n\n /**\n * Produces a human-readable description of every rule in the set.\n *\n * This is derived directly from the rules (it does not duplicate them), so it\n * stays in sync as rules are added or changed. It is primarily intended for\n * surfacing a rule set to a user, e.g. via the CLI.\n *\n * @returns A description for every rule, in the order the rules were added.\n */\n public describe(): RuleDescription[] {\n return this._rules.map((rule) => {\n // Probe the matcher for the values it considers relevant (hints).\n const values: any[] = [];\n let hinted = false;\n rule.matcher(DESCRIBE_PROBE, {\n hints: (allowed) => {\n hinted = true;\n if (allowed) {\n values.push(...allowed);\n }\n },\n });\n\n // A field is required if the rule is not satisfied when the value is absent.\n const passesWhenAbsent = rule.matcher(undefined);\n const required = rule.type === RuleType.PASS ? !passesWhenAbsent : passesWhenAbsent;\n\n return {\n field: rule.field,\n type: rule.type,\n required,\n values: hinted ? values : undefined,\n };\n });\n }\n}\n\n/**\n * Helper to wrap a matcher with error reporting and hints\n */\nfunction wrapMatcher(matcher: Matcher, message: (actual: any) => string, allowed?: any[]): Matcher {\n return (value, options) => {\n options?.reporter?.(message(value));\n if (allowed) {\n options?.hints?.(allowed);\n }\n return matcher(value);\n };\n}\n\n/**\n * Helper to implement loose equality that is safe for any value\n * Needed because there are some values that are equal as object, but not with ==\n * There are also values that cannot be compared using == and will throw\n */\nfunction looseEqual(a: any, b: any): boolean {\n try {\n // if one of the values is an object (or array), but the other isn't - never consider them the same\n if ([typeof a, typeof b].filter((t) => t === 'object').length === 1) {\n return false;\n }\n // if both values are the same object\n // or if both values are loose equal\n return Object.is(a, b) || a == b;\n } catch {\n return false;\n }\n}\n\nexport class Match {\n /**\n * Value is optional, but if present should match\n */\n public static optional(matcher: Matcher): Matcher {\n return (value, options) => {\n if (value == null) {\n return true;\n }\n return matcher(value, options);\n };\n }\n\n /**\n * Value must be one of the allowed options\n */\n public static oneOf(...allowed: Array<string | number>): Matcher {\n return wrapMatcher(\n (actual) => allowed.includes(actual),\n (actual) => `Expected value to be one of ${JSON.stringify(allowed)}, got: ${JSON.stringify(actual)}`,\n allowed,\n );\n }\n\n /**\n * Value must be loosely equal to the expected value\n * Arrays are compared by elements\n */\n public static eq(expected: any): Matcher {\n return (actual, options) => {\n if (Array.isArray(expected)) {\n return Match.arrEq(expected)(actual, options);\n }\n\n options?.hints?.([expected]);\n options?.reporter?.(`Expected value ${JSON.stringify(expected)}, got: ${JSON.stringify(actual)}`);\n return looseEqual(actual, expected);\n };\n }\n\n /**\n * Value must be loosely equal to the expected value\n * Arrays are compared by elements\n */\n public static arrEq(expected: any[]): Matcher {\n return wrapMatcher(\n (actual) => {\n // if both are arrays and of the same length, compare elements\n // if one of them is not, or they are a different length,\n // skip comparing elements as the the equality check later will fail\n if (Array.isArray(expected) && Array.isArray(actual) && expected.length == actual.length) {\n // compare all elements with loose typing\n return expected.every((e) => actual.some((a) => looseEqual(a, e)));\n }\n\n // all other values and arrays of different shape\n return looseEqual(actual, expected);\n },\n (actual) => `Expected array matching ${JSON.stringify(expected)}, got: ${JSON.stringify(actual)}`,\n [expected],\n );\n }\n\n /**\n * Compare strings, allows setting cases sensitivity\n */\n public static strEq(expected: string, caseSensitive = false): Matcher {\n return wrapMatcher(\n (actual) => {\n // case insensitive\n if (!caseSensitive && typeof actual === 'string') {\n return looseEqual(expected.toLowerCase(), actual.toLowerCase());\n }\n\n // case sensitive\n return looseEqual(actual, expected);\n },\n (actual: any) => `Expected string ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,\n [expected],\n );\n }\n\n /**\n * Allows any value\n */\n public static ANY: Matcher = (_val, _options) => true;\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static TRUE: Matcher = Match.eq(true);\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static FALSE: Matcher = Match.eq(false);\n\n /**\n * Missing (undefined) value\n */\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static MISSING = wrapMatcher(\n (actual) => actual === null || actual === undefined,\n (actual) => `Expected value to be present, got ${JSON.stringify(actual)}`,\n [undefined, null],\n );\n}\n\nexport interface Violation {\n field: string;\n message: string;\n}\n\nexport class ValidationError extends Error {\n constructor(public readonly violations: Violation[]) {\n // error message is a list of violations\n super('Data is invalid:\\n' + violations.map((v) => v.field + ': ' + v.message).join('\\n'));\n\n // Set the prototype explicitly.\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class ObjectValidator {\n public constructor(public ruleSet: RuleSet, private readonly dataName: string = 'data') {}\n\n /**\n * Validated the provided data against the set of rules.\n *\n * @throws when the data is invalid\n *\n * @param data the data to be validated\n */\n public validate(data: { [field: string]: any }) {\n // make sure data is an object\n if (!(typeof data === 'object' && !Array.isArray(data) && data !== null)) {\n throw new ValidationError([\n { field: this.dataName, message: 'Provided data must be an object, got: ' + JSON.stringify(data) },\n ]);\n }\n\n const checkedFields = new Set();\n const violations: Violation[] = [];\n\n // first check all defined rules\n for (const rule of this.ruleSet.rules) {\n const value = data[rule.field];\n\n // Use a fallback message, but allow the matcher to report a better arrow\n let violationMessage = 'Value is not allowed, got: ' + JSON.stringify(value);\n const matchResult = rule.matcher(value, {\n reporter: (message: string) => {\n violationMessage = message;\n },\n });\n\n switch (rule.type) {\n case RuleType.PASS:\n if (!matchResult) {\n violations.push({\n field: rule.field,\n message: violationMessage,\n });\n }\n break;\n case RuleType.FAIL:\n if (matchResult) {\n violations.push({\n field: rule.field,\n message: violationMessage,\n });\n }\n break;\n default:\n continue;\n }\n\n checkedFields.add(rule.field);\n }\n\n // finally check fields without any rules if they should fail the validation\n if (this.ruleSet.options.unexpectedFields === RuleType.FAIL) {\n const receivedFields = Object.keys(data);\n for (const field of receivedFields) {\n if (!checkedFields.has(field)) {\n violations.push({ field: field, message: `Unexpected field, got: ${field}` });\n }\n }\n }\n\n // if we have encountered a violation, throw an error\n if (violations.length > 0) {\n throw new ValidationError(violations);\n }\n }\n}\n"]}
|
package/lib/version.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The short version number for this JSII compiler (e.g: `X.Y.Z`) */
|
|
2
|
-
export declare const SHORT_VERSION = "5.9.
|
|
2
|
+
export declare const SHORT_VERSION = "5.9.48-dev.3";
|
|
3
3
|
/** The qualified version number for this JSII compiler (e.g: `X.Y.Z (build #######)`) */
|
|
4
|
-
export declare const VERSION = "5.9.
|
|
4
|
+
export declare const VERSION = "5.9.48-dev.3 (build 4cc17a1)";
|
|
5
5
|
/** The release line identifier for this JSII compiler (e.g: `X.Y`) */
|
|
6
6
|
export declare const RELEASE_LINE = "5.9";
|
|
7
7
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/version.js
CHANGED
|
@@ -4,9 +4,9 @@ exports.RELEASE_LINE = exports.VERSION = exports.SHORT_VERSION = void 0;
|
|
|
4
4
|
const typescript_1 = require("typescript");
|
|
5
5
|
// GENERATED: This file is generated by build-tools/code-gen.ts -- Do not edit by hand!
|
|
6
6
|
/** The short version number for this JSII compiler (e.g: `X.Y.Z`) */
|
|
7
|
-
exports.SHORT_VERSION = '5.9.
|
|
7
|
+
exports.SHORT_VERSION = '5.9.48-dev.3';
|
|
8
8
|
/** The qualified version number for this JSII compiler (e.g: `X.Y.Z (build #######)`) */
|
|
9
|
-
exports.VERSION = '5.9.
|
|
9
|
+
exports.VERSION = '5.9.48-dev.3 (build 4cc17a1)';
|
|
10
10
|
/** The release line identifier for this JSII compiler (e.g: `X.Y`) */
|
|
11
11
|
exports.RELEASE_LINE = typescript_1.versionMajorMinor;
|
|
12
12
|
//# sourceMappingURL=version.js.map
|
package/lib/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA,2CAA+C;AAE/C,uFAAuF;AAEvF,qEAAqE;AACxD,QAAA,aAAa,GAAG,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA,2CAA+C;AAE/C,uFAAuF;AAEvF,qEAAqE;AACxD,QAAA,aAAa,GAAG,cAAc,CAAC;AAE5C,yFAAyF;AAC5E,QAAA,OAAO,GAAG,8BAA8B,CAAC;AAEtD,sEAAsE;AACzD,QAAA,YAAY,GAAG,8BAAiB,CAAC","sourcesContent":["import { versionMajorMinor } from 'typescript';\n\n// GENERATED: This file is generated by build-tools/code-gen.ts -- Do not edit by hand!\n\n/** The short version number for this JSII compiler (e.g: `X.Y.Z`) */\nexport const SHORT_VERSION = '5.9.48-dev.3';\n\n/** The qualified version number for this JSII compiler (e.g: `X.Y.Z (build #######)`) */\nexport const VERSION = '5.9.48-dev.3 (build 4cc17a1)';\n\n/** The release line identifier for this JSII compiler (e.g: `X.Y`) */\nexport const RELEASE_LINE = versionMajorMinor;\n"]}
|
package/package.json
CHANGED
|
@@ -62,24 +62,24 @@
|
|
|
62
62
|
"npm": "^9.9.4",
|
|
63
63
|
"npm-check-updates": "^20",
|
|
64
64
|
"prettier": "^2.8.8",
|
|
65
|
-
"projen": "^0.
|
|
66
|
-
"tar": "^7.5.
|
|
65
|
+
"projen": "^0.100.2",
|
|
66
|
+
"tar": "^7.5.16",
|
|
67
67
|
"ts-jest": "^29.4.11",
|
|
68
68
|
"ts-node": "^10.9.2"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@jsii/check-node": "1.
|
|
72
|
-
"@jsii/spec": "1.
|
|
71
|
+
"@jsii/check-node": "1.136.0",
|
|
72
|
+
"@jsii/spec": "1.136.0",
|
|
73
73
|
"case": "^1.6.3",
|
|
74
74
|
"chalk": "^4",
|
|
75
75
|
"fast-deep-equal": "^3.1.3",
|
|
76
76
|
"log4js": "^6.9.1",
|
|
77
|
-
"semver": "^7.8.
|
|
77
|
+
"semver": "^7.8.5",
|
|
78
78
|
"semver-intersect": "^1.5.0",
|
|
79
79
|
"sort-json": "^2.0.1",
|
|
80
80
|
"spdx-license-list": "^6.11.0",
|
|
81
81
|
"typescript": "~5.9",
|
|
82
|
-
"yargs": "^17.7.
|
|
82
|
+
"yargs": "^17.7.3"
|
|
83
83
|
},
|
|
84
84
|
"engines": {
|
|
85
85
|
"node": ">= 20.16.0"
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public"
|
|
99
99
|
},
|
|
100
|
-
"version": "5.9.
|
|
100
|
+
"version": "5.9.48-dev.3",
|
|
101
101
|
"packageManager": "yarn@4.13.0",
|
|
102
102
|
"types": "lib/index.d.ts",
|
|
103
103
|
"exports": {
|
|
@@ -106,5 +106,6 @@
|
|
|
106
106
|
"./package.json": "./package.json",
|
|
107
107
|
"./common": "./lib/common/index.js"
|
|
108
108
|
},
|
|
109
|
-
"//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"yarn projen\"."
|
|
109
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"yarn projen\".",
|
|
110
|
+
"stableVersion": "0.0.0"
|
|
110
111
|
}
|