@unrdf/hooks 26.4.3 → 26.4.4
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 +24 -0
- package/README.md +562 -53
- package/examples/atomvm-fibo-hooks-demo.mjs +323 -0
- package/examples/delta-monitoring-example.mjs +213 -0
- package/examples/fibo-jtbd-governance.mjs +388 -0
- package/examples/hook-chains/node_modules/.bin/jiti +0 -0
- package/examples/hook-chains/node_modules/.bin/msw +0 -0
- package/examples/hook-chains/node_modules/.bin/terser +0 -0
- package/examples/hook-chains/node_modules/.bin/tsc +0 -0
- package/examples/hook-chains/node_modules/.bin/tsserver +0 -0
- package/examples/hook-chains/node_modules/.bin/tsx +0 -0
- package/examples/hook-chains/node_modules/.bin/validate-hooks +0 -0
- package/examples/hook-chains/node_modules/.bin/vite +0 -0
- package/examples/hook-chains/node_modules/.bin/vitest +0 -0
- package/examples/hook-chains/node_modules/.bin/yaml +0 -0
- package/examples/hooks-marketplace.mjs +261 -0
- package/examples/n3-reasoning-example.mjs +279 -0
- package/examples/policy-hooks/node_modules/.bin/jiti +0 -0
- package/examples/policy-hooks/node_modules/.bin/msw +0 -0
- package/examples/policy-hooks/node_modules/.bin/terser +0 -0
- package/examples/policy-hooks/node_modules/.bin/tsc +0 -0
- package/examples/policy-hooks/node_modules/.bin/tsserver +0 -0
- package/examples/policy-hooks/node_modules/.bin/tsx +0 -0
- package/examples/policy-hooks/node_modules/.bin/validate-hooks +0 -0
- package/examples/policy-hooks/node_modules/.bin/vite +0 -0
- package/examples/policy-hooks/node_modules/.bin/vitest +0 -0
- package/examples/policy-hooks/node_modules/.bin/yaml +0 -0
- package/examples/shacl-repair-example.mjs +191 -0
- package/examples/window-condition-example.mjs +285 -0
- package/package.json +26 -23
- package/src/atomvm.mjs +9 -0
- package/src/define.mjs +114 -0
- package/src/executor.mjs +23 -0
- package/src/hooks/atomvm-bridge.mjs +332 -0
- package/src/hooks/builtin-hooks.mjs +13 -7
- package/src/hooks/condition-evaluator.mjs +684 -77
- package/src/hooks/define-hook.mjs +23 -23
- package/src/hooks/effect-executor.mjs +630 -0
- package/src/hooks/effect-sandbox.mjs +19 -9
- package/src/hooks/file-resolver.mjs +155 -1
- package/src/hooks/hook-chain-compiler.mjs +11 -1
- package/src/hooks/hook-executor.mjs +98 -73
- package/src/hooks/knowledge-hook-engine.mjs +133 -7
- package/src/hooks/ontology-learner.mjs +190 -0
- package/src/hooks/query.mjs +3 -3
- package/src/hooks/schemas.mjs +47 -3
- package/src/hooks/security/error-sanitizer.mjs +46 -24
- package/src/hooks/self-play-autonomics.mjs +423 -0
- package/src/hooks/telemetry.mjs +32 -9
- package/src/hooks/validate.mjs +100 -33
- package/src/index.mjs +2 -0
- package/src/lib/admit-hook.mjs +615 -0
- package/src/policy-compiler.mjs +12 -2
- package/dist/index.d.mts +0 -1738
- package/dist/index.d.ts +0 -1738
- package/dist/index.mjs +0 -1738
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unrdf/hooks - N3 Forward-Chaining Reasoning Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates semantic inference using N3 rules and EYE reasoner.
|
|
5
|
+
* Derives new facts from existing data through logical rules.
|
|
6
|
+
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - RDFS/OWL-like reasoning (class hierarchies, property inference)
|
|
9
|
+
* - Business rule execution (access control, workflow logic)
|
|
10
|
+
* - Data enrichment (derive properties from rules)
|
|
11
|
+
* - Compliance checking (derive compliance status)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createStore } from '@unrdf/oxigraph';
|
|
15
|
+
import { evaluateCondition } from '../src/hooks/condition-evaluator.mjs';
|
|
16
|
+
import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
|
|
17
|
+
|
|
18
|
+
const { namedNode, literal, quad } = DataFactory;
|
|
19
|
+
|
|
20
|
+
console.log('=== N3 Forward-Chaining Reasoning Example ===\n');
|
|
21
|
+
|
|
22
|
+
// Example 1: Simple class inheritance
|
|
23
|
+
console.log('1. Simple Class Inheritance\n');
|
|
24
|
+
|
|
25
|
+
const classInheritanceCondition = {
|
|
26
|
+
kind: 'n3',
|
|
27
|
+
rules: `
|
|
28
|
+
@prefix : <http://example.org/> .
|
|
29
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
30
|
+
|
|
31
|
+
# Rule: If X is subclass of Y and Z is instance of X, then Z is instance of Y
|
|
32
|
+
{ ?x rdfs:subClassOf ?y . ?z a ?x } => { ?z a ?y } .
|
|
33
|
+
`,
|
|
34
|
+
askQuery: 'ASK { ?s a <http://example.org/Animal> }'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
console.log('Rules:');
|
|
38
|
+
console.log(classInheritanceCondition.rules);
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log('Scenario:');
|
|
41
|
+
console.log(' Data: Dog subClassOf Animal, Fido a Dog');
|
|
42
|
+
console.log(' Inference: Fido a Animal (derived)');
|
|
43
|
+
console.log(' Query: ASK { ?s a Animal } → true\n');
|
|
44
|
+
|
|
45
|
+
// Example 2: Access control reasoning
|
|
46
|
+
console.log('2. Access Control Reasoning\n');
|
|
47
|
+
|
|
48
|
+
const accessControlCondition = {
|
|
49
|
+
kind: 'n3',
|
|
50
|
+
rules: `
|
|
51
|
+
@prefix : <http://example.org/> .
|
|
52
|
+
|
|
53
|
+
# Rule 1: Admins can access everything
|
|
54
|
+
{ ?user a :Admin } => { ?user :canAccess :SecureArea } .
|
|
55
|
+
|
|
56
|
+
# Rule 2: Group members inherit group permissions
|
|
57
|
+
{ ?user :isMemberOf ?group . ?group :hasPermission ?perm }
|
|
58
|
+
=> { ?user :hasPermission ?perm } .
|
|
59
|
+
|
|
60
|
+
# Rule 3: Users with edit permission need audit logging
|
|
61
|
+
{ ?user :hasPermission :EditContent }
|
|
62
|
+
=> { ?user :requiresAuditLog true } .
|
|
63
|
+
|
|
64
|
+
# Rule 4: Audit logging required if accessing secure area
|
|
65
|
+
{ ?user :canAccess :SecureArea }
|
|
66
|
+
=> { ?user :requiresAuditLog true } .
|
|
67
|
+
`,
|
|
68
|
+
askQuery: 'ASK { ?user :requiresAuditLog true }'
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
console.log('Rules demonstrate multi-level inference:');
|
|
72
|
+
console.log(' Rule 1: Admin role → access permission');
|
|
73
|
+
console.log(' Rule 2: Group membership → inherit permissions');
|
|
74
|
+
console.log(' Rule 3: Edit permission → audit requirement');
|
|
75
|
+
console.log(' Rule 4: Secure access → audit requirement');
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log('Scenario:');
|
|
78
|
+
console.log(' Data: alice a Admin, bob :isMemberOf :editors');
|
|
79
|
+
console.log(' Step 1: alice a Admin → alice :canAccess :SecureArea');
|
|
80
|
+
console.log(' Step 2: alice :canAccess :SecureArea → alice :requiresAuditLog true');
|
|
81
|
+
console.log(' Step 3: bob :isMemberOf :editors → check group permissions');
|
|
82
|
+
console.log(' Result: Audit requirements derived from roles\n');
|
|
83
|
+
|
|
84
|
+
// Example 3: Business process workflow
|
|
85
|
+
console.log('3. Business Process Workflow Reasoning\n');
|
|
86
|
+
|
|
87
|
+
const workflowCondition = {
|
|
88
|
+
kind: 'n3',
|
|
89
|
+
rules: `
|
|
90
|
+
@prefix : <http://example.org/> .
|
|
91
|
+
|
|
92
|
+
# Rule 1: Large trades require compliance review
|
|
93
|
+
{ ?trade a :Trade ; :amount ?amt . ?amt > 1000000 }
|
|
94
|
+
=> { ?trade :requiresCompliance true } .
|
|
95
|
+
|
|
96
|
+
# Rule 2: Compliance required trades need risk assessment
|
|
97
|
+
{ ?trade :requiresCompliance true }
|
|
98
|
+
=> { ?trade :requiresRiskAssessment true } .
|
|
99
|
+
|
|
100
|
+
# Rule 3: Risk assessment must be approved by senior reviewer
|
|
101
|
+
{ ?trade :requiresRiskAssessment true }
|
|
102
|
+
=> { ?trade :requiresApprovalLevel :Senior } .
|
|
103
|
+
|
|
104
|
+
# Rule 4: High-risk trades need compliance officer sign-off
|
|
105
|
+
{ ?trade :riskLevel :High ; :requiresApprovalLevel :Senior }
|
|
106
|
+
=> { ?trade :requiresComplianceOfficer true } .
|
|
107
|
+
|
|
108
|
+
# Rule 5: Anything needing compliance officer needs audit trail
|
|
109
|
+
{ ?trade :requiresComplianceOfficer true }
|
|
110
|
+
=> { ?trade :auditTrailRequired true } .
|
|
111
|
+
`,
|
|
112
|
+
askQuery: 'ASK { ?trade :auditTrailRequired true }'
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
console.log('Multi-step workflow rules:');
|
|
116
|
+
console.log(' Trade amount > $1M → requires compliance');
|
|
117
|
+
console.log(' Requires compliance → requires risk assessment');
|
|
118
|
+
console.log(' Requires risk assessment → requires senior approval');
|
|
119
|
+
console.log(' High risk + senior approval → needs compliance officer');
|
|
120
|
+
console.log(' Needs compliance officer → needs audit trail');
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log('Execution:');
|
|
123
|
+
console.log(' Input: Trade with amount $1.5M');
|
|
124
|
+
console.log(' Derives: auditTrailRequired = true');
|
|
125
|
+
console.log(' Effect: Create audit record in system\n');
|
|
126
|
+
|
|
127
|
+
// Example 4: Data enrichment
|
|
128
|
+
console.log('4. Data Enrichment Through Reasoning\n');
|
|
129
|
+
|
|
130
|
+
const enrichmentCondition = {
|
|
131
|
+
kind: 'n3',
|
|
132
|
+
rules: `
|
|
133
|
+
@prefix : <http://example.org/> .
|
|
134
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
135
|
+
|
|
136
|
+
# Rule 1: Calculate age from birthDate
|
|
137
|
+
{ ?person :birthDate ?birth }
|
|
138
|
+
=> { ?person :age ?age } . # Would need SPARQL for real calculation
|
|
139
|
+
|
|
140
|
+
# Rule 2: Categorize by age
|
|
141
|
+
{ ?person :age ?age . ?age > 65 }
|
|
142
|
+
=> { ?person :category :Senior } .
|
|
143
|
+
|
|
144
|
+
{ ?person :age ?age . ?age >= 18 . ?age <= 65 }
|
|
145
|
+
=> { ?person :category :Adult } .
|
|
146
|
+
|
|
147
|
+
{ ?person :age ?age . ?age < 18 }
|
|
148
|
+
=> { ?person :category :Minor } .
|
|
149
|
+
|
|
150
|
+
# Rule 3: Seniors get special benefits
|
|
151
|
+
{ ?person :category :Senior }
|
|
152
|
+
=> { ?person :eligibleFor :SeniorDiscount } .
|
|
153
|
+
|
|
154
|
+
# Rule 4: Mark complete profiles
|
|
155
|
+
{ ?person :name ?n ; :email ?e ; :category ?c }
|
|
156
|
+
=> { ?person :profileComplete true } .
|
|
157
|
+
`,
|
|
158
|
+
askQuery: 'ASK { ?p :profileComplete true }'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
console.log('Enrichment rules:');
|
|
162
|
+
console.log(' Birthdate → derive age');
|
|
163
|
+
console.log(' Age → categorize as Senior/Adult/Minor');
|
|
164
|
+
console.log(' Senior → eligible for discount');
|
|
165
|
+
console.log(' Complete profile (name + email + category) → mark as complete');
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log('Input: Person with name, email, age');
|
|
168
|
+
console.log('Output: Category, discounts, completeness flag\n');
|
|
169
|
+
|
|
170
|
+
// Example 5: Compliance rule engine
|
|
171
|
+
console.log('5. Compliance Rule Engine\n');
|
|
172
|
+
|
|
173
|
+
const complianceCondition = {
|
|
174
|
+
kind: 'n3',
|
|
175
|
+
rules: `
|
|
176
|
+
@prefix : <http://example.org/> .
|
|
177
|
+
|
|
178
|
+
# GDPR Rules
|
|
179
|
+
{ ?entity a :PersonalData ; :storedIn ?jurisdiction .
|
|
180
|
+
?jurisdiction :region ?region . ?region != :EU }
|
|
181
|
+
=> { ?entity :gdprViolation :DataResidency } .
|
|
182
|
+
|
|
183
|
+
# PCI-DSS Rules
|
|
184
|
+
{ ?entity a :CardData ; :encryptionLevel ?level .
|
|
185
|
+
?level < 256 }
|
|
186
|
+
=> { ?entity :pciViolation :InsufficientEncryption } .
|
|
187
|
+
|
|
188
|
+
# SOX Rules (for public companies)
|
|
189
|
+
{ ?company a :PublicCompany ;
|
|
190
|
+
:hasFinancialData ?data }
|
|
191
|
+
=> { ?company :requiresSoxCompliance true } .
|
|
192
|
+
|
|
193
|
+
# Any violation → requires remediation
|
|
194
|
+
{ ?entity :gdprViolation ?v } => { ?entity :requiresRemediation true } .
|
|
195
|
+
{ ?entity :pciViolation ?v } => { ?entity :requiresRemediation true } .
|
|
196
|
+
|
|
197
|
+
# Mark non-compliant if has violations
|
|
198
|
+
{ ?entity :requiresRemediation true }
|
|
199
|
+
=> { ?entity :complianceStatus :NonCompliant } .
|
|
200
|
+
`,
|
|
201
|
+
askQuery: 'ASK { ?entity :complianceStatus :NonCompliant }'
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
console.log('Compliance engine checks:');
|
|
205
|
+
console.log(' GDPR: Personal data must be in EU jurisdiction');
|
|
206
|
+
console.log(' PCI-DSS: Card data must be 256-bit encrypted');
|
|
207
|
+
console.log(' SOX: Public companies must audit financial data');
|
|
208
|
+
console.log(' Any violation → mark non-compliant\n');
|
|
209
|
+
|
|
210
|
+
// Performance considerations
|
|
211
|
+
console.log('6. Performance Considerations\n');
|
|
212
|
+
|
|
213
|
+
console.log('Forward-chaining semantics:');
|
|
214
|
+
console.log(' - All applicable rules fire until fixpoint');
|
|
215
|
+
console.log(' - Derives all possible new facts');
|
|
216
|
+
console.log(' - Complete closure of logical consequences');
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log('Performance factors:');
|
|
219
|
+
console.log(' 1. Rule count: More rules = more inference steps');
|
|
220
|
+
console.log(' 2. Data size: Large graphs = more match attempts');
|
|
221
|
+
console.log(' 3. Rule complexity: Join patterns in antecedents');
|
|
222
|
+
console.log(' 4. Iteration count: Fixpoint may require many passes');
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log('Optimization tips:');
|
|
225
|
+
console.log(' ✓ Materialize frequently derived facts');
|
|
226
|
+
console.log(' ✓ Use specific patterns (avoid ?x ?p ?o)');
|
|
227
|
+
console.log(' ✓ Order rules: simple → complex');
|
|
228
|
+
console.log(' ✗ Avoid rules that derive rule premises');
|
|
229
|
+
console.log(' ✗ Don\'t use reasoning for high-frequency checks\n');
|
|
230
|
+
|
|
231
|
+
// Full hook example
|
|
232
|
+
console.log('7. Complete Hook with N3 Reasoning\n');
|
|
233
|
+
|
|
234
|
+
console.log(`
|
|
235
|
+
const dataEnrichmentHook = {
|
|
236
|
+
name: 'enriched-trade-data',
|
|
237
|
+
|
|
238
|
+
condition: {
|
|
239
|
+
kind: 'n3',
|
|
240
|
+
rules: \`
|
|
241
|
+
@prefix : <http://example.org/> .
|
|
242
|
+
|
|
243
|
+
{ ?trade a :Trade ; :amount ?amt . ?amt > 500000 }
|
|
244
|
+
=> { ?trade :largeTradeIndicator true } .
|
|
245
|
+
|
|
246
|
+
{ ?trade :largeTradeIndicator true }
|
|
247
|
+
=> { ?trade :requiresReview true } .
|
|
248
|
+
|
|
249
|
+
{ ?trade :requiresReview true ; :counterparty ?cp }
|
|
250
|
+
=> { ?cp :hadLargeTrade true } .
|
|
251
|
+
\`,
|
|
252
|
+
askQuery: 'ASK { ?t :requiresReview true }'
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
effects: [{
|
|
256
|
+
kind: 'sparql-construct',
|
|
257
|
+
query: \`
|
|
258
|
+
CONSTRUCT {
|
|
259
|
+
?trade :reviewStatus ex:Pending ;
|
|
260
|
+
:derivedFrom ex:N3Rules ;
|
|
261
|
+
:timestamp ?now .
|
|
262
|
+
}
|
|
263
|
+
WHERE {
|
|
264
|
+
?trade :requiresReview true .
|
|
265
|
+
BIND (NOW() as ?now)
|
|
266
|
+
}
|
|
267
|
+
\`
|
|
268
|
+
}]
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
Execution:
|
|
272
|
+
1. Trade added with amount > $500K
|
|
273
|
+
2. N3 reasoning: derives :requiresReview true
|
|
274
|
+
3. Condition ASK: "is there a :requiresReview?" → true
|
|
275
|
+
4. Effect executes: marks trade as pending review
|
|
276
|
+
5. Counterparty flagged for trading pattern analysis
|
|
277
|
+
`);
|
|
278
|
+
|
|
279
|
+
console.log('\n=== Example Complete ===');
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unrdf/hooks - SHACL Repair Mode Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates SHACL validation with automatic repair.
|
|
5
|
+
* When validation fails, repair queries fix data, then re-validate.
|
|
6
|
+
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - Auto-filling missing required properties with defaults
|
|
9
|
+
* - Normalizing invalid references
|
|
10
|
+
* - Fixing data quality issues automatically
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createStore } from '@unrdf/oxigraph';
|
|
14
|
+
import { evaluateCondition } from '../src/hooks/condition-evaluator.mjs';
|
|
15
|
+
import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
|
|
16
|
+
|
|
17
|
+
const { namedNode, literal, quad } = DataFactory;
|
|
18
|
+
|
|
19
|
+
console.log('=== SHACL Repair Mode Example ===\n');
|
|
20
|
+
|
|
21
|
+
// Create a test store
|
|
22
|
+
const store = createStore();
|
|
23
|
+
|
|
24
|
+
// Add test data (some valid, some missing required properties)
|
|
25
|
+
console.log('1. Loading test data...');
|
|
26
|
+
store.add(
|
|
27
|
+
quad(
|
|
28
|
+
namedNode('http://example.org/trade/t1'),
|
|
29
|
+
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
|
|
30
|
+
namedNode('http://example.org/Trade')
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
store.add(
|
|
34
|
+
quad(
|
|
35
|
+
namedNode('http://example.org/trade/t1'),
|
|
36
|
+
namedNode('http://example.org/amount'),
|
|
37
|
+
literal('150000')
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
// Note: missing riskScore
|
|
41
|
+
|
|
42
|
+
store.add(
|
|
43
|
+
quad(
|
|
44
|
+
namedNode('http://example.org/trade/t2'),
|
|
45
|
+
namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
|
|
46
|
+
namedNode('http://example.org/Trade')
|
|
47
|
+
)
|
|
48
|
+
);
|
|
49
|
+
// Note: missing both amount and riskScore
|
|
50
|
+
|
|
51
|
+
console.log(` Loaded ${store.size} quads\n`);
|
|
52
|
+
|
|
53
|
+
// Define SHACL condition with repair query
|
|
54
|
+
console.log('2. Defining SHACL repair condition...\n');
|
|
55
|
+
|
|
56
|
+
const shaclRepairCondition = {
|
|
57
|
+
kind: 'shacl',
|
|
58
|
+
ref: {
|
|
59
|
+
uri: 'file:///shapes/trade-shape.ttl',
|
|
60
|
+
// Note: in production, provide actual sha256 hash
|
|
61
|
+
// sha256: 'abc123def456...'
|
|
62
|
+
},
|
|
63
|
+
enforcementMode: 'repair',
|
|
64
|
+
repairConstruct: `
|
|
65
|
+
# Fill in missing required properties with defaults
|
|
66
|
+
CONSTRUCT {
|
|
67
|
+
?trade ex:riskScore ?defaultRisk ;
|
|
68
|
+
ex:amount ?defaultAmount ;
|
|
69
|
+
ex:status ex:Pending .
|
|
70
|
+
}
|
|
71
|
+
WHERE {
|
|
72
|
+
?trade a ex:Trade .
|
|
73
|
+
OPTIONAL { ?trade ex:riskScore ?existing . }
|
|
74
|
+
OPTIONAL { ?trade ex:amount ?existingAmount . }
|
|
75
|
+
FILTER (!BOUND(?existing) || !BOUND(?existingAmount))
|
|
76
|
+
BIND (50 as ?defaultRisk)
|
|
77
|
+
BIND (0 as ?defaultAmount)
|
|
78
|
+
}
|
|
79
|
+
`
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
console.log('Repair CONSTRUCT query:');
|
|
83
|
+
console.log(shaclRepairCondition.repairConstruct);
|
|
84
|
+
console.log('');
|
|
85
|
+
|
|
86
|
+
// Example 1: Block mode (strictest - no repairs)
|
|
87
|
+
console.log('3. Example: Block Mode (no repairs)\n');
|
|
88
|
+
const blockCondition = {
|
|
89
|
+
...shaclRepairCondition,
|
|
90
|
+
enforcementMode: 'block'
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
console.log('With block mode:');
|
|
94
|
+
console.log('- Validation failure = hook fails (false)');
|
|
95
|
+
console.log('- No automatic repair attempted');
|
|
96
|
+
console.log('- Application must handle fix separately\n');
|
|
97
|
+
|
|
98
|
+
// Example 2: Annotate mode (audit trail)
|
|
99
|
+
console.log('4. Example: Annotate Mode (logging)\n');
|
|
100
|
+
const annotateCondition = {
|
|
101
|
+
...shaclRepairCondition,
|
|
102
|
+
enforcementMode: 'annotate'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
console.log('With annotate mode:');
|
|
106
|
+
console.log('- Validation failure = add sh:ValidationResult triples');
|
|
107
|
+
console.log('- Returns true (permits operation)');
|
|
108
|
+
console.log('- Violations recorded in RDF for audit trail');
|
|
109
|
+
console.log('- Good for compliance tracking\n');
|
|
110
|
+
|
|
111
|
+
// Example 3: Repair mode (automatic fixing)
|
|
112
|
+
console.log('5. Example: Repair Mode (automatic fix)\n');
|
|
113
|
+
const repairCondition = {
|
|
114
|
+
...shaclRepairCondition,
|
|
115
|
+
enforcementMode: 'repair'
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
console.log('With repair mode:');
|
|
119
|
+
console.log('- Validation failure = execute repairConstruct');
|
|
120
|
+
console.log('- Repair adds missing properties with defaults');
|
|
121
|
+
console.log('- Re-validates after repair');
|
|
122
|
+
console.log('- Returns success/failure of final validation\n');
|
|
123
|
+
|
|
124
|
+
// Example 4: Multi-phase repair strategy
|
|
125
|
+
console.log('6. Complex Example: Multi-Phase Repair\n');
|
|
126
|
+
|
|
127
|
+
const complexRepairCondition = {
|
|
128
|
+
kind: 'shacl',
|
|
129
|
+
ref: { uri: 'file:///shapes/comprehensive.ttl' },
|
|
130
|
+
enforcementMode: 'repair',
|
|
131
|
+
repairConstruct: `
|
|
132
|
+
PREFIX ex: <http://example.org/>
|
|
133
|
+
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
|
134
|
+
|
|
135
|
+
CONSTRUCT {
|
|
136
|
+
?entity ex:status ex:Reviewed ;
|
|
137
|
+
ex:lastChecked ?now ;
|
|
138
|
+
ex:quality ?quality .
|
|
139
|
+
}
|
|
140
|
+
WHERE {
|
|
141
|
+
?entity a ex:Entity .
|
|
142
|
+
BIND (NOW() as ?now)
|
|
143
|
+
|
|
144
|
+
# Quality assessment: calculate based on completeness
|
|
145
|
+
OPTIONAL { ?entity ex:description ?desc . }
|
|
146
|
+
OPTIONAL { ?entity ex:classification ?class . }
|
|
147
|
+
OPTIONAL { ?entity ex:owner ?owner . }
|
|
148
|
+
|
|
149
|
+
BIND (
|
|
150
|
+
IF(BOUND(?desc) && BOUND(?class) && BOUND(?owner),
|
|
151
|
+
"high",
|
|
152
|
+
"medium")
|
|
153
|
+
as ?quality
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
`
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
console.log('Multi-phase repair includes:');
|
|
160
|
+
console.log('1. Add status field if missing');
|
|
161
|
+
console.log('2. Record timestamp of check');
|
|
162
|
+
console.log('3. Calculate quality score based on available properties\n');
|
|
163
|
+
|
|
164
|
+
// Practical workflow
|
|
165
|
+
console.log('7. Practical Workflow\n');
|
|
166
|
+
console.log('Step 1: Data arrives (potentially with gaps)');
|
|
167
|
+
console.log('Step 2: evaluateCondition() with shacl/repair');
|
|
168
|
+
console.log('Step 3: If validation fails:');
|
|
169
|
+
console.log(' - Auto repair executes');
|
|
170
|
+
console.log(' - Missing properties filled with defaults');
|
|
171
|
+
console.log(' - Re-validation checks if repair succeeded');
|
|
172
|
+
console.log('Step 4: Result indicates success/failure');
|
|
173
|
+
console.log('Step 5: Application continues based on result\n');
|
|
174
|
+
|
|
175
|
+
// Best practices
|
|
176
|
+
console.log('8. Best Practices for Repair Mode\n');
|
|
177
|
+
console.log('✓ Use repair for:');
|
|
178
|
+
console.log(' - Filling optional properties with sensible defaults');
|
|
179
|
+
console.log(' - Normalizing data format (URI standardization)');
|
|
180
|
+
console.log(' - Adding audit/lifecycle properties');
|
|
181
|
+
console.log('');
|
|
182
|
+
console.log('✗ Avoid repair for:');
|
|
183
|
+
console.log(' - Changing core business data semantics');
|
|
184
|
+
console.log(' - Complex transformations (use effects instead)');
|
|
185
|
+
console.log(' - Expensive computations (will run on every violation)');
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log('💡 Combine with effects:');
|
|
188
|
+
console.log(' 1. Condition: shacl/repair → auto-fix violations');
|
|
189
|
+
console.log(' 2. Effect: sparql-construct → apply business logic\n');
|
|
190
|
+
|
|
191
|
+
console.log('=== Example Complete ===');
|