Skip to content

Commit 4e0e8d6

Browse files
fix: address Copilot review on N3 PATCH parser
- Skip '.' and ';' inside angle-bracket IRIs during statement splitting - Remove 'a' → rdf:type from expandPredicate (only apply in N3 parsing) - Assert inserted values in test, not just key existence
1 parent 39b8bda commit 4e0e8d6

2 files changed

Lines changed: 29 additions & 8 deletions

File tree

src/patch/n3-patch.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,31 @@ function splitStatements(content) {
113113
let current = '';
114114
let inString = false;
115115
let stringChar = null;
116+
let inIri = false;
116117

117118
for (let i = 0; i < content.length; i++) {
118119
const char = content[i];
119120

120-
if (!inString && (char === '"' || char === "'")) {
121+
if (!inString && !inIri && char === '<') {
122+
inIri = true;
123+
current += char;
124+
} else if (inIri && char === '>') {
125+
inIri = false;
126+
current += char;
127+
} else if (!inIri && !inString && (char === '"' || char === "'")) {
121128
inString = true;
122129
stringChar = char;
123130
current += char;
124131
} else if (inString && char === stringChar && content[i - 1] !== '\\') {
125132
inString = false;
126133
stringChar = null;
127134
current += char;
128-
} else if (!inString && char === '.') {
135+
} else if (!inString && !inIri && char === '.') {
129136
if (current.trim()) {
130137
statements.push(current);
131138
}
132139
current = '';
133-
} else if (!inString && char === ';') {
140+
} else if (!inString && !inIri && char === ';') {
134141
// Turtle shorthand - same subject, different predicate
135142
if (current.trim()) {
136143
statements.push(current);
@@ -440,7 +447,6 @@ function convertToJsonLd(object) {
440447
* Expand a potentially prefixed predicate to full URI
441448
*/
442449
function expandPredicate(predicate) {
443-
if (predicate === 'a') return 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
444450
const commonPrefixes = {
445451
'solid': SOLID_NS,
446452
'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',

test/patch.test.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,25 @@ describe('PATCH Operations', () => {
226226
const data = await verify.json();
227227
const node = data['@graph'].find(n => n['@id'] && n['@id'].includes('#reg1'));
228228
assert.ok(node, 'Should have the reg1 node');
229-
assert.ok(node['rdf:type'] || node['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'],
230-
'Should have rdf:type (from "a" keyword)');
231-
assert.ok(node['solid:forClass'], 'Should have solid:forClass');
232-
assert.ok(node['solid:instance'], 'Should have solid:instance');
229+
230+
// Check rdf:type value (from 'a' keyword)
231+
const rdfType = node['rdf:type'] || node['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'];
232+
assert.ok(rdfType, 'Should have rdf:type (from "a" keyword)');
233+
const typeId = rdfType['@id'] || rdfType;
234+
assert.ok(String(typeId).includes('TypeRegistration'), `rdf:type should be TypeRegistration, got ${typeId}`);
235+
236+
// Check solid:forClass value
237+
const forClass = node['solid:forClass'];
238+
assert.ok(forClass, 'Should have solid:forClass');
239+
const forClassId = forClass['@id'] || forClass;
240+
assert.ok(String(forClassId).includes('Tracker'), `solid:forClass should be Tracker, got ${forClassId}`);
241+
242+
// Check solid:instance value (contains a dot in the IRI - tests IRI splitting)
243+
const instance = node['solid:instance'];
244+
assert.ok(instance, 'Should have solid:instance');
245+
const instanceId = instance['@id'] || instance;
246+
assert.strictEqual(instanceId, 'https://example.com/todo/data.jsonld#this',
247+
'solid:instance should have full IRI preserved');
233248
});
234249
});
235250

0 commit comments

Comments
 (0)