eyeling 1.12.13 → 1.12.15
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/examples/annotation.n3 +2 -2
- package/examples/context-association.n3 +4 -4
- package/examples/odrl-dpv-risk-ranked.n3 +479 -0
- package/examples/odrl-risk-mitigation.n3 +870 -0
- package/examples/output/odrl-dpv-risk-ranked.n3 +95 -0
- package/examples/output/odrl-risk-mitigation.n3 +207 -0
- package/examples/reifies.n3 +2 -1
- package/package.json +1 -1
- package/tools/n3gen.js +80 -27
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
@prefix : <https://example.org/odrl-dpv-risk-ranked#> .
|
|
2
|
+
@prefix dct: <http://purl.org/dc/terms/> .
|
|
3
|
+
@prefix dpv: <https://w3id.org/dpv#> .
|
|
4
|
+
@prefix genid: <https://eyereasoner.github.io/.well-known/genid/> .
|
|
5
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
6
|
+
@prefix risk: <https://w3id.org/dpv/risk#> .
|
|
7
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
8
|
+
|
|
9
|
+
genid:1c780f80-9b90-f310-2ce9-2d829e5616d8 a risk:RiskSource .
|
|
10
|
+
genid:1c780f80-9b90-f310-2ce9-2d829e5616d8 a risk:LegalComplianceRisk .
|
|
11
|
+
genid:1c780f80-9b90-f310-2ce9-2d829e5616d8 dct:source :PermDeleteAccount .
|
|
12
|
+
genid:1c780f80-9b90-f310-2ce9-2d829e5616d8 dct:description "Account removal permitted without notice safeguards." .
|
|
13
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc a dpv:Risk .
|
|
14
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc a risk:UnwantedDataDeletion .
|
|
15
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc a risk:DataUnavailable .
|
|
16
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc a risk:DataErasureError .
|
|
17
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc a risk:DataLoss .
|
|
18
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dct:source :PermDeleteAccount .
|
|
19
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc risk:hasRiskSource genid:1c780f80-9b90-f310-2ce9-2d829e5616d8 .
|
|
20
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasConsequence risk:DataLoss .
|
|
21
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasConsequence risk:DataUnavailable .
|
|
22
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasConsequence risk:CustomerConfidenceLoss .
|
|
23
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasImpact risk:FinancialLoss .
|
|
24
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasImpact risk:NonMaterialDamage .
|
|
25
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc :aboutClause :ClauseC1 .
|
|
26
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc :scoreRaw 110 .
|
|
27
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc :violatesNeed :Need_DataCannotBeRemoved .
|
|
28
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dct:description "Risk: account/data removal is permitted without notice safeguards (no notice constraint and no duty to inform). Clause C1: Provider may remove the user account (and associated data) at its discretion." .
|
|
29
|
+
:ProcessContext1 dpv:hasRisk genid:59bf9d7c-6868-401e-bb47-667826cd85bc .
|
|
30
|
+
genid:b00dbc9c-519f-4664-518c-32853c2cfabc a risk:RiskSource .
|
|
31
|
+
genid:b00dbc9c-519f-4664-518c-32853c2cfabc a risk:PolicyRisk .
|
|
32
|
+
genid:b00dbc9c-519f-4664-518c-32853c2cfabc dct:source :PermChangeTerms .
|
|
33
|
+
genid:b00dbc9c-519f-4664-518c-32853c2cfabc dct:description "Notice for changing terms is shorter than consumer requirement." .
|
|
34
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca a dpv:Risk .
|
|
35
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca a risk:PolicyRisk .
|
|
36
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca a risk:CustomerConfidenceLoss .
|
|
37
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dct:source :PermChangeTerms .
|
|
38
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca risk:hasRiskSource genid:b00dbc9c-519f-4664-518c-32853c2cfabc .
|
|
39
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dpv:hasConsequence risk:CustomerConfidenceLoss .
|
|
40
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dpv:hasImpact risk:NonMaterialDamage .
|
|
41
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca :aboutClause :ClauseC2 .
|
|
42
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca :scoreRaw 85 .
|
|
43
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca :violatesNeed :Need_ChangeOnlyWithPriorNotice .
|
|
44
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dct:description "Risk: terms may change with notice (3 days) below consumer requirement (14 days). Clause C2: Provider may change terms by informing users at least 3 days in advance." .
|
|
45
|
+
:ProcessContext1 dpv:hasRisk genid:423c1420-b028-620c-fcd2-78f08f0da0ca .
|
|
46
|
+
genid:e4304204-5fbc-1dc2-cb50-da7597604550 a risk:RiskSource .
|
|
47
|
+
genid:e4304204-5fbc-1dc2-cb50-da7597604550 a risk:PolicyRisk .
|
|
48
|
+
genid:e4304204-5fbc-1dc2-cb50-da7597604550 dct:source :PermShareData .
|
|
49
|
+
genid:e4304204-5fbc-1dc2-cb50-da7597604550 dct:description "Data sharing permitted without explicit consent constraint." .
|
|
50
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c a dpv:Risk .
|
|
51
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c a risk:UnwantedDisclosureData .
|
|
52
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c a risk:CustomerConfidenceLoss .
|
|
53
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dct:source :PermShareData .
|
|
54
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c risk:hasRiskSource genid:e4304204-5fbc-1dc2-cb50-da7597604550 .
|
|
55
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dpv:hasConsequence risk:CustomerConfidenceLoss .
|
|
56
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dpv:hasImpact risk:NonMaterialDamage .
|
|
57
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dpv:hasImpact risk:FinancialLoss .
|
|
58
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c :aboutClause :ClauseC3 .
|
|
59
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c :scoreRaw 97 .
|
|
60
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c :violatesNeed :Need_NoSharingWithoutConsent .
|
|
61
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dct:description "Risk: user data sharing is permitted without an explicit consent constraint. Clause C3: Provider may share user data with partners for business purposes." .
|
|
62
|
+
:ProcessContext1 dpv:hasRisk genid:dbffbd20-c09d-995c-7973-d378be8f6d4c .
|
|
63
|
+
genid:f83f5ee8-215f-977e-4e89-f9812cda0c04 a risk:RiskSource .
|
|
64
|
+
genid:f83f5ee8-215f-977e-4e89-f9812cda0c04 a risk:PolicyRisk .
|
|
65
|
+
genid:f83f5ee8-215f-977e-4e89-f9812cda0c04 dct:source :ProhibitExportData .
|
|
66
|
+
genid:f83f5ee8-215f-977e-4e89-f9812cda0c04 dct:description "Data export is prohibited, reducing portability." .
|
|
67
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c a dpv:Risk .
|
|
68
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c a risk:PolicyRisk .
|
|
69
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c a risk:CustomerConfidenceLoss .
|
|
70
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dct:source :ProhibitExportData .
|
|
71
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c risk:hasRiskSource genid:f83f5ee8-215f-977e-4e89-f9812cda0c04 .
|
|
72
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dpv:hasConsequence risk:CustomerConfidenceLoss .
|
|
73
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dpv:hasImpact risk:NonMaterialDamage .
|
|
74
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c :aboutClause :ClauseC4 .
|
|
75
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c :scoreRaw 70 .
|
|
76
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c :violatesNeed :Need_DataPortability .
|
|
77
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dct:description "Risk: portability is restricted because exporting user data is prohibited. Clause C4: Users are not permitted to export their data." .
|
|
78
|
+
:ProcessContext1 dpv:hasRisk genid:ee944cc3-a770-063a-274c-98e4f8af162c .
|
|
79
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc :score "100"^^xsd:integer .
|
|
80
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca :score 85 .
|
|
81
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c :score 97 .
|
|
82
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c :score 70 .
|
|
83
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasSeverity risk:HighSeverity .
|
|
84
|
+
genid:59bf9d7c-6868-401e-bb47-667826cd85bc dpv:hasRiskLevel risk:HighRisk .
|
|
85
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dpv:hasSeverity risk:HighSeverity .
|
|
86
|
+
genid:423c1420-b028-620c-fcd2-78f08f0da0ca dpv:hasRiskLevel risk:HighRisk .
|
|
87
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dpv:hasSeverity risk:HighSeverity .
|
|
88
|
+
genid:dbffbd20-c09d-995c-7973-d378be8f6d4c dpv:hasRiskLevel risk:HighRisk .
|
|
89
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dpv:hasSeverity risk:ModerateSeverity .
|
|
90
|
+
genid:ee944cc3-a770-063a-274c-98e4f8af162c dpv:hasRiskLevel risk:ModerateRisk .
|
|
91
|
+
(:Agreement1 :ConsumerExample 0) log:outputString "\n=== Ranked DPV Risk Report ===\nAgreement: Example Agreement\nProfile: Example consumer profile\n\n" .
|
|
92
|
+
(:Agreement1 :ConsumerExample 1 900 genid:59bf9d7c-6868-401e-bb47-667826cd85bc) log:outputString "score=100 (https://w3id.org/dpv/risk#HighRisk, https://w3id.org/dpv/risk#HighSeverity) clause C1\n Risk: account/data removal is permitted without notice safeguards (no notice constraint and no duty to inform). Clause C1: Provider may remove the user account (and associated data) at its discretion.\n\n" .
|
|
93
|
+
(:Agreement1 :ConsumerExample 1 915 genid:423c1420-b028-620c-fcd2-78f08f0da0ca) log:outputString "score=85 (https://w3id.org/dpv/risk#HighRisk, https://w3id.org/dpv/risk#HighSeverity) clause C2\n Risk: terms may change with notice (3 days) below consumer requirement (14 days). Clause C2: Provider may change terms by informing users at least 3 days in advance.\n\n" .
|
|
94
|
+
(:Agreement1 :ConsumerExample 1 903 genid:dbffbd20-c09d-995c-7973-d378be8f6d4c) log:outputString "score=97 (https://w3id.org/dpv/risk#HighRisk, https://w3id.org/dpv/risk#HighSeverity) clause C3\n Risk: user data sharing is permitted without an explicit consent constraint. Clause C3: Provider may share user data with partners for business purposes.\n\n" .
|
|
95
|
+
(:Agreement1 :ConsumerExample 1 930 genid:ee944cc3-a770-063a-274c-98e4f8af162c) log:outputString "score=70 (https://w3id.org/dpv/risk#ModerateRisk, https://w3id.org/dpv/risk#ModerateSeverity) clause C4\n Risk: portability is restricted because exporting user data is prohibited. Clause C4: Users are not permitted to export their data.\n\n" .
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
@prefix : <https://example.org/odrl-mitigation-demo#> .
|
|
2
|
+
@prefix genid: <https://eyereasoner.github.io/.well-known/genid/> .
|
|
3
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
4
|
+
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
|
|
5
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
6
|
+
|
|
7
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c a :Risk .
|
|
8
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :aboutAgreement :Agreement3 .
|
|
9
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :forProfile :ConsumerCarol .
|
|
10
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :aboutClause :ClauseD1 .
|
|
11
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :clauseId "D1" .
|
|
12
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :issue :NoticeTooShort .
|
|
13
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :baseScore 70 .
|
|
14
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :needWeight 15 .
|
|
15
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :rawScore 85 .
|
|
16
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :title "Notice period too short" .
|
|
17
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :explanation "This clause is risky because the notice period (3 days) is below the consumer requirement (14 days). Clause D1: We may change these terms with notice. Notice may be as short as 3 days." .
|
|
18
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :violatesNeed :Need_ChangeOnlyWithPriorNotice .
|
|
19
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 a :Risk .
|
|
20
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :aboutAgreement :Agreement3 .
|
|
21
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :forProfile :ConsumerCarol .
|
|
22
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :aboutClause :ClauseD2 .
|
|
23
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :clauseId "D2" .
|
|
24
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :issue :AutoRenewNoReminder .
|
|
25
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :baseScore 75 .
|
|
26
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :needWeight 10 .
|
|
27
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :rawScore 85 .
|
|
28
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :title "Auto-renewal without reminder" .
|
|
29
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :explanation "This clause is risky because it allows auto-renewal without a reminder. Consumer needs at least 7 days reminder. Clause D2: Your subscription renews automatically unless you cancel." .
|
|
30
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :violatesNeed :Need_ReminderBeforeAutoRenew .
|
|
31
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 a :Risk .
|
|
32
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :aboutAgreement :Agreement3 .
|
|
33
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :forProfile :ConsumerCarol .
|
|
34
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :aboutClause :ClauseD3 .
|
|
35
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :clauseId "D3" .
|
|
36
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :issue :NonRefundableFee .
|
|
37
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :baseScore 70 .
|
|
38
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :needWeight 9 .
|
|
39
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :rawScore 79 .
|
|
40
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :title "Non-refundable fees" .
|
|
41
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :explanation "This clause is risky because it declares fees non-refundable, conflicting with a refund/cooling-off expectation (>= 14 days). Clause D3: All fees are non-refundable." .
|
|
42
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :violatesNeed :Need_RefundRequired .
|
|
43
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 a :Risk .
|
|
44
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :aboutAgreement :Agreement3 .
|
|
45
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :forProfile :ConsumerCarol .
|
|
46
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :aboutClause :ClauseD4 .
|
|
47
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :clauseId "D4" .
|
|
48
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :issue :TrackingNoOptIn .
|
|
49
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :baseScore 80 .
|
|
50
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :needWeight 9 .
|
|
51
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :rawScore 89 .
|
|
52
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :title "Tracking without opt-in" .
|
|
53
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :explanation "This clause is risky because it permits tracking without explicit opt-in consent. Clause D4: We may track your activity to improve services." .
|
|
54
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :violatesNeed :Need_NoTrackingWithoutOptIn .
|
|
55
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 a :Risk .
|
|
56
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :aboutAgreement :Agreement3 .
|
|
57
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :forProfile :ConsumerCarol .
|
|
58
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :aboutClause :ClauseD5 .
|
|
59
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :clauseId "D5" .
|
|
60
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :issue :NoDataExport .
|
|
61
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :baseScore 85 .
|
|
62
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :needWeight 8 .
|
|
63
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :rawScore 93 .
|
|
64
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :title "No data export / portability" .
|
|
65
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :explanation "This clause is risky because it prohibits exporting data, undermining portability. Clause D5: You may not export or download your data from the service." .
|
|
66
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :violatesNeed :Need_DataPortability .
|
|
67
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 a :Risk .
|
|
68
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :aboutAgreement :Agreement3 .
|
|
69
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :forProfile :ConsumerCarol .
|
|
70
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :aboutClause :ClauseD6 .
|
|
71
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :clauseId "D6" .
|
|
72
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :issue :ProviderMayDeleteData .
|
|
73
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :baseScore 90 .
|
|
74
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :needWeight 12 .
|
|
75
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :rawScore 102 .
|
|
76
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :title "Provider can delete user data" .
|
|
77
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :explanation "This clause is risky because it allows the provider to delete the consumer’s data. Clause D6: We may delete your data at our discretion." .
|
|
78
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :violatesNeed :Need_DataNotRemoved .
|
|
79
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 a :Risk .
|
|
80
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :aboutAgreement :Agreement3 .
|
|
81
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :forProfile :ConsumerCarol .
|
|
82
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :aboutClause :ClauseD2 .
|
|
83
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :clauseId "D2" .
|
|
84
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :issue :LiabilityCapTooLow .
|
|
85
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :baseScore 65 .
|
|
86
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :needWeight 8 .
|
|
87
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :rawScore 73 .
|
|
88
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :title "Liability cap too low" .
|
|
89
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :explanation "This clause is risky because the liability cap (20 EUR) is below the consumer minimum (200 EUR). Clause D2: Your subscription renews automatically unless you cancel." .
|
|
90
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :violatesNeed :Need_MinLiabilityCap .
|
|
91
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :hasMitigation genid:b3e644a0-842d-779a-8ba9-1dc01addf40c .
|
|
92
|
+
genid:b3e644a0-842d-779a-8ba9-1dc01addf40c a :Mitigation .
|
|
93
|
+
genid:b3e644a0-842d-779a-8ba9-1dc01addf40c :forRisk genid:3f3359e8-5625-adf0-e2cd-874038dc706c .
|
|
94
|
+
genid:b3e644a0-842d-779a-8ba9-1dc01addf40c :fixText "Suggested fix: ensure prior-notice duty specifies noticeDays >= 14." .
|
|
95
|
+
genid:b3e644a0-842d-779a-8ba9-1dc01addf40c :suggestAdd {
|
|
96
|
+
:PermChangeTerms odrl:duty _:sk_0 .
|
|
97
|
+
_:sk_0 a odrl:Duty .
|
|
98
|
+
_:sk_0 odrl:action :notifyPriorNotice .
|
|
99
|
+
_:sk_0 odrl:constraint _:sk_1 .
|
|
100
|
+
_:sk_1 a odrl:Constraint .
|
|
101
|
+
_:sk_1 odrl:leftOperand :noticeDays .
|
|
102
|
+
_:sk_1 odrl:operator odrl:gteq .
|
|
103
|
+
_:sk_1 odrl:rightOperand 14 .
|
|
104
|
+
} .
|
|
105
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :hasMitigation genid:53e75400-cf4d-9998-7ed7-3eeae4d6be7c .
|
|
106
|
+
genid:53e75400-cf4d-9998-7ed7-3eeae4d6be7c a :Mitigation .
|
|
107
|
+
genid:53e75400-cf4d-9998-7ed7-3eeae4d6be7c :forRisk genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 .
|
|
108
|
+
genid:53e75400-cf4d-9998-7ed7-3eeae4d6be7c :fixText "Suggested fix: add a reminder duty for auto-renewal with reminderDays >= 7." .
|
|
109
|
+
genid:53e75400-cf4d-9998-7ed7-3eeae4d6be7c :suggestAdd {
|
|
110
|
+
:PermAutoRenew odrl:duty _:sk_2 .
|
|
111
|
+
_:sk_2 a odrl:Duty .
|
|
112
|
+
_:sk_2 odrl:action :sendRenewalReminder .
|
|
113
|
+
_:sk_2 odrl:constraint _:sk_3 .
|
|
114
|
+
_:sk_3 a odrl:Constraint .
|
|
115
|
+
_:sk_3 odrl:leftOperand :reminderDays .
|
|
116
|
+
_:sk_3 odrl:operator odrl:gteq .
|
|
117
|
+
_:sk_3 odrl:rightOperand 7 .
|
|
118
|
+
} .
|
|
119
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :hasMitigation genid:585ce30c-2b91-8280-fe57-6f28f39a3ed8 .
|
|
120
|
+
genid:585ce30c-2b91-8280-fe57-6f28f39a3ed8 a :Mitigation .
|
|
121
|
+
genid:585ce30c-2b91-8280-fe57-6f28f39a3ed8 :forRisk genid:3a9b6398-3d57-879a-90e6-498980eeaf08 .
|
|
122
|
+
genid:585ce30c-2b91-8280-fe57-6f28f39a3ed8 :fixText "Suggested fix: allow refunds (e.g., refundAllowed=true) or define a cooling-off period >= 14 days." .
|
|
123
|
+
genid:585ce30c-2b91-8280-fe57-6f28f39a3ed8 :suggestAdd {
|
|
124
|
+
:PermChargeFee odrl:constraint _:sk_4 .
|
|
125
|
+
_:sk_4 a odrl:Constraint .
|
|
126
|
+
_:sk_4 odrl:leftOperand :refundAllowed .
|
|
127
|
+
_:sk_4 odrl:operator odrl:eq .
|
|
128
|
+
_:sk_4 odrl:rightOperand true .
|
|
129
|
+
:PermChargeFee odrl:constraint _:sk_5 .
|
|
130
|
+
_:sk_5 a odrl:Constraint .
|
|
131
|
+
_:sk_5 odrl:leftOperand :coolingOffDays .
|
|
132
|
+
_:sk_5 odrl:operator odrl:gteq .
|
|
133
|
+
_:sk_5 odrl:rightOperand 14 .
|
|
134
|
+
} .
|
|
135
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :hasMitigation genid:622a8baf-e258-fe50-fb3b-81463784ae40 .
|
|
136
|
+
genid:622a8baf-e258-fe50-fb3b-81463784ae40 a :Mitigation .
|
|
137
|
+
genid:622a8baf-e258-fe50-fb3b-81463784ae40 :forRisk genid:8468c67c-e2dd-8af8-fa31-006485a75788 .
|
|
138
|
+
genid:622a8baf-e258-fe50-fb3b-81463784ae40 :fixText "Suggested fix: require opt-in consent for tracking (optInConsent=true)." .
|
|
139
|
+
genid:622a8baf-e258-fe50-fb3b-81463784ae40 :suggestAdd {
|
|
140
|
+
:PermTrackUser odrl:constraint _:sk_6 .
|
|
141
|
+
_:sk_6 a odrl:Constraint .
|
|
142
|
+
_:sk_6 odrl:leftOperand :optInConsent .
|
|
143
|
+
_:sk_6 odrl:operator odrl:eq .
|
|
144
|
+
_:sk_6 odrl:rightOperand true .
|
|
145
|
+
} .
|
|
146
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :hasMitigation genid:4728cce8-e55c-33a6-ff43-0284c37b050c .
|
|
147
|
+
genid:4728cce8-e55c-33a6-ff43-0284c37b050c a :Mitigation .
|
|
148
|
+
genid:4728cce8-e55c-33a6-ff43-0284c37b050c :forRisk genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 .
|
|
149
|
+
genid:4728cce8-e55c-33a6-ff43-0284c37b050c :fixText "Suggested fix: add a permission to export/download user data (data portability)." .
|
|
150
|
+
genid:4728cce8-e55c-33a6-ff43-0284c37b050c :suggestAdd {
|
|
151
|
+
:Policy3 odrl:permission _:sk_7 .
|
|
152
|
+
_:sk_7 a odrl:Permission .
|
|
153
|
+
_:sk_7 odrl:action :exportData .
|
|
154
|
+
_:sk_7 odrl:target :UserData .
|
|
155
|
+
} .
|
|
156
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :hasMitigation genid:33f8e7b9-1987-7832-0892-a8ec90448424 .
|
|
157
|
+
genid:33f8e7b9-1987-7832-0892-a8ec90448424 a :Mitigation .
|
|
158
|
+
genid:33f8e7b9-1987-7832-0892-a8ec90448424 :forRisk genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 .
|
|
159
|
+
genid:33f8e7b9-1987-7832-0892-a8ec90448424 :fixText "Suggested fix: remove provider discretion to delete data; allow deletion only on consumer request or legal obligation." .
|
|
160
|
+
genid:33f8e7b9-1987-7832-0892-a8ec90448424 :suggestAdd {
|
|
161
|
+
:PermDeleteUserData odrl:constraint _:sk_8 .
|
|
162
|
+
_:sk_8 a odrl:Constraint .
|
|
163
|
+
_:sk_8 odrl:leftOperand :deletionGround .
|
|
164
|
+
_:sk_8 odrl:operator odrl:isAnyOf .
|
|
165
|
+
_:sk_8 odrl:rightOperand (:consumerRequest :legalObligation) .
|
|
166
|
+
} .
|
|
167
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :hasMitigation genid:478eac18-8c36-6188-b439-dda12b98fac8 .
|
|
168
|
+
genid:478eac18-8c36-6188-b439-dda12b98fac8 a :Mitigation .
|
|
169
|
+
genid:478eac18-8c36-6188-b439-dda12b98fac8 :forRisk genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 .
|
|
170
|
+
genid:478eac18-8c36-6188-b439-dda12b98fac8 :fixText "Suggested fix: raise liabilityCapEuro so it is >= 200 EUR (or remove the cap where inappropriate)." .
|
|
171
|
+
genid:478eac18-8c36-6188-b439-dda12b98fac8 :suggestAdd {
|
|
172
|
+
:PermAutoRenew odrl:constraint _:sk_9 .
|
|
173
|
+
_:sk_9 a odrl:Constraint .
|
|
174
|
+
_:sk_9 odrl:leftOperand :liabilityCapEuro .
|
|
175
|
+
_:sk_9 odrl:operator odrl:gteq .
|
|
176
|
+
_:sk_9 odrl:rightOperand 200 .
|
|
177
|
+
} .
|
|
178
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :score 100 .
|
|
179
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :score 85 .
|
|
180
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :score 85 .
|
|
181
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :score 79 .
|
|
182
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :score 89 .
|
|
183
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :score 93 .
|
|
184
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :score 73 .
|
|
185
|
+
genid:3f3359e8-5625-adf0-e2cd-874038dc706c :severity :High .
|
|
186
|
+
genid:d48f3244-c9ff-62e2-46d1-44d4c6a9c3d8 :severity :High .
|
|
187
|
+
genid:8468c67c-e2dd-8af8-fa31-006485a75788 :severity :High .
|
|
188
|
+
genid:e1830d38-0c5f-d24e-add5-a27d9cf99088 :severity :High .
|
|
189
|
+
genid:c5c6e14a-6858-7d40-10ca-c460597f1ae8 :severity :High .
|
|
190
|
+
genid:3a9b6398-3d57-879a-90e6-498980eeaf08 :severity :Medium .
|
|
191
|
+
genid:9bdfab08-d724-d5c8-ba20-5e23053c80f4 :severity :Medium .
|
|
192
|
+
(:Agreement3 :ConsumerCarol 0) log:outputString "\n=== Risk report for Example Platform Agreement (with fixes) (profile: Carol (example consumer)) ===\n" .
|
|
193
|
+
(:Agreement3 :ConsumerCarol 999) log:outputString "\n--- Suggested mitigations (highest risk first) ---\n" .
|
|
194
|
+
(:Agreement3 :ConsumerCarol 1) log:outputString "1) score=100 (https://example.org/odrl-mitigation-demo#High), clause D6 — Provider can delete user data. This clause is risky because it allows the provider to delete the consumer’s data. Clause D6: We may delete your data at our discretion.\n" .
|
|
195
|
+
(:Agreement3 :ConsumerCarol 2) log:outputString "2) score=93 (https://example.org/odrl-mitigation-demo#High), clause D5 — No data export / portability. This clause is risky because it prohibits exporting data, undermining portability. Clause D5: You may not export or download your data from the service.\n" .
|
|
196
|
+
(:Agreement3 :ConsumerCarol 3) log:outputString "3) score=89 (https://example.org/odrl-mitigation-demo#High), clause D4 — Tracking without opt-in. This clause is risky because it permits tracking without explicit opt-in consent. Clause D4: We may track your activity to improve services.\n" .
|
|
197
|
+
(:Agreement3 :ConsumerCarol 4) log:outputString "4) score=85 (https://example.org/odrl-mitigation-demo#High), clause D2 — Auto-renewal without reminder. This clause is risky because it allows auto-renewal without a reminder. Consumer needs at least 7 days reminder. Clause D2: Your subscription renews automatically unless you cancel.\n" .
|
|
198
|
+
(:Agreement3 :ConsumerCarol 5) log:outputString "5) score=85 (https://example.org/odrl-mitigation-demo#High), clause D1 — Notice period too short. This clause is risky because the notice period (3 days) is below the consumer requirement (14 days). Clause D1: We may change these terms with notice. Notice may be as short as 3 days.\n" .
|
|
199
|
+
(:Agreement3 :ConsumerCarol 6) log:outputString "6) score=79 (https://example.org/odrl-mitigation-demo#Medium), clause D3 — Non-refundable fees. This clause is risky because it declares fees non-refundable, conflicting with a refund/cooling-off expectation (>= 14 days). Clause D3: All fees are non-refundable.\n" .
|
|
200
|
+
(:Agreement3 :ConsumerCarol 7) log:outputString "7) score=73 (https://example.org/odrl-mitigation-demo#Medium), clause D2 — Liability cap too low. This clause is risky because the liability cap (20 EUR) is below the consumer minimum (200 EUR). Clause D2: Your subscription renews automatically unless you cancel.\n" .
|
|
201
|
+
(:Agreement3 :ConsumerCarol (1000 1)) log:outputString "1) clause D6 — Provider can delete user data (score=100). Suggested fix: remove provider discretion to delete data; allow deletion only on consumer request or legal obligation.\n" .
|
|
202
|
+
(:Agreement3 :ConsumerCarol (1000 2)) log:outputString "2) clause D5 — No data export / portability (score=93). Suggested fix: add a permission to export/download user data (data portability).\n" .
|
|
203
|
+
(:Agreement3 :ConsumerCarol (1000 3)) log:outputString "3) clause D4 — Tracking without opt-in (score=89). Suggested fix: require opt-in consent for tracking (optInConsent=true).\n" .
|
|
204
|
+
(:Agreement3 :ConsumerCarol (1000 4)) log:outputString "4) clause D2 — Auto-renewal without reminder (score=85). Suggested fix: add a reminder duty for auto-renewal with reminderDays >= 7.\n" .
|
|
205
|
+
(:Agreement3 :ConsumerCarol (1000 5)) log:outputString "5) clause D1 — Notice period too short (score=85). Suggested fix: ensure prior-notice duty specifies noticeDays >= 14.\n" .
|
|
206
|
+
(:Agreement3 :ConsumerCarol (1000 6)) log:outputString "6) clause D3 — Non-refundable fees (score=79). Suggested fix: allow refunds (e.g., refundAllowed=true) or define a cooling-off period >= 14 days.\n" .
|
|
207
|
+
(:Agreement3 :ConsumerCarol (1000 7)) log:outputString "7) clause D2 — Liability cap too low (score=73). Suggested fix: raise liabilityCapEuro so it is >= 200 EUR (or remove the cap where inappropriate).\n" .
|
package/examples/reifies.n3
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
2
2
|
@prefix : <http://www.example.org/> .
|
|
3
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
3
4
|
|
|
4
5
|
_:b rdf:reifies { :Socrates a :Human . } .
|
|
5
6
|
_:b :is true .
|
|
6
7
|
:employee38 :familyName "Smith" .
|
|
7
|
-
_:id
|
|
8
|
+
_:id log:nameOf { :employee38 :jobTitle "Assistant Designer" . } .
|
|
8
9
|
_:id :accordingTo :employee22 .
|
package/package.json
CHANGED
package/tools/n3gen.js
CHANGED
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* *
|
|
12
12
|
* TriG → N3 mapping (named graphs)
|
|
13
13
|
* TriG: <graphName> { ...triples... }
|
|
14
|
-
* N3: <graphName>
|
|
14
|
+
* N3: <graphName> log:nameOf { ...triples... } .
|
|
15
15
|
*
|
|
16
16
|
*
|
|
17
17
|
* RDF 1.2 Turtle-star / TriG-star
|
|
18
|
-
* - triple terms:
|
|
18
|
+
* - triple terms: log:nameOf <<( s p o )>>
|
|
19
19
|
* - sugar form: << s p o >> :is true .
|
|
20
20
|
* triple terms are emitted as singleton graph terms in N3:
|
|
21
|
-
*
|
|
21
|
+
* log:nameOf { s p o . } .
|
|
22
22
|
*
|
|
23
23
|
* ----------------------------------------------------------------------------
|
|
24
24
|
* Usage
|
|
@@ -91,13 +91,17 @@ function _pnLocalSafe(s) {
|
|
|
91
91
|
// Mapping namespace
|
|
92
92
|
// ---------------------------------------------------------------------------
|
|
93
93
|
|
|
94
|
-
// Use the W3C
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
// Use the W3C log: vocabulary to represent:
|
|
95
|
+
// - TriG named graphs as N3 graph terms:
|
|
96
|
+
// <g> log:nameOf { ... } .
|
|
97
|
+
// - RDF 1.2 Turtle-star / TriG-star reified triples:
|
|
98
|
+
// <reifier> log:nameOf { <s> <p> <o> . } .
|
|
99
|
+
const LOG_NS = 'http://www.w3.org/2000/10/swap/log#';
|
|
100
|
+
const log = {
|
|
101
|
+
nameOf: `${LOG_NS}nameOf`,
|
|
99
102
|
};
|
|
100
103
|
|
|
104
|
+
|
|
101
105
|
// ---------------------------------------------------------------------------
|
|
102
106
|
// Minimal Turtle/N3 model + lexer + parser
|
|
103
107
|
// ---------------------------------------------------------------------------
|
|
@@ -825,13 +829,13 @@ class TurtleParser {
|
|
|
825
829
|
}
|
|
826
830
|
|
|
827
831
|
// Emit the implicit (or explicit) reifier triple required by RDF 1.2 reifiedTriple sugar:
|
|
828
|
-
// reifier
|
|
832
|
+
// reifier log:nameOf tripleTerm .
|
|
829
833
|
// We represent tripleTerm in N3 as a quoted graph term: { s p o . }
|
|
830
834
|
emitReifies(reifier, tripleGraph) {
|
|
831
835
|
const key = `${this._termKey(reifier)}|${this._termKey(tripleGraph)}`;
|
|
832
836
|
if (this._reifiesEmitted.has(key)) return;
|
|
833
837
|
this._reifiesEmitted.add(key);
|
|
834
|
-
this.pendingTriples.push(new Triple(reifier, internIri(
|
|
838
|
+
this.pendingTriples.push(new Triple(reifier, internIri(LOG_NS + 'nameOf'), tripleGraph));
|
|
835
839
|
}
|
|
836
840
|
|
|
837
841
|
// Accept '.' OR (when inside {...}) accept '}' as implicit terminator for last triple
|
|
@@ -1050,7 +1054,7 @@ class TurtleParser {
|
|
|
1050
1054
|
return new GraphTerm([new Triple(s, p, o)]);
|
|
1051
1055
|
}
|
|
1052
1056
|
|
|
1053
|
-
// reifiedTriple sugar -> expand to a reifier node that
|
|
1057
|
+
// reifiedTriple sugar -> expand to a reifier node that log:nameOf a tripleTerm
|
|
1054
1058
|
const s = this.parseTerm();
|
|
1055
1059
|
const p = this.parseTerm();
|
|
1056
1060
|
const o = this.parseTerm();
|
|
@@ -1205,7 +1209,7 @@ class TurtleParser {
|
|
|
1205
1209
|
// ~ <reifier>
|
|
1206
1210
|
// {| <predicateObjectList> |}
|
|
1207
1211
|
// We convert these into eyeling-friendly N3 by emitting:
|
|
1208
|
-
// <reifier>
|
|
1212
|
+
// <reifier> log:nameOf { <s> <p> <o> . } .
|
|
1209
1213
|
// <reifier> <annP> <annO> .
|
|
1210
1214
|
|
|
1211
1215
|
parseAnnotationBlock(reifier) {
|
|
@@ -1769,16 +1773,14 @@ function isIri(t, iri) {
|
|
|
1769
1773
|
return t instanceof Iri && t.value === iri;
|
|
1770
1774
|
}
|
|
1771
1775
|
|
|
1772
|
-
function renderPrefixPrologue(prefixes
|
|
1776
|
+
function renderPrefixPrologue(prefixes) {
|
|
1773
1777
|
const out = [];
|
|
1774
|
-
if (includeRdfg) out.push(`@prefix rdfg: <${RDFG_NS}> .`);
|
|
1775
1778
|
|
|
1776
1779
|
if (prefixes && prefixes.baseIri) out.push(`@base <${prefixes.baseIri}> .`);
|
|
1777
1780
|
|
|
1778
1781
|
if (prefixes && prefixes.map) {
|
|
1779
1782
|
for (const [pfx, iri] of Object.entries(prefixes.map)) {
|
|
1780
1783
|
if (!iri) continue;
|
|
1781
|
-
if (includeRdfg && pfx === 'rdfg') continue;
|
|
1782
1784
|
const label = pfx === '' ? ':' : `${pfx}:`;
|
|
1783
1785
|
out.push(`@prefix ${label} <${iri}> .`);
|
|
1784
1786
|
}
|
|
@@ -1798,6 +1800,57 @@ function ensureSkolemPrefix(prefixes, skolemMap) {
|
|
|
1798
1800
|
return new PrefixEnv(newMap, baseIri);
|
|
1799
1801
|
}
|
|
1800
1802
|
|
|
1803
|
+
// Ensure log: prefix is available whenever we emit log:nameOf (or any other log:* IRI).
|
|
1804
|
+
function usesLogNamespace(triples) {
|
|
1805
|
+
let used = false;
|
|
1806
|
+
|
|
1807
|
+
function visitTerm(t) {
|
|
1808
|
+
if (!t || used) return;
|
|
1809
|
+
|
|
1810
|
+
if (t instanceof Iri) {
|
|
1811
|
+
if (t.value.startsWith(LOG_NS)) used = true;
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
if (t instanceof Literal) {
|
|
1816
|
+
// Detect log: use in typed literal tokens, or explicit IRI datatypes in LOG_NS.
|
|
1817
|
+
if (t.value.includes('^^log:') || t.value.includes(`^^<${LOG_NS}`)) used = true;
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
if (t instanceof ListTerm) {
|
|
1822
|
+
for (const e of t.elems) visitTerm(e);
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
if (t instanceof GraphTerm) {
|
|
1827
|
+
for (const tr of t.triples) {
|
|
1828
|
+
visitTerm(tr.s);
|
|
1829
|
+
visitTerm(tr.p);
|
|
1830
|
+
visitTerm(tr.o);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
for (const tr of triples || []) {
|
|
1836
|
+
// triples may be instances of Triple or plain objects with {s,p,o}
|
|
1837
|
+
visitTerm(tr.s);
|
|
1838
|
+
visitTerm(tr.p);
|
|
1839
|
+
visitTerm(tr.o);
|
|
1840
|
+
if (used) break;
|
|
1841
|
+
}
|
|
1842
|
+
return used;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
function ensureLogPrefixIfUsed(prefixes, triples) {
|
|
1846
|
+
if (!usesLogNamespace(triples)) return prefixes;
|
|
1847
|
+
|
|
1848
|
+
const baseMap = prefixes && prefixes.map ? prefixes.map : {};
|
|
1849
|
+
const newMap = { ...baseMap, log: LOG_NS }; // overwrite any existing log: mapping
|
|
1850
|
+
const baseIri = prefixes ? prefixes.baseIri : '';
|
|
1851
|
+
return new PrefixEnv(newMap, baseIri);
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1801
1854
|
function usesRdfNamespace(triples) {
|
|
1802
1855
|
let used = false;
|
|
1803
1856
|
|
|
@@ -1922,17 +1975,17 @@ function groupQuadsByGraph(quads) {
|
|
|
1922
1975
|
return m;
|
|
1923
1976
|
}
|
|
1924
1977
|
|
|
1925
|
-
function
|
|
1978
|
+
function writeN3LogNameOf({ datasetQuads, prefixes }) {
|
|
1926
1979
|
const blocks = [];
|
|
1927
1980
|
const grouped = groupQuadsByGraph(datasetQuads);
|
|
1928
1981
|
|
|
1929
1982
|
// For prefix pruning + Skolemization we build a synthetic triple stream that
|
|
1930
1983
|
// matches the *output* structure:
|
|
1931
1984
|
// - default graph triples are “outside” any GraphTerm
|
|
1932
|
-
// - each named graph is wrapped as: gTerm
|
|
1985
|
+
// - each named graph is wrapped as: gTerm log:nameOf { ... }
|
|
1933
1986
|
// This allows us to detect blank nodes that must corefer across graphs.
|
|
1934
1987
|
const pseudoTriplesForUse = [];
|
|
1935
|
-
const
|
|
1988
|
+
const logNameOfIri = new Iri(log.nameOf);
|
|
1936
1989
|
|
|
1937
1990
|
if (grouped.has('DEFAULT')) {
|
|
1938
1991
|
const { triples } = grouped.get('DEFAULT');
|
|
@@ -1942,19 +1995,19 @@ function writeN3RdfgIsGraph({ datasetQuads, prefixes }) {
|
|
|
1942
1995
|
for (const [k, { gTerm, triples }] of grouped.entries()) {
|
|
1943
1996
|
if (k === 'DEFAULT') continue;
|
|
1944
1997
|
const folded = foldRdfLists(triples);
|
|
1945
|
-
pseudoTriplesForUse.push({ s: gTerm, p:
|
|
1998
|
+
pseudoTriplesForUse.push({ s: gTerm, p: logNameOfIri, o: new GraphTerm(folded) });
|
|
1946
1999
|
}
|
|
1947
2000
|
|
|
1948
2001
|
const prunedPrefixes = pruneUnusedPrefixes(prefixes, pseudoTriplesForUse);
|
|
1949
2002
|
const skolemMap = buildSkolemMapForBnodesThatCrossScopes(pseudoTriplesForUse);
|
|
1950
2003
|
const outPrefixes = ensureRdfPrefixIfUsed(
|
|
1951
|
-
ensureXsdPrefixIfUsed(ensureSkolemPrefix(prunedPrefixes, skolemMap), pseudoTriplesForUse),
|
|
2004
|
+
ensureXsdPrefixIfUsed(ensureLogPrefixIfUsed(ensureSkolemPrefix(prunedPrefixes, skolemMap), pseudoTriplesForUse), pseudoTriplesForUse),
|
|
1952
2005
|
pseudoTriplesForUse,
|
|
1953
2006
|
);
|
|
1954
|
-
const pro = renderPrefixPrologue(outPrefixes
|
|
2007
|
+
const pro = renderPrefixPrologue(outPrefixes).trim();
|
|
1955
2008
|
if (pro) blocks.push(pro, '');
|
|
1956
2009
|
|
|
1957
|
-
// default graph: emit triples at top-level (no
|
|
2010
|
+
// default graph: emit triples at top-level (no log:nameOf wrapper)
|
|
1958
2011
|
if (grouped.has('DEFAULT')) {
|
|
1959
2012
|
const { triples } = grouped.get('DEFAULT');
|
|
1960
2013
|
const folded = foldRdfLists(triples);
|
|
@@ -1969,7 +2022,7 @@ function writeN3RdfgIsGraph({ datasetQuads, prefixes }) {
|
|
|
1969
2022
|
const named = [...grouped.entries()].filter(([k]) => k !== 'DEFAULT');
|
|
1970
2023
|
named.sort((a, b) => a[0].localeCompare(b[0]));
|
|
1971
2024
|
for (const [, { gTerm, triples }] of named) {
|
|
1972
|
-
blocks.push(`${termToText(gTerm, outPrefixes, skolemMap)}
|
|
2025
|
+
blocks.push(`${termToText(gTerm, outPrefixes, skolemMap)} log:nameOf {`);
|
|
1973
2026
|
const folded = foldRdfLists(triples);
|
|
1974
2027
|
if (folded.length) {
|
|
1975
2028
|
blocks.push(
|
|
@@ -1988,7 +2041,7 @@ function writeN3RdfgIsGraph({ datasetQuads, prefixes }) {
|
|
|
1988
2041
|
}
|
|
1989
2042
|
|
|
1990
2043
|
// ---------------------------------------------------------------------------
|
|
1991
|
-
// Roundtrip: TriG <-> N3 (
|
|
2044
|
+
// Roundtrip: TriG <-> N3 (log:nameOf mapping)
|
|
1992
2045
|
// ---------------------------------------------------------------------------
|
|
1993
2046
|
|
|
1994
2047
|
function parseTriG(text) {
|
|
@@ -2006,11 +2059,11 @@ function writeN3Triples({ triples, prefixes }) {
|
|
|
2006
2059
|
const prunedPrefixes = pruneUnusedPrefixes(prefixes, foldedTriples);
|
|
2007
2060
|
const skolemMap = buildSkolemMapForBnodesThatCrossScopes(foldedTriples);
|
|
2008
2061
|
const outPrefixes = ensureRdfPrefixIfUsed(
|
|
2009
|
-
ensureXsdPrefixIfUsed(ensureSkolemPrefix(prunedPrefixes, skolemMap), foldedTriples),
|
|
2062
|
+
ensureXsdPrefixIfUsed(ensureLogPrefixIfUsed(ensureSkolemPrefix(prunedPrefixes, skolemMap), foldedTriples), foldedTriples),
|
|
2010
2063
|
foldedTriples,
|
|
2011
2064
|
);
|
|
2012
2065
|
const blocks = [];
|
|
2013
|
-
const pro = renderPrefixPrologue(outPrefixes
|
|
2066
|
+
const pro = renderPrefixPrologue(outPrefixes).trim();
|
|
2014
2067
|
if (pro) blocks.push(pro, '');
|
|
2015
2068
|
for (const tr of foldedTriples) {
|
|
2016
2069
|
blocks.push(
|
|
@@ -2027,7 +2080,7 @@ function turtleToN3(ttlText) {
|
|
|
2027
2080
|
|
|
2028
2081
|
function trigToN3(trigText) {
|
|
2029
2082
|
const { quads, prefixes } = parseTriG(trigText);
|
|
2030
|
-
return
|
|
2083
|
+
return writeN3LogNameOf({ datasetQuads: quads, prefixes });
|
|
2031
2084
|
}
|
|
2032
2085
|
|
|
2033
2086
|
function printHelp() {
|