@primmel/primmel 1.6.1 → 1.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.
@@ -187,6 +187,7 @@ function createDuplicateIdChecker() {
187
187
  function parse(mmelString, parsers, options = {}) {
188
188
  const tokens = tokenizeWithPositions(mmelString);
189
189
  const dupChecker = createDuplicateIdChecker();
190
+ const constructs = [];
190
191
  let ctx = {
191
192
  root: "",
192
193
  metadata: null,
@@ -298,6 +299,15 @@ function parse(mmelString, parsers, options = {}) {
298
299
  ctx.issues.push(issue);
299
300
  }
300
301
  }
302
+ if (options.withProvenance) {
303
+ constructs.push({
304
+ field: cfg.field ?? keyword,
305
+ id: idTok.value,
306
+ keyword,
307
+ start: tok.start,
308
+ end: payloadTok.end
309
+ });
310
+ }
301
311
  updateCtx = cfg.parse(idTok.value, payloadTok.value);
302
312
  } else {
303
313
  if (i >= tokens.length) {
@@ -306,6 +316,15 @@ function parse(mmelString, parsers, options = {}) {
306
316
  );
307
317
  }
308
318
  const payloadTok = tokens[i++];
319
+ if (options.withProvenance) {
320
+ constructs.push({
321
+ field: cfg.field ?? keyword,
322
+ id: "",
323
+ keyword,
324
+ start: tok.start,
325
+ end: payloadTok.end
326
+ });
327
+ }
309
328
  updateCtx = cfg.parse(payloadTok.value);
310
329
  }
311
330
  const next = updateCtx(ctx);
@@ -314,6 +333,9 @@ function parse(mmelString, parsers, options = {}) {
314
333
  }
315
334
  ctx = next;
316
335
  }
336
+ if (options.withProvenance) {
337
+ ctx.constructs = constructs;
338
+ }
317
339
  return ctx;
318
340
  }
319
341
 
@@ -432,8 +454,12 @@ function forEachAttribute(data, visitor, errCtx) {
432
454
  while (i < t.length) {
433
455
  if (t[i] === "ref") {
434
456
  const nameParts2 = [t[i++]];
435
- if (i < t.length) nameParts2.push(t[i++]);
436
- if (i < t.length) nameParts2.push(t[i++]);
457
+ if (i < t.length) {
458
+ nameParts2.push(t[i++]);
459
+ }
460
+ if (i < t.length) {
461
+ nameParts2.push(t[i++]);
462
+ }
437
463
  let blockContent = "";
438
464
  if (i < t.length && t[i].charAt(0) === "{") {
439
465
  blockContent = unwrapBlock(t[i++]);
@@ -642,7 +668,9 @@ var parseDataClass = function(id, data) {
642
668
  const ref = { predicate: m[1], target: m[2] };
643
669
  if (details) {
644
670
  const noteMatch = /note\s+"([^"]*)"/.exec(details) ?? /note\s+(\S+)/.exec(details);
645
- if (noteMatch) ref.note = noteMatch[1];
671
+ if (noteMatch) {
672
+ ref.note = noteMatch[1];
673
+ }
646
674
  }
647
675
  result.ref ??= [];
648
676
  result.ref.push(ref);
@@ -792,7 +820,9 @@ var dumpDataClass = function(dataclass) {
792
820
  if (dataclass.ref && dataclass.ref.length > 0) {
793
821
  for (const r of dataclass.ref) {
794
822
  out += " ref " + r.predicate + ' "' + escapeString(r.target) + '"';
795
- if (r.note) out += ' { note "' + escapeString(r.note) + '" }';
823
+ if (r.note) {
824
+ out += ' { note "' + escapeString(r.note) + '" }';
825
+ }
796
826
  out += "\n";
797
827
  }
798
828
  }
@@ -13230,6 +13260,55 @@ function packageFiles(dir) {
13230
13260
  }
13231
13261
  return files;
13232
13262
  }
13263
+ function countNewlines(text) {
13264
+ let n = 0;
13265
+ for (let i = 0; i < text.length; i++) {
13266
+ if (text.charAt(i) === "\n") {
13267
+ n++;
13268
+ }
13269
+ }
13270
+ return n;
13271
+ }
13272
+ function chunkify(files) {
13273
+ const chunks = [];
13274
+ let offset = 0;
13275
+ let line = 1;
13276
+ for (const f of files) {
13277
+ if (f.role !== "content") {
13278
+ continue;
13279
+ }
13280
+ const text = preprocessIncludes(f.path);
13281
+ chunks.push({ path: f.path, text, start: offset, lineStart: line });
13282
+ offset += text.length + 2;
13283
+ line += countNewlines(text) + 2;
13284
+ }
13285
+ return chunks;
13286
+ }
13287
+ function joinChunks(chunks) {
13288
+ return chunks.map((c) => c.text).join("\n\n");
13289
+ }
13290
+ function mapConstructs(parsed, chunks, packageId) {
13291
+ const out = {};
13292
+ let ci = 0;
13293
+ for (const c of parsed) {
13294
+ while (ci + 1 < chunks.length && c.start.offset >= chunks[ci + 1].start) {
13295
+ ci++;
13296
+ }
13297
+ const chunk = chunks[ci];
13298
+ const local = (p) => ({
13299
+ line: p.line - chunk.lineStart + 1,
13300
+ col: p.col,
13301
+ offset: p.offset - chunk.start
13302
+ });
13303
+ const source = {
13304
+ file: chunk.path,
13305
+ ...packageId !== void 0 ? { package: packageId } : {},
13306
+ span: { start: local(c.start), end: local(c.end) }
13307
+ };
13308
+ (out[c.field] ??= {})[c.id] = source;
13309
+ }
13310
+ return out;
13311
+ }
13233
13312
  function readPackageManifest(path) {
13234
13313
  const manifestPath = join(resolve3(path), "package.primmel");
13235
13314
  if (!existsSync2(manifestPath)) {
@@ -13248,24 +13327,21 @@ function readPackageManifest(path) {
13248
13327
  }
13249
13328
  return manifest;
13250
13329
  }
13251
- function loadPackageInternal(dir, options = {}) {
13330
+ function loadPackageInternal(dir, options = {}, withProvenance = false) {
13252
13331
  const files = packageFiles(dir);
13253
13332
  if (files.length === 0) {
13254
13333
  throw new Error(`loadPackage: no package files found in ${resolve3(dir)}`);
13255
13334
  }
13256
13335
  let manifest = null;
13257
- const chunks = [];
13258
- for (const f of files) {
13259
- if (f.role === "manifest") {
13260
- manifest = readPackageManifest(dir);
13261
- } else {
13262
- chunks.push(preprocessIncludes(f.path));
13263
- }
13336
+ if (files.some((f) => f.role === "manifest")) {
13337
+ manifest = readPackageManifest(dir);
13264
13338
  }
13339
+ const chunks = chunkify(files);
13265
13340
  if (manifest && options.resolvePackage && effectiveUses(manifest).length > 0) {
13266
- return composePackage(dir, options, manifest);
13341
+ return composePackage(dir, options, manifest, withProvenance);
13267
13342
  }
13268
- const ctx = parse(chunks.join("\n\n"), PARSER_CONFIG, options);
13343
+ const parseOptions = withProvenance ? { ...options, withProvenance: true } : options;
13344
+ const ctx = parse(joinChunks(chunks), PARSER_CONFIG, parseOptions);
13269
13345
  if (manifest) {
13270
13346
  ctx.packageManifest = manifest;
13271
13347
  const deprecated = extendsDeprecationIssue(manifest);
@@ -13274,7 +13350,15 @@ function loadPackageInternal(dir, options = {}) {
13274
13350
  }
13275
13351
  }
13276
13352
  const standard = resolve(ctx, RESOLVER_CONFIG);
13277
- return { standard, issues: ctx.issues };
13353
+ const result = { standard, issues: ctx.issues };
13354
+ if (withProvenance) {
13355
+ const manifestFile = files.find((f) => f.role === "manifest")?.path;
13356
+ result.provenance = {
13357
+ ...manifestFile !== void 0 ? { manifest: manifestFile } : {},
13358
+ constructs: mapConstructs(ctx.constructs ?? [], chunks, manifest?.id)
13359
+ };
13360
+ }
13361
+ return result;
13278
13362
  }
13279
13363
  function loadPackageWithIssues(dir, options = {}) {
13280
13364
  return loadPackageInternal(dir, options);
@@ -13373,15 +13457,11 @@ var MERGE_FIELDS = [
13373
13457
  "texts"
13374
13458
  ];
13375
13459
  function parsePackageContent(dir, options) {
13376
- const chunks = [];
13377
- for (const f of packageFiles(dir)) {
13378
- if (f.role === "content") {
13379
- chunks.push(preprocessIncludes(f.path));
13380
- }
13381
- }
13382
- return parse(chunks.join("\n\n"), PARSER_CONFIG, options);
13460
+ const chunks = chunkify(packageFiles(dir));
13461
+ const ctx = parse(joinChunks(chunks), PARSER_CONFIG, options);
13462
+ return { ctx, chunks };
13383
13463
  }
13384
- function composePackage(rootDir, options, rootManifest) {
13464
+ function composePackage(rootDir, options, rootManifest, withProvenance = false) {
13385
13465
  const locate = options.resolvePackage;
13386
13466
  const rootId = rootManifest.id;
13387
13467
  const dirs = /* @__PURE__ */ new Map([[rootId, resolve3(rootDir)]]);
@@ -13432,9 +13512,13 @@ function composePackage(rootDir, options, rootManifest) {
13432
13512
  order.push(id);
13433
13513
  };
13434
13514
  visit(rootId);
13515
+ const parseOptions = withProvenance ? { ...options, withProvenance: true } : options;
13435
13516
  const ctxs = /* @__PURE__ */ new Map();
13517
+ const pkgChunks = /* @__PURE__ */ new Map();
13436
13518
  for (const id of order) {
13437
- ctxs.set(id, parsePackageContent(dirs.get(id), options));
13519
+ const parsed = parsePackageContent(dirs.get(id), parseOptions);
13520
+ ctxs.set(id, parsed.ctx);
13521
+ pkgChunks.set(id, parsed.chunks);
13438
13522
  }
13439
13523
  const provenance = /* @__PURE__ */ new Map();
13440
13524
  for (const field of MERGE_FIELDS) {
@@ -13519,11 +13603,32 @@ function composePackage(rootDir, options, rootManifest) {
13519
13603
  }
13520
13604
  acc.packageManifest = rootManifest;
13521
13605
  const standard = resolve(acc, RESOLVER_CONFIG);
13522
- return {
13606
+ const result = {
13523
13607
  standard,
13524
13608
  issues: [...acc.issues, ...compositionIssues],
13525
13609
  composition: { root: rootId, order }
13526
13610
  };
13611
+ if (withProvenance) {
13612
+ const constructs = {};
13613
+ for (const id of order) {
13614
+ const perPackage = mapConstructs(
13615
+ ctxs.get(id).constructs ?? [],
13616
+ pkgChunks.get(id),
13617
+ id
13618
+ );
13619
+ for (const [field, byId2] of Object.entries(perPackage)) {
13620
+ const target = constructs[field] ??= {};
13621
+ for (const [constructId, source] of Object.entries(byId2)) {
13622
+ target[constructId] = source;
13623
+ }
13624
+ }
13625
+ }
13626
+ result.provenance = {
13627
+ manifest: join(resolve3(rootDir), "package.primmel"),
13628
+ constructs
13629
+ };
13630
+ }
13631
+ return result;
13527
13632
  }
13528
13633
 
13529
13634
  // src/ser-des/prm.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primmel/primmel",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "Primmel — parser, types, and serializer for the Primmel modelling language (successor to MMEL)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",