@relational-fabric/canon 1.0.0 → 1.2.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 +5 -5
- package/package.json +23 -11
- package/src/_/antfu.ts +2 -0
- package/src/_/defu.ts +2 -0
- package/src/_/immutable.ts +4 -0
- package/src/_/object-hash.ts +2 -0
- package/src/_/yaml.ts +1 -0
- package/src/index.ts +7 -4
- package/src/kit.ts +21 -0
- package/src/meta.ts +32 -0
- package/src/radar/converter.ts +7 -4
- package/src/radar/validator.ts +2 -2
- package/src/registry.ts +2 -2
- package/src/shell.ts +2 -1
- package/src/types/axioms.ts +2 -1
- package/src/types/canons.ts +2 -1
- package/src/types/guards.ts +2 -1
- package/src/types/index.ts +1 -0
- package/src/types/js.ts +2 -1
- package/src/types/metadata.ts +1 -0
- package/src/types/objects.ts +2 -1
- package/src/types/radar.ts +7 -6
package/README.md
CHANGED
|
@@ -183,7 +183,7 @@ Universal APIs provide functions that work across all registered canons. They ar
|
|
|
183
183
|
- Automatic adaptation to different data shapes
|
|
184
184
|
- Full type safety maintained across all shapes
|
|
185
185
|
|
|
186
|
-
See [reference/api.md](reference/api.md) for available APIs.
|
|
186
|
+
See [docs/reference/api.md](docs/reference/api.md) for available APIs.
|
|
187
187
|
|
|
188
188
|
## Package Exports
|
|
189
189
|
|
|
@@ -306,11 +306,11 @@ Canon provides comprehensive documentation to help you understand and use the sy
|
|
|
306
306
|
|
|
307
307
|
### Reference Documentation
|
|
308
308
|
|
|
309
|
-
- **[API Reference](reference/api.md)** - Complete API documentation
|
|
310
|
-
- **[Core Axioms](reference/axioms.md)** - Detailed axiom specifications
|
|
311
|
-
- **[Canons Reference](reference/canons.md)** - Canon implementation guide
|
|
309
|
+
- **[API Reference](docs/reference/api.md)** - Complete API documentation
|
|
310
|
+
- **[Core Axioms](docs/reference/axioms.md)** - Detailed axiom specifications
|
|
311
|
+
- **[Canons Reference](docs/reference/canons.md)** - Canon implementation guide
|
|
312
312
|
- **[Type Testing Utilities](docs/type-testing/)** - Compile-time type assertions and invariants
|
|
313
|
-
- **[Third-Party
|
|
313
|
+
- **[Canon Kit & Third-Party Utilities](docs/reference/kit.md)** - Curated third-party surface and transparent access paths
|
|
314
314
|
|
|
315
315
|
### Examples
|
|
316
316
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relational-fabric/canon",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "A modern TypeScript package template with ESLint and TypeScript configurations for starting new projects",
|
|
6
6
|
"author": "Relational Fabric",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
"types": "./src/index.ts",
|
|
25
25
|
"import": "./src/index.ts"
|
|
26
26
|
},
|
|
27
|
+
"./_/*": {
|
|
28
|
+
"types": "./src/_/*.ts",
|
|
29
|
+
"import": "./src/_/*.ts"
|
|
30
|
+
},
|
|
31
|
+
"./index": {
|
|
32
|
+
"types": "./src/index.ts",
|
|
33
|
+
"import": "./src/index.ts"
|
|
34
|
+
},
|
|
27
35
|
"./radar": {
|
|
28
36
|
"types": "./src/radar/index.ts",
|
|
29
37
|
"import": "./src/radar/index.ts"
|
|
@@ -85,33 +93,37 @@
|
|
|
85
93
|
}
|
|
86
94
|
},
|
|
87
95
|
"dependencies": {
|
|
88
|
-
"@antfu/eslint-config": "^
|
|
89
|
-
"@tsconfig/node-lts": "^
|
|
90
|
-
"
|
|
96
|
+
"@antfu/eslint-config": "^6.2.0",
|
|
97
|
+
"@tsconfig/node-lts": "^22.0.2",
|
|
98
|
+
"immutable": "^5.1.4",
|
|
99
|
+
"object-hash": "^3.0.0",
|
|
100
|
+
"reflect-metadata": "^0.2.2",
|
|
101
|
+
"yaml": "^2.8.1"
|
|
91
102
|
},
|
|
92
103
|
"optionalDependencies": {
|
|
93
104
|
"defu": "^6.1.4"
|
|
94
105
|
},
|
|
95
106
|
"devDependencies": {
|
|
96
107
|
"@types/mdast": "^4.0.4",
|
|
97
|
-
"@types/node": "^24.
|
|
98
|
-
"@vitest/coverage-v8": "^
|
|
108
|
+
"@types/node": "^24.10.0",
|
|
109
|
+
"@vitest/coverage-v8": "^4.0.8",
|
|
99
110
|
"adr-tools": "^2.0.4",
|
|
100
111
|
"chokidar-cli": "^3.0.0",
|
|
101
112
|
"dedent": "^1.7.0",
|
|
102
113
|
"depcheck": "^1.4.7",
|
|
103
|
-
"eslint": "^9.
|
|
114
|
+
"eslint": "^9.39.1",
|
|
104
115
|
"husky": "^9.1.7",
|
|
105
116
|
"lint-staged": "^16.2.6",
|
|
117
|
+
"npm-check-updates": "^19.1.2",
|
|
106
118
|
"npm-run-all": "^4.1.5",
|
|
107
119
|
"remark": "^15.0.1",
|
|
108
120
|
"remark-parse": "^11.0.0",
|
|
109
121
|
"remark-stringify": "^11.0.0",
|
|
110
|
-
"tsx": "^4.
|
|
111
|
-
"typescript": "^5.
|
|
122
|
+
"tsx": "^4.20.6",
|
|
123
|
+
"typescript": "^5.9.3",
|
|
112
124
|
"unified": "^11.0.5",
|
|
113
|
-
"vitepress": "^1.
|
|
114
|
-
"vitest": "^
|
|
125
|
+
"vitepress": "^1.6.4",
|
|
126
|
+
"vitest": "^4.0.8"
|
|
115
127
|
},
|
|
116
128
|
"husky": {
|
|
117
129
|
"hooks": {
|
package/src/_/antfu.ts
ADDED
package/src/_/defu.ts
ADDED
package/src/_/yaml.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'yaml'
|
package/src/index.ts
CHANGED
|
@@ -9,22 +9,25 @@ export * from './axioms/version.js'
|
|
|
9
9
|
|
|
10
10
|
export * from './canon.js'
|
|
11
11
|
|
|
12
|
+
// Opinionated kit exports
|
|
13
|
+
export * from './kit.js'
|
|
14
|
+
|
|
15
|
+
// Metadata helpers
|
|
16
|
+
export * from './meta.js'
|
|
12
17
|
// Radar
|
|
13
18
|
export * from './radar/index.js'
|
|
14
19
|
|
|
15
20
|
// Registry and Shell
|
|
16
21
|
export * from './registry.js'
|
|
22
|
+
|
|
17
23
|
export * from './shell.js'
|
|
18
24
|
|
|
19
25
|
// Type testing utilities (compile-time helpers only)
|
|
20
26
|
export * from './testing.js'
|
|
21
|
-
|
|
22
27
|
// Type system (includes defineAxiom, defineCanon)
|
|
23
28
|
export * from './types/index.js'
|
|
24
29
|
|
|
25
30
|
// Utilities
|
|
26
31
|
export * from './utils/guards.js'
|
|
27
|
-
export * from './utils/objects.js'
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
export { defu } from 'defu'
|
|
33
|
+
export * from './utils/objects.js'
|
package/src/kit.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import ImmutableNamespace from 'immutable'
|
|
2
|
+
import * as eslintModule from '../eslint.js'
|
|
3
|
+
|
|
4
|
+
type CreateEslintConfig = (
|
|
5
|
+
options?: Record<string, unknown>,
|
|
6
|
+
...configs: Record<string, unknown>[]
|
|
7
|
+
) => Record<string, unknown>
|
|
8
|
+
|
|
9
|
+
const moduleDefault = (eslintModule as { default?: CreateEslintConfig }).default
|
|
10
|
+
const createEslintConfigExport = (
|
|
11
|
+
moduleDefault ?? (eslintModule as unknown as CreateEslintConfig)
|
|
12
|
+
) as CreateEslintConfig
|
|
13
|
+
|
|
14
|
+
// Third-party dependencies blessed for consumer use
|
|
15
|
+
export { defu } from 'defu'
|
|
16
|
+
export const Immutable = ImmutableNamespace
|
|
17
|
+
export { default as objectHash } from 'object-hash'
|
|
18
|
+
export * from 'object-hash'
|
|
19
|
+
export { parse as parseYaml } from 'yaml'
|
|
20
|
+
|
|
21
|
+
export const createEslintConfig = createEslintConfigExport
|
package/src/meta.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Metadata } from './types/metadata.js'
|
|
2
|
+
|
|
3
|
+
import 'reflect-metadata'
|
|
4
|
+
|
|
5
|
+
const METADATA_KEY = Symbol.for('@relational-fabric/canon:meta')
|
|
6
|
+
|
|
7
|
+
export function metaOf<T extends object, M extends Metadata = Metadata>(obj: T): M {
|
|
8
|
+
const existing = Reflect.getMetadata(METADATA_KEY, obj) as M | undefined
|
|
9
|
+
return (existing ?? ({} as M))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function withMeta<T extends object, M extends Metadata = Metadata>(obj: T, metadata: M): T {
|
|
13
|
+
Reflect.defineMetadata(METADATA_KEY, metadata, obj)
|
|
14
|
+
return obj
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function updateMeta<T extends object, M extends Metadata = Metadata>(
|
|
18
|
+
obj: T,
|
|
19
|
+
updater: (metadata?: M) => M | undefined,
|
|
20
|
+
): T {
|
|
21
|
+
const current = Reflect.getMetadata(METADATA_KEY, obj) as M | undefined
|
|
22
|
+
const next = updater(current)
|
|
23
|
+
|
|
24
|
+
if (next === undefined) {
|
|
25
|
+
if (Reflect.hasMetadata(METADATA_KEY, obj))
|
|
26
|
+
Reflect.deleteMetadata(METADATA_KEY, obj)
|
|
27
|
+
} else {
|
|
28
|
+
Reflect.defineMetadata(METADATA_KEY, next, obj)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return obj
|
|
32
|
+
}
|
package/src/radar/converter.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import type { CsvRow, QuadrantKey, RadarData, RingKey } from '../types/radar.js'
|
|
6
6
|
|
|
7
|
+
import { Console } from 'node:console'
|
|
7
8
|
import { readFileSync, writeFileSync } from 'node:fs'
|
|
8
9
|
import process from 'node:process'
|
|
9
|
-
import {
|
|
10
|
+
import { parseYaml } from '../kit.js'
|
|
11
|
+
|
|
12
|
+
const logger = new Console(process.stdout, process.stderr)
|
|
10
13
|
|
|
11
14
|
// Quadrant mapping for CSV output
|
|
12
15
|
const QUADRANT_MAP: Record<QuadrantKey, string> = {
|
|
@@ -28,7 +31,7 @@ const RING_MAP: Record<RingKey, string> = {
|
|
|
28
31
|
* Convert YAML radar data to CSV format
|
|
29
32
|
*/
|
|
30
33
|
export function convertYamlToCsv(yamlContent: string): string {
|
|
31
|
-
const data =
|
|
34
|
+
const data = parseYaml(yamlContent) as RadarData
|
|
32
35
|
|
|
33
36
|
// Generate CSV content
|
|
34
37
|
const csvRows: string[] = ['name,ring,quadrant,isNew,description']
|
|
@@ -72,7 +75,7 @@ export function convertYamlFileToCsv(yamlPath: string, csvPath: string): void {
|
|
|
72
75
|
writeFileSync(csvPath, csvContent)
|
|
73
76
|
// Success: Converted YAML to CSV
|
|
74
77
|
} catch (error) {
|
|
75
|
-
|
|
78
|
+
logger.error(
|
|
76
79
|
'❌ Error converting YAML to CSV:',
|
|
77
80
|
error instanceof Error ? error.message : 'Unknown error',
|
|
78
81
|
)
|
|
@@ -112,7 +115,7 @@ function escapeCsvField(field: string): string {
|
|
|
112
115
|
* Parse YAML radar data
|
|
113
116
|
*/
|
|
114
117
|
export function parseRadarYaml(yamlContent: string): RadarData {
|
|
115
|
-
return
|
|
118
|
+
return parseYaml(yamlContent) as RadarData
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
/**
|
package/src/radar/validator.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { QuadrantKey, RadarData, RingKey } from '../types/radar.js'
|
|
6
|
+
import { parseYaml } from '../kit.js'
|
|
6
7
|
|
|
7
8
|
const VALID_QUADRANTS: QuadrantKey[] = [
|
|
8
9
|
'tools-libraries',
|
|
@@ -288,10 +289,9 @@ function validateRadarEntry(
|
|
|
288
289
|
export async function validateRadarFile(filePath: string): Promise<ValidationResult> {
|
|
289
290
|
try {
|
|
290
291
|
const fs = await import('node:fs')
|
|
291
|
-
const yaml = await import('yaml')
|
|
292
292
|
|
|
293
293
|
const yamlContent = fs.readFileSync(filePath, 'utf8')
|
|
294
|
-
const data =
|
|
294
|
+
const data = parseYaml(yamlContent) as RadarData
|
|
295
295
|
|
|
296
296
|
return validateRadarData(data)
|
|
297
297
|
} catch (error) {
|
package/src/registry.ts
CHANGED
|
@@ -38,8 +38,8 @@ export class Registry {
|
|
|
38
38
|
/**
|
|
39
39
|
* Make registry iterable - iterates over canon configs
|
|
40
40
|
*/
|
|
41
|
-
*[Symbol.iterator](): Iterator<CanonConfig> {
|
|
42
|
-
yield
|
|
41
|
+
* [Symbol.iterator](): Iterator<CanonConfig> {
|
|
42
|
+
yield* this.canons.values()
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
package/src/shell.ts
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Singleton registry instance with convenience API.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { Registry } from './registry.js'
|
|
7
8
|
import type { CanonConfig, Canons } from './types/index.js'
|
|
8
|
-
import { createRegistry
|
|
9
|
+
import { createRegistry } from './registry.js'
|
|
9
10
|
import { defineCanon } from './types/index.js'
|
|
10
11
|
|
|
11
12
|
/**
|
package/src/types/axioms.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* (like ID, type, version) that can be found in different data structures.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { Expect } from '../testing.js'
|
|
8
9
|
import type { TypeGuard } from './guards.js'
|
|
9
|
-
import {
|
|
10
|
+
import { invariant } from '../testing.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Base axiom type that merges configuration with metadata
|
package/src/types/canons.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* different formats.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { Expect } from '../testing.js'
|
|
9
10
|
import type { AxiomConfig, Axioms } from './axioms.js'
|
|
10
|
-
import {
|
|
11
|
+
import { invariant } from '../testing.js'
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Canon type that maps axiom labels to their type-level configurations
|
package/src/types/guards.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Type guard utilities for Canon type system
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { Expect } from '../testing.js'
|
|
6
|
+
import { invariant } from '../testing.js'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Type guard pattern that preserves specific types when narrowing
|
package/src/types/index.ts
CHANGED
package/src/types/js.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Metadata = Record<PropertyKey, unknown>
|
package/src/types/objects.ts
CHANGED
package/src/types/radar.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Technology Radar data structures and types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { Expect } from '../testing.js'
|
|
6
|
+
import { invariant } from '../testing.js'
|
|
6
7
|
|
|
7
8
|
export interface RadarEntry {
|
|
8
9
|
/** The name of the technology or practice */
|
|
@@ -83,11 +84,11 @@ export interface CsvRow {
|
|
|
83
84
|
description: string
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
export type QuadrantKey
|
|
87
|
-
| 'tools-libraries'
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
export type QuadrantKey
|
|
88
|
+
= | 'tools-libraries'
|
|
89
|
+
| 'techniques-patterns'
|
|
90
|
+
| 'features-capabilities'
|
|
91
|
+
| 'data-structures-formats'
|
|
91
92
|
export type RingKey = 'adopt' | 'trial' | 'assess' | 'hold'
|
|
92
93
|
|
|
93
94
|
// ---------------------------------------------------------------------------
|