@sprig-and-prose/sprig-universe 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,157 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { scan } from './scanner.js';
5
+ import { parseUniverse, debugAst } from './parser.js';
6
+ import { buildGraph } from './graph.js';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ // Load the universe.prose file
12
+ const prosePath = join(__dirname, 'universe.prose');
13
+ const proseContent = readFileSync(prosePath, 'utf-8');
14
+
15
+ console.log('=== Scanning universe.prose ===\n');
16
+ console.log(`File: ${prosePath}`);
17
+ console.log(`Content length: ${proseContent.length} characters\n`);
18
+
19
+ // Run the scanner
20
+ const tokens = scan(proseContent, prosePath);
21
+
22
+ // Print token summary
23
+ console.log(`Found ${tokens.length} tokens\n`);
24
+
25
+ // Run the parser
26
+ console.log('=== Parsing tokens ===\n');
27
+ const { ast, diags } = parseUniverse({
28
+ tokens,
29
+ sourceText: proseContent,
30
+ filePath: prosePath,
31
+ });
32
+
33
+ // Print parser diagnostics
34
+ if (diags.length > 0) {
35
+ console.log(`Found ${diags.length} parser diagnostic(s):\n`);
36
+ diags.forEach((diag, index) => {
37
+ const { severity, message, source } = diag;
38
+ const loc = source
39
+ ? `${source.file}:${source.start.line}:${source.start.col}`
40
+ : 'unknown location';
41
+ console.log(` ${index + 1}. [${severity}] ${message}`);
42
+ console.log(` at ${loc}\n`);
43
+ });
44
+ } else {
45
+ console.log('No parser diagnostics (parsing succeeded)\n');
46
+ }
47
+
48
+ // Print AST summary
49
+ console.log('=== AST Summary ===\n');
50
+ console.log(`AST kind: ${ast.kind}`);
51
+ console.log(`Top-level declarations: ${ast.decls.length}`);
52
+ if (ast.source) {
53
+ console.log(`Source span: ${ast.source.start.line}:${ast.source.start.col} - ${ast.source.end.line}:${ast.source.end.col}`);
54
+ }
55
+ console.log('');
56
+
57
+ // Print AST tree using debugAst
58
+ console.log('=== AST Tree ===\n');
59
+ debugAst(ast);
60
+ console.log('');
61
+
62
+ // Run the graph builder
63
+ console.log('=== Building graph ===\n');
64
+ const fileAST = {
65
+ ...ast,
66
+ sourceText: proseContent,
67
+ };
68
+ const graph = buildGraph(fileAST);
69
+
70
+ // Print graph diagnostics
71
+ if (graph.diagnostics.length > 0) {
72
+ console.log(`Found ${graph.diagnostics.length} graph diagnostic(s):\n`);
73
+ graph.diagnostics.forEach((diag, index) => {
74
+ const { severity, message, source } = diag;
75
+ const loc = source
76
+ ? `${source.file}:${source.start.line}:${source.start.col}`
77
+ : 'unknown location';
78
+ console.log(` ${index + 1}. [${severity}] ${message}`);
79
+ console.log(` at ${loc}\n`);
80
+ });
81
+ } else {
82
+ console.log('No graph diagnostics (graph building succeeded)\n');
83
+ }
84
+
85
+ // Print graph summary
86
+ console.log('=== Graph Summary ===\n');
87
+ console.log(`Version: ${graph.version}`);
88
+ console.log(`Universes: ${Object.keys(graph.universes).length}`);
89
+ if (Object.keys(graph.universes).length > 0) {
90
+ for (const [name, universe] of Object.entries(graph.universes)) {
91
+ console.log(` - ${name} (root: ${universe.root})`);
92
+ }
93
+ }
94
+ console.log(`Nodes: ${Object.keys(graph.nodes).length}`);
95
+ console.log(`Edges: ${graph.edges ? graph.edges.length : 0}`);
96
+ console.log(`Asserted edges: ${graph.edgesAsserted ? graph.edgesAsserted.length : 0}`);
97
+ console.log(`Repositories: ${graph.repositories ? Object.keys(graph.repositories).length : 0}`);
98
+ console.log(`References: ${graph.references ? Object.keys(graph.references).length : 0}`);
99
+ console.log(`Relationship declarations: ${graph.relationshipDecls ? Object.keys(graph.relationshipDecls).reduce((sum, univ) => sum + Object.keys(graph.relationshipDecls[univ]).length, 0) : 0}`);
100
+ console.log('');
101
+
102
+ // Print node summary
103
+ console.log('=== Node Summary ===\n');
104
+ const nodesByKind = {};
105
+ for (const [id, node] of Object.entries(graph.nodes)) {
106
+ const kind = node.kind || 'unknown';
107
+ if (!nodesByKind[kind]) {
108
+ nodesByKind[kind] = [];
109
+ }
110
+ nodesByKind[kind].push(node.name);
111
+ }
112
+
113
+ for (const [kind, names] of Object.entries(nodesByKind)) {
114
+ console.log(`${kind}: ${names.length}`);
115
+ if (names.length <= 10) {
116
+ names.forEach(name => console.log(` - ${name}`));
117
+ } else {
118
+ names.slice(0, 10).forEach(name => console.log(` - ${name}`));
119
+ console.log(` ... and ${names.length - 10} more`);
120
+ }
121
+ }
122
+ console.log('');
123
+
124
+ // Print edge summary
125
+ if (graph.edges && graph.edges.length > 0) {
126
+ console.log('=== Edge Summary ===\n');
127
+ const edgesByVia = {};
128
+ for (const edge of graph.edges) {
129
+ const via = edge.via || 'unknown';
130
+ if (!edgesByVia[via]) {
131
+ edgesByVia[via] = 0;
132
+ }
133
+ edgesByVia[via]++;
134
+ }
135
+
136
+ for (const [via, count] of Object.entries(edgesByVia)) {
137
+ console.log(`${via}: ${count} edge(s)`);
138
+ }
139
+ console.log('');
140
+
141
+ // Print first few edges
142
+ console.log('=== Sample Edges (first 10) ===\n');
143
+ graph.edges.slice(0, 10).forEach((edge, index) => {
144
+ const fromNode = graph.nodes[edge.from];
145
+ const toNode = graph.nodes[edge.to];
146
+ const fromName = fromNode ? fromNode.name : edge.from;
147
+ const toName = toNode ? toNode.name : edge.to;
148
+ console.log(` ${index + 1}. ${fromName} --[${edge.via}]--> ${toName}${edge.asserted ? '' : ' (inferred)'}`);
149
+ });
150
+ if (graph.edges.length > 10) {
151
+ console.log(` ... and ${graph.edges.length - 10} more edges`);
152
+ }
153
+ console.log('');
154
+ }
155
+
156
+ console.log('=== Graph build complete ===');
157
+
@@ -0,0 +1,61 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { scan } from './scanner.js';
5
+ import { parseUniverse, debugAst } from './parser.js';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ // Load the universe.prose file
11
+ const prosePath = join(__dirname, 'universe.prose');
12
+ const proseContent = readFileSync(prosePath, 'utf-8');
13
+
14
+ console.log('=== Scanning universe.prose ===\n');
15
+ console.log(`File: ${prosePath}`);
16
+ console.log(`Content length: ${proseContent.length} characters\n`);
17
+
18
+ // Run the scanner
19
+ const tokens = scan(proseContent, prosePath);
20
+
21
+ // Print token summary
22
+ console.log(`Found ${tokens.length} tokens\n`);
23
+
24
+ // Run the parser
25
+ console.log('=== Parsing tokens ===\n');
26
+ const { ast, diags } = parseUniverse({
27
+ tokens,
28
+ sourceText: proseContent,
29
+ filePath: prosePath,
30
+ });
31
+
32
+ // Print diagnostics
33
+ if (diags.length > 0) {
34
+ console.log(`Found ${diags.length} diagnostic(s):\n`);
35
+ diags.forEach((diag, index) => {
36
+ const { severity, message, source } = diag;
37
+ const loc = source
38
+ ? `${source.file}:${source.start.line}:${source.start.col}`
39
+ : 'unknown location';
40
+ console.log(` ${index + 1}. [${severity}] ${message}`);
41
+ console.log(` at ${loc}\n`);
42
+ });
43
+ } else {
44
+ console.log('No diagnostics (parsing succeeded)\n');
45
+ }
46
+
47
+ // Print AST summary
48
+ console.log('=== AST Summary ===\n');
49
+ console.log(`AST kind: ${ast.kind}`);
50
+ console.log(`Top-level declarations: ${ast.decls.length}`);
51
+ if (ast.source) {
52
+ console.log(`Source span: ${ast.source.start.line}:${ast.source.start.col} - ${ast.source.end.line}:${ast.source.end.col}`);
53
+ }
54
+ console.log('');
55
+
56
+ // Print AST tree using debugAst
57
+ console.log('=== AST Tree ===\n');
58
+ debugAst(ast);
59
+
60
+ console.log('\n=== Parse complete ===');
61
+
@@ -0,0 +1,37 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { scan } from './scanner.js';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ // Load the universe.prose file
10
+ const prosePath = join(__dirname, 'universe.prose');
11
+ const proseContent = readFileSync(prosePath, 'utf-8');
12
+
13
+ console.log('=== Scanning universe.prose ===\n');
14
+ console.log(`File: ${prosePath}`);
15
+ console.log(`Content length: ${proseContent.length} characters\n`);
16
+
17
+ // Run the scanner
18
+ const tokens = scan(proseContent, prosePath);
19
+
20
+ // Print the tokens
21
+ console.log(`Found ${tokens.length} tokens:\n`);
22
+ tokens.forEach((token, index) => {
23
+ const { type, value, span } = token;
24
+ const { start, end } = span;
25
+
26
+ // Format the value for display (truncate long strings)
27
+ let displayValue = value;
28
+ if (type === 'STRING' && value.length > 50) {
29
+ displayValue = `"${value.substring(0, 47)}..."`;
30
+ } else if (value.length > 30) {
31
+ displayValue = value.substring(0, 27) + '...';
32
+ }
33
+
34
+ console.log(`${index.toString().padStart(4)}: ${type.padEnd(12)} | ${displayValue.padEnd(30)} | ${start.line}:${start.col}-${end.line}:${end.col}`);
35
+ });
36
+
37
+ console.log('\n=== Scan complete ===');
@@ -0,0 +1,169 @@
1
+ universe CanonicalUniverse {
2
+ note {
3
+ This universe contains every possible feature for testing the parser and
4
+ compiler.
5
+ }
6
+
7
+ anthology NestedAnthology {
8
+ series NestedSeries {
9
+ book NestedBook {
10
+ chapter NestedChapter {
11
+ concept NestedConcept { }
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ relates NestedConcept and ExternalConcept {
18
+ describe {
19
+ A relationship between a nested concept and an external concept.
20
+ }
21
+
22
+ from NestedConcept {
23
+ relationships { 'relates to' }
24
+ describe {
25
+ A nested concept that relates to an external concept.
26
+ }
27
+ }
28
+
29
+ from ExternalConcept {
30
+ relationships { 'is related to' }
31
+ describe {
32
+ An external concept that is related to a nested concept.
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ anthology AnthologyWithRelationships in CanonicalUniverse {
39
+ relationship singleton {
40
+ describe {
41
+ A singleton relationship.
42
+ }
43
+ }
44
+
45
+ relationship owns and ownedBy {
46
+ describe {
47
+ A bidirectional relationship between two entities.
48
+ }
49
+
50
+ from ownedBy {
51
+ label { 'is owned by' }
52
+ describe {
53
+ An entity that is owned by another entity.
54
+ }
55
+ }
56
+ }
57
+
58
+ alias other { book }
59
+
60
+ other OtherConcept {
61
+ describe {
62
+ This book is masquerading as `other`.
63
+ }
64
+
65
+ chapter OtherChapter {
66
+ describe {
67
+ A chapter can still be nested under an aliased book.
68
+ }
69
+
70
+ owns {
71
+ ExternalOtherChapter,
72
+ ExternalBook,
73
+ }
74
+
75
+ singleton {
76
+ ExternalAnthology
77
+ ExternalSeries
78
+ }
79
+ }
80
+
81
+ chapter AnotherExample {
82
+ relationships {
83
+ ownedBy {
84
+ ExternalChapter
85
+ ExternalBook {
86
+ describe {
87
+ An example where an array element is a block.
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ chapter ExternalOtherChapter in OtherConcept {
96
+ describe {
97
+ A chapter can still reference an external aliased book.
98
+ }
99
+ }
100
+
101
+ repository InternalRepository {
102
+ title { GitHub }
103
+ url { 'https://github.com/owner/repository/tree/main' }
104
+ }
105
+
106
+ reference NamedReference1 {
107
+ url { 'https://github.com/owner/repository/tree/main' }
108
+ describe {
109
+ References can have describe blocks.
110
+ }
111
+ }
112
+
113
+ reference NamedReference2 {
114
+ url { 'https://github.com/owner/repository/tree/main' }
115
+ describe {
116
+ References can have describe blocks.
117
+ }
118
+ }
119
+
120
+ reference NamedReferenceInRepository in InternalRepository {
121
+ url { 'https://github.com/owner/repository/tree/main' }
122
+ }
123
+
124
+ concept ConceptWithDirectReference {
125
+ reference {
126
+ url { 'https://github.com/owner/repository/tree/main' }
127
+ }
128
+ }
129
+
130
+ concept ConceptWithReferences {
131
+ references { NamedReference1 NamedReference2 }
132
+ }
133
+
134
+ concept ConceptWithReferenceInRepository {
135
+ reference in ExternalRepository {
136
+ kind { 'documentation' }
137
+ paths {
138
+ 'path/to/file1.md'
139
+ 'path/to/file2.md'
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ anthology ExternalAnthology in CanonicalUniverse {
146
+ aliases {
147
+ bookAlias { book }
148
+ chapterAlias { chapter }
149
+ }
150
+
151
+ bookAlias BookAlias {
152
+ chapterAlias NestedChapterAlias { }
153
+ }
154
+
155
+ chapterAlias ExternalChapterAlias in BookAlias { }
156
+ }
157
+
158
+ series ExternalSeries in ExternalAnthology { }
159
+
160
+ book ExternalBook in ExternalSeries { }
161
+
162
+ chapter ExternalChapter in ExternalBook { }
163
+
164
+ concept ExternalConcept in ExternalChapter { }
165
+
166
+ repository ExternalRepository in CanonicalUniverse {
167
+ title { GitHub }
168
+ url { 'https://github.com/owner/repository/tree/main' }
169
+ }