legal-markdown-js 3.4.0 → 3.4.2

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.
Files changed (75) hide show
  1. package/dist/{browser-modern-BP5EJrCS.js → browser-modern-CeecamQe.js} +417 -62
  2. package/dist/browser-modern-CeecamQe.js.map +1 -0
  3. package/dist/core/pipeline/index.d.ts +3 -0
  4. package/dist/core/pipeline/index.d.ts.map +1 -1
  5. package/dist/core/pipeline/index.js +5 -0
  6. package/dist/core/pipeline/index.js.map +1 -1
  7. package/dist/core/pipeline/loops-adapter.d.ts +48 -0
  8. package/dist/core/pipeline/loops-adapter.d.ts.map +1 -0
  9. package/dist/core/pipeline/loops-adapter.js +46 -0
  10. package/dist/core/pipeline/loops-adapter.js.map +1 -0
  11. package/dist/core/pipeline/pipeline-builder.d.ts +123 -0
  12. package/dist/core/pipeline/pipeline-builder.d.ts.map +1 -0
  13. package/dist/core/pipeline/pipeline-builder.js +216 -0
  14. package/dist/core/pipeline/pipeline-builder.js.map +1 -0
  15. package/dist/core/pipeline/preprocessor-adapter.d.ts +73 -0
  16. package/dist/core/pipeline/preprocessor-adapter.d.ts.map +1 -0
  17. package/dist/core/pipeline/preprocessor-adapter.js +73 -0
  18. package/dist/core/pipeline/preprocessor-adapter.js.map +1 -0
  19. package/dist/core/utils/frontmatter-merger.d.ts.map +1 -1
  20. package/dist/core/utils/frontmatter-merger.js +36 -1
  21. package/dist/core/utils/frontmatter-merger.js.map +1 -1
  22. package/dist/core/utils/object-flattener.d.ts +34 -3
  23. package/dist/core/utils/object-flattener.d.ts.map +1 -1
  24. package/dist/core/utils/object-flattener.js +110 -17
  25. package/dist/core/utils/object-flattener.js.map +1 -1
  26. package/dist/examples/imports/frontmatter-merging/output/contract-metadata.json +2 -2
  27. package/dist/examples/imports/frontmatter-merging/output/contract-metadata.yaml +2 -2
  28. package/dist/examples/imports/frontmatter-merging/templates/output/enterprise-contract-metadata.json +2 -2
  29. package/dist/examples/imports/frontmatter-merging/templates/output/enterprise-contract-metadata.yaml +2 -2
  30. package/dist/extensions/remark/legal-markdown-processor.d.ts.map +1 -1
  31. package/dist/extensions/remark/legal-markdown-processor.js +29 -3
  32. package/dist/extensions/remark/legal-markdown-processor.js.map +1 -1
  33. package/dist/extensions/template-loops.d.ts +10 -0
  34. package/dist/extensions/template-loops.d.ts.map +1 -1
  35. package/dist/extensions/template-loops.js +155 -1
  36. package/dist/extensions/template-loops.js.map +1 -1
  37. package/dist/{web/force-commands-parser-DDda8v0G.js → force-commands-parser-C5oEpEj4.js} +2 -2
  38. package/dist/{web/force-commands-parser-DDda8v0G.js.map → force-commands-parser-C5oEpEj4.js.map} +1 -1
  39. package/dist/legal-markdown-browser.js +1 -1
  40. package/dist/legal-markdown.umd.min.js +1 -1
  41. package/dist/legal-markdown.umd.min.js.map +1 -1
  42. package/dist/plugins/remark/imports.d.ts.map +1 -1
  43. package/dist/plugins/remark/imports.js +3 -0
  44. package/dist/plugins/remark/imports.js.map +1 -1
  45. package/dist/plugins/remark/legal-headers-parser.d.ts.map +1 -1
  46. package/dist/plugins/remark/legal-headers-parser.js +153 -4
  47. package/dist/plugins/remark/legal-headers-parser.js.map +1 -1
  48. package/dist/plugins/remark/loops-ast.d.ts +44 -0
  49. package/dist/plugins/remark/loops-ast.d.ts.map +1 -0
  50. package/dist/plugins/remark/loops-ast.js +419 -0
  51. package/dist/plugins/remark/loops-ast.js.map +1 -0
  52. package/dist/plugins/remark/plugin-metadata-registry.d.ts.map +1 -1
  53. package/dist/plugins/remark/plugin-metadata-registry.js +68 -38
  54. package/dist/plugins/remark/plugin-metadata-registry.js.map +1 -1
  55. package/dist/plugins/remark/plugin-order-validator.d.ts +15 -2
  56. package/dist/plugins/remark/plugin-order-validator.d.ts.map +1 -1
  57. package/dist/plugins/remark/plugin-order-validator.js +64 -3
  58. package/dist/plugins/remark/plugin-order-validator.js.map +1 -1
  59. package/dist/plugins/remark/template-fields.d.ts.map +1 -1
  60. package/dist/plugins/remark/template-fields.js +15 -2
  61. package/dist/plugins/remark/template-fields.js.map +1 -1
  62. package/dist/plugins/remark/types.d.ts +97 -4
  63. package/dist/plugins/remark/types.d.ts.map +1 -1
  64. package/dist/plugins/remark/types.js +54 -1
  65. package/dist/plugins/remark/types.js.map +1 -1
  66. package/dist/web/{browser-modern-BP5EJrCS.js → browser-modern-CeecamQe.js} +417 -62
  67. package/dist/web/browser-modern-CeecamQe.js.map +1 -0
  68. package/dist/{force-commands-parser-DDda8v0G.js → web/force-commands-parser-C5oEpEj4.js} +2 -2
  69. package/dist/{force-commands-parser-DDda8v0G.js.map → web/force-commands-parser-C5oEpEj4.js.map} +1 -1
  70. package/dist/web/legal-markdown-browser.js +1 -1
  71. package/dist/web/legal-markdown.umd.min.js +1 -1
  72. package/dist/web/legal-markdown.umd.min.js.map +1 -1
  73. package/package.json +6 -2
  74. package/dist/browser-modern-BP5EJrCS.js.map +0 -1
  75. package/dist/web/browser-modern-BP5EJrCS.js.map +0 -1
@@ -16229,10 +16229,11 @@ function extractTemplateFields(text, patterns) {
16229
16229
  if (isInsideLoopOrConditional(text, match.index)) {
16230
16230
  continue;
16231
16231
  }
16232
+ const unescapedExpression = trimmedExpression.replace(/\\_/g, "_");
16232
16233
  fields.push({
16233
16234
  pattern: fullMatch,
16234
- fieldName: trimmedExpression,
16235
- expression: trimmedExpression,
16235
+ fieldName: unescapedExpression,
16236
+ expression: unescapedExpression,
16236
16237
  startIndex: match.index,
16237
16238
  endIndex: match.index + fullMatch.length
16238
16239
  });
@@ -17247,7 +17248,7 @@ function evaluateCondition$1(condition, metadata) {
17247
17248
  if (!sanitizedCondition) {
17248
17249
  return false;
17249
17250
  }
17250
- return evaluateSimpleCondition(sanitizedCondition, metadata);
17251
+ return evaluateSimpleCondition$1(sanitizedCondition, metadata);
17251
17252
  }
17252
17253
  function sanitizeCondition(condition) {
17253
17254
  if (/<[^>]*>/.test(condition)) {
@@ -17269,26 +17270,26 @@ function sanitizeCondition(condition) {
17269
17270
  }
17270
17271
  return condition;
17271
17272
  }
17272
- function evaluateSimpleCondition(condition, metadata) {
17273
+ function evaluateSimpleCondition$1(condition, metadata) {
17273
17274
  if (condition.includes("&&") || condition.includes("||")) {
17274
- return evaluateBooleanExpression(condition, metadata);
17275
+ return evaluateBooleanExpression$1(condition, metadata);
17275
17276
  }
17276
17277
  if (condition.includes("==") || condition.includes("!=") || condition.includes(">") || condition.includes("<")) {
17277
- return evaluateComparisonExpression(condition, metadata);
17278
+ return evaluateComparisonExpression$1(condition, metadata);
17278
17279
  }
17279
17280
  if (condition.includes(".")) {
17280
17281
  return evaluateNestedVariable(condition, metadata);
17281
17282
  }
17282
17283
  const value = metadata[condition.trim()];
17283
- return isTruthy(value);
17284
+ return isTruthy$1(value);
17284
17285
  }
17285
- function evaluateBooleanExpression(condition, metadata) {
17286
+ function evaluateBooleanExpression$1(condition, metadata) {
17286
17287
  const orParts = condition.split("||");
17287
17288
  for (const orPart of orParts) {
17288
17289
  const andParts = orPart.split("&&");
17289
17290
  let allAndTrue = true;
17290
17291
  for (const andPart of andParts) {
17291
- if (!evaluateSimpleCondition(andPart.trim(), metadata)) {
17292
+ if (!evaluateSimpleCondition$1(andPart.trim(), metadata)) {
17292
17293
  allAndTrue = false;
17293
17294
  break;
17294
17295
  }
@@ -17299,7 +17300,7 @@ function evaluateBooleanExpression(condition, metadata) {
17299
17300
  }
17300
17301
  return false;
17301
17302
  }
17302
- function evaluateComparisonExpression(condition, metadata) {
17303
+ function evaluateComparisonExpression$1(condition, metadata) {
17303
17304
  let operator = "";
17304
17305
  let leftSide = "";
17305
17306
  let rightSide = "";
@@ -17346,7 +17347,7 @@ function evaluateComparisonExpression(condition, metadata) {
17346
17347
  }
17347
17348
  function evaluateNestedVariable(condition, metadata) {
17348
17349
  const value = getNestedValue$1(metadata, condition.trim());
17349
- return isTruthy(value);
17350
+ return isTruthy$1(value);
17350
17351
  }
17351
17352
  function getVariableValue(variable, metadata) {
17352
17353
  if (variable.includes(".")) {
@@ -17370,7 +17371,7 @@ function parseValue(value, metadata) {
17370
17371
  if (value === "false") return false;
17371
17372
  return getVariableValue(value, metadata);
17372
17373
  }
17373
- function isTruthy(value) {
17374
+ function isTruthy$1(value) {
17374
17375
  if (value === null || value === void 0) return false;
17375
17376
  if (typeof value === "boolean") return value;
17376
17377
  if (typeof value === "number") return value !== 0;
@@ -20694,6 +20695,45 @@ function formatDateForYaml(date, format) {
20694
20695
  }
20695
20696
  }
20696
20697
 
20698
+ const NUMERIC_TYPED_ARRAY_TYPES = [
20699
+ Int8Array,
20700
+ Uint8Array,
20701
+ Uint8ClampedArray,
20702
+ Int16Array,
20703
+ Uint16Array,
20704
+ Int32Array,
20705
+ Uint32Array,
20706
+ Float32Array,
20707
+ Float64Array
20708
+ ];
20709
+ function isBuffer(value) {
20710
+ return typeof Buffer !== "undefined" && value instanceof Buffer;
20711
+ }
20712
+ function isBigIntTypedArray(value) {
20713
+ if (typeof BigInt64Array !== "undefined" && value instanceof BigInt64Array) {
20714
+ return true;
20715
+ }
20716
+ if (typeof BigUint64Array !== "undefined" && value instanceof BigUint64Array) {
20717
+ return true;
20718
+ }
20719
+ return false;
20720
+ }
20721
+ function isTypedArray(value) {
20722
+ return NUMERIC_TYPED_ARRAY_TYPES.some((Type) => value instanceof Type) || isBigIntTypedArray(value);
20723
+ }
20724
+ function isAtomicValue(value) {
20725
+ if (value === null || value === void 0) return true;
20726
+ if (typeof value !== "object") return true;
20727
+ if (Array.isArray(value)) return true;
20728
+ if (value instanceof Date) return true;
20729
+ if (value instanceof RegExp) return true;
20730
+ if (value instanceof Error) return true;
20731
+ if (isBuffer(value)) return true;
20732
+ if (value instanceof Set || value instanceof WeakSet) return true;
20733
+ if (value instanceof Map || value instanceof WeakMap) return true;
20734
+ if (isTypedArray(value)) return true;
20735
+ return false;
20736
+ }
20697
20737
  function flattenObject(obj, prefix = "", visited = /* @__PURE__ */ new WeakSet(), startTime = Date.now(), timeoutMs = 5e3) {
20698
20738
  if (Date.now() - startTime > timeoutMs) {
20699
20739
  const message = `Object flattening timed out after ${timeoutMs}ms. This may indicate a complex nested structure or circular references.`;
@@ -20703,7 +20743,7 @@ function flattenObject(obj, prefix = "", visited = /* @__PURE__ */ new WeakSet()
20703
20743
  return {};
20704
20744
  }
20705
20745
  const flattened = {};
20706
- if (typeof obj !== "object" || Array.isArray(obj)) {
20746
+ if (isAtomicValue(obj)) {
20707
20747
  if (prefix) {
20708
20748
  flattened[prefix] = obj;
20709
20749
  }
@@ -20719,14 +20759,10 @@ function flattenObject(obj, prefix = "", visited = /* @__PURE__ */ new WeakSet()
20719
20759
  visited.add(obj);
20720
20760
  for (const [key, value] of Object.entries(obj)) {
20721
20761
  const newKey = prefix ? `${prefix}.${key}` : key;
20722
- if (value === null || value === void 0) {
20762
+ if (isAtomicValue(value)) {
20723
20763
  flattened[newKey] = value;
20724
- } else if (Array.isArray(value)) {
20725
- flattened[newKey] = value;
20726
- } else if (typeof value === "object") {
20727
- Object.assign(flattened, flattenObject(value, newKey, visited, startTime, timeoutMs));
20728
20764
  } else {
20729
- flattened[newKey] = value;
20765
+ Object.assign(flattened, flattenObject(value, newKey, visited, startTime, timeoutMs));
20730
20766
  }
20731
20767
  }
20732
20768
  visited.delete(obj);
@@ -20948,8 +20984,12 @@ function validateMergeCompatibility(current, imported, key) {
20948
20984
  // Can parse strings as numbers
20949
20985
  ["boolean", "string"],
20950
20986
  // Can convert boolean to string
20951
- ["string", "boolean"]
20987
+ ["string", "boolean"],
20952
20988
  // Can parse strings as boolean
20989
+ ["date", "string"],
20990
+ // YAML can serialize Date as string
20991
+ ["string", "date"]
20992
+ // String can represent a date
20953
20993
  ];
20954
20994
  const isCompatible = compatibleCombinations.some(
20955
20995
  ([type1, type2]) => currentType === type1 && importedType === type2 || currentType === type2 && importedType === type1
@@ -20968,6 +21008,14 @@ function getValueType(value) {
20968
21008
  if (value === null) return "null";
20969
21009
  if (value === void 0) return "undefined";
20970
21010
  if (Array.isArray(value)) return "array";
21011
+ if (value instanceof Date) return "date";
21012
+ if (value instanceof RegExp) return "regexp";
21013
+ if (value instanceof Error) return "error";
21014
+ if (isBuffer(value)) return "buffer";
21015
+ if (value instanceof Set || value instanceof WeakSet) return "set";
21016
+ if (value instanceof Map || value instanceof WeakMap) return "map";
21017
+ if (NUMERIC_TYPED_ARRAY_TYPES.some((Type) => value instanceof Type)) return "typedarray";
21018
+ if (isBigIntTypedArray(value)) return "typedarray";
20971
21019
  return typeof value;
20972
21020
  }
20973
21021
  function mergeSequentially(initial, imports, options = {}) {
@@ -21050,6 +21098,15 @@ function checkNestedConflicts(key, importedValue, currentFlat, logOperations) {
21050
21098
  return { hasConflict: false, conflictedField: "" };
21051
21099
  }
21052
21100
 
21101
+ var ProcessingPhase = /* @__PURE__ */ ((ProcessingPhase2) => {
21102
+ ProcessingPhase2[ProcessingPhase2["CONTENT_LOADING"] = 1] = "CONTENT_LOADING";
21103
+ ProcessingPhase2[ProcessingPhase2["VARIABLE_EXPANSION"] = 2] = "VARIABLE_EXPANSION";
21104
+ ProcessingPhase2[ProcessingPhase2["CONDITIONAL_EVAL"] = 3] = "CONDITIONAL_EVAL";
21105
+ ProcessingPhase2[ProcessingPhase2["STRUCTURE_PARSING"] = 4] = "STRUCTURE_PARSING";
21106
+ ProcessingPhase2[ProcessingPhase2["POST_PROCESSING"] = 5] = "POST_PROCESSING";
21107
+ return ProcessingPhase2;
21108
+ })(ProcessingPhase || {});
21109
+
21053
21110
  const remarkImports = (options) => {
21054
21111
  const {
21055
21112
  basePath = ".",
@@ -21403,6 +21460,8 @@ async function expandMixinsInAST(nodes, metadata) {
21403
21460
  }
21404
21461
  return processedNodes;
21405
21462
  }
21463
+ ({
21464
+ phase: ProcessingPhase.CONTENT_LOADING});
21406
21465
 
21407
21466
  const LEGAL_HEADER_PATTERN = /^(l{1,9})\.\s+(.+)$/;
21408
21467
  function getHeadingLevel(pattern) {
@@ -21478,7 +21537,98 @@ const remarkLegalHeadersParser = (options = {}) => {
21478
21537
  const nodesToReplace = [];
21479
21538
  visit(tree, "paragraph", (node, index, parent) => {
21480
21539
  if (parent && typeof index === "number") {
21481
- if (node.children.length === 1 && node.children[0].type === "text") {
21540
+ if (node.children.length === 1 && node.children[0].type === "html") {
21541
+ const htmlNode = node.children[0];
21542
+ const htmlValue = htmlNode.value || "";
21543
+ if (htmlValue.includes("\n")) {
21544
+ const lines = htmlValue.split("\n");
21545
+ const hasLegalHeaders = lines.some((line) => /^(l{1,9})\.\s+/.test(line));
21546
+ if (hasLegalHeaders) {
21547
+ const newNodes = [];
21548
+ const nonHeaderLines = [];
21549
+ for (const line of lines) {
21550
+ const match = line.match(/^(l{1,9})\.\s+(.*)$/);
21551
+ if (match) {
21552
+ if (nonHeaderLines.length > 0) {
21553
+ newNodes.push({
21554
+ type: "paragraph",
21555
+ children: [
21556
+ {
21557
+ type: "html",
21558
+ value: nonHeaderLines.join("\n")
21559
+ }
21560
+ ]
21561
+ });
21562
+ nonHeaderLines.length = 0;
21563
+ }
21564
+ const [, levelPattern, remainingHtml] = match;
21565
+ const level = getHeadingLevel(levelPattern);
21566
+ if (debug) {
21567
+ console.log(
21568
+ `🔄 [remarkLegalHeadersParser] Converting HTML legal header (multiline) to level ${level} heading`
21569
+ );
21570
+ }
21571
+ const headingNode = {
21572
+ type: "heading",
21573
+ depth: level,
21574
+ children: [
21575
+ {
21576
+ type: "html",
21577
+ value: remainingHtml.trim()
21578
+ }
21579
+ ]
21580
+ };
21581
+ headingNode.data = { isLegalHeader: true };
21582
+ newNodes.push(headingNode);
21583
+ convertedCount++;
21584
+ } else {
21585
+ nonHeaderLines.push(line);
21586
+ }
21587
+ }
21588
+ if (nonHeaderLines.length > 0) {
21589
+ newNodes.push({
21590
+ type: "paragraph",
21591
+ children: [
21592
+ {
21593
+ type: "html",
21594
+ value: nonHeaderLines.join("\n")
21595
+ }
21596
+ ]
21597
+ });
21598
+ }
21599
+ if (newNodes.length > 0) {
21600
+ nodesToReplace.push({ parent, index, newNodes });
21601
+ }
21602
+ }
21603
+ } else {
21604
+ const match = htmlValue.match(/^(l{1,9})\.\s+(.*)$/);
21605
+ if (match) {
21606
+ const [, levelPattern, remainingHtml] = match;
21607
+ const level = getHeadingLevel(levelPattern);
21608
+ if (debug) {
21609
+ console.log(
21610
+ `🔄 [remarkLegalHeadersParser] Converting HTML legal header to level ${level} heading`
21611
+ );
21612
+ }
21613
+ const heading = {
21614
+ type: "heading",
21615
+ depth: level,
21616
+ children: [
21617
+ {
21618
+ type: "html",
21619
+ value: remainingHtml.trim()
21620
+ }
21621
+ ]
21622
+ };
21623
+ heading.data = {
21624
+ isLegalHeader: true,
21625
+ hProperties: {}
21626
+ };
21627
+ nodesToReplace.push({ parent, index, newNodes: [heading] });
21628
+ convertedCount++;
21629
+ }
21630
+ }
21631
+ } else if (node.children.length === 1 && node.children[0].type === "text") {
21482
21632
  const textNode = node.children[0];
21483
21633
  const lines = textNode.value.split("\n");
21484
21634
  const hasLegalHeaders = lines.some((line) => LEGAL_HEADER_PATTERN.test(line));
@@ -21645,6 +21795,25 @@ const remarkLegalHeadersParser = (options = {}) => {
21645
21795
  };
21646
21796
  function parseMarkdownInlineFormatting(text) {
21647
21797
  const children = [];
21798
+ const templateFieldRanges = [];
21799
+ const templateFieldRegex = /\{\{[^}]+\}\}/g;
21800
+ let templateMatch;
21801
+ while ((templateMatch = templateFieldRegex.exec(text)) !== null) {
21802
+ templateFieldRanges.push({
21803
+ start: templateMatch.index,
21804
+ end: templateMatch.index + templateMatch[0].length
21805
+ });
21806
+ }
21807
+ const isInsideTemplateField = (start, end) => {
21808
+ return templateFieldRanges.some(
21809
+ (range) => (
21810
+ // Match starts inside range
21811
+ start >= range.start && start < range.end || // Match ends inside range
21812
+ end > range.start && end <= range.end || // Match completely encompasses range
21813
+ start <= range.start && end >= range.end
21814
+ )
21815
+ );
21816
+ };
21648
21817
  const patterns = [
21649
21818
  { regex: /\[([^\]]+)\]\([^)]+\)/g, type: "link" },
21650
21819
  // [text](url) - extract just the text
@@ -21663,9 +21832,14 @@ function parseMarkdownInlineFormatting(text) {
21663
21832
  for (const pattern of patterns) {
21664
21833
  let match;
21665
21834
  while ((match = pattern.regex.exec(text)) !== null) {
21835
+ const matchStart = match.index;
21836
+ const matchEnd = match.index + match[0].length;
21837
+ if (isInsideTemplateField(matchStart, matchEnd)) {
21838
+ continue;
21839
+ }
21666
21840
  allMatches.push({
21667
- start: match.index,
21668
- end: match.index + match[0].length,
21841
+ start: matchStart,
21842
+ end: matchEnd,
21669
21843
  type: pattern.type,
21670
21844
  content: match[1]
21671
21845
  });
@@ -22035,6 +22209,8 @@ class PluginOrderValidator {
22035
22209
  }
22036
22210
  const circularErrors = this.detectCircularDependencies(pluginNames);
22037
22211
  errors.push(...circularErrors);
22212
+ const capabilityErrors = this.validateCapabilities(pluginNames, { debug });
22213
+ errors.push(...capabilityErrors);
22038
22214
  if (logWarnings && warnings.length > 0) {
22039
22215
  for (const warning of warnings) {
22040
22216
  console.warn(`[PluginOrderValidator] WARNING: ${warning.message}`);
@@ -22195,6 +22371,55 @@ Suggested order: ${suggestedOrder.join(" → ")}` : ""}`
22195
22371
  registerPlugin(metadata) {
22196
22372
  this.registry.set(metadata.name, metadata);
22197
22373
  }
22374
+ /**
22375
+ * Validate that all required capabilities are provided
22376
+ *
22377
+ * Checks that for each plugin's requiresCapabilities, there is at least
22378
+ * one earlier plugin in the execution order that provides that capability.
22379
+ *
22380
+ * @param pluginNames - List of plugin names in execution order
22381
+ * @param options - Validation options
22382
+ * @returns Array of capability validation errors
22383
+ */
22384
+ validateCapabilities(pluginNames, options = {}) {
22385
+ const errors = [];
22386
+ const providedCapabilities = /* @__PURE__ */ new Set();
22387
+ for (const pluginName of pluginNames) {
22388
+ const metadata = this.registry.get(pluginName);
22389
+ if (!metadata) continue;
22390
+ if (metadata.requiresCapabilities) {
22391
+ for (const requiredCap of metadata.requiresCapabilities) {
22392
+ if (!providedCapabilities.has(requiredCap)) {
22393
+ errors.push({
22394
+ type: "capability-missing",
22395
+ plugin: pluginName,
22396
+ message: `Plugin "${pluginName}" requires capability "${requiredCap}" but no earlier plugin provides it`
22397
+ });
22398
+ }
22399
+ }
22400
+ }
22401
+ if (metadata.requiresPhases && metadata.phase) {
22402
+ for (const requiredPhase of metadata.requiresPhases) {
22403
+ if (requiredPhase >= metadata.phase) {
22404
+ errors.push({
22405
+ type: "phase-dependency",
22406
+ plugin: pluginName,
22407
+ message: `Plugin "${pluginName}" (Phase ${metadata.phase}) requires Phase ${requiredPhase} which runs at the same time or later`
22408
+ });
22409
+ }
22410
+ }
22411
+ }
22412
+ if (metadata.capabilities) {
22413
+ for (const cap of metadata.capabilities) {
22414
+ providedCapabilities.add(cap);
22415
+ if (options.debug) {
22416
+ console.log(`[PluginOrderValidator] Plugin "${pluginName}" provides: ${cap}`);
22417
+ }
22418
+ }
22419
+ }
22420
+ }
22421
+ return errors;
22422
+ }
22198
22423
  }
22199
22424
  function createPluginRegistry(metadataList) {
22200
22425
  const registry = /* @__PURE__ */ new Map();
@@ -22205,96 +22430,124 @@ function createPluginRegistry(metadataList) {
22205
22430
  }
22206
22431
 
22207
22432
  const PLUGIN_METADATA_LIST = [
22208
- // Phase 1: Import Processing
22433
+ // ========== PHASE 1: CONTENT LOADING ==========
22209
22434
  {
22210
22435
  name: "remarkImports",
22436
+ phase: ProcessingPhase.CONTENT_LOADING,
22211
22437
  description: "Process @import directives and insert content as AST nodes",
22212
- runBefore: [
22213
- "remarkTemplateFields",
22214
- "remarkLegalHeadersParser",
22215
- "remarkFieldTracking",
22216
- "remarkMixins"
22217
- ],
22438
+ capabilities: ["content:imported", "metadata:merged"],
22439
+ runBefore: ["remarkLegalHeadersParser", "remarkMixins"],
22218
22440
  required: false,
22219
22441
  version: "2.0.0"
22220
22442
  // Version 2.0 uses AST-based insertion
22221
22443
  },
22222
- // Phase 2: Mixin and Field Processing
22444
+ // ========== PHASE 2: VARIABLE EXPANSION ==========
22223
22445
  {
22224
22446
  name: "remarkMixins",
22225
- description: "Process mixin definitions and expansions",
22226
- runAfter: ["remarkImports"],
22447
+ phase: ProcessingPhase.VARIABLE_EXPANSION,
22448
+ description: "Expand mixin definitions ({{variable}} patterns)",
22449
+ requiresPhases: [ProcessingPhase.CONTENT_LOADING],
22450
+ requiresCapabilities: ["metadata:merged"],
22451
+ capabilities: ["mixins:expanded"],
22227
22452
  runBefore: ["remarkTemplateFields"],
22228
22453
  required: false
22229
22454
  },
22230
22455
  {
22231
22456
  name: "remarkTemplateFields",
22457
+ phase: ProcessingPhase.VARIABLE_EXPANSION,
22232
22458
  description: "Process {{field}} template patterns and resolve values",
22233
- runAfter: ["remarkImports", "remarkMixins"],
22234
- runBefore: ["remarkFieldTracking"],
22459
+ runAfter: ["remarkMixins"],
22460
+ capabilities: ["fields:expanded", "variables:resolved"],
22235
22461
  required: true
22236
22462
  },
22237
- // Phase 3: Header Processing
22463
+ // ========== PHASE 3: CONDITIONAL EVALUATION ==========
22238
22464
  {
22239
- name: "remarkLegalHeadersParser",
22240
- description: "Parse legal header markers (l., ll., lll.) into structured headers",
22241
- runAfter: ["remarkImports"],
22242
- runBefore: ["remarkHeaders"],
22465
+ name: "processTemplateLoops",
22466
+ phase: ProcessingPhase.CONDITIONAL_EVAL,
22467
+ description: "Evaluate {{#if}}, {{#unless}}, {{#each}} conditionals",
22468
+ requiresPhases: [ProcessingPhase.VARIABLE_EXPANSION],
22469
+ requiresCapabilities: ["variables:resolved"],
22470
+ capabilities: ["conditionals:evaluated"],
22243
22471
  required: true
22244
22472
  },
22245
22473
  {
22246
- name: "remarkHeaders",
22247
- description: "Process headers and add CSS classes (legal-header-level-X)",
22248
- runAfter: ["remarkLegalHeadersParser"],
22249
- required: true
22474
+ name: "remarkClauses",
22475
+ phase: ProcessingPhase.CONDITIONAL_EVAL,
22476
+ description: "Process conditional clauses",
22477
+ capabilities: ["clauses:processed"],
22478
+ required: false
22250
22479
  },
22251
- // Phase 4: Field Tracking
22480
+ // ========== PHASE 4: STRUCTURE PARSING ==========
22252
22481
  {
22253
- name: "remarkFieldTracking",
22254
- description: "Track template fields for highlighting and analysis",
22255
- runAfter: ["remarkTemplateFields"],
22256
- required: false
22482
+ name: "remarkLegalHeadersParser",
22483
+ phase: ProcessingPhase.STRUCTURE_PARSING,
22484
+ description: "Parse legal header markers (l., ll., lll.) into structured headers",
22485
+ requiresPhases: [ProcessingPhase.CONTENT_LOADING],
22486
+ runBefore: ["remarkHeaders", "remarkCrossReferences"],
22487
+ capabilities: ["headers:parsed"],
22488
+ required: true
22257
22489
  },
22258
- // Phase 5: Cross-References and Clauses
22259
22490
  {
22260
22491
  name: "remarkCrossReferences",
22492
+ phase: ProcessingPhase.STRUCTURE_PARSING,
22261
22493
  description: "Process cross-references between document sections",
22262
- // Must run BEFORE remarkHeaders to extract |key| patterns before headers removes them
22263
- runBefore: ["remarkHeaders"],
22264
22494
  runAfter: ["remarkLegalHeadersParser"],
22265
- // After headers are parsed, before they're processed
22495
+ runBefore: ["remarkHeaders"],
22496
+ requiresCapabilities: ["headers:parsed"],
22497
+ capabilities: ["crossrefs:resolved"],
22266
22498
  required: false
22267
22499
  },
22268
22500
  {
22269
22501
  name: "remarkCrossReferencesAst",
22502
+ phase: ProcessingPhase.STRUCTURE_PARSING,
22270
22503
  description: "AST-based cross-reference processing (alternative to remarkCrossReferences)",
22271
22504
  runAfter: ["remarkHeaders", "remarkLegalHeadersParser"],
22505
+ requiresCapabilities: ["headers:parsed"],
22506
+ capabilities: ["crossrefs:resolved"],
22272
22507
  conflicts: ["remarkCrossReferences"],
22273
22508
  // Can't use both
22274
22509
  required: false
22275
22510
  },
22276
22511
  {
22277
- name: "remarkClauses",
22278
- description: "Process conditional clauses ({{#if}}, {{#unless}})",
22279
- // Note: Can run before or after remarkTemplateFields depending on use case
22280
- required: false
22512
+ name: "remarkHeaders",
22513
+ phase: ProcessingPhase.STRUCTURE_PARSING,
22514
+ description: "Number headers and add CSS classes",
22515
+ // Note: remarkLegalHeadersParser.runBefore already declares the parser→headers dependency,
22516
+ // so we don't need to duplicate it here with runAfter: ['remarkLegalHeadersParser'].
22517
+ // Declaring dependencies from both sides causes double in-degree increments in topological sort.
22518
+ runAfter: ["remarkCrossReferences"],
22519
+ requiresCapabilities: ["headers:parsed"],
22520
+ capabilities: ["headers:numbered"],
22521
+ required: true
22281
22522
  },
22282
- // Phase 6: Date Processing
22523
+ // ========== PHASE 5: POST-PROCESSING ==========
22283
22524
  {
22284
22525
  name: "remarkDates",
22526
+ phase: ProcessingPhase.POST_PROCESSING,
22285
22527
  description: "Process date fields and formatting",
22286
- // Note: Can run before or after remarkTemplateFields depending on use case
22528
+ capabilities: ["dates:formatted"],
22287
22529
  required: false
22288
22530
  },
22289
- // Phase 7: Signature Lines
22290
22531
  {
22291
22532
  name: "remarkSignatureLines",
22533
+ phase: ProcessingPhase.POST_PROCESSING,
22292
22534
  description: "Process signature line markers",
22535
+ capabilities: ["signatures:processed"],
22536
+ required: false
22537
+ },
22538
+ {
22539
+ name: "remarkFieldTracking",
22540
+ phase: ProcessingPhase.POST_PROCESSING,
22541
+ description: "Track template fields for highlighting and analysis",
22542
+ requiresPhases: [ProcessingPhase.VARIABLE_EXPANSION],
22543
+ requiresCapabilities: ["fields:expanded"],
22544
+ capabilities: ["tracking:enabled"],
22293
22545
  required: false
22294
22546
  },
22295
22547
  // Utility Plugins
22296
22548
  {
22297
22549
  name: "remarkDebugAst",
22550
+ phase: ProcessingPhase.POST_PROCESSING,
22298
22551
  description: "Debug plugin for visualizing AST structure",
22299
22552
  required: false
22300
22553
  }
@@ -22808,7 +23061,103 @@ function convertMarkdownListToHtml(content) {
22808
23061
  return content;
22809
23062
  }
22810
23063
  function evaluateCondition(condition, metadata) {
23064
+ if (condition.includes("&&") || condition.includes("||")) {
23065
+ return evaluateBooleanExpression(condition, metadata);
23066
+ }
23067
+ if (condition.includes("==") || condition.includes("!=") || condition.includes(">=") || condition.includes("<=") || condition.includes(">") || condition.includes("<")) {
23068
+ return evaluateComparisonExpression(condition, metadata);
23069
+ }
23070
+ const value = resolveVariablePath(condition, metadata);
23071
+ if (value === null || value === void 0) return false;
23072
+ if (typeof value === "boolean") return value;
23073
+ if (typeof value === "number") return value !== 0;
23074
+ if (typeof value === "string") return value.length > 0;
23075
+ if (Array.isArray(value)) return value.length > 0;
23076
+ if (typeof value === "object") return Object.keys(value).length > 0;
23077
+ return Boolean(value);
23078
+ }
23079
+ function evaluateBooleanExpression(condition, metadata) {
23080
+ const orParts = condition.split("||");
23081
+ for (const orPart of orParts) {
23082
+ const andParts = orPart.split("&&");
23083
+ let allAndTrue = true;
23084
+ for (const andPart of andParts) {
23085
+ if (!evaluateSimpleCondition(andPart.trim(), metadata)) {
23086
+ allAndTrue = false;
23087
+ break;
23088
+ }
23089
+ }
23090
+ if (allAndTrue) {
23091
+ return true;
23092
+ }
23093
+ }
23094
+ return false;
23095
+ }
23096
+ function evaluateSimpleCondition(condition, metadata) {
23097
+ if (condition.includes("==") || condition.includes("!=") || condition.includes(">=") || condition.includes("<=") || condition.includes(">") || condition.includes("<")) {
23098
+ return evaluateComparisonExpression(condition, metadata);
23099
+ }
22811
23100
  const value = resolveVariablePath(condition, metadata);
23101
+ return isTruthy(value);
23102
+ }
23103
+ function evaluateComparisonExpression(condition, metadata) {
23104
+ let operator = "";
23105
+ let leftSide = "";
23106
+ let rightSide = "";
23107
+ if (condition.includes("==")) {
23108
+ [leftSide, rightSide] = condition.split("==");
23109
+ operator = "==";
23110
+ } else if (condition.includes("!=")) {
23111
+ [leftSide, rightSide] = condition.split("!=");
23112
+ operator = "!=";
23113
+ } else if (condition.includes(">=")) {
23114
+ [leftSide, rightSide] = condition.split(">=");
23115
+ operator = ">=";
23116
+ } else if (condition.includes("<=")) {
23117
+ [leftSide, rightSide] = condition.split("<=");
23118
+ operator = "<=";
23119
+ } else if (condition.includes(">")) {
23120
+ [leftSide, rightSide] = condition.split(">");
23121
+ operator = ">";
23122
+ } else if (condition.includes("<")) {
23123
+ [leftSide, rightSide] = condition.split("<");
23124
+ operator = "<";
23125
+ }
23126
+ if (!operator || !leftSide || !rightSide) {
23127
+ return false;
23128
+ }
23129
+ const leftValue = resolveVariablePath(leftSide.trim(), metadata);
23130
+ const rightValue = parseComparisonValue(rightSide.trim(), metadata);
23131
+ switch (operator) {
23132
+ case "==":
23133
+ return leftValue == rightValue;
23134
+ case "!=":
23135
+ return leftValue != rightValue;
23136
+ case ">":
23137
+ return Number(leftValue) > Number(rightValue);
23138
+ case "<":
23139
+ return Number(leftValue) < Number(rightValue);
23140
+ case ">=":
23141
+ return Number(leftValue) >= Number(rightValue);
23142
+ case "<=":
23143
+ return Number(leftValue) <= Number(rightValue);
23144
+ default:
23145
+ return false;
23146
+ }
23147
+ }
23148
+ function parseComparisonValue(value, metadata) {
23149
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
23150
+ return value.slice(1, -1);
23151
+ }
23152
+ if (/^\d+(\.\d+)?$/.test(value)) {
23153
+ return Number(value);
23154
+ }
23155
+ if (value === "true") return true;
23156
+ if (value === "false") return false;
23157
+ if (value === "null") return null;
23158
+ return resolveVariablePath(value, metadata);
23159
+ }
23160
+ function isTruthy(value) {
22812
23161
  if (value === null || value === void 0) return false;
22813
23162
  if (typeof value === "boolean") return value;
22814
23163
  if (typeof value === "number") return value !== 0;
@@ -23045,6 +23394,12 @@ const unsafeWithoutUnderscores = [
23045
23394
  ];
23046
23395
  function escapeTemplateUnderscores(content) {
23047
23396
  return content.replace(/\{\{([^}]+)\}\}/g, (match, inner) => {
23397
+ const trimmed = inner.trim();
23398
+ if (trimmed.startsWith("#") || // {{#if}}, {{#each}}, etc.
23399
+ trimmed.startsWith("/") || // {{/if}}, {{/each}}, etc.
23400
+ trimmed === "else") {
23401
+ return match;
23402
+ }
23048
23403
  const escaped = inner.replace(/_/g, "\\_");
23049
23404
  return `{{${escaped}}}`;
23050
23405
  });
@@ -23247,7 +23602,7 @@ async function processLegalMarkdownWithRemark(content, options = {}) {
23247
23602
  ...yamlMetadata,
23248
23603
  ...options.additionalMetadata
23249
23604
  };
23250
- const { parseForceCommands, applyForceCommands } = await import('./force-commands-parser-DDda8v0G.js');
23605
+ const { parseForceCommands, applyForceCommands } = await import('./force-commands-parser-C5oEpEj4.js');
23251
23606
  let updatedOptions = { ...options };
23252
23607
  if (combinedMetadata.force_commands && typeof combinedMetadata.force_commands === "string") {
23253
23608
  const forceCommands = parseForceCommands(combinedMetadata.force_commands, combinedMetadata);
@@ -23439,4 +23794,4 @@ if (typeof window !== "undefined" && window.DEBUG_LEGAL_MARKDOWN) {
23439
23794
  }
23440
23795
 
23441
23796
  export { LegalMarkdown as L, processLegalMarkdown as a, processLegalMarkdownSync as b, extensionHelpers as e, fieldTracker as f, logger as l, processTemplateLoops as p };
23442
- //# sourceMappingURL=browser-modern-BP5EJrCS.js.map
23797
+ //# sourceMappingURL=browser-modern-CeecamQe.js.map