mdld-parse 0.6.2 → 0.7.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/src/utils.js CHANGED
@@ -262,6 +262,9 @@ export function expandIRI(term, ctx) {
262
262
  result = t;
263
263
  } else if (t.includes(':')) {
264
264
  const [prefix, ref] = t.split(':', 2);
265
+ if (prefix && !ctx[prefix] && prefix !== '@vocab') {
266
+ console.warn(`Undefined prefix "${prefix}" in IRI "${t}" - treating as literal`);
267
+ }
265
268
  result = ctx[prefix] ? ctx[prefix] + ref : t;
266
269
  } else {
267
270
  result = (ctx['@vocab'] || '') + t;
@@ -314,19 +317,32 @@ export function parseSemanticBlock(raw) {
314
317
  let m;
315
318
 
316
319
  while ((m = re.exec(cleaned)) !== null) {
317
- const token = m[0];
320
+ let token = m[0];
318
321
  const relStart = 1 + m.index;
319
322
  const relEnd = relStart + token.length;
320
323
  const entryIndex = result.entries.length;
321
324
 
325
+ // Handle remove polarity - strip leading - and set remove flag
326
+ let remove = false;
327
+ if (token.startsWith('-') && token.length > 1) {
328
+ remove = true;
329
+ token = token.slice(1);
330
+ }
331
+
322
332
  // Handle special tokens
323
333
  if (token === '=') {
334
+ if (remove) {
335
+ console.warn('-= is not valid, subject declarations have no polarity');
336
+ }
324
337
  result.subject = 'RESET';
325
338
  result.entries.push({ kind: 'subjectReset', relRange: { start: relStart, end: relEnd }, raw: token });
326
339
  continue;
327
340
  }
328
341
 
329
342
  if (token.startsWith('=') && !token.startsWith('=#')) {
343
+ if (remove) {
344
+ console.warn('-= is not valid, subject declarations have no polarity');
345
+ }
330
346
  const iri = token.substring(1);
331
347
  result.subject = iri;
332
348
  result.entries.push({ kind: 'subject', iri, relRange: { start: relStart, end: relEnd }, raw: token });
@@ -337,7 +353,7 @@ export function parseSemanticBlock(raw) {
337
353
  let processed = false;
338
354
  for (const [pattern, config] of Object.entries(TOKEN_PATTERNS)) {
339
355
  if (token.startsWith(pattern)) {
340
- const entry = { kind: config.kind, relRange: { start: relStart, end: relEnd }, raw: token };
356
+ const entry = { kind: config.kind, relRange: { start: relStart, end: relEnd }, raw: m[0] };
341
357
  const extracted = config.extract(token);
342
358
 
343
359
  if (config.kind === 'fragment') {
@@ -347,22 +363,36 @@ export function parseSemanticBlock(raw) {
347
363
  result.object = `#${extracted}`;
348
364
  entry.fragment = extracted;
349
365
  } else if (config.kind === 'object') {
366
+ if (remove) {
367
+ console.warn('-+ is not valid, object declarations have no polarity');
368
+ remove = false;
369
+ }
350
370
  result.object = extracted;
351
371
  entry.iri = extracted;
352
372
  } else if (config.kind === 'datatype') {
373
+ if (remove) {
374
+ console.warn('-^^ is not valid, datatype modifiers have no polarity');
375
+ remove = false;
376
+ }
353
377
  if (!result.language) result.datatype = extracted;
354
378
  entry.datatype = extracted;
355
379
  } else if (config.kind === 'language') {
380
+ if (remove) {
381
+ console.warn('-@ is not valid, language modifiers have no polarity');
382
+ remove = false;
383
+ }
356
384
  result.language = extracted;
357
385
  result.datatype = null;
358
386
  entry.language = extracted;
359
387
  } else if (config.kind === 'type') {
360
- result.types.push({ iri: extracted, entryIndex });
388
+ result.types.push({ iri: extracted, entryIndex, remove });
361
389
  entry.iri = extracted;
390
+ entry.remove = remove;
362
391
  } else if (config.kind === 'property') {
363
- result.predicates.push({ iri: extracted, form: config.form, entryIndex });
392
+ result.predicates.push({ iri: extracted, form: config.form, entryIndex, remove });
364
393
  entry.iri = extracted;
365
394
  entry.form = config.form;
395
+ entry.remove = remove;
366
396
  }
367
397
 
368
398
  result.entries.push(entry);
@@ -373,8 +403,8 @@ export function parseSemanticBlock(raw) {
373
403
 
374
404
  // Default case (no pattern match)
375
405
  if (!processed) {
376
- result.predicates.push({ iri: token, form: '', entryIndex });
377
- result.entries.push({ kind: 'property', iri: token, form: '', relRange: { start: relStart, end: relEnd }, raw: token });
406
+ result.predicates.push({ iri: token, form: '', entryIndex, remove });
407
+ result.entries.push({ kind: 'property', iri: token, form: '', relRange: { start: relStart, end: relEnd }, raw: m[0], remove });
378
408
  }
379
409
  }
380
410
 
@@ -392,121 +422,8 @@ export function quadIndexKey(subject, predicate, object) {
392
422
  return JSON.stringify([subject.value, predicate.value, objKey]);
393
423
  }
394
424
 
395
- export function normalizeQuad(q) {
396
- if (!q) return null;
397
- const { subject, predicate, object } = q;
398
- if (object?.termType === 'Literal') {
399
- const language = typeof object.language === 'string' ? object.language : '';
400
- const datatype = object.datatype || { termType: 'NamedNode', value: 'http://www.w3.org/2001/XMLSchema#string' };
401
- return { ...q, subject, predicate, object: { ...object, language, datatype } };
402
- }
403
- return { ...q, subject, predicate, object };
404
- }
405
-
406
- export function objectSignature(o) {
407
- if (!o) return '';
408
- if (o.termType === 'Literal') {
409
- return JSON.stringify({ t: 'Literal', v: o.value, lang: o.language || '', dt: o.datatype?.value || '' });
410
- }
411
- return JSON.stringify({ t: o.termType, v: o.value });
412
- }
413
-
414
425
  export function quadToKeyForOrigin(q) {
415
- const nq = normalizeQuad(q);
416
- return nq ? quadIndexKey(nq.subject, nq.predicate, nq.object) : null;
417
- }
418
-
419
- export function parseQuadIndexKey(key) {
420
- try {
421
- const [s, p, objKey] = JSON.parse(key);
422
- return { s, p, o: JSON.parse(objKey) };
423
- } catch {
424
- return null;
425
- }
426
- }
427
-
428
- // Direct slot management functions - unified with block data
429
- export function createUnifiedSlot(block, entryIndex, meta = {}) {
430
- const slotId = meta.subject && meta.predicate ? hash(`${meta.subject.value}|${meta.predicate.value}`) : null;
431
- return {
432
- // Block metadata
433
- id: block.id,
434
- range: block.range,
435
- attrsRange: block.attrsRange,
436
- valueRange: block.valueRange,
437
- carrierType: block.carrierType,
438
- subject: block.subject,
439
- types: block.types,
440
- predicates: block.predicates,
441
- context: block.context,
442
-
443
- // Slot metadata
444
- entryIndex,
445
- slotId,
446
- isVacant: false,
447
- lastValue: null,
448
- vacantSince: null,
449
-
450
- // Quad metadata
451
- ...meta
452
- };
453
- }
454
-
455
- export function markSlotAsVacant(slotInfo, deletedValue) {
456
- return slotInfo ? {
457
- ...slotInfo,
458
- isVacant: true,
459
- lastValue: deletedValue,
460
- vacantSince: Date.now()
461
- } : null;
462
- }
463
-
464
- export function findVacantSlot(quadMap, subject, predicate) {
465
- const targetSlotId = hash(`${subject.value}|${predicate.value}`);
466
- return Array.from(quadMap.values())
467
- .find(slot => slot.slotId === targetSlotId && slot.isVacant);
468
- }
469
-
470
- export function occupySlot(slotInfo, newValue) {
471
- return slotInfo && slotInfo.isVacant ? {
472
- ...slotInfo,
473
- isVacant: false,
474
- lastValue: newValue,
475
- vacantSince: null
476
- } : null;
477
- }
478
-
479
- export function normalizeAttrsTokens(attrsText) {
480
- const cleaned = String(attrsText || '').replace(/^\s*\{|\}\s*$/g, '').trim();
481
- return cleaned ? cleaned.split(/\s+/).filter(Boolean) : [];
482
- }
483
-
484
- export function writeAttrsTokens(tokens) {
485
- return `{${tokens.join(' ').trim()}}`;
486
- }
487
-
488
- export function removeOneToken(tokens, matchFn) {
489
- const i = tokens.findIndex(matchFn);
490
- return i === -1 ? { tokens, removed: false } : { tokens: [...tokens.slice(0, i), ...tokens.slice(i + 1)], removed: true };
491
- }
492
-
493
- // Direct token management - no wrapper function needed
494
- export function addObjectToken(tokens, iri) {
495
- const token = `+${iri}`;
496
- return tokens.includes(token) ? tokens : [...tokens, token];
497
- }
498
-
499
- export function removeObjectToken(tokens, iri) {
500
- return removeOneToken(tokens, t => t === `+${iri}`);
501
- }
502
-
503
- export function addSoftFragmentToken(tokens, fragment) {
504
- const token = `+#${fragment}`;
505
- return tokens.includes(token) ? tokens : [...tokens, token];
506
- }
507
-
508
- export function removeSoftFragmentToken(tokens, fragment) {
509
- return removeOneToken(tokens, t => t === `+#${fragment}`);
426
+ return q ? quadIndexKey(q.subject, q.predicate, q.object) : null;
510
427
  }
511
428
 
512
429
  export function createLiteral(value, datatype, language, context, dataFactory) {