@cordiacode/core 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/LICENSE +201 -0
- package/dist/compiler/compiler.d.ts +28 -0
- package/dist/compiler/compiler.d.ts.map +1 -0
- package/dist/compiler/compiler.js +83 -0
- package/dist/compiler/compiler.js.map +1 -0
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +24 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lexer/index.d.ts +3 -0
- package/dist/lexer/index.d.ts.map +1 -0
- package/dist/lexer/index.js +3 -0
- package/dist/lexer/index.js.map +1 -0
- package/dist/lexer/lexer.d.ts +22 -0
- package/dist/lexer/lexer.d.ts.map +1 -0
- package/dist/lexer/lexer.js +170 -0
- package/dist/lexer/lexer.js.map +1 -0
- package/dist/lexer/token.d.ts +78 -0
- package/dist/lexer/token.d.ts.map +1 -0
- package/dist/lexer/token.js +68 -0
- package/dist/lexer/token.js.map +1 -0
- package/dist/parser/ast.d.ts +59 -0
- package/dist/parser/ast.d.ts.map +1 -0
- package/dist/parser/ast.js +32 -0
- package/dist/parser/ast.js.map +1 -0
- package/dist/parser/index.d.ts +3 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/parser.d.ts +30 -0
- package/dist/parser/parser.d.ts.map +1 -0
- package/dist/parser/parser.js +164 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/validator/index.d.ts +2 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +2 -0
- package/dist/validator/index.js.map +1 -0
- package/dist/validator/validator.d.ts +41 -0
- package/dist/validator/validator.d.ts.map +1 -0
- package/dist/validator/validator.js +138 -0
- package/dist/validator/validator.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { parse } from '../parser/index.js';
|
|
2
|
+
/** Machine-readable validator error codes. */
|
|
3
|
+
export const ValidationErrorCode = {
|
|
4
|
+
MissingGoal: 'CORDIA_VAL_MISSING_GOAL',
|
|
5
|
+
MultipleGoals: 'CORDIA_VAL_MULTIPLE_GOALS',
|
|
6
|
+
EmptyValue: 'CORDIA_VAL_EMPTY_VALUE',
|
|
7
|
+
Duplicate: 'CORDIA_VAL_DUPLICATE',
|
|
8
|
+
DuplicateMilestone: 'CORDIA_VAL_DUPLICATE_MILESTONE',
|
|
9
|
+
TestMissingArrow: 'CORDIA_VAL_TEST_MISSING_ARROW',
|
|
10
|
+
TestEmptyInput: 'CORDIA_VAL_TEST_EMPTY_INPUT',
|
|
11
|
+
TestEmptyExpected: 'CORDIA_VAL_TEST_EMPTY_EXPECTED',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Semantically validate a parsed {@link SpecAst}.
|
|
15
|
+
*
|
|
16
|
+
* Enforces the rules the grammar/schema cannot express on their own
|
|
17
|
+
* (`spec/ambiguities.md`): exactly one goal, no empty values, well-formed
|
|
18
|
+
* tests, and no duplicates in the lists where repetition is meaningless. Every
|
|
19
|
+
* diagnostic carries an error code and the offending node's line/column —
|
|
20
|
+
* "validation rejects, never guesses."
|
|
21
|
+
*/
|
|
22
|
+
export function validate(spec) {
|
|
23
|
+
const errors = [];
|
|
24
|
+
const add = (code, message, at) => {
|
|
25
|
+
errors.push({ code, message, line: at.line, column: at.column });
|
|
26
|
+
};
|
|
27
|
+
// --- Goal cardinality (exactly one). ---
|
|
28
|
+
if (spec.goals.length === 0) {
|
|
29
|
+
errors.push({
|
|
30
|
+
code: ValidationErrorCode.MissingGoal,
|
|
31
|
+
message: 'Specification is missing a goal (`[ … ]`)',
|
|
32
|
+
line: 1,
|
|
33
|
+
column: 1,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
for (const extra of spec.goals.slice(1)) {
|
|
38
|
+
add(ValidationErrorCode.MultipleGoals, 'Only one goal (`[ … ]`) is allowed', extra);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// --- Empty values: every construct must carry non-empty text. ---
|
|
42
|
+
const valueLists = [
|
|
43
|
+
['goal', spec.goals],
|
|
44
|
+
['context entry', spec.context],
|
|
45
|
+
['inspiration', spec.inspirations],
|
|
46
|
+
['tech-stack item', spec.stack],
|
|
47
|
+
['agent', spec.agents],
|
|
48
|
+
['feature', spec.features],
|
|
49
|
+
['exclusion', spec.exclusions],
|
|
50
|
+
['requirement', spec.requirements],
|
|
51
|
+
['priority', spec.priorities],
|
|
52
|
+
['rule', spec.rules],
|
|
53
|
+
['file', spec.files],
|
|
54
|
+
['success criterion', spec.successCriteria],
|
|
55
|
+
['deliverable', spec.deliverables],
|
|
56
|
+
['question', spec.questions],
|
|
57
|
+
['debug task', spec.debugTasks],
|
|
58
|
+
];
|
|
59
|
+
for (const [label, nodes] of valueLists) {
|
|
60
|
+
for (const node of nodes) {
|
|
61
|
+
if (node.value.trim() === '')
|
|
62
|
+
add(ValidationErrorCode.EmptyValue, `Empty ${label}`, node);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// --- Tests: must split into non-empty input and expected. ---
|
|
66
|
+
for (const test of spec.tests) {
|
|
67
|
+
if (!test.hasArrow) {
|
|
68
|
+
add(ValidationErrorCode.TestMissingArrow, 'Test must be written as `input -> expected`', test);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (test.input.trim() === '')
|
|
72
|
+
add(ValidationErrorCode.TestEmptyInput, 'Test input is empty', test);
|
|
73
|
+
if (test.expected.trim() === '') {
|
|
74
|
+
add(ValidationErrorCode.TestEmptyExpected, 'Test expected value is empty', test);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// --- Milestones: non-empty names and features. ---
|
|
78
|
+
for (const milestone of spec.milestones) {
|
|
79
|
+
if (milestone.name.trim() === '') {
|
|
80
|
+
add(ValidationErrorCode.EmptyValue, 'Empty milestone name', milestone);
|
|
81
|
+
}
|
|
82
|
+
for (const feature of milestone.features) {
|
|
83
|
+
if (feature.value.trim() === '') {
|
|
84
|
+
add(ValidationErrorCode.EmptyValue, 'Empty milestone feature', feature);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// --- Duplicates where repetition is meaningless (ambiguities §7). ---
|
|
89
|
+
const dedupeLists = [
|
|
90
|
+
['feature', spec.features],
|
|
91
|
+
['exclusion', spec.exclusions],
|
|
92
|
+
['requirement', spec.requirements],
|
|
93
|
+
['priority', spec.priorities],
|
|
94
|
+
['rule', spec.rules],
|
|
95
|
+
['file', spec.files],
|
|
96
|
+
['agent', spec.agents],
|
|
97
|
+
['inspiration', spec.inspirations],
|
|
98
|
+
['tech-stack item', spec.stack],
|
|
99
|
+
['deliverable', spec.deliverables],
|
|
100
|
+
];
|
|
101
|
+
for (const [label, nodes] of dedupeLists) {
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const node of nodes) {
|
|
104
|
+
const key = node.value.trim();
|
|
105
|
+
if (key === '')
|
|
106
|
+
continue; // already reported as empty
|
|
107
|
+
if (seen.has(key))
|
|
108
|
+
add(ValidationErrorCode.Duplicate, `Duplicate ${label}: "${key}"`, node);
|
|
109
|
+
else
|
|
110
|
+
seen.add(key);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// --- Duplicate milestone names. ---
|
|
114
|
+
const seenMilestones = new Set();
|
|
115
|
+
for (const milestone of spec.milestones) {
|
|
116
|
+
const key = milestone.name.trim();
|
|
117
|
+
if (key === '')
|
|
118
|
+
continue;
|
|
119
|
+
if (seenMilestones.has(key)) {
|
|
120
|
+
add(ValidationErrorCode.DuplicateMilestone, `Duplicate milestone: "${key}"`, milestone);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
seenMilestones.add(key);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { errors };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Lex, parse, and validate VibeSpec source in one call. Diagnostics are
|
|
130
|
+
* concatenated in pipeline order (lexer → parser → validator). This is the
|
|
131
|
+
* entry point the CLI's `bloom validate` will use.
|
|
132
|
+
*/
|
|
133
|
+
export function analyze(source) {
|
|
134
|
+
const { spec, errors } = parse(source);
|
|
135
|
+
const { errors: validationErrors } = validate(spec);
|
|
136
|
+
return { spec, errors: [...errors, ...validationErrors] };
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator/validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cordiacode/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bloom compiler for Cordia VibeSpec: lexer, parser, validator, and Prompt JSON compiler.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Parth Verma",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"cordia",
|
|
22
|
+
"vibespec",
|
|
23
|
+
"compiler",
|
|
24
|
+
"intent",
|
|
25
|
+
"prompt",
|
|
26
|
+
"bloom"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/Parthverma-0/cordia.git",
|
|
34
|
+
"directory": "packages/core"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/Parthverma-0/cordia#readme",
|
|
37
|
+
"bugs": "https://github.com/Parthverma-0/cordia/issues",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@cordiacode/schema": "0.1.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|