@open-operational-state/validator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/__tests__/fixture-runner.test.d.ts +8 -0
- package/dist/__tests__/fixture-runner.test.d.ts.map +1 -0
- package/dist/__tests__/fixture-runner.test.js +100 -0
- package/dist/__tests__/fixture-runner.test.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +228 -0
- package/dist/cli.js.map +1 -0
- package/dist/conformance.d.ts +14 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +149 -0
- package/dist/conformance.js.map +1 -0
- package/dist/fixture-runner.d.ts +54 -0
- package/dist/fixture-runner.d.ts.map +1 -0
- package/dist/fixture-runner.js +112 -0
- package/dist/fixture-runner.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @open-operational-state/validator
|
|
2
|
+
|
|
3
|
+
Conformance validation and CLI for [Open Operational State](https://github.com/open-operational-state).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @open-operational-state/validator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## CLI
|
|
12
|
+
|
|
13
|
+
The `oos` CLI is included in this package.
|
|
14
|
+
|
|
15
|
+
### Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Validate a JSON file against conformance levels
|
|
19
|
+
oos validate <file>
|
|
20
|
+
|
|
21
|
+
# Fetch a URL, auto-detect format, parse to core model
|
|
22
|
+
oos probe <url>
|
|
23
|
+
|
|
24
|
+
# Run all conformance fixtures in a directory
|
|
25
|
+
oos fixtures <dir>
|
|
26
|
+
|
|
27
|
+
# Parse a JSON file, pretty-print core model
|
|
28
|
+
oos inspect <file>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Options
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
--format=json|table Output format (default: json)
|
|
35
|
+
--help Show help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Examples
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Validate a health response
|
|
42
|
+
oos validate response.json
|
|
43
|
+
|
|
44
|
+
# Probe a live endpoint
|
|
45
|
+
oos probe https://api.example.com/health
|
|
46
|
+
|
|
47
|
+
# Run conformance test suite
|
|
48
|
+
oos fixtures ../status-conformance/fixtures/core --format=table
|
|
49
|
+
# ✓ /positive-minimal-snapshot.json
|
|
50
|
+
# ✓ /negative-missing-condition.json
|
|
51
|
+
# ✓ /negative-invalid-condition.json
|
|
52
|
+
# 3 passed, 0 failed
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Programmatic API
|
|
56
|
+
|
|
57
|
+
### `checkConformanceLevel( snapshot )`
|
|
58
|
+
|
|
59
|
+
Assess which conformance tier a `Snapshot` satisfies.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { checkConformanceLevel } from '@open-operational-state/validator';
|
|
63
|
+
|
|
64
|
+
const result = checkConformanceLevel( snapshot );
|
|
65
|
+
// { level: 'standard', basic: true, standard: true, extended: false }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `loadFixture( path )` / `runFixture( fixture )`
|
|
69
|
+
|
|
70
|
+
Load and execute conformance fixtures.
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
import { loadFixture, runFixture } from '@open-operational-state/validator';
|
|
74
|
+
|
|
75
|
+
const fixture = loadFixture( './fixtures/core/positive-minimal-snapshot.json' );
|
|
76
|
+
const result = runFixture( fixture );
|
|
77
|
+
// { passed: true, diagnostics: [] }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `runFixtureDir( dirPath )`
|
|
81
|
+
|
|
82
|
+
Recursively find and execute all fixtures in a directory.
|
|
83
|
+
|
|
84
|
+
## Dependencies
|
|
85
|
+
|
|
86
|
+
- `@open-operational-state/types`
|
|
87
|
+
- `@open-operational-state/core`
|
|
88
|
+
- `@open-operational-state/parser`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture-runner.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fixture-runner.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture Runner Tests
|
|
3
|
+
*
|
|
4
|
+
* Runs all conformance fixtures from the status-conformance repository.
|
|
5
|
+
* Fixtures are read directly from the sibling repo — no copying.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect } from 'bun:test';
|
|
8
|
+
import { resolve, join, basename } from 'node:path';
|
|
9
|
+
import { readdirSync, statSync, existsSync } from 'node:fs';
|
|
10
|
+
import { loadFixture, runFixture } from '../fixture-runner.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Fixture root resolution
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
const FIXTURE_ROOT = process.env.OOS_FIXTURE_ROOT
|
|
15
|
+
|| resolve(import.meta.dir, '../../../../..', 'status-conformance');
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
function findFixtures(dirPath) {
|
|
20
|
+
if (!existsSync(dirPath)) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const files = [];
|
|
24
|
+
for (const entry of readdirSync(dirPath)) {
|
|
25
|
+
const fullPath = join(dirPath, entry);
|
|
26
|
+
const stat = statSync(fullPath);
|
|
27
|
+
if (stat.isDirectory()) {
|
|
28
|
+
files.push(...findFixtures(fullPath));
|
|
29
|
+
}
|
|
30
|
+
else if (entry.endsWith('.json')) {
|
|
31
|
+
files.push(fullPath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
function runAndReport(fixturePath) {
|
|
37
|
+
const fixture = loadFixture(fixturePath);
|
|
38
|
+
return runFixture(fixture);
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Core fixtures
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
describe('core fixtures', () => {
|
|
44
|
+
const dir = join(FIXTURE_ROOT, 'fixtures', 'core');
|
|
45
|
+
const files = findFixtures(dir);
|
|
46
|
+
if (files.length === 0) {
|
|
47
|
+
it.skip('no core fixtures found', () => { });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
for (const filePath of files) {
|
|
51
|
+
it(basename(filePath), () => {
|
|
52
|
+
const result = runAndReport(filePath);
|
|
53
|
+
expect(result.passed).toBe(true);
|
|
54
|
+
if (!result.passed) {
|
|
55
|
+
console.error('Diagnostics:', result.diagnostics);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Profile fixtures
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
describe('profile fixtures', () => {
|
|
64
|
+
const dir = join(FIXTURE_ROOT, 'fixtures', 'profiles');
|
|
65
|
+
const files = findFixtures(dir);
|
|
66
|
+
if (files.length === 0) {
|
|
67
|
+
it.skip('no profile fixtures found', () => { });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const filePath of files) {
|
|
71
|
+
it(basename(filePath), () => {
|
|
72
|
+
const result = runAndReport(filePath);
|
|
73
|
+
expect(result.passed).toBe(true);
|
|
74
|
+
if (!result.passed) {
|
|
75
|
+
console.error('Diagnostics:', result.diagnostics);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Serialization fixtures
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
describe('serialization fixtures', () => {
|
|
84
|
+
const dir = join(FIXTURE_ROOT, 'fixtures', 'serializations');
|
|
85
|
+
const files = findFixtures(dir);
|
|
86
|
+
if (files.length === 0) {
|
|
87
|
+
it.skip('no serialization fixtures found', () => { });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
for (const filePath of files) {
|
|
91
|
+
it(basename(filePath), () => {
|
|
92
|
+
const result = runAndReport(filePath);
|
|
93
|
+
expect(result.passed).toBe(true);
|
|
94
|
+
if (!result.passed) {
|
|
95
|
+
console.error('Diagnostics:', result.diagnostics);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=fixture-runner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture-runner.test.js","sourceRoot":"","sources":["../../src/__tests__/fixture-runner.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* OOS CLI — Open Operational State command-line tool
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* oos validate <file> Validate a JSON file against conformance levels
|
|
7
|
+
* oos probe <url> Fetch a URL, auto-detect format, parse to core model
|
|
8
|
+
* oos fixtures <dir> Run all conformance fixtures in a directory
|
|
9
|
+
* oos inspect <file> Parse a JSON file, pretty-print core model
|
|
10
|
+
*
|
|
11
|
+
* Options:
|
|
12
|
+
* --format=json|table Output format (default: json)
|
|
13
|
+
* --help Show help
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* OOS CLI — Open Operational State command-line tool
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* oos validate <file> Validate a JSON file against conformance levels
|
|
7
|
+
* oos probe <url> Fetch a URL, auto-detect format, parse to core model
|
|
8
|
+
* oos fixtures <dir> Run all conformance fixtures in a directory
|
|
9
|
+
* oos inspect <file> Parse a JSON file, pretty-print core model
|
|
10
|
+
*
|
|
11
|
+
* Options:
|
|
12
|
+
* --format=json|table Output format (default: json)
|
|
13
|
+
* --help Show help
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
16
|
+
import { resolve } from 'node:path';
|
|
17
|
+
import { normalizeSnapshot, validateSnapshot } from '@open-operational-state/core';
|
|
18
|
+
import { parse } from '@open-operational-state/parser';
|
|
19
|
+
import { checkConformanceLevel } from './conformance.js';
|
|
20
|
+
import { runFixtureDir } from './fixture-runner.js';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Arg parsing
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const flags = {};
|
|
26
|
+
const positional = [];
|
|
27
|
+
for (const arg of args) {
|
|
28
|
+
if (arg.startsWith('--')) {
|
|
29
|
+
const [key, value] = arg.slice(2).split('=');
|
|
30
|
+
flags[key] = value || 'true';
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
positional.push(arg);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const command = positional[0];
|
|
37
|
+
const target = positional[1];
|
|
38
|
+
const format = flags.format || 'json';
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Output helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
function output(data) {
|
|
43
|
+
if (format === 'table' && typeof data === 'object' && data !== null) {
|
|
44
|
+
console.table(data);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(JSON.stringify(data, null, 2));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function exitError(message) {
|
|
51
|
+
console.error(`Error: ${message}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Commands
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
function showHelp() {
|
|
58
|
+
console.log(`
|
|
59
|
+
OOS — Open Operational State CLI
|
|
60
|
+
|
|
61
|
+
Usage:
|
|
62
|
+
oos validate <file> Validate a JSON file against conformance levels
|
|
63
|
+
oos probe <url> Fetch a URL, auto-detect format, parse to core model
|
|
64
|
+
oos fixtures <dir> Run all conformance fixtures in a directory
|
|
65
|
+
oos inspect <file> Parse a JSON file, pretty-print core model
|
|
66
|
+
|
|
67
|
+
Options:
|
|
68
|
+
--format=json|table Output format (default: json)
|
|
69
|
+
--help Show this help
|
|
70
|
+
`.trim());
|
|
71
|
+
}
|
|
72
|
+
async function cmdValidate(filePath) {
|
|
73
|
+
const absPath = resolve(filePath);
|
|
74
|
+
if (!existsSync(absPath)) {
|
|
75
|
+
exitError(`File not found: ${absPath}`);
|
|
76
|
+
}
|
|
77
|
+
const raw = JSON.parse(readFileSync(absPath, 'utf-8'));
|
|
78
|
+
const snapshot = normalizeSnapshot(raw);
|
|
79
|
+
const validation = validateSnapshot(snapshot);
|
|
80
|
+
const conformance = checkConformanceLevel(snapshot);
|
|
81
|
+
output({
|
|
82
|
+
file: absPath,
|
|
83
|
+
validation,
|
|
84
|
+
conformance: {
|
|
85
|
+
level: conformance.level,
|
|
86
|
+
basic: conformance.basic,
|
|
87
|
+
standard: conformance.standard,
|
|
88
|
+
extended: conformance.extended,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
if (!validation.valid) {
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function cmdProbe(url) {
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(url);
|
|
98
|
+
const contentType = response.headers.get('content-type') || '';
|
|
99
|
+
let body;
|
|
100
|
+
try {
|
|
101
|
+
body = await response.json();
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
body = await response.text();
|
|
105
|
+
}
|
|
106
|
+
const headers = {};
|
|
107
|
+
response.headers.forEach((value, key) => {
|
|
108
|
+
headers[key] = value;
|
|
109
|
+
});
|
|
110
|
+
const snapshot = parse({
|
|
111
|
+
contentType,
|
|
112
|
+
body,
|
|
113
|
+
url,
|
|
114
|
+
httpStatus: response.status,
|
|
115
|
+
headers,
|
|
116
|
+
});
|
|
117
|
+
const validation = validateSnapshot(snapshot);
|
|
118
|
+
const conformance = checkConformanceLevel(snapshot);
|
|
119
|
+
output({
|
|
120
|
+
url,
|
|
121
|
+
httpStatus: response.status,
|
|
122
|
+
contentType,
|
|
123
|
+
snapshot,
|
|
124
|
+
validation: { valid: validation.valid, errorCount: validation.errors.length },
|
|
125
|
+
conformance: { level: conformance.level },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
// Connection failure
|
|
130
|
+
const snapshot = parse({
|
|
131
|
+
url,
|
|
132
|
+
connectionError: true,
|
|
133
|
+
});
|
|
134
|
+
output({
|
|
135
|
+
url,
|
|
136
|
+
connectionError: true,
|
|
137
|
+
snapshot,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function cmdFixtures(dirPath) {
|
|
142
|
+
const absPath = resolve(dirPath);
|
|
143
|
+
if (!existsSync(absPath)) {
|
|
144
|
+
exitError(`Directory not found: ${absPath}`);
|
|
145
|
+
}
|
|
146
|
+
const results = runFixtureDir(absPath);
|
|
147
|
+
const passed = results.filter((r) => r.passed).length;
|
|
148
|
+
const failed = results.filter((r) => !r.passed).length;
|
|
149
|
+
if (format === 'table') {
|
|
150
|
+
for (const r of results) {
|
|
151
|
+
const status = r.passed ? '✓' : '✗';
|
|
152
|
+
const name = r.fixture.filePath.replace(absPath, '');
|
|
153
|
+
console.log(` ${status} ${name}`);
|
|
154
|
+
if (!r.passed) {
|
|
155
|
+
for (const d of r.diagnostics) {
|
|
156
|
+
console.log(` → ${d}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log(`\n ${passed} passed, ${failed} failed`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
output({
|
|
164
|
+
total: results.length,
|
|
165
|
+
passed,
|
|
166
|
+
failed,
|
|
167
|
+
results: results.map((r) => ({
|
|
168
|
+
file: r.fixture.filePath,
|
|
169
|
+
passed: r.passed,
|
|
170
|
+
diagnostics: r.diagnostics,
|
|
171
|
+
})),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (failed > 0) {
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function cmdInspect(filePath) {
|
|
179
|
+
const absPath = resolve(filePath);
|
|
180
|
+
if (!existsSync(absPath)) {
|
|
181
|
+
exitError(`File not found: ${absPath}`);
|
|
182
|
+
}
|
|
183
|
+
const raw = JSON.parse(readFileSync(absPath, 'utf-8'));
|
|
184
|
+
const snapshot = normalizeSnapshot(raw);
|
|
185
|
+
output(snapshot);
|
|
186
|
+
}
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
// Main
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
async function main() {
|
|
191
|
+
if (flags.help || !command) {
|
|
192
|
+
showHelp();
|
|
193
|
+
process.exit(0);
|
|
194
|
+
}
|
|
195
|
+
switch (command) {
|
|
196
|
+
case 'validate':
|
|
197
|
+
if (!target) {
|
|
198
|
+
exitError('validate requires a file path');
|
|
199
|
+
}
|
|
200
|
+
await cmdValidate(target);
|
|
201
|
+
break;
|
|
202
|
+
case 'probe':
|
|
203
|
+
if (!target) {
|
|
204
|
+
exitError('probe requires a URL');
|
|
205
|
+
}
|
|
206
|
+
await cmdProbe(target);
|
|
207
|
+
break;
|
|
208
|
+
case 'fixtures':
|
|
209
|
+
if (!target) {
|
|
210
|
+
exitError('fixtures requires a directory path');
|
|
211
|
+
}
|
|
212
|
+
cmdFixtures(target);
|
|
213
|
+
break;
|
|
214
|
+
case 'inspect':
|
|
215
|
+
if (!target) {
|
|
216
|
+
exitError('inspect requires a file path');
|
|
217
|
+
}
|
|
218
|
+
cmdInspect(target);
|
|
219
|
+
break;
|
|
220
|
+
default:
|
|
221
|
+
exitError(`Unknown command: ${command}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
main().catch((err) => {
|
|
225
|
+
console.error(err);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
});
|
|
228
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conformance Level Checking
|
|
3
|
+
*
|
|
4
|
+
* Determines Basic / Standard / Extended conformance per
|
|
5
|
+
* status-conformance/CONFORMANCE.md.
|
|
6
|
+
*/
|
|
7
|
+
import type { Snapshot, ConformanceResult } from '@open-operational-state/types';
|
|
8
|
+
/**
|
|
9
|
+
* Assess the conformance level of a Snapshot.
|
|
10
|
+
*
|
|
11
|
+
* Levels are cumulative: Standard implies Basic, Extended implies Standard.
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkConformanceLevel(snapshot: Snapshot): ConformanceResult;
|
|
14
|
+
//# sourceMappingURL=conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACR,QAAQ,EACR,iBAAiB,EAGpB,MAAM,+BAA+B,CAAC;AAkBvC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAE,QAAQ,EAAE,QAAQ,GAAI,iBAAiB,CAqB7E"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conformance Level Checking
|
|
3
|
+
*
|
|
4
|
+
* Determines Basic / Standard / Extended conformance per
|
|
5
|
+
* status-conformance/CONFORMANCE.md.
|
|
6
|
+
*/
|
|
7
|
+
import { isProfileId, isHealthCondition, isLivenessCondition, isReadinessCondition, isExtensionCondition, isProvenance, } from '@open-operational-state/types';
|
|
8
|
+
import { validateSnapshot } from '@open-operational-state/core';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Public API
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Assess the conformance level of a Snapshot.
|
|
14
|
+
*
|
|
15
|
+
* Levels are cumulative: Standard implies Basic, Extended implies Standard.
|
|
16
|
+
*/
|
|
17
|
+
export function checkConformanceLevel(snapshot) {
|
|
18
|
+
const errors = [];
|
|
19
|
+
const warnings = [];
|
|
20
|
+
const basicOk = checkBasic(snapshot, errors);
|
|
21
|
+
const standardOk = basicOk && checkStandard(snapshot, errors, warnings);
|
|
22
|
+
const extendedOk = standardOk && checkExtended(snapshot, errors, warnings);
|
|
23
|
+
let level = null;
|
|
24
|
+
if (extendedOk) {
|
|
25
|
+
level = 'extended';
|
|
26
|
+
}
|
|
27
|
+
else if (standardOk) {
|
|
28
|
+
level = 'standard';
|
|
29
|
+
}
|
|
30
|
+
else if (basicOk) {
|
|
31
|
+
level = 'basic';
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
level,
|
|
35
|
+
basic: basicOk,
|
|
36
|
+
standard: standardOk,
|
|
37
|
+
extended: extendedOk,
|
|
38
|
+
errors,
|
|
39
|
+
warnings,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Basic
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
function checkBasic(snapshot, errors) {
|
|
46
|
+
let ok = true;
|
|
47
|
+
// Valid condition field
|
|
48
|
+
if (!snapshot.condition) {
|
|
49
|
+
errors.push({ path: 'condition', message: 'Basic: missing condition', code: 'BASIC_MISSING_CONDITION' });
|
|
50
|
+
ok = false;
|
|
51
|
+
}
|
|
52
|
+
// Subject with id
|
|
53
|
+
if (!snapshot.subject?.id) {
|
|
54
|
+
errors.push({ path: 'subject.id', message: 'Basic: missing subject.id', code: 'BASIC_MISSING_SUBJECT' });
|
|
55
|
+
ok = false;
|
|
56
|
+
}
|
|
57
|
+
// Profiles array with at least one valid profile
|
|
58
|
+
if (!Array.isArray(snapshot.profiles) || snapshot.profiles.length === 0) {
|
|
59
|
+
errors.push({ path: 'profiles', message: 'Basic: missing or empty profiles', code: 'BASIC_MISSING_PROFILES' });
|
|
60
|
+
ok = false;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const hasValidProfile = snapshot.profiles.some(isProfileId);
|
|
64
|
+
if (!hasValidProfile) {
|
|
65
|
+
errors.push({ path: 'profiles', message: 'Basic: no valid profile identifier', code: 'BASIC_NO_VALID_PROFILE' });
|
|
66
|
+
ok = false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Condition value is in a recognized vocabulary
|
|
70
|
+
if (snapshot.condition) {
|
|
71
|
+
const inVocab = isLivenessCondition(snapshot.condition) ||
|
|
72
|
+
isReadinessCondition(snapshot.condition) ||
|
|
73
|
+
isHealthCondition(snapshot.condition) ||
|
|
74
|
+
isExtensionCondition(snapshot.condition);
|
|
75
|
+
if (!inVocab) {
|
|
76
|
+
errors.push({
|
|
77
|
+
path: 'condition',
|
|
78
|
+
message: `Basic: condition '${snapshot.condition}' not in any vocabulary`,
|
|
79
|
+
code: 'BASIC_INVALID_CONDITION',
|
|
80
|
+
});
|
|
81
|
+
ok = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return ok;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Standard
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
function checkStandard(snapshot, errors, warnings) {
|
|
90
|
+
let ok = true;
|
|
91
|
+
// Full model validation passes
|
|
92
|
+
const modelResult = validateSnapshot(snapshot);
|
|
93
|
+
if (!modelResult.valid) {
|
|
94
|
+
for (const e of modelResult.errors) {
|
|
95
|
+
errors.push({ ...e, code: `STANDARD_${e.code}` });
|
|
96
|
+
}
|
|
97
|
+
ok = false;
|
|
98
|
+
}
|
|
99
|
+
warnings.push(...modelResult.warnings);
|
|
100
|
+
// Timing uses RFC 3339 (already covered by validateSnapshot)
|
|
101
|
+
// All declared profiles' MUST-level requirements are satisfied
|
|
102
|
+
// (already covered by validateSnapshot)
|
|
103
|
+
return ok;
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Extended
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
function checkExtended(snapshot, errors, warnings) {
|
|
109
|
+
let ok = true;
|
|
110
|
+
// Multiple profiles
|
|
111
|
+
if (!Array.isArray(snapshot.profiles) || snapshot.profiles.length < 2) {
|
|
112
|
+
errors.push({
|
|
113
|
+
path: 'profiles',
|
|
114
|
+
message: 'Extended: requires multiple profiles',
|
|
115
|
+
code: 'EXTENDED_SINGLE_PROFILE',
|
|
116
|
+
});
|
|
117
|
+
ok = false;
|
|
118
|
+
}
|
|
119
|
+
// Explicit provenance
|
|
120
|
+
if (!snapshot.provenance) {
|
|
121
|
+
errors.push({
|
|
122
|
+
path: 'provenance',
|
|
123
|
+
message: 'Extended: requires explicit provenance',
|
|
124
|
+
code: 'EXTENDED_MISSING_PROVENANCE',
|
|
125
|
+
});
|
|
126
|
+
ok = false;
|
|
127
|
+
}
|
|
128
|
+
else if (!isProvenance(snapshot.provenance)) {
|
|
129
|
+
errors.push({
|
|
130
|
+
path: 'provenance',
|
|
131
|
+
message: `Extended: unrecognized provenance '${snapshot.provenance}'`,
|
|
132
|
+
code: 'EXTENDED_INVALID_PROVENANCE',
|
|
133
|
+
});
|
|
134
|
+
ok = false;
|
|
135
|
+
}
|
|
136
|
+
// Evidence for non-operational conditions
|
|
137
|
+
if (snapshot.condition && snapshot.condition !== 'operational' && snapshot.condition !== 'alive' && snapshot.condition !== 'ready') {
|
|
138
|
+
if (!snapshot.evidence) {
|
|
139
|
+
errors.push({
|
|
140
|
+
path: 'evidence',
|
|
141
|
+
message: 'Extended: requires evidence for non-operational conditions',
|
|
142
|
+
code: 'EXTENDED_MISSING_EVIDENCE',
|
|
143
|
+
});
|
|
144
|
+
ok = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return ok;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.js","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture Runner
|
|
3
|
+
*
|
|
4
|
+
* Load and execute conformance fixtures from the status-conformance repository.
|
|
5
|
+
*/
|
|
6
|
+
import type { ValidationResult, Snapshot } from '@open-operational-state/types';
|
|
7
|
+
export interface FixtureMetadata {
|
|
8
|
+
layer: string;
|
|
9
|
+
polarity: string;
|
|
10
|
+
description: string;
|
|
11
|
+
license?: string;
|
|
12
|
+
profile?: string;
|
|
13
|
+
adapter?: string;
|
|
14
|
+
fidelity?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface FixtureExpected {
|
|
17
|
+
valid?: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
condition?: string;
|
|
20
|
+
profiles?: string[];
|
|
21
|
+
profiles_satisfied?: string[];
|
|
22
|
+
subject?: Record<string, unknown>;
|
|
23
|
+
provenance?: string;
|
|
24
|
+
checks?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface Fixture {
|
|
27
|
+
metadata: FixtureMetadata;
|
|
28
|
+
input: Record<string, unknown>;
|
|
29
|
+
expected: FixtureExpected;
|
|
30
|
+
filePath: string;
|
|
31
|
+
}
|
|
32
|
+
export interface FixtureResult {
|
|
33
|
+
fixture: Fixture;
|
|
34
|
+
passed: boolean;
|
|
35
|
+
validation?: ValidationResult;
|
|
36
|
+
snapshot?: Snapshot;
|
|
37
|
+
diagnostics: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load a single fixture from a JSON file path.
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadFixture(filePath: string): Fixture;
|
|
43
|
+
/**
|
|
44
|
+
* Execute a single fixture:
|
|
45
|
+
* 1. Normalize the input into a Snapshot.
|
|
46
|
+
* 2. Validate the Snapshot.
|
|
47
|
+
* 3. Compare the validation result against the fixture's expected outcome.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runFixture(fixture: Fixture): FixtureResult;
|
|
50
|
+
/**
|
|
51
|
+
* Recursively discover and run all `.json` fixture files in a directory.
|
|
52
|
+
*/
|
|
53
|
+
export declare function runFixtureDir(dirPath: string): FixtureResult[];
|
|
54
|
+
//# sourceMappingURL=fixture-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture-runner.d.ts","sourceRoot":"","sources":["../src/fixture-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAMhF,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,OAAO;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACzB;AAMD;;GAEG;AACH,wBAAgB,WAAW,CAAE,QAAQ,EAAE,MAAM,GAAI,OAAO,CASvD;AAMD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAE,OAAO,EAAE,OAAO,GAAI,aAAa,CA8D5D;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAE,OAAO,EAAE,MAAM,GAAI,aAAa,EAAE,CAUhE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture Runner
|
|
3
|
+
*
|
|
4
|
+
* Load and execute conformance fixtures from the status-conformance repository.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
7
|
+
import { join, extname } from 'node:path';
|
|
8
|
+
import { normalizeSnapshot, validateSnapshot } from '@open-operational-state/core';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Load
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Load a single fixture from a JSON file path.
|
|
14
|
+
*/
|
|
15
|
+
export function loadFixture(filePath) {
|
|
16
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
return {
|
|
19
|
+
metadata: parsed._metadata || {},
|
|
20
|
+
input: parsed.input || {},
|
|
21
|
+
expected: parsed.expected || {},
|
|
22
|
+
filePath,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Run
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Execute a single fixture:
|
|
30
|
+
* 1. Normalize the input into a Snapshot.
|
|
31
|
+
* 2. Validate the Snapshot.
|
|
32
|
+
* 3. Compare the validation result against the fixture's expected outcome.
|
|
33
|
+
*/
|
|
34
|
+
export function runFixture(fixture) {
|
|
35
|
+
const diagnostics = [];
|
|
36
|
+
// Normalize input → Snapshot
|
|
37
|
+
const snapshot = normalizeSnapshot(fixture.input);
|
|
38
|
+
// Validate
|
|
39
|
+
const validation = validateSnapshot(snapshot);
|
|
40
|
+
let passed = true;
|
|
41
|
+
// ── Check expected validity ────────────────────────────────────────
|
|
42
|
+
if (fixture.expected.valid !== undefined) {
|
|
43
|
+
if (validation.valid !== fixture.expected.valid) {
|
|
44
|
+
passed = false;
|
|
45
|
+
diagnostics.push(`Expected valid=${fixture.expected.valid}, got valid=${validation.valid}` +
|
|
46
|
+
(validation.errors.length > 0
|
|
47
|
+
? ` (errors: ${validation.errors.map((e) => e.message).join('; ')})`
|
|
48
|
+
: ''));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ── Check expected error message or code (negative fixtures) ────────
|
|
52
|
+
if (fixture.expected.error && fixture.expected.valid === false) {
|
|
53
|
+
const expectedError = fixture.expected.error;
|
|
54
|
+
const hasMatchingError = validation.errors.some((e) => e.message === expectedError || e.code === expectedError);
|
|
55
|
+
if (!hasMatchingError) {
|
|
56
|
+
// Check for partial match on message
|
|
57
|
+
const hasPartialMatch = validation.errors.some((e) => e.message.includes(expectedError.split(':')[0]));
|
|
58
|
+
if (!hasPartialMatch) {
|
|
59
|
+
passed = false;
|
|
60
|
+
diagnostics.push(`Expected error containing '${expectedError}', got: ${JSON.stringify(validation.errors.map((e) => `${e.code}: ${e.message}`))}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ── Check profiles_satisfied (positive fixtures) ───────────────────
|
|
65
|
+
if (fixture.expected.profiles_satisfied) {
|
|
66
|
+
// profiles_satisfied is informational — we verify the snapshot's
|
|
67
|
+
// declared profiles are a subset
|
|
68
|
+
const declared = new Set(snapshot.profiles);
|
|
69
|
+
for (const expected of fixture.expected.profiles_satisfied) {
|
|
70
|
+
if (!declared.has(expected)) {
|
|
71
|
+
// Check if the profile would be hierarchically satisfied
|
|
72
|
+
// (e.g., a health response satisfies liveness)
|
|
73
|
+
// This is informational, not a hard failure
|
|
74
|
+
diagnostics.push(`Note: expected satisfied profile '${expected}' not in declared profiles`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { fixture, passed, validation, snapshot, diagnostics };
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Batch
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Recursively discover and run all `.json` fixture files in a directory.
|
|
85
|
+
*/
|
|
86
|
+
export function runFixtureDir(dirPath) {
|
|
87
|
+
const results = [];
|
|
88
|
+
const files = discoverFixtures(dirPath);
|
|
89
|
+
for (const filePath of files) {
|
|
90
|
+
const fixture = loadFixture(filePath);
|
|
91
|
+
results.push(runFixture(fixture));
|
|
92
|
+
}
|
|
93
|
+
return results;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Recursively find all `.json` files in a directory tree.
|
|
97
|
+
*/
|
|
98
|
+
function discoverFixtures(dirPath) {
|
|
99
|
+
const files = [];
|
|
100
|
+
for (const entry of readdirSync(dirPath)) {
|
|
101
|
+
const fullPath = join(dirPath, entry);
|
|
102
|
+
const stat = statSync(fullPath);
|
|
103
|
+
if (stat.isDirectory()) {
|
|
104
|
+
files.push(...discoverFixtures(fullPath));
|
|
105
|
+
}
|
|
106
|
+
else if (extname(entry) === '.json') {
|
|
107
|
+
files.push(fullPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return files;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=fixture-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture-runner.js","sourceRoot":"","sources":["../src/fixture-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @open-operational-state/validator
|
|
3
|
+
*
|
|
4
|
+
* Conformance validation, fixture execution, and conformance level checking.
|
|
5
|
+
*/
|
|
6
|
+
export { loadFixture, runFixture, runFixtureDir } from './fixture-runner.js';
|
|
7
|
+
export type { Fixture, FixtureResult, FixtureMetadata, FixtureExpected } from './fixture-runner.js';
|
|
8
|
+
export { checkConformanceLevel } from './conformance.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEpG,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @open-operational-state/validator
|
|
3
|
+
*
|
|
4
|
+
* Conformance validation, fixture execution, and conformance level checking.
|
|
5
|
+
*/
|
|
6
|
+
export { loadFixture, runFixture, runFixtureDir } from './fixture-runner.js';
|
|
7
|
+
export { checkConformanceLevel } from './conformance.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-operational-state/validator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Conformance validation, fixture runner, and CLI for Open Operational State",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"oos": "./dist/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/open-operational-state/status-tooling.git",
|
|
27
|
+
"directory": "packages/validator"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"test": "bun test"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@open-operational-state/types": "^0.1.0",
|
|
37
|
+
"@open-operational-state/core": "^0.1.0",
|
|
38
|
+
"@open-operational-state/parser": "^0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"typescript": "^5.8.0"
|
|
42
|
+
}
|
|
43
|
+
}
|