@chartguard/core 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/diagnostic.d.ts +131 -0
- package/dist/diagnostic.d.ts.map +1 -0
- package/dist/diagnostic.js +2 -0
- package/dist/diagnostic.js.map +1 -0
- package/dist/fix.d.ts +13 -0
- package/dist/fix.d.ts.map +1 -0
- package/dist/fix.js +109 -0
- package/dist/fix.js.map +1 -0
- package/dist/guard.d.ts +19 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +22 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/json-source.d.ts +54 -0
- package/dist/json-source.d.ts.map +1 -0
- package/dist/json-source.js +184 -0
- package/dist/json-source.js.map +1 -0
- package/dist/object.d.ts +18 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/object.js +23 -0
- package/dist/object.js.map +1 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +54 -0
- package/dist/paths.js.map +1 -0
- package/dist/reference.d.ts +15 -0
- package/dist/reference.d.ts.map +1 -0
- package/dist/reference.js +20 -0
- package/dist/reference.js.map +1 -0
- package/dist/result.d.ts +9 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +36 -0
- package/dist/result.js.map +1 -0
- package/dist/suggestion.d.ts +21 -0
- package/dist/suggestion.d.ts.map +1 -0
- package/dist/suggestion.js +81 -0
- package/dist/suggestion.js.map +1 -0
- package/package.json +35 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ChartGuard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @chartguard/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared diagnostics, statuses and runtime contracts.
|
|
4
|
+
|
|
5
|
+
Every ChartGuard package speaks the types defined here: a `Diagnostic` (code, severity, path, message, confidence, an optional fix), a `ValidationResult` (`valid`, `status`, `coverage`, the schema that checked it) and a `QualityReport`. You use it directly to apply a fix, to locate a finding in JSON text, or to stop a chart from being created with an invalid config.
|
|
6
|
+
|
|
7
|
+
**Status:** pre-release (0.x). Coverage is partial, and the API and settings may still change between minor versions.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @chartguard/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Chart, type ChartConfiguration } from "chart.js";
|
|
15
|
+
import { createValidateBeforeCreate, locateJsonPath, parseJsonSource } from "@chartguard/core";
|
|
16
|
+
import { validate } from "@chartguard/config-chartjs";
|
|
17
|
+
|
|
18
|
+
// Creates the chart only when the config has no confirmed errors; otherwise throws
|
|
19
|
+
// ConfigValidationError, which carries the full result.
|
|
20
|
+
const validateBeforeCreate = createValidateBeforeCreate("chartjs", validate);
|
|
21
|
+
const chart = validateBeforeCreate(config, (checked) => new Chart(canvas, checked as ChartConfiguration));
|
|
22
|
+
|
|
23
|
+
// Where a finding is in the JSON text it came from (1-based line and column).
|
|
24
|
+
const text = '{ "type": "bar", "options": { "responsive": "yes" } }';
|
|
25
|
+
const parsed = parseJsonSource(text);
|
|
26
|
+
if (parsed.ok) {
|
|
27
|
+
const { line, column } = locateJsonPath(parsed.root, "$.options.responsive");
|
|
28
|
+
console.log(line, column);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- **Status and validity:** `valid` is true when nothing is a confirmed error; `status` is `valid`, `partial` (something could not be checked: an unknown schema part, a dynamic value) or `invalid`. Read `status` before trusting a `valid`.
|
|
33
|
+
- **Confidence:** `certain` findings rest on a schema fact from the library's own declarations; `inferred` on a derived or hand-written one (reported as warnings); `unknown` findings claim nothing.
|
|
34
|
+
- **Paths** use one notation everywhere: `$.series[0].type`, `$.title["te.xt"]`; `pathSegments` and `keySegment` read and write it.
|
|
35
|
+
|
|
36
|
+
## Fixes
|
|
37
|
+
|
|
38
|
+
A `Diagnostic` may carry a `fix`. There are two kinds:
|
|
39
|
+
|
|
40
|
+
- **`rename-key`** preserves behaviour: the runtime already reads the option under its new name, so a tool may apply it.
|
|
41
|
+
- **`set-option`** changes what is drawn, as a quality finding asks. It names the option (`path`), the value it held when the finding was made (`from`; absent when unset), the new `value` and its `effect`. Apply it only at the user's request.
|
|
42
|
+
|
|
43
|
+
`applyFix(config, fix, path?)` returns a new config with the fix applied. `path` is the finding's path, needed for a rename.
|
|
44
|
+
|
|
45
|
+
- Only the objects on the path are copied; everything else is shared.
|
|
46
|
+
- The input is never written and no getter runs.
|
|
47
|
+
- It throws `FixError` when the fix no longer applies: the option changed since the finding, a getter, a primitive or a missing array element is on the way, or a renamed key's new name is taken.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** How serious a finding is; only `error` is a confirmed error that makes a result invalid. */
|
|
2
|
+
export type Severity = 'error' | 'warning' | 'info';
|
|
3
|
+
/**
|
|
4
|
+
* `invalid`: at least one confirmed error; `partial`: none, but coverage is partial or a finding is not
|
|
5
|
+
* `certain`; `valid`: none, full coverage and every finding certain.
|
|
6
|
+
*/
|
|
7
|
+
export type ValidationStatus = 'valid' | 'invalid' | 'partial';
|
|
8
|
+
/**
|
|
9
|
+
* How sure a finding is: `certain`, `inferred` (a likely problem read from a schema fact that is not
|
|
10
|
+
* authoritative) or `unknown` (could not be decided). Anything but `certain` keeps a result from `valid`.
|
|
11
|
+
*/
|
|
12
|
+
export type Confidence = 'certain' | 'inferred' | 'unknown';
|
|
13
|
+
/** Whether the schema checked the whole config (`full`) or only what it describes (`partial`). */
|
|
14
|
+
export type Coverage = 'partial' | 'full';
|
|
15
|
+
/**
|
|
16
|
+
* A behaviour-preserving edit a tool may apply to the reported key: the runtime already reads the
|
|
17
|
+
* key under its new name (a rename it performs itself), and the new name is not set yet.
|
|
18
|
+
*/
|
|
19
|
+
export interface KeyRename {
|
|
20
|
+
readonly kind: 'rename-key';
|
|
21
|
+
readonly to: string;
|
|
22
|
+
}
|
|
23
|
+
/** An option value an edit reads or writes: JSON's primitives. */
|
|
24
|
+
export type OptionValue = string | number | boolean | null;
|
|
25
|
+
/**
|
|
26
|
+
* An edit that changes what is drawn, to what a quality finding asks (CG-05-06): set the option at
|
|
27
|
+
* `path` (the finding notation) to `value`. It holds `from` when the finding was made, or nothing
|
|
28
|
+
* when `from` is absent; `applyFix` refuses it once that is no longer so. `effect` says what changes.
|
|
29
|
+
* Never applied without the user: unlike `rename-key`, it does not preserve behaviour.
|
|
30
|
+
*/
|
|
31
|
+
export interface OptionEdit {
|
|
32
|
+
readonly kind: 'set-option';
|
|
33
|
+
readonly path: string;
|
|
34
|
+
readonly from?: OptionValue;
|
|
35
|
+
readonly value: OptionValue;
|
|
36
|
+
readonly effect: string;
|
|
37
|
+
}
|
|
38
|
+
/** An edit a finding offers: a behaviour-preserving `rename-key`, or a `set-option` that changes what is drawn. */
|
|
39
|
+
export type Fix = KeyRename | OptionEdit;
|
|
40
|
+
/**
|
|
41
|
+
* One finding at `path` (the finding notation, `$.series[0].type`), with its `code`, `severity` and
|
|
42
|
+
* `confidence`; `file`, `line` and `column` locate it when it was read from source.
|
|
43
|
+
*/
|
|
44
|
+
export interface Diagnostic {
|
|
45
|
+
code: string;
|
|
46
|
+
severity: Severity;
|
|
47
|
+
message: string;
|
|
48
|
+
path: string;
|
|
49
|
+
ruleId?: string;
|
|
50
|
+
suggestion?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Where the finding is explained: its code's anchor in the published reference, or a page the
|
|
53
|
+
* adapter names for it (a deprecation's migration). Present on every finding of a result or report.
|
|
54
|
+
*/
|
|
55
|
+
documentationUrl?: string;
|
|
56
|
+
/**
|
|
57
|
+
* `rename-key`: present only when applying it cannot change what the runtime does, so a tool may
|
|
58
|
+
* apply it. `set-option`: changes what is drawn, as the finding asks, offered only when the edit was
|
|
59
|
+
* verified to resolve the finding without a new one; apply it only at the user's request.
|
|
60
|
+
*/
|
|
61
|
+
fix?: Fix;
|
|
62
|
+
confidence: Confidence;
|
|
63
|
+
file?: string;
|
|
64
|
+
line?: number;
|
|
65
|
+
column?: number;
|
|
66
|
+
/** Where the source range the finding is about ends (exclusive), when it is known (CG-03-07). */
|
|
67
|
+
endLine?: number;
|
|
68
|
+
endColumn?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What the caller's runtime has registered in one registry (CG-02-04). `complete`: `names` is
|
|
72
|
+
* everything registered (a tree-shaken build), so anything else is rejected by the runtime.
|
|
73
|
+
* Otherwise `names` are extensions known to be registered on top of the built-ins.
|
|
74
|
+
*/
|
|
75
|
+
export interface RegistryContext {
|
|
76
|
+
readonly names: readonly string[];
|
|
77
|
+
readonly complete: boolean;
|
|
78
|
+
}
|
|
79
|
+
/** What the caller knows about its input and runtime, passed to every validation. */
|
|
80
|
+
export interface ValidationOptions {
|
|
81
|
+
/**
|
|
82
|
+
* The input is a partial extraction (unresolved spreads or values were left out), so a
|
|
83
|
+
* missing required key is unresolved rather than confirmed missing, and coverage is partial.
|
|
84
|
+
*/
|
|
85
|
+
readonly incomplete?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The exact upstream version the caller runs (`4.4.1`). Another minor or patch than the
|
|
88
|
+
* schema's turns confirmed errors into warnings; another major is not validated (CG-01-07).
|
|
89
|
+
*/
|
|
90
|
+
readonly libraryVersion?: string;
|
|
91
|
+
/** Registered names per registry id the schema uses (`echarts`, `chartjs.controllers`). */
|
|
92
|
+
readonly registries?: Readonly<Record<string, RegistryContext>>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The outcome of one validation. `valid` and `status` are derived from `coverage` and `diagnostics` by
|
|
96
|
+
* `result()` only, never assembled by hand.
|
|
97
|
+
*/
|
|
98
|
+
export interface ValidationResult {
|
|
99
|
+
/** No confirmed errors; read `status` for completeness. */
|
|
100
|
+
valid: boolean;
|
|
101
|
+
status: ValidationStatus;
|
|
102
|
+
library: string;
|
|
103
|
+
/** The upstream version the schema describes. */
|
|
104
|
+
schemaVersion: string;
|
|
105
|
+
/** The exact schema artifact that produced this result (`sha256-…`), when it is generated. */
|
|
106
|
+
schemaDigest?: string;
|
|
107
|
+
/** The plugin extensions the schema was extended with (CG-02-05), by id. */
|
|
108
|
+
extensions?: string[];
|
|
109
|
+
coverage: Coverage;
|
|
110
|
+
diagnostics: Diagnostic[];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A finding that was not reported, and why: the caller's settings ignore it at its path (`setting`),
|
|
114
|
+
* or the context the caller declares meets the rule's concern (`context`). It is kept, never dropped.
|
|
115
|
+
*/
|
|
116
|
+
export interface Suppression {
|
|
117
|
+
readonly diagnostic: Diagnostic;
|
|
118
|
+
readonly by: 'setting' | 'context';
|
|
119
|
+
readonly reason: string;
|
|
120
|
+
}
|
|
121
|
+
/** Advisory findings about a chart's presentation. Never a verdict: there is no `valid` and no error severity. */
|
|
122
|
+
export interface QualityReport {
|
|
123
|
+
readonly library: string;
|
|
124
|
+
readonly rulesVersion: string;
|
|
125
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
126
|
+
/** Findings the caller's settings or context suppressed, in rule order. */
|
|
127
|
+
readonly suppressed: readonly Suppression[];
|
|
128
|
+
/** The rules the caller's settings turned off, by id: they did not run. */
|
|
129
|
+
readonly disabled: readonly string[];
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=diagnostic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostic.d.ts","sourceRoot":"","sources":["../src/diagnostic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostic.js","sourceRoot":"","sources":["../src/diagnostic.ts"],"names":[],"mappings":""}
|
package/dist/fix.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Fix } from './diagnostic.js';
|
|
2
|
+
/** A fix that cannot be applied to this config: the option changed since the finding, or the path cannot be edited. */
|
|
3
|
+
export declare class FixError extends Error {
|
|
4
|
+
readonly name = "FixError";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The config with `fix` applied (`path`: the finding's, for a rename): a new object, the input never
|
|
8
|
+
* written and no getter run. Throws `FixError` when it no longer applies: a `set-option` whose option
|
|
9
|
+
* is not `from` any more, a rename whose key is gone or whose new name is taken, a path through a
|
|
10
|
+
* getter, a primitive or a missing array element.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyFix(config: unknown, fix: Fix, path?: string): unknown;
|
|
13
|
+
//# sourceMappingURL=fix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../src/fix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAyB,MAAM,iBAAiB,CAAC;AAIlE,uHAAuH;AACvH,qBAAa,QAAS,SAAQ,KAAK;IAClC,SAAkB,IAAI,cAAc;CACpC;AA2FD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAI1E"}
|
package/dist/fix.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isContainer } from './object.js';
|
|
2
|
+
import { pathSegments } from './paths.js';
|
|
3
|
+
/** A fix that cannot be applied to this config: the option changed since the finding, or the path cannot be edited. */
|
|
4
|
+
export class FixError extends Error {
|
|
5
|
+
name = 'FixError';
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A shallow copy that keeps the prototype and every property, symbol-keyed ones included: getters are
|
|
9
|
+
* copied, never run. The copy is ours, so its properties are configurable (a frozen input stays frozen;
|
|
10
|
+
* its copy can be edited). A typed array is copied as a typed array of its own kind (A13: a list).
|
|
11
|
+
*/
|
|
12
|
+
function copyOf(value) {
|
|
13
|
+
if (ArrayBuffer.isView(value) && !(value instanceof DataView))
|
|
14
|
+
return value.slice();
|
|
15
|
+
const array = Array.isArray(value);
|
|
16
|
+
const shell = array ? [] : Object.create(Object.getPrototypeOf(value));
|
|
17
|
+
const descriptors = {};
|
|
18
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
19
|
+
if (array && key === 'length')
|
|
20
|
+
continue;
|
|
21
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
22
|
+
if (descriptor === undefined)
|
|
23
|
+
continue;
|
|
24
|
+
// A symbol key is a valid key of a property descriptor map; `PropertyDescriptorMap` only says strings.
|
|
25
|
+
descriptors[key] =
|
|
26
|
+
'value' in descriptor
|
|
27
|
+
? { ...descriptor, writable: true, configurable: true }
|
|
28
|
+
: { ...descriptor, configurable: true };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperties(shell, descriptors);
|
|
31
|
+
if (array)
|
|
32
|
+
shell.length = value.length;
|
|
33
|
+
return shell;
|
|
34
|
+
}
|
|
35
|
+
/** The own data value at `key`, `absent`, or a refusal for a getter (never run). */
|
|
36
|
+
function own(target, key, path) {
|
|
37
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, String(key));
|
|
38
|
+
if (descriptor === undefined)
|
|
39
|
+
return 'absent';
|
|
40
|
+
if (!('value' in descriptor))
|
|
41
|
+
throw new FixError(`${path}: a getter is on the way; it is never run`);
|
|
42
|
+
return { value: descriptor.value };
|
|
43
|
+
}
|
|
44
|
+
function define(target, key, value) {
|
|
45
|
+
Object.defineProperty(target, String(key), { value, writable: true, enumerable: true, configurable: true });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The config with `edit(parent, key)` applied to the object holding the last segment of `path`, every
|
|
49
|
+
* object on the way copied and everything else shared: the input is never written. Missing objects
|
|
50
|
+
* on the way are created for keys, never for array indices.
|
|
51
|
+
*/
|
|
52
|
+
function edited(config, path, edit) {
|
|
53
|
+
const segments = pathSegments(path);
|
|
54
|
+
if (segments === undefined || segments.length === 0)
|
|
55
|
+
throw new FixError(`${path}: not a path to an option`);
|
|
56
|
+
const descend = (value, index) => {
|
|
57
|
+
if (!isContainer(value))
|
|
58
|
+
throw new FixError(`${path}: ${typeof value} on the way, not an object`);
|
|
59
|
+
const key = segments[index];
|
|
60
|
+
if (key === undefined)
|
|
61
|
+
throw new FixError(`${path}: not a path to an option`);
|
|
62
|
+
const copy = copyOf(value);
|
|
63
|
+
if (index === segments.length - 1) {
|
|
64
|
+
edit(copy, key);
|
|
65
|
+
return copy;
|
|
66
|
+
}
|
|
67
|
+
const next = own(value, key, path);
|
|
68
|
+
if (next === 'absent' && typeof key === 'number')
|
|
69
|
+
throw new FixError(`${path}: no element ${String(key)}`);
|
|
70
|
+
define(copy, key, descend(next === 'absent' ? {} : next.value, index + 1));
|
|
71
|
+
return copy;
|
|
72
|
+
};
|
|
73
|
+
return descend(config, 0);
|
|
74
|
+
}
|
|
75
|
+
function setOption(config, { path, from, value }, hadFrom) {
|
|
76
|
+
return edited(config, path, (parent, key) => {
|
|
77
|
+
const current = own(parent, key, path);
|
|
78
|
+
const holds = hadFrom ? current !== 'absent' && Object.is(current.value, from) : current === 'absent';
|
|
79
|
+
if (!holds)
|
|
80
|
+
throw new FixError(`${path}: the option is no longer ${hadFrom ? JSON.stringify(from) : 'unset'}`);
|
|
81
|
+
define(parent, key, value);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function renameKey(config, path, { to }) {
|
|
85
|
+
return edited(config, path, (parent, key) => {
|
|
86
|
+
const current = own(parent, key, path);
|
|
87
|
+
if (current === 'absent' || current.value === null)
|
|
88
|
+
throw new FixError(`${path}: nothing to rename`);
|
|
89
|
+
const target = own(parent, to, path);
|
|
90
|
+
if (target !== 'absent' && target.value !== undefined)
|
|
91
|
+
throw new FixError(`${path}: ${to} is already set`);
|
|
92
|
+
Reflect.deleteProperty(parent, String(key));
|
|
93
|
+
define(parent, to, current.value);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The config with `fix` applied (`path`: the finding's, for a rename): a new object, the input never
|
|
98
|
+
* written and no getter run. Throws `FixError` when it no longer applies: a `set-option` whose option
|
|
99
|
+
* is not `from` any more, a rename whose key is gone or whose new name is taken, a path through a
|
|
100
|
+
* getter, a primitive or a missing array element.
|
|
101
|
+
*/
|
|
102
|
+
export function applyFix(config, fix, path) {
|
|
103
|
+
if (fix.kind === 'set-option')
|
|
104
|
+
return setOption(config, fix, Object.hasOwn(fix, 'from'));
|
|
105
|
+
if (path === undefined)
|
|
106
|
+
throw new FixError('a rename needs the path of the key it renames');
|
|
107
|
+
return renameKey(config, path, fix);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=fix.js.map
|
package/dist/fix.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../src/fix.ts"],"names":[],"mappings":"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"}
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ValidationOptions, ValidationResult } from './diagnostic.js';
|
|
2
|
+
/** Validates a config for one library and returns the full result; findings are never thrown. */
|
|
3
|
+
export type ConfigValidator = (config: unknown, options?: ValidationOptions) => ValidationResult;
|
|
4
|
+
/** Receives a validation's result before the chart is created or refused. */
|
|
5
|
+
export type ValidationReporter = (validation: ValidationResult) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Validates `config` with `options` (the version the caller runs, what its runtime registered), then
|
|
8
|
+
* creates the chart with `create`, or throws `ConfigValidationError` when the config has confirmed errors.
|
|
9
|
+
*/
|
|
10
|
+
export type ValidateBeforeCreate = <T>(config: unknown, create: (value: unknown) => T, report?: ValidationReporter, options?: ValidationOptions) => T;
|
|
11
|
+
/** Thrown instead of creating a chart; carries the full result so callers can inspect every diagnostic. */
|
|
12
|
+
export declare class ConfigValidationError extends Error {
|
|
13
|
+
readonly result: ValidationResult;
|
|
14
|
+
readonly name = "ConfigValidationError";
|
|
15
|
+
constructor(library: string, result: ValidationResult);
|
|
16
|
+
}
|
|
17
|
+
/** Never monkey-patches global APIs. Caller owns the original factory and side effects. */
|
|
18
|
+
export declare function createValidateBeforeCreate(library: string, validate: ConfigValidator): ValidateBeforeCreate;
|
|
19
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAG3E,iGAAiG;AACjG,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;AACjG,6EAA6E;AAC7E,MAAM,MAAM,kBAAkB,GAAG,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;AACxE;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,EACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,EAC7B,MAAM,CAAC,EAAE,kBAAkB,EAC3B,OAAO,CAAC,EAAE,iBAAiB,KACvB,CAAC,CAAC;AAEP,2GAA2G;AAC3G,qBAAa,qBAAsB,SAAQ,KAAK;IAK9C,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IAJlC,SAAkB,IAAI,2BAA2B;gBAGhD,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,gBAAgB;CAKlC;AAED,2FAA2F;AAC3F,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,oBAAoB,CAO3G"}
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isConfirmedError } from './result.js';
|
|
2
|
+
/** Thrown instead of creating a chart; carries the full result so callers can inspect every diagnostic. */
|
|
3
|
+
export class ConfigValidationError extends Error {
|
|
4
|
+
result;
|
|
5
|
+
name = 'ConfigValidationError';
|
|
6
|
+
constructor(library, result) {
|
|
7
|
+
const paths = result.diagnostics.filter(isConfirmedError).map((diagnostic) => diagnostic.path);
|
|
8
|
+
super(`${library} config invalid: ${paths.join(', ')}`);
|
|
9
|
+
this.result = result;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Never monkey-patches global APIs. Caller owns the original factory and side effects. */
|
|
13
|
+
export function createValidateBeforeCreate(library, validate) {
|
|
14
|
+
return (config, create, report, options) => {
|
|
15
|
+
const checked = validate(config, options);
|
|
16
|
+
report?.(checked);
|
|
17
|
+
if (!checked.valid)
|
|
18
|
+
throw new ConfigValidationError(library, checked);
|
|
19
|
+
return create(config);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,2GAA2G;AAC3G,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAKrC;IAJQ,IAAI,GAAG,uBAAuB,CAAC;IAEjD,YACC,OAAe,EACN,MAAwB;QAEjC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/F,KAAK,CAAC,GAAG,OAAO,oBAAoB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAH/C,WAAM,GAAN,MAAM,CAAkB;IAIlC,CAAC;CACD;AAED,2FAA2F;AAC3F,MAAM,UAAU,0BAA0B,CAAC,OAAe,EAAE,QAAyB;IACpF,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,KAAK;YAAE,MAAM,IAAI,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACtE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { Confidence, Coverage, Diagnostic, Fix, KeyRename, OptionEdit, OptionValue, QualityReport, RegistryContext, Severity, Suppression, ValidationOptions, ValidationResult, ValidationStatus } from './diagnostic.js';
|
|
2
|
+
export { applyFix, FixError } from './fix.js';
|
|
3
|
+
export type { ConfigValidator, ValidateBeforeCreate, ValidationReporter } from './guard.js';
|
|
4
|
+
export { ConfigValidationError, createValidateBeforeCreate } from './guard.js';
|
|
5
|
+
export type { JsonNode, JsonSource, JsonSpan } from './json-source.js';
|
|
6
|
+
export { locateJsonKey, locateJsonPath, parseJsonSource } from './json-source.js';
|
|
7
|
+
export type { OwnProperty } from './object.js';
|
|
8
|
+
export { isContainer, isRecord, ownDataProperty } from './object.js';
|
|
9
|
+
export { keySegment, pathSegments } from './paths.js';
|
|
10
|
+
export { documented, REFERENCE_URL, referenceUrl } from './reference.js';
|
|
11
|
+
export { isConfirmedError, result } from './result.js';
|
|
12
|
+
export { suggestion, type SuggestionBudget, suggestionBudget } from './suggestion.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,UAAU,EACV,QAAQ,EACR,UAAU,EACV,GAAG,EACH,SAAS,EACT,UAAU,EACV,WAAW,EACX,aAAa,EACb,eAAe,EACf,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAClF,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { applyFix, FixError } from './fix.js';
|
|
2
|
+
export { ConfigValidationError, createValidateBeforeCreate } from './guard.js';
|
|
3
|
+
export { locateJsonKey, locateJsonPath, parseJsonSource } from './json-source.js';
|
|
4
|
+
export { isContainer, isRecord, ownDataProperty } from './object.js';
|
|
5
|
+
export { keySegment, pathSegments } from './paths.js';
|
|
6
|
+
export { documented, REFERENCE_URL, referenceUrl } from './reference.js';
|
|
7
|
+
export { isConfirmedError, result } from './result.js';
|
|
8
|
+
export { suggestion, suggestionBudget } from './suggestion.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAElF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,UAAU,EAAyB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A JSON text read with the position of every value (CG-06-02), so a finding's path can be shown
|
|
3
|
+
* where it is: in an editor (the playground) or in a SARIF log (the CLI). Exactly `JSON.parse`'s
|
|
4
|
+
* grammar; positions are offsets and 1-based lines and columns (UTF-16 code units, as editors count).
|
|
5
|
+
*/
|
|
6
|
+
export interface JsonSpan {
|
|
7
|
+
readonly start: number;
|
|
8
|
+
readonly end: number;
|
|
9
|
+
readonly line: number;
|
|
10
|
+
readonly column: number;
|
|
11
|
+
readonly endLine: number;
|
|
12
|
+
readonly endColumn: number;
|
|
13
|
+
}
|
|
14
|
+
/** A JSON value with its span: a scalar, an array of items, or an object of entries by key. */
|
|
15
|
+
export type JsonNode = (JsonSpan & {
|
|
16
|
+
readonly kind: 'scalar';
|
|
17
|
+
}) | (JsonSpan & {
|
|
18
|
+
readonly kind: 'array';
|
|
19
|
+
readonly items: readonly JsonNode[];
|
|
20
|
+
}) | (JsonSpan & {
|
|
21
|
+
readonly kind: 'object';
|
|
22
|
+
readonly entries: ReadonlyMap<string, JsonNode>;
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* What `parseJsonSource` read: the root value with every position, or, for a text that is not JSON,
|
|
26
|
+
* the reason and where it was found.
|
|
27
|
+
*/
|
|
28
|
+
export type JsonSource = {
|
|
29
|
+
readonly ok: true;
|
|
30
|
+
readonly root: JsonNode;
|
|
31
|
+
} | {
|
|
32
|
+
readonly ok: false;
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly offset: number;
|
|
35
|
+
readonly line: number;
|
|
36
|
+
readonly column: number;
|
|
37
|
+
};
|
|
38
|
+
/** The JSON text with the position of every value, or its first syntax error and where. Never throws. */
|
|
39
|
+
export declare function parseJsonSource(text: string): JsonSource;
|
|
40
|
+
/**
|
|
41
|
+
* Where the value at a finding's `path` is. A path that does not exist (a missing required key)
|
|
42
|
+
* resolves to its deepest existing ancestor and is marked inexact; a path that is not one the
|
|
43
|
+
* engine writes is the root, inexact.
|
|
44
|
+
*/
|
|
45
|
+
export declare function locateJsonPath(root: JsonNode, path: string): JsonSpan & {
|
|
46
|
+
readonly exact: boolean;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Where the key token of `key` in an object `parseJsonSource` read is (quotes included), so an
|
|
50
|
+
* editor can rename it (CG-06-06); for a duplicate key the last, whose value `JSON.parse` keeps.
|
|
51
|
+
* Undefined when the object has no such key, or the node was not read by `parseJsonSource`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function locateJsonKey(object: JsonNode, key: string): JsonSpan | undefined;
|
|
54
|
+
//# sourceMappingURL=json-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-source.d.ts","sourceRoot":"","sources":["../src/json-source.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GACjB,CAAC,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GACxC,CAAC,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,CAAC,GAC5E,CAAC,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAAE,CAAC,CAAC;AAK7F;;;GAGG;AACH,MAAM,MAAM,UAAU,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC9C;IACA,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACvB,CAAC;AAqIL,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQxD;AAWD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAkBnG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAEjF"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { pathSegments } from './paths.js';
|
|
2
|
+
/** The key tokens of each object `parseJsonSource` read, by key: what `locateJsonKey` answers from. */
|
|
3
|
+
const KEYS = new WeakMap();
|
|
4
|
+
/** The 1-based line and column of each offset of a text. */
|
|
5
|
+
class Lines {
|
|
6
|
+
starts = [0];
|
|
7
|
+
constructor(text) {
|
|
8
|
+
for (let index = 0; index < text.length; index++)
|
|
9
|
+
if (text[index] === '\n')
|
|
10
|
+
this.starts.push(index + 1);
|
|
11
|
+
}
|
|
12
|
+
at(offset) {
|
|
13
|
+
let low = 0;
|
|
14
|
+
let high = this.starts.length - 1;
|
|
15
|
+
while (low < high) {
|
|
16
|
+
const middle = Math.ceil((low + high) / 2);
|
|
17
|
+
if ((this.starts[middle] ?? 0) <= offset)
|
|
18
|
+
low = middle;
|
|
19
|
+
else
|
|
20
|
+
high = middle - 1;
|
|
21
|
+
}
|
|
22
|
+
return { line: low + 1, column: offset - (this.starts[low] ?? 0) + 1 };
|
|
23
|
+
}
|
|
24
|
+
span(start, end) {
|
|
25
|
+
const from = this.at(start);
|
|
26
|
+
const to = this.at(end);
|
|
27
|
+
return { start, end, line: from.line, column: from.column, endLine: to.line, endColumn: to.column };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
class SyntaxProblem extends Error {
|
|
31
|
+
offset;
|
|
32
|
+
constructor(message, offset) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.offset = offset;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** JSON whitespace: space, tab, line feed and carriage return only, not every Unicode space (H13). */
|
|
38
|
+
const WHITESPACE = /[ \t\n\r]/;
|
|
39
|
+
/** A string with only the escapes JSON knows, a number, `true`, `false` or `null`. */
|
|
40
|
+
const SCALAR = /^(?:"(?:[^"\\\u0000-\u001f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/;
|
|
41
|
+
/** A strict JSON reader that keeps the position of every value; it reports the first syntax error. */
|
|
42
|
+
class Reader {
|
|
43
|
+
text;
|
|
44
|
+
lines;
|
|
45
|
+
offset = 0;
|
|
46
|
+
constructor(text, lines) {
|
|
47
|
+
this.text = text;
|
|
48
|
+
this.lines = lines;
|
|
49
|
+
}
|
|
50
|
+
document() {
|
|
51
|
+
const root = this.value();
|
|
52
|
+
this.skip();
|
|
53
|
+
if (this.offset < this.text.length)
|
|
54
|
+
this.fail('Unexpected text after the JSON value');
|
|
55
|
+
return root;
|
|
56
|
+
}
|
|
57
|
+
value() {
|
|
58
|
+
this.skip();
|
|
59
|
+
const next = this.text[this.offset];
|
|
60
|
+
if (next === '{')
|
|
61
|
+
return this.object();
|
|
62
|
+
if (next === '[')
|
|
63
|
+
return this.array();
|
|
64
|
+
return this.scalar();
|
|
65
|
+
}
|
|
66
|
+
object() {
|
|
67
|
+
const start = this.offset++;
|
|
68
|
+
const entries = new Map();
|
|
69
|
+
const keys = new Map();
|
|
70
|
+
if (this.peek() !== '}')
|
|
71
|
+
do {
|
|
72
|
+
this.skip();
|
|
73
|
+
const { kind: _kind, ...token } = this.require(this.scalar(), 'a property name');
|
|
74
|
+
const key = JSON.parse(this.text.slice(token.start, token.end));
|
|
75
|
+
this.expect(':');
|
|
76
|
+
entries.set(key, this.value());
|
|
77
|
+
keys.set(key, token);
|
|
78
|
+
} while (this.consume(','));
|
|
79
|
+
this.expect('}');
|
|
80
|
+
const node = { kind: 'object', ...this.lines.span(start, this.offset), entries };
|
|
81
|
+
KEYS.set(node, keys);
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
array() {
|
|
85
|
+
const start = this.offset++;
|
|
86
|
+
const items = [];
|
|
87
|
+
if (this.peek() !== ']')
|
|
88
|
+
do
|
|
89
|
+
items.push(this.value());
|
|
90
|
+
while (this.consume(','));
|
|
91
|
+
this.expect(']');
|
|
92
|
+
return { kind: 'array', ...this.lines.span(start, this.offset), items };
|
|
93
|
+
}
|
|
94
|
+
scalar() {
|
|
95
|
+
const match = SCALAR.exec(this.text.slice(this.offset));
|
|
96
|
+
if (match === null)
|
|
97
|
+
this.fail('Expected a JSON value');
|
|
98
|
+
const start = this.offset;
|
|
99
|
+
this.offset += match[0].length;
|
|
100
|
+
return { kind: 'scalar', ...this.lines.span(start, this.offset) };
|
|
101
|
+
}
|
|
102
|
+
require(span, what) {
|
|
103
|
+
if (this.text[span.start] !== '"')
|
|
104
|
+
throw new SyntaxProblem(`Expected ${what} in double quotes`, span.start);
|
|
105
|
+
return span;
|
|
106
|
+
}
|
|
107
|
+
peek() {
|
|
108
|
+
this.skip();
|
|
109
|
+
return this.text[this.offset];
|
|
110
|
+
}
|
|
111
|
+
consume(token) {
|
|
112
|
+
if (this.peek() !== token)
|
|
113
|
+
return false;
|
|
114
|
+
this.offset++;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
expect(token) {
|
|
118
|
+
if (!this.consume(token))
|
|
119
|
+
this.fail(`Expected "${token}"`);
|
|
120
|
+
}
|
|
121
|
+
skip() {
|
|
122
|
+
while (this.offset < this.text.length && WHITESPACE.test(this.text.charAt(this.offset)))
|
|
123
|
+
this.offset++;
|
|
124
|
+
}
|
|
125
|
+
fail(message) {
|
|
126
|
+
throw new SyntaxProblem(message, this.offset);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** The JSON text with the position of every value, or its first syntax error and where. Never throws. */
|
|
130
|
+
export function parseJsonSource(text) {
|
|
131
|
+
const lines = new Lines(text);
|
|
132
|
+
try {
|
|
133
|
+
return { ok: true, root: new Reader(text, lines).document() };
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (!(error instanceof SyntaxProblem))
|
|
137
|
+
throw error;
|
|
138
|
+
return { ok: false, message: error.message, offset: error.offset, ...lines.at(error.offset) };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function child(node, segment) {
|
|
142
|
+
if (node.kind === 'array' && typeof segment === 'number')
|
|
143
|
+
return node.items[segment];
|
|
144
|
+
if (node.kind === 'object' && typeof segment === 'string')
|
|
145
|
+
return node.entries.get(segment);
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
/** A run of holes (`[3..9]`, one finding for a sparse list) is read as its first index. */
|
|
149
|
+
const HOLE_RUN = /\[(\d+)\.\.\d+\]/gu;
|
|
150
|
+
/**
|
|
151
|
+
* Where the value at a finding's `path` is. A path that does not exist (a missing required key)
|
|
152
|
+
* resolves to its deepest existing ancestor and is marked inexact; a path that is not one the
|
|
153
|
+
* engine writes is the root, inexact.
|
|
154
|
+
*/
|
|
155
|
+
export function locateJsonPath(root, path) {
|
|
156
|
+
const segments = pathSegments(path.replace(HOLE_RUN, '[$1]'));
|
|
157
|
+
const span = (node) => ({
|
|
158
|
+
start: node.start,
|
|
159
|
+
end: node.end,
|
|
160
|
+
line: node.line,
|
|
161
|
+
column: node.column,
|
|
162
|
+
endLine: node.endLine,
|
|
163
|
+
endColumn: node.endColumn
|
|
164
|
+
});
|
|
165
|
+
if (segments === undefined)
|
|
166
|
+
return { ...span(root), exact: false };
|
|
167
|
+
let node = root;
|
|
168
|
+
for (const segment of segments) {
|
|
169
|
+
const next = child(node, segment);
|
|
170
|
+
if (next === undefined)
|
|
171
|
+
return { ...span(node), exact: false };
|
|
172
|
+
node = next;
|
|
173
|
+
}
|
|
174
|
+
return { ...span(node), exact: true };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Where the key token of `key` in an object `parseJsonSource` read is (quotes included), so an
|
|
178
|
+
* editor can rename it (CG-06-06); for a duplicate key the last, whose value `JSON.parse` keeps.
|
|
179
|
+
* Undefined when the object has no such key, or the node was not read by `parseJsonSource`.
|
|
180
|
+
*/
|
|
181
|
+
export function locateJsonKey(object, key) {
|
|
182
|
+
return KEYS.get(object)?.get(key);
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=json-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-source.js","sourceRoot":"","sources":["../src/json-source.ts"],"names":[],"mappings":"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"}
|
package/dist/object.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** `accessor`: the key exists but holds a getter/setter, whose value cannot be known without running it. */
|
|
2
|
+
export type OwnProperty = {
|
|
3
|
+
readonly found: true;
|
|
4
|
+
readonly value: unknown;
|
|
5
|
+
} | {
|
|
6
|
+
readonly found: false;
|
|
7
|
+
readonly accessor: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Whether `value` is a non-null object that is not an array. */
|
|
10
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
11
|
+
/** Whether `value` is a non-null object, arrays included: something that can hold properties. */
|
|
12
|
+
export declare function isContainer(value: unknown): value is object;
|
|
13
|
+
/**
|
|
14
|
+
* Reads an own data property. Accessors are reported as missing so getters never run.
|
|
15
|
+
* A Proxy is the caller's object: its `getOwnPropertyDescriptor` trap does run, and an error it throws propagates.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ownDataProperty(target: object, key: string): OwnProperty;
|
|
18
|
+
//# sourceMappingURL=object.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"AAAA,4GAA4G;AAC5G,MAAM,MAAM,WAAW,GACtB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAK3G,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAKxE"}
|
package/dist/object.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const MISSING = { found: false, accessor: false };
|
|
2
|
+
const ACCESSOR = { found: false, accessor: true };
|
|
3
|
+
/** Whether `value` is a non-null object that is not an array. */
|
|
4
|
+
export function isRecord(value) {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
/** Whether `value` is a non-null object, arrays included: something that can hold properties. */
|
|
8
|
+
export function isContainer(value) {
|
|
9
|
+
return typeof value === 'object' && value !== null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Reads an own data property. Accessors are reported as missing so getters never run.
|
|
13
|
+
* A Proxy is the caller's object: its `getOwnPropertyDescriptor` trap does run, and an error it throws propagates.
|
|
14
|
+
*/
|
|
15
|
+
export function ownDataProperty(target, key) {
|
|
16
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
17
|
+
if (descriptor === undefined)
|
|
18
|
+
return MISSING;
|
|
19
|
+
if (!('value' in descriptor))
|
|
20
|
+
return ACCESSOR;
|
|
21
|
+
return { found: true, value: descriptor.value };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.js","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,GAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC/D,MAAM,QAAQ,GAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,GAAW;IAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC7C,IAAI,CAAC,CAAC,OAAO,IAAI,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAgB,EAAE,CAAC;AAC5D,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The path segment of an object key: `.key` for an identifier, `["key"]` (JSON-quoted) for any
|
|
3
|
+
* other, so every path names exactly one place (`$.title["te.xt"]` is not `$.title.te.xt`).
|
|
4
|
+
*/
|
|
5
|
+
export declare function keySegment(key: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* The keys and indices a path names, in order: the inverse of the notation `keySegment` writes
|
|
8
|
+
* (`$.series[0].label["a b"]` → `['series', 0, 'label', 'a b']`); undefined for anything else. Only
|
|
9
|
+
* that one spelling is read, so a place has one path (`[01]`, `["a"]` or an escaped key are not
|
|
10
|
+
* paths, E29), and a malformed one is undefined, never a thrown error (K15).
|
|
11
|
+
*/
|
|
12
|
+
export declare function pathSegments(path: string): (string | number)[] | undefined;
|
|
13
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAyBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,SAAS,CAa1E"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
|
|
2
|
+
/**
|
|
3
|
+
* The path segment of an object key: `.key` for an identifier, `["key"]` (JSON-quoted) for any
|
|
4
|
+
* other, so every path names exactly one place (`$.title["te.xt"]` is not `$.title.te.xt`).
|
|
5
|
+
*/
|
|
6
|
+
export function keySegment(key) {
|
|
7
|
+
return IDENTIFIER.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
|
|
8
|
+
}
|
|
9
|
+
const SEGMENT = /\.([A-Za-z_$][\w$]*)|\[(0|[1-9]\d*)\]|\[("(?:[^"\\]|\\.)*")\]/y;
|
|
10
|
+
/** The key a quoted segment names, when it is quoted as `keySegment` quotes it; otherwise undefined. */
|
|
11
|
+
function quotedKey(quoted) {
|
|
12
|
+
let key;
|
|
13
|
+
try {
|
|
14
|
+
key = JSON.parse(quoted);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return typeof key === 'string' && keySegment(key) === `[${quoted}]` ? key : undefined;
|
|
20
|
+
}
|
|
21
|
+
/** One segment as `SEGMENT` matched it; undefined for a spelling `keySegment` does not write. */
|
|
22
|
+
function segmentOf([, name, index, quoted]) {
|
|
23
|
+
if (name !== undefined)
|
|
24
|
+
return name;
|
|
25
|
+
if (index !== undefined) {
|
|
26
|
+
const value = Number(index);
|
|
27
|
+
return Number.isSafeInteger(value) ? value : undefined;
|
|
28
|
+
}
|
|
29
|
+
return quoted === undefined ? undefined : quotedKey(quoted);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The keys and indices a path names, in order: the inverse of the notation `keySegment` writes
|
|
33
|
+
* (`$.series[0].label["a b"]` → `['series', 0, 'label', 'a b']`); undefined for anything else. Only
|
|
34
|
+
* that one spelling is read, so a place has one path (`[01]`, `["a"]` or an escaped key are not
|
|
35
|
+
* paths, E29), and a malformed one is undefined, never a thrown error (K15).
|
|
36
|
+
*/
|
|
37
|
+
export function pathSegments(path) {
|
|
38
|
+
if (!path.startsWith('$'))
|
|
39
|
+
return undefined;
|
|
40
|
+
const segments = [];
|
|
41
|
+
SEGMENT.lastIndex = 1;
|
|
42
|
+
while (SEGMENT.lastIndex < path.length) {
|
|
43
|
+
const start = SEGMENT.lastIndex;
|
|
44
|
+
const match = SEGMENT.exec(path);
|
|
45
|
+
if (match?.index !== start)
|
|
46
|
+
return undefined;
|
|
47
|
+
const segment = segmentOf(match);
|
|
48
|
+
if (segment === undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
segments.push(segment);
|
|
51
|
+
}
|
|
52
|
+
return segments;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,oBAAoB,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACrC,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AACtE,CAAC;AAED,MAAM,OAAO,GAAG,gEAAgE,CAAC;AAEjF,wGAAwG;AACxG,SAAS,SAAS,CAAC,MAAc;IAChC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACvF,CAAC;AAED,iGAAiG;AACjG,SAAS,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAkB;IAC1D,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACxC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IACtB,OAAO,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;QAChC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7C,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Diagnostic } from './diagnostic.js';
|
|
2
|
+
/**
|
|
3
|
+
* The published reference (CG-06-07): the repository's GitHub Pages site, with the reference at
|
|
4
|
+
* `/reference/`. Its codes page has an anchor for every code a package emits, the quality codes
|
|
5
|
+
* included, so a link is formed from the code alone and core still knows no code.
|
|
6
|
+
*/
|
|
7
|
+
export declare const REFERENCE_URL = "https://dovicsin.github.io/chartguard/reference/";
|
|
8
|
+
/** Where `code` is explained: its anchor on the reference's codes page. */
|
|
9
|
+
export declare function referenceUrl(code: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* The finding with a link to where it is explained: its own when it has one (a migration page the
|
|
12
|
+
* adapter names), else its code's anchor in the reference.
|
|
13
|
+
*/
|
|
14
|
+
export declare function documented(diagnostic: Diagnostic): Diagnostic;
|
|
15
|
+
//# sourceMappingURL=reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,aAAa,qDAAqD,CAAC;AAEhF,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAI7D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The published reference (CG-06-07): the repository's GitHub Pages site, with the reference at
|
|
3
|
+
* `/reference/`. Its codes page has an anchor for every code a package emits, the quality codes
|
|
4
|
+
* included, so a link is formed from the code alone and core still knows no code.
|
|
5
|
+
*/
|
|
6
|
+
export const REFERENCE_URL = 'https://dovicsin.github.io/chartguard/reference/';
|
|
7
|
+
/** Where `code` is explained: its anchor on the reference's codes page. */
|
|
8
|
+
export function referenceUrl(code) {
|
|
9
|
+
return `${REFERENCE_URL}codes.html#${encodeURIComponent(code)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The finding with a link to where it is explained: its own when it has one (a migration page the
|
|
13
|
+
* adapter names), else its code's anchor in the reference.
|
|
14
|
+
*/
|
|
15
|
+
export function documented(diagnostic) {
|
|
16
|
+
return diagnostic.documentationUrl === undefined
|
|
17
|
+
? { ...diagnostic, documentationUrl: referenceUrl(diagnostic.code) }
|
|
18
|
+
: diagnostic;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,kDAAkD,CAAC;AAEhF,2EAA2E;AAC3E,MAAM,UAAU,YAAY,CAAC,IAAY;IACxC,OAAO,GAAG,aAAa,cAAc,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAAsB;IAChD,OAAO,UAAU,CAAC,gBAAgB,KAAK,SAAS;QAC/C,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,gBAAgB,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;QACpE,CAAC,CAAC,UAAU,CAAC;AACf,CAAC"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Coverage, Diagnostic, ValidationResult } from './diagnostic.js';
|
|
2
|
+
/** Whether the finding is a confirmed error: severity `error`, whatever its code. */
|
|
3
|
+
export declare function isConfirmedError(diagnostic: Diagnostic): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* The only place that derives `valid` and `status`; callers never assemble a result by hand. Every
|
|
6
|
+
* finding leaves it with a `documentationUrl`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function result(library: string, schemaVersion: string, coverage: Coverage, diagnostics: Diagnostic[]): ValidationResult;
|
|
9
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAoB,MAAM,iBAAiB,CAAC;AAGhG,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAEhE;AAiBD;;;GAGG;AACH,wBAAgB,MAAM,CACrB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,UAAU,EAAE,GACvB,gBAAgB,CAUlB"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { documented } from './reference.js';
|
|
2
|
+
/** Whether the finding is a confirmed error: severity `error`, whatever its code. */
|
|
3
|
+
export function isConfirmedError(diagnostic) {
|
|
4
|
+
return diagnostic.severity === 'error';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Producers mark anything they could not decide with `confidence: 'unknown'`, and a likely problem
|
|
8
|
+
* read from a schema fact that is not authoritative with `'inferred'` (CG-02-07). Either keeps a
|
|
9
|
+
* result from `valid`, which needs a complete, authoritative check. Codes carry no meaning here.
|
|
10
|
+
*/
|
|
11
|
+
function isUndecided(diagnostic) {
|
|
12
|
+
return diagnostic.confidence !== 'certain';
|
|
13
|
+
}
|
|
14
|
+
function statusOf(coverage, diagnostics) {
|
|
15
|
+
if (diagnostics.some(isConfirmedError))
|
|
16
|
+
return 'invalid';
|
|
17
|
+
if (coverage === 'partial' || diagnostics.some(isUndecided))
|
|
18
|
+
return 'partial';
|
|
19
|
+
return 'valid';
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The only place that derives `valid` and `status`; callers never assemble a result by hand. Every
|
|
23
|
+
* finding leaves it with a `documentationUrl`.
|
|
24
|
+
*/
|
|
25
|
+
export function result(library, schemaVersion, coverage, diagnostics) {
|
|
26
|
+
const status = statusOf(coverage, diagnostics);
|
|
27
|
+
return {
|
|
28
|
+
valid: status !== 'invalid',
|
|
29
|
+
status,
|
|
30
|
+
library,
|
|
31
|
+
schemaVersion,
|
|
32
|
+
coverage,
|
|
33
|
+
diagnostics: diagnostics.map(documented)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,qFAAqF;AACrF,MAAM,UAAU,gBAAgB,CAAC,UAAsB;IACtD,OAAO,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,UAAsB;IAC1C,OAAO,UAAU,CAAC,UAAU,KAAK,SAAS,CAAC;AAC5C,CAAC;AAED,SAAS,QAAQ,CAAC,QAAkB,EAAE,WAAkC;IACvE,IAAI,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAAC;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,QAAQ,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9E,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CACrB,OAAe,EACf,aAAqB,EACrB,QAAkB,EAClB,WAAyB;IAEzB,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/C,OAAO;QACN,KAAK,EAAE,MAAM,KAAK,SAAS;QAC3B,MAAM;QACN,OAAO;QACP,aAAa;QACb,QAAQ;QACR,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;KACxC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The work typo hints may still do, in distance cells. Both the names and how many are compared come
|
|
3
|
+
* from the input, so one run shares one budget; once it is spent, no further hint is searched for.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SuggestionBudget {
|
|
6
|
+
private left;
|
|
7
|
+
constructor(left: number);
|
|
8
|
+
/** The cells not yet spent. */
|
|
9
|
+
get cells(): number;
|
|
10
|
+
/** Spends `cells` when that many are left; false (nothing spent) otherwise. */
|
|
11
|
+
spend(cells: number): boolean;
|
|
12
|
+
}
|
|
13
|
+
/** A fresh budget for one run (`cells`: for tests and callers with their own bound). */
|
|
14
|
+
export declare function suggestionBudget(cells?: number): SuggestionBudget;
|
|
15
|
+
/**
|
|
16
|
+
* Closest candidate within a typo-sized edit distance, if any: the first one at the smallest
|
|
17
|
+
* distance. Bounded for untrusted names: none for a name over 100 characters, candidates whose length
|
|
18
|
+
* alone rules them out are skipped, and the search stops (no hint) when `budget` is spent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function suggestion(input: string, candidates: readonly string[], budget?: SuggestionBudget): string | undefined;
|
|
21
|
+
//# sourceMappingURL=suggestion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion.d.ts","sourceRoot":"","sources":["../src/suggestion.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,qBAAa,gBAAgB;IAChB,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAEhC,+BAA+B;IAC/B,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,+EAA+E;IAC/E,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAK7B;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,MAAkB,GAAG,gBAAgB,CAE5E;AA0BD;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,GAAE,gBAA+C,GACrD,MAAM,GAAG,SAAS,CAepB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Names longer than this get no typo hint: a typo-sized edit of a long name is no longer a typo. */
|
|
2
|
+
const MAX_HINT_LENGTH = 100;
|
|
3
|
+
/** Distance cells one call may compute when the caller gives no budget of its own. */
|
|
4
|
+
const CALL_CELLS = 100_000;
|
|
5
|
+
/** Distance cells one run (a validation) may spend on hints, whatever the input holds. */
|
|
6
|
+
const RUN_CELLS = 2_000_000;
|
|
7
|
+
/**
|
|
8
|
+
* The work typo hints may still do, in distance cells. Both the names and how many are compared come
|
|
9
|
+
* from the input, so one run shares one budget; once it is spent, no further hint is searched for.
|
|
10
|
+
*/
|
|
11
|
+
export class SuggestionBudget {
|
|
12
|
+
left;
|
|
13
|
+
constructor(left) {
|
|
14
|
+
this.left = left;
|
|
15
|
+
}
|
|
16
|
+
/** The cells not yet spent. */
|
|
17
|
+
get cells() {
|
|
18
|
+
return this.left;
|
|
19
|
+
}
|
|
20
|
+
/** Spends `cells` when that many are left; false (nothing spent) otherwise. */
|
|
21
|
+
spend(cells) {
|
|
22
|
+
if (this.left < cells)
|
|
23
|
+
return false;
|
|
24
|
+
this.left -= cells;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** A fresh budget for one run (`cells`: for tests and callers with their own bound). */
|
|
29
|
+
export function suggestionBudget(cells = RUN_CELLS) {
|
|
30
|
+
return new SuggestionBudget(cells);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Levenshtein distance with a single rolling row, given only up to `limit`: `limit + 1` once every
|
|
34
|
+
* cell of a row exceeds it, `undefined` when the budget is spent first.
|
|
35
|
+
*/
|
|
36
|
+
function distanceWithin(source, target, limit, budget) {
|
|
37
|
+
const row = Array.from({ length: target.length + 1 }, (_, index) => index);
|
|
38
|
+
for (let i = 1; i <= source.length; i++) {
|
|
39
|
+
if (!budget.spend(target.length))
|
|
40
|
+
return undefined;
|
|
41
|
+
let diagonal = i - 1;
|
|
42
|
+
row[0] = i;
|
|
43
|
+
let lowest = i;
|
|
44
|
+
for (let k = 1; k <= target.length; k++) {
|
|
45
|
+
const above = row[k] ?? 0;
|
|
46
|
+
const left = row[k - 1] ?? 0;
|
|
47
|
+
const substitution = source.charAt(i - 1) === target.charAt(k - 1) ? 0 : 1;
|
|
48
|
+
row[k] = Math.min(left + 1, above + 1, diagonal + substitution);
|
|
49
|
+
lowest = Math.min(lowest, row[k] ?? 0);
|
|
50
|
+
diagonal = above;
|
|
51
|
+
}
|
|
52
|
+
if (lowest > limit)
|
|
53
|
+
return limit + 1;
|
|
54
|
+
}
|
|
55
|
+
return row[target.length] ?? 0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Closest candidate within a typo-sized edit distance, if any: the first one at the smallest
|
|
59
|
+
* distance. Bounded for untrusted names: none for a name over 100 characters, candidates whose length
|
|
60
|
+
* alone rules them out are skipped, and the search stops (no hint) when `budget` is spent.
|
|
61
|
+
*/
|
|
62
|
+
export function suggestion(input, candidates, budget = suggestionBudget(CALL_CELLS)) {
|
|
63
|
+
if (input.length > MAX_HINT_LENGTH)
|
|
64
|
+
return undefined;
|
|
65
|
+
let best;
|
|
66
|
+
let bestDistance = Math.max(1, Math.floor(input.length / 4)) + 1;
|
|
67
|
+
for (const candidate of candidates) {
|
|
68
|
+
// The distance is at least the difference in length: such a candidate cannot be closer.
|
|
69
|
+
if (Math.abs(candidate.length - input.length) >= bestDistance)
|
|
70
|
+
continue;
|
|
71
|
+
const distance = distanceWithin(input, candidate, bestDistance - 1, budget);
|
|
72
|
+
if (distance === undefined)
|
|
73
|
+
return undefined;
|
|
74
|
+
if (distance < bestDistance) {
|
|
75
|
+
best = candidate;
|
|
76
|
+
bestDistance = distance;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=suggestion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion.js","sourceRoot":"","sources":["../src/suggestion.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,sFAAsF;AACtF,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,0FAA0F;AAC1F,MAAM,SAAS,GAAG,SAAS,CAAC;AAE5B;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IACR;IAApB,YAAoB,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAEpC,+BAA+B;IAC/B,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,KAAa;QAClB,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC;QACnB,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,QAAgB,SAAS;IACzD,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,MAAc,EAAE,MAAc,EAAE,KAAa,EAAE,MAAwB;IAC9F,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC3E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC;QACnD,IAAI,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3E,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;YAChE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACvC,QAAQ,GAAG,KAAK,CAAC;QAClB,CAAC;QACD,IAAI,MAAM,GAAG,KAAK;YAAE,OAAO,KAAK,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACzB,KAAa,EACb,UAA6B,EAC7B,SAA2B,gBAAgB,CAAC,UAAU,CAAC;IAEvD,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe;QAAE,OAAO,SAAS,CAAC;IACrD,IAAI,IAAwB,CAAC;IAC7B,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,wFAAwF;QACxF,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,YAAY;YAAE,SAAS;QACxE,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,YAAY,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5E,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC7C,IAAI,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC7B,IAAI,GAAG,SAAS,CAAC;YACjB,YAAY,GAAG,QAAQ,CAAC;QACzB,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@chartguard/core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Shared diagnostics, statuses and runtime contracts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/dovicsin/chartguard.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22.12.0"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -b",
|
|
31
|
+
"test": "node --test tests/*.test.mjs"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
}
|
|
36
|
+
}
|