@bitcobblers/wod-wiki-lang 0.44.2160 → 0.45.2167

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/dist/index.mjs CHANGED
@@ -2,8 +2,9 @@ import { wallClockNow, formatDurationSmart } from './chunk-PFQDVQQO.mjs';
2
2
  export { createBrowserRuntimeNow, frozenNow, getRuntimeNowMs, wallClockNow } from './chunk-PFQDVQQO.mjs';
3
3
  import { MetricType, MetricContainer, BlockKey, REFERENCE_METADATA_KEY, ParsedCodeStatement, TAG_REFERENCE_METADATA_KEY, getReferenceMetadata, OutputStatement, valueKindOf, normalizeFieldPath, getTagReference } from '@bitcobblers/wod-wiki-core';
4
4
  import { LRParser } from '@lezer/lr';
5
- import { LRLanguage, LanguageSupport } from '@codemirror/language';
5
+ import { LRLanguage, LanguageSupport, syntaxTree } from '@codemirror/language';
6
6
  import { NodeProp } from '@lezer/common';
7
+ import { snippetCompletion, autocompletion } from '@codemirror/autocomplete';
7
8
  import { v7 } from 'uuid';
8
9
 
9
10
  // src/registry/Registry.ts
@@ -648,6 +649,40 @@ function residualMeta(effortMeta, rest) {
648
649
  raw: rest
649
650
  };
650
651
  }
652
+ var TRAILING_WORD = /^([\s\S]*?)([a-zA-Z]+)$/;
653
+ function splitTrailingWord(text) {
654
+ const m = TRAILING_WORD.exec(text.trimEnd());
655
+ if (!m) return null;
656
+ return { rest: m[1].trim(), token: m[2] };
657
+ }
658
+ function trailingResidualMeta(effortMeta, rest) {
659
+ if (!effortMeta) return effortMeta;
660
+ return {
661
+ line: effortMeta.line,
662
+ startOffset: effortMeta.startOffset,
663
+ endOffset: effortMeta.startOffset !== void 0 ? effortMeta.startOffset + rest.length : effortMeta.endOffset,
664
+ columnStart: effortMeta.columnStart,
665
+ columnEnd: effortMeta.columnStart !== void 0 ? effortMeta.columnStart + rest.length : effortMeta.columnEnd,
666
+ length: rest.length,
667
+ raw: rest
668
+ };
669
+ }
670
+ function trailingTokenMeta(effortMeta, token) {
671
+ if (!effortMeta) return effortMeta;
672
+ const tokenStart = Math.max(
673
+ 0,
674
+ (effortMeta.raw?.trimEnd().length ?? (effortMeta.endOffset ?? 0) - (effortMeta.startOffset ?? 0)) - token.length
675
+ );
676
+ return {
677
+ line: effortMeta.line,
678
+ startOffset: effortMeta.startOffset !== void 0 ? effortMeta.startOffset + tokenStart : void 0,
679
+ endOffset: effortMeta.startOffset !== void 0 ? effortMeta.startOffset + tokenStart + token.length : effortMeta.endOffset,
680
+ columnStart: effortMeta.columnStart !== void 0 ? effortMeta.columnStart + tokenStart : void 0,
681
+ columnEnd: effortMeta.columnStart !== void 0 ? effortMeta.columnStart + tokenStart + token.length : effortMeta.columnEnd,
682
+ length: token.length,
683
+ raw: token
684
+ };
685
+ }
651
686
  function spanMeta(firstMeta, lastMeta) {
652
687
  if (!firstMeta || !lastMeta) return firstMeta ?? lastMeta;
653
688
  const startOffset = firstMeta.startOffset;
@@ -784,6 +819,22 @@ function fusePairs(pairs, units) {
784
819
  }
785
820
  }
786
821
  }
822
+ if (!next) {
823
+ const text = effortText(cur.metric);
824
+ const split = text !== null ? splitTrailingWord(text) : null;
825
+ const unit = split ? units.get(split.token) : void 0;
826
+ if (split && split.rest && unit && unit.canonical === "bw") {
827
+ out.push({
828
+ metric: new EffortMetric(split.rest),
829
+ meta: trailingResidualMeta(cur.meta, split.rest)
830
+ });
831
+ out.push({
832
+ metric: metricForDimension(void 0, split.token, unit.dimension),
833
+ meta: trailingTokenMeta(cur.meta, split.token)
834
+ });
835
+ continue;
836
+ }
837
+ }
787
838
  out.push(cur);
788
839
  }
789
840
  return out;
@@ -915,6 +966,13 @@ var WodDialect = class {
915
966
  return { metrics: hintsToContainer(hints) };
916
967
  }
917
968
  };
969
+ var CARDIO_ACTIVITY_KEYWORDS = [
970
+ { keywords: ["RUN", "JOG", "SPRINT"], hints: ["workout.run", "behavior.aerobic"] },
971
+ { keywords: ["ROW", "ROWING"], hints: ["workout.row", "behavior.aerobic"] },
972
+ { keywords: ["BIKE", "CYCLE", "CYCLING"], hints: ["workout.bike", "behavior.aerobic"] },
973
+ { keywords: ["SWIM", "SWIMMING"], hints: ["workout.swim", "behavior.aerobic"] },
974
+ { keywords: ["WALK", "WALKING"], hints: ["workout.walk"] }
975
+ ];
918
976
  var CardioDialect = class {
919
977
  id = "cardio";
920
978
  name = "Cardio Dialect";
@@ -929,29 +987,10 @@ var CardioDialect = class {
929
987
  analyze(statement) {
930
988
  const hints = [];
931
989
  const metrics = MetricContainer.from(statement.metrics);
932
- if (this.hasKeyword(metrics, "RUN") || this.hasKeyword(metrics, "JOG") || this.hasKeyword(metrics, "SPRINT")) {
933
- hints.push("domain.cardio");
934
- hints.push("workout.run");
935
- hints.push("behavior.aerobic");
936
- }
937
- if (this.hasKeyword(metrics, "ROW") || this.hasKeyword(metrics, "ROWING")) {
938
- hints.push("domain.cardio");
939
- hints.push("workout.row");
940
- hints.push("behavior.aerobic");
941
- }
942
- if (this.hasKeyword(metrics, "BIKE") || this.hasKeyword(metrics, "CYCLE") || this.hasKeyword(metrics, "CYCLING")) {
943
- hints.push("domain.cardio");
944
- hints.push("workout.bike");
945
- hints.push("behavior.aerobic");
946
- }
947
- if (this.hasKeyword(metrics, "SWIM") || this.hasKeyword(metrics, "SWIMMING")) {
948
- hints.push("domain.cardio");
949
- hints.push("workout.swim");
950
- hints.push("behavior.aerobic");
951
- }
952
- if (this.hasKeyword(metrics, "WALK") || this.hasKeyword(metrics, "WALKING")) {
953
- hints.push("domain.cardio");
954
- hints.push("workout.walk");
990
+ for (const activity of CARDIO_ACTIVITY_KEYWORDS) {
991
+ if (activity.keywords.some((keyword2) => this.hasKeyword(metrics, keyword2))) {
992
+ hints.push("domain.cardio", ...activity.hints);
993
+ }
955
994
  }
956
995
  if (hints.length === 0 && this.hasDistance(metrics)) {
957
996
  hints.push("domain.cardio");
@@ -2503,7 +2542,7 @@ var WhiteboardScript = class {
2503
2542
 
2504
2543
  // src/effort-registry/types.ts
2505
2544
  var EFFORT_REGISTRY_ORIGINS = ["bundled", "user"];
2506
- var CATALOG_PRECEDENCE_RANK = {
2545
+ var SEED_PRECEDENCE_RANK = {
2507
2546
  core: 0,
2508
2547
  community: 1,
2509
2548
  imported: 2,
@@ -2519,14 +2558,14 @@ function resolveSourceTier(sourceIdOrMetaKey, explicitTier) {
2519
2558
  return "imported";
2520
2559
  }
2521
2560
  function resolveSourceRank(sourceIdOrMetaKey, explicitTier) {
2522
- return CATALOG_PRECEDENCE_RANK[resolveSourceTier(sourceIdOrMetaKey, explicitTier)];
2561
+ return SEED_PRECEDENCE_RANK[resolveSourceTier(sourceIdOrMetaKey, explicitTier)];
2523
2562
  }
2524
2563
  function resolveEntityTier(entity) {
2525
2564
  if (entity.registrySource === "user") return "user";
2526
2565
  return resolveSourceTier(entity.sourceId);
2527
2566
  }
2528
2567
  function resolveEntityRank(entity) {
2529
- return CATALOG_PRECEDENCE_RANK[resolveEntityTier(entity)];
2568
+ return SEED_PRECEDENCE_RANK[resolveEntityTier(entity)];
2530
2569
  }
2531
2570
  function dedupeEntitiesByPrecedence(entities) {
2532
2571
  const bySlug = /* @__PURE__ */ new Map();
@@ -3643,6 +3682,273 @@ tagHighlighter([
3643
3682
  { tag: tags.invalid, class: "tok-invalid" },
3644
3683
  { tag: tags.punctuation, class: "tok-punctuation" }
3645
3684
  ]);
3685
+ var whiteboardScriptSnippets = [
3686
+ {
3687
+ name: "circuit",
3688
+ label: "Circuit",
3689
+ detail: "Rounds over indented movements",
3690
+ template: "(${1:3})\n ${2:10 Air Squats}\n ${3:10 Push Ups}\n ${4:10 Ring Rows}\n${0}"
3691
+ },
3692
+ {
3693
+ name: "5x5",
3694
+ label: "5x5",
3695
+ detail: "Inline strength sets",
3696
+ template: "${1:5}x${2:5} ${3:Back Squat} @${4:100kg}\n${0}"
3697
+ },
3698
+ {
3699
+ name: "emom",
3700
+ label: "EMOM",
3701
+ detail: "Every minute on the minute",
3702
+ template: "(${1:10}) ${2::60 EMOM}\n + ${3:5 Burpees}\n + ${4:10 Kettlebell Swings 24kg}\n${0}"
3703
+ },
3704
+ {
3705
+ name: "amrap",
3706
+ label: "AMRAP",
3707
+ detail: "As many rounds as possible",
3708
+ template: "${1:10:00 AMRAP}\n ${2:5 Pull Ups}\n ${3:10 Push Ups}\n ${4:15 Air Squats}\n${0}"
3709
+ },
3710
+ {
3711
+ name: "tabata",
3712
+ label: "Tabata",
3713
+ detail: "Work/rest intervals",
3714
+ template: "(${1:8}) ${2::20 Work}\n * ${3::10 Rest}\n ${4:KB Snatch 16kg}\n${0}"
3715
+ },
3716
+ {
3717
+ name: "ladder",
3718
+ label: "Ladder",
3719
+ detail: "Rep ladder (21-15-9)",
3720
+ template: "(${1:21-15-9})\n ${2:Thrusters 95lb}\n ${3:Pull-ups}\n${0}"
3721
+ },
3722
+ {
3723
+ name: "choice",
3724
+ label: "Choice",
3725
+ detail: "Athlete choice between alternatives",
3726
+ template: "${1:10 Power Cleans 135/95 lb}\n${0}"
3727
+ },
3728
+ {
3729
+ name: "superset",
3730
+ label: "Superset",
3731
+ detail: "Compound set via + lap markers",
3732
+ template: "+ ${1:5 Pull Ups}\n+ ${2:10 Push Ups}\n${0}"
3733
+ },
3734
+ {
3735
+ name: "collectible",
3736
+ label: "Collectible",
3737
+ detail: "Measure time instead of prescribing it (:?)",
3738
+ template: "${1::? 400m Run}\n${0}"
3739
+ }
3740
+ ];
3741
+ function applyTemplateDefaults(template) {
3742
+ return template.replace(/\$\{\d+:([^}]*)\}/g, "$1").replace(/\$\{\d+\}/g, "").replace(/\$\d+/g, "");
3743
+ }
3744
+ function snippetCompletions() {
3745
+ return whiteboardScriptSnippets.map(
3746
+ (snippet) => snippetCompletion(snippet.template, {
3747
+ label: snippet.label,
3748
+ detail: snippet.detail,
3749
+ type: "text",
3750
+ boost: 10
3751
+ })
3752
+ );
3753
+ }
3754
+
3755
+ // src/parser/completion.ts
3756
+ var COMPLETION_PROPERTY_KEYS = ["effort", "equipment", ...Object.keys(PROPERTY_KEY_TO_METRIC_TYPE)];
3757
+ var STRUCTURE_KEYWORD_LABELS = ["amrap", "emom", "tabata", "for time", "rest"];
3758
+ var STRUCTURE_KEYWORD_DISPLAY = {
3759
+ "for time": "FOR TIME",
3760
+ rest: "Rest"
3761
+ };
3762
+ function unitCompletions(units, dimension) {
3763
+ return units.toArray().filter((def) => !dimension || def.dimension === dimension).flatMap((def) => [
3764
+ { label: def.canonical, detail: def.dimension, type: "unit", boost: 1 },
3765
+ ...def.aliases.map((alias) => ({ label: alias, detail: def.dimension, type: "unit" }))
3766
+ ]);
3767
+ }
3768
+ function titleCase(word) {
3769
+ return word.toLowerCase().replace(/(^|[\s])([a-z])/g, (_, lead, ch) => lead + ch.toUpperCase());
3770
+ }
3771
+ function unique(words) {
3772
+ return [...new Set(words)];
3773
+ }
3774
+ var SPORT_VOCABULARY = {
3775
+ cardio: () => unique(CARDIO_ACTIVITY_KEYWORDS.flatMap((activity) => activity.keywords)).map((word) => ({
3776
+ label: titleCase(word),
3777
+ detail: "cardio",
3778
+ type: "text"
3779
+ })),
3780
+ yoga: () => unique([
3781
+ ...YogaDialect.POSE_KEYWORDS,
3782
+ ...YogaDialect.FLOW_KEYWORDS,
3783
+ ...YogaDialect.BREATHING_KEYWORDS,
3784
+ ...YogaDialect.MEDITATION_KEYWORDS
3785
+ ]).filter((word) => /^[A-Z ]+$/.test(word)).map((word) => ({ label: titleCase(word), detail: "yoga", type: "text" })),
3786
+ habits: () => unique([...HabitsDialect.HABIT_KEYWORDS, ...HabitsDialect.STREAK_KEYWORDS]).map((word) => ({
3787
+ label: titleCase(word),
3788
+ detail: "habits",
3789
+ type: "text"
3790
+ })),
3791
+ climb: () => [
3792
+ ...unique(Object.values(SEND_ALIASES)).map((send) => ({ label: send, detail: "send", type: "text" })),
3793
+ ...unique(Object.values(DISCIPLINE_KEYWORDS)).map((discipline) => ({ label: discipline, detail: "discipline", type: "text" }))
3794
+ ]
3795
+ };
3796
+ function structureKeywords() {
3797
+ return STRUCTURE_KEYWORD_LABELS.filter((word) => STRUCTURAL_EFFORT_WORDS.has(word)).map((word) => ({
3798
+ label: STRUCTURE_KEYWORD_DISPLAY[word] ?? word.toUpperCase(),
3799
+ detail: "structure",
3800
+ type: "keyword",
3801
+ boost: 5,
3802
+ apply: STRUCTURE_KEYWORD_DISPLAY[word] ?? word.toUpperCase()
3803
+ }));
3804
+ }
3805
+ function toCompletions(values, detail, quoteValues = false) {
3806
+ return values.map((value) => ({
3807
+ label: value.label ?? value.value,
3808
+ // `Property` values only lex as String | Number | Identifier, and
3809
+ // Identifier is `[a-zA-Z][a-zA-Z0-9]*` — quote slugs it cannot represent
3810
+ // (hyphens, spaces, leading digits) so they insert parse-valid text;
3811
+ // `parsePropertyValue` unwraps the quotes when the property is consumed.
3812
+ apply: quoteValues && !/^[A-Za-z][A-Za-z0-9]*$/.test(value.value) ? JSON.stringify(value.value) : value.value,
3813
+ detail: value.detail ?? detail,
3814
+ type: "text",
3815
+ info: value.info
3816
+ }));
3817
+ }
3818
+ function dialectWords(sport) {
3819
+ if (!sport) return [];
3820
+ const vocabulary = SPORT_VOCABULARY[SPORT_ALIASES[sport] ?? sport];
3821
+ return vocabulary ? vocabulary() : [];
3822
+ }
3823
+ function ancestor(node, name2) {
3824
+ for (let current = node; current; current = current.parent) {
3825
+ if (current.name === name2) return current;
3826
+ }
3827
+ return null;
3828
+ }
3829
+ function currentStatement(context) {
3830
+ const tree = syntaxTree(context.state);
3831
+ const line = context.state.doc.lineAt(context.pos);
3832
+ if (context.pos === line.from) return null;
3833
+ const resolved = tree.resolveInner(context.pos, -1);
3834
+ const statement = ancestor(resolved, "Block") ?? ancestor(resolved, "Property");
3835
+ if (statement) return statement;
3836
+ const beforeCursor = tree.resolveInner(context.pos - 1, -1);
3837
+ return ancestor(beforeCursor, "Block") ?? ancestor(beforeCursor, "Property");
3838
+ }
3839
+ function suppliedPropertyKeys(context) {
3840
+ const keys = /* @__PURE__ */ new Set();
3841
+ for (const property of syntaxTree(context.state).topNode.getChildren("Property")) {
3842
+ const identifier = property.firstChild;
3843
+ if (identifier?.name === "Identifier") {
3844
+ keys.add(context.state.doc.sliceString(identifier.from, identifier.to).toLowerCase());
3845
+ }
3846
+ }
3847
+ return keys;
3848
+ }
3849
+ function isUnitFragment(context, fragment, units) {
3850
+ return fragment.firstChild?.name === "Effort" && units.has(context.state.doc.sliceString(fragment.from, fragment.to));
3851
+ }
3852
+ function trailingEffortRun(context, statement, units) {
3853
+ const nodes = statement?.name === "Block" ? statement.getChildren("Fragment") : [];
3854
+ let end = nodes.length;
3855
+ while (end > 0 && nodes[end - 1].from >= context.pos) end--;
3856
+ let start = end;
3857
+ while (start > 0 && nodes[start - 1].firstChild?.name === "Effort") start--;
3858
+ const run = nodes.slice(start, end);
3859
+ let firstEffort = 0;
3860
+ while (firstEffort < run.length - 1 && isUnitFragment(context, run[firstEffort], units)) firstEffort++;
3861
+ return run.slice(firstEffort);
3862
+ }
3863
+ function inNode(context, names) {
3864
+ for (let node = syntaxTree(context.state).resolveInner(context.pos, -1); node; node = node.parent) {
3865
+ if (names.has(node.name)) return true;
3866
+ }
3867
+ return false;
3868
+ }
3869
+ var SUPPRESSED_NODES = /* @__PURE__ */ new Set(["Text", "textComment", "Heading", "heading", "MetricObject"]);
3870
+ function whiteboardScriptCompletionSource(options = {}) {
3871
+ const sportWords = dialectWords(options.sport);
3872
+ const keywords = structureKeywords();
3873
+ const snippets = snippetCompletions();
3874
+ const units = options.units ?? UnitRegistry.standard();
3875
+ const allUnitOptions = unitCompletions(units);
3876
+ const massUnitOptions = unitCompletions(units, "mass");
3877
+ return async (context) => {
3878
+ if (inNode(context, SUPPRESSED_NODES)) return null;
3879
+ const pos = context.pos;
3880
+ const line = context.state.doc.lineAt(pos);
3881
+ const before = line.text.slice(0, pos - line.from);
3882
+ const word = /([A-Za-z0-9-]*)$/.exec(before)[1];
3883
+ const beforeWord = before.slice(0, before.length - word.length);
3884
+ if (beforeWord.endsWith("#") && options.tags) {
3885
+ return { from: pos - word.length, options: toCompletions(await options.tags(), "tag") };
3886
+ }
3887
+ const statement = currentStatement(context);
3888
+ if (statement?.name === "Property") {
3889
+ const keyNode = statement.firstChild;
3890
+ if (keyNode?.name !== "Identifier") return null;
3891
+ const key = context.state.doc.sliceString(keyNode.from, keyNode.to).toLowerCase();
3892
+ const value = keyNode.nextSibling;
3893
+ if (value && !value.type.isError && pos > value.to) return null;
3894
+ const source = key === "effort" ? options.efforts : key === "equipment" ? options.equipment : key === "sound" ? options.sounds : void 0;
3895
+ if (source) return { from: value && !value.type.isError ? value.from : pos, options: toCompletions(await source(), key, true) };
3896
+ return null;
3897
+ }
3898
+ const efforts = options.efforts ? toCompletions(await options.efforts(), "effort") : [];
3899
+ const effortOptions = [...keywords, ...efforts, ...sportWords];
3900
+ if (/^[ \t]*[A-Za-z][A-Za-z0-9]*$/.test(before)) {
3901
+ const supplied = suppliedPropertyKeys(context);
3902
+ return {
3903
+ from: pos - before.trimStart().length,
3904
+ options: [...COMPLETION_PROPERTY_KEYS.filter((key) => !supplied.has(key)).map((key) => ({ label: key, detail: "property", type: "property", boost: 5 })), ...snippets, ...keywords, ...efforts, ...sportWords],
3905
+ validFor: /^[A-Za-z]*$/
3906
+ };
3907
+ }
3908
+ const nodes = statement?.name === "Block" ? statement.getChildren("Fragment") : [];
3909
+ let end = nodes.length;
3910
+ while (end > 0 && nodes[end - 1].from >= pos) end--;
3911
+ const last = nodes[end - 1];
3912
+ const completingWord = last?.firstChild?.name === "Effort" && last.to === pos;
3913
+ const quantityFragment = completingWord ? nodes[end - 2] : last;
3914
+ const quantity = quantityFragment?.firstChild?.name === "Quantity" ? quantityFragment.firstChild : null;
3915
+ const incompleteAction = statement?.name === "Block" && statement.getChildren("Fragment").some(
3916
+ (fragment) => fragment.firstChild?.name === "Action" && fragment.from < (quantity?.from ?? pos) && !context.state.doc.sliceString(fragment.from, fragment.to).includes(":")
3917
+ );
3918
+ if (quantity && !incompleteAction) {
3919
+ return {
3920
+ from: completingWord ? last.from : pos,
3921
+ options: [...quantity.getChild("AtSign") ? massUnitOptions : allUnitOptions, ...effortOptions],
3922
+ validFor: /^[A-Za-z]*$/
3923
+ };
3924
+ }
3925
+ if (before.trim() === "") {
3926
+ return { from: pos, options: [...snippets, ...keywords, ...efforts, ...sportWords] };
3927
+ }
3928
+ if (word.length === 0 && /[ \t]$/.test(before)) {
3929
+ const effortRun = trailingEffortRun(context, statement, units);
3930
+ const last2 = effortRun[effortRun.length - 1];
3931
+ if (last2 && !isUnitFragment(context, last2, units)) return null;
3932
+ return { from: pos, options: effortOptions };
3933
+ }
3934
+ if (word.length > 0 && /^[A-Za-z][A-Za-z0-9'-]*$/.test(word)) {
3935
+ const effortRun = trailingEffortRun(context, statement, units);
3936
+ const first = effortRun[0];
3937
+ const last2 = effortRun[effortRun.length - 1];
3938
+ if (!first || !last2 || last2.to < pos) return null;
3939
+ const typed = context.state.doc.sliceString(first.from, pos).toLowerCase();
3940
+ const compatible = effortOptions.filter((option) => {
3941
+ const inserted = typeof option.apply === "string" ? option.apply : option.label;
3942
+ return inserted.toLowerCase().startsWith(typed);
3943
+ });
3944
+ return { from: first.from, options: compatible, validFor: /^[A-Za-z ]*$/ };
3945
+ }
3946
+ return null;
3947
+ };
3948
+ }
3949
+ function whiteboardScriptCompletion(options = {}) {
3950
+ return autocompletion({ override: [whiteboardScriptCompletionSource(options)] });
3951
+ }
3646
3952
 
3647
3953
  // src/parser/whiteboard-script-language.ts
3648
3954
  var whiteboardScriptLanguage = LRLanguage.define({
@@ -3678,8 +3984,8 @@ var whiteboardScriptLanguage = LRLanguage.define({
3678
3984
  closeBrackets: { brackets: ["(", "[", "'", '"'] }
3679
3985
  }
3680
3986
  });
3681
- function whiteboardScript() {
3682
- return new LanguageSupport(whiteboardScriptLanguage);
3987
+ function whiteboardScript(options) {
3988
+ return new LanguageSupport(whiteboardScriptLanguage, whiteboardScriptCompletion(options ?? {}));
3683
3989
  }
3684
3990
 
3685
3991
  // src/effort-registry/disciplines.ts
@@ -12713,7 +13019,12 @@ var IntervalLogicStrategy = class {
12713
13019
  const hasEmomAction = statements.some((s) => s.metrics.some(
12714
13020
  (f) => (f.type === MetricType.Action || f.type === MetricType.Effort) && typeof f.value === "string" && f.value.toLowerCase() === "emom"
12715
13021
  ));
12716
- return hasTimer && (isInterval || hasEmomAction);
13022
+ const isAmrapIdentified = statements.some(
13023
+ (s) => hasHint(s, CONSUMED_HINTS.LABEL_AMRAP) || s.metrics.some((f) => f.type === MetricType.Rounds && typeof f.value === "string" && f.value.toLowerCase() === "amrap")
13024
+ );
13025
+ const isTabataIdentified = statements.some((s) => hasHint(s, CONSUMED_HINTS.LABEL_TABATA) || s.metrics.some((f) => f.type === MetricType.Effort && typeof f.value === "string" && f.value.toLowerCase() === "tabata"));
13026
+ const hasIntervalCount = hasEmomAction || statements.some((s) => s.metrics.some((f) => f.type === MetricType.Rounds));
13027
+ return hasTimer && (isInterval || hasEmomAction) && !isAmrapIdentified && (!isTabataIdentified || hasIntervalCount);
12717
13028
  }
12718
13029
  apply(builder, statements, runtime) {
12719
13030
  const firstStatementWithTimer = statements.find((s) => s.metrics.some(
@@ -15134,6 +15445,6 @@ function compareStatement(expectations, actual, mode) {
15134
15445
  return diffs;
15135
15446
  }
15136
15447
 
15137
- export { ABSENT, AGGREGATE_BUILTINS, AUTHORITATIVE_CASTS, AbortSessionAction, AmrapLogicStrategy, AnalyticsEngine, AnalyticsTransformer, BUILTIN_CALCS, BUNDLED_EFFORT_COUNT, BehaviorContext, BlockBuilder, BlockContext, ButtonBehavior, CATALOG_PRECEDENCE_RANK, CONSUMED_HINTS, CONSUMED_HINT_KEYS, CONTEXT_ATOMS, CalcEngine, CalcEvalError, CalcParseError, CalcRegistrationError, CalcUnitError, CalculateBlockProcessor, CalculationRegistry, CardioDialect, ChildSelectionBehavior, ChildrenStrategy, ChoiceGroupMetric, ClearChildrenAction, ClimbDialect, ClimbMetricType, CompileAndPushBlockAction, CompletionTimestampBehavior, CompositeEffortRegistry, CountdownTimerBehavior, CountupTimerBehavior, CrossFitDialect, DAY, DEFAULT_RESOLVER_OPTIONS, DEFAULT_RUNTIME_OPTIONS, DEFAULT_SOUND_PROFILE, DEFAULT_UNRESOLVED_EFFORT_MET, DIM_COUNT, DIM_ENERGY, DIM_LENGTH, DIM_MASS, DIM_TIME, DIM_ZERO, DISCIPLINE_FACTORS, DialectStack, EFFORT_DATA_METRIC_TYPE, EFFORT_DISCIPLINES, EFFORT_REGISTRY_ORIGINS, EffortBlock, EffortFallbackStrategy, EffortResolver, EmitEventAction, EmitSystemOutputAction, ErrorAction, EventBus, ExecutionContext, ExitBehavior, FixtureSyntaxError, GenericGroupStrategy, GenericLoopStrategy, GenericTimerStrategy, HabitsDialect, INTENSITY_TIERS, InMemoryEffortRegistry, IntervalLogicStrategy, JitCompiler, LabelingBehavior, LocalEventProvider, LocalRuntimeSubscription, LookupRegistry, MAX_TAG_CONTRIBUTION_DEPTH, MdTimerRuntime, MemoryLocation, MemoryTypeEnum, MetricPromotionBehavior, NAMED_COMPOUNDS, NextAction, NextEvent, NextEventHandler, OutputEmitter, PRODUCTION_STRATEGIES, PopBlockAction, PushBlockAction, PushRestBlockAction, REST_EXCLUSION, RPE_LABELS, RUNTIME_LOG_SUBJECT_WIDTH, RegisterEventHandlerAction, Registry, ReportOutputBehavior, ReportOutputStrategy, RestBlock, RoundsMetric, RuntimeAdapter, RuntimeBlock, RuntimeBuilder, RuntimeClock, RuntimeFactory, RuntimeLogger, RuntimeMemory, RuntimeObservers, RuntimeStack, SOUND_PLAY_EVENT, SOUND_PROFILE_METRIC, STANDARD_UNITS, STORE_CALCS, STREAM_ATOMS, ScriptRuntime, SessionRootBlock, SessionRootStrategy, SnapshotClock, SoundProfileBehavior, SoundStrategy, SpanTrackingBehavior, StandardAnalyticsProfile, StartSessionAction, StartWorkoutAction, SubscriptionManager, TAG_MARKER_PREFIX, ThrowError, ThrowErrorAction, TimeSpan, TwoPassEffortResolutionProcess, TypedMemoryReference, UNITS, UnitRegistry, UnitSet, UnitsDialect, UnregisterEventHandlerAction, UpdateNextPreviewAction, VISIBILITY_ICONS, VISIBILITY_LABELS, WaitingToStartBlock, WaitingToStartInjectorBehavior, WhiteboardScript, WodDialect, YogaDialect, addAliasToEffort, addDim, buildStaticLookups, buildTooltip, bundledEfforts, calculateElapsed, canonicalizeType, checkCalcLine, classifyStatements, closeCurrentSpan, collapseUnresolvedChoices, commonFixtureSet, compareStatement, compileLineForm, composeDivUnit, composeMulUnit, compoundName, computeColumnLabel, computeLabel, computeWorkloadRollups, convertScalar, createAnalyticsEngineForBlock, createCalcEngine, createCalcStack, createCompiler, createDialectStack, createDisciplinesTable, createEffortTable, createLineLocator, createPolicy as createMetricPresentationPolicy, createMockClock, createParser, createProfileTable, createReferenceIndex, createRpeLabelsTable, dailySessionLoads, dayBucket, dedupeEntitiesByPrecedence, dialectRegistry, dialectStack, diffStatement, dimEquals, disciplineFactorFor, documentToEffort, documentToEquipment, effortToDocument, equipmentToDocument, evaluate, evaluateCalculateDefinitions, extractEffortData, extractMetrics, extractStatementRefs, extractStatements, extractStatementsRaw, extractSyntaxFacts, filterTagsByVisibility, findBestFuzzyMatch, findTagContributionCycles, findUnresolvedChoices, fixtureBackSquat, fixtureBurpee, fixturePlank, fixtureRowing, fixtureRunning, fixtureUserCustom, fixtureUserOverride, formatDim, formatDuration, formatRuntimeLogLine, formatRuntimeLogRule, formatRuntimeTimestamp, formatSoundTrigger, metricsToLabel as fragmentsToLabel, fullFixtureSet, fuseUnits, fuseUnitsInMetrics, getAnalyticsFromLogs, getAnalyticsFromRuntime, getHints, getMetricVisibility, getUnit, hasHint, hintMetric, hintsToContainer, inferDim, isCastSubscription, isChoiceResolved, isDimensionless, isEffortDiscipline, isFragmentTag, isTimeLikeMetric, isWithinThreshold, levenshteinDistance, metricPresentation, mutateTimerSpans, normalizeForFuzzy, num, openSpan, outputNodeId, outputNodeIds, padRuntimeLogEvent, padRuntimeLogSubject, parseCalcLine, parseCalculateBlock, parseEffortFile, parseEquipmentFile, parseExpression, parseMetricLine, parseScript, parseSoundTrigger, printCalculation, readNestedSection, readTimer, realtimeProcessorRegistry, renderMetric, resolveDominantOrigin, resolveEntityRank, resolveEntityTier, resolveProfileRules, resolveSoundProfile, resolveSourceRank, resolveSourceTier, resolveTagContributions, slugifyRefLabel, startSpan, str, strategyRegistry, subDim, summaryProcessorRegistry, tagContributionMetrics, tagMarkerSlug, tagMarkerSlugs, tagMarkerType, toStoredOutputStatement, truthy, validateOutputUnit, parser as whiteboardParser, whiteboardScript, whiteboardScriptLanguage, writeChoiceSelection };
15448
+ export { ABSENT, AGGREGATE_BUILTINS, AUTHORITATIVE_CASTS, AbortSessionAction, AmrapLogicStrategy, AnalyticsEngine, AnalyticsTransformer, BUILTIN_CALCS, BUNDLED_EFFORT_COUNT, BehaviorContext, BlockBuilder, BlockContext, ButtonBehavior, COMPLETION_PROPERTY_KEYS, CONSUMED_HINTS, CONSUMED_HINT_KEYS, CONTEXT_ATOMS, CalcEngine, CalcEvalError, CalcParseError, CalcRegistrationError, CalcUnitError, CalculateBlockProcessor, CalculationRegistry, CardioDialect, ChildSelectionBehavior, ChildrenStrategy, ChoiceGroupMetric, ClearChildrenAction, ClimbDialect, ClimbMetricType, CompileAndPushBlockAction, CompletionTimestampBehavior, CompositeEffortRegistry, CountdownTimerBehavior, CountupTimerBehavior, CrossFitDialect, DAY, DEFAULT_RESOLVER_OPTIONS, DEFAULT_RUNTIME_OPTIONS, DEFAULT_SOUND_PROFILE, DEFAULT_UNRESOLVED_EFFORT_MET, DIM_COUNT, DIM_ENERGY, DIM_LENGTH, DIM_MASS, DIM_TIME, DIM_ZERO, DISCIPLINE_FACTORS, DialectStack, EFFORT_DATA_METRIC_TYPE, EFFORT_DISCIPLINES, EFFORT_REGISTRY_ORIGINS, EffortBlock, EffortFallbackStrategy, EffortResolver, EmitEventAction, EmitSystemOutputAction, ErrorAction, EventBus, ExecutionContext, ExitBehavior, FixtureSyntaxError, GenericGroupStrategy, GenericLoopStrategy, GenericTimerStrategy, HabitsDialect, INTENSITY_TIERS, InMemoryEffortRegistry, IntervalLogicStrategy, JitCompiler, LabelingBehavior, LocalEventProvider, LocalRuntimeSubscription, LookupRegistry, MAX_TAG_CONTRIBUTION_DEPTH, MdTimerRuntime, MemoryLocation, MemoryTypeEnum, MetricPromotionBehavior, NAMED_COMPOUNDS, NextAction, NextEvent, NextEventHandler, OutputEmitter, PRODUCTION_STRATEGIES, PROPERTY_KEY_TO_METRIC_TYPE, PopBlockAction, PushBlockAction, PushRestBlockAction, REFERENCE_PAIR_KEYS, REST_EXCLUSION, RPE_LABELS, RUNTIME_LOG_SUBJECT_WIDTH, RegisterEventHandlerAction, Registry, ReportOutputBehavior, ReportOutputStrategy, RestBlock, RoundsMetric, RuntimeAdapter, RuntimeBlock, RuntimeBuilder, RuntimeClock, RuntimeFactory, RuntimeLogger, RuntimeMemory, RuntimeObservers, RuntimeStack, SEED_PRECEDENCE_RANK, SOUND_PLAY_EVENT, SOUND_PROFILE_METRIC, STANDARD_UNITS, STORE_CALCS, STREAM_ATOMS, STRUCTURAL_EFFORT_WORDS, ScriptRuntime, SessionRootBlock, SessionRootStrategy, SnapshotClock, SoundProfileBehavior, SoundStrategy, SpanTrackingBehavior, StandardAnalyticsProfile, StartSessionAction, StartWorkoutAction, SubscriptionManager, TAG_MARKER_PREFIX, ThrowError, ThrowErrorAction, TimeSpan, TwoPassEffortResolutionProcess, TypedMemoryReference, UNITS, UnitRegistry, UnitSet, UnitsDialect, UnregisterEventHandlerAction, UpdateNextPreviewAction, VISIBILITY_ICONS, VISIBILITY_LABELS, WaitingToStartBlock, WaitingToStartInjectorBehavior, WhiteboardScript, WodDialect, YogaDialect, addAliasToEffort, addDim, applyTemplateDefaults, buildStaticLookups, buildTooltip, bundledEfforts, calculateElapsed, canonicalizeType, checkCalcLine, classifyStatements, closeCurrentSpan, collapseUnresolvedChoices, commonFixtureSet, compareStatement, compileLineForm, composeDivUnit, composeMulUnit, compoundName, computeColumnLabel, computeLabel, computeWorkloadRollups, convertScalar, createAnalyticsEngineForBlock, createCalcEngine, createCalcStack, createCompiler, createDialectStack, createDisciplinesTable, createEffortTable, createLineLocator, createPolicy as createMetricPresentationPolicy, createMockClock, createParser, createProfileTable, createReferenceIndex, createRpeLabelsTable, dailySessionLoads, dayBucket, dedupeEntitiesByPrecedence, dialectRegistry, dialectStack, diffStatement, dimEquals, disciplineFactorFor, documentToEffort, documentToEquipment, effortToDocument, equipmentToDocument, evaluate, evaluateCalculateDefinitions, extractEffortData, extractMetrics, extractStatementRefs, extractStatements, extractStatementsRaw, extractSyntaxFacts, filterTagsByVisibility, findBestFuzzyMatch, findTagContributionCycles, findUnresolvedChoices, fixtureBackSquat, fixtureBurpee, fixturePlank, fixtureRowing, fixtureRunning, fixtureUserCustom, fixtureUserOverride, formatDim, formatDuration, formatRuntimeLogLine, formatRuntimeLogRule, formatRuntimeTimestamp, formatSoundTrigger, metricsToLabel as fragmentsToLabel, fullFixtureSet, fuseUnits, fuseUnitsInMetrics, getAnalyticsFromLogs, getAnalyticsFromRuntime, getHints, getMetricVisibility, getUnit, hasHint, hintMetric, hintsToContainer, inferDim, isCastSubscription, isChoiceResolved, isDimensionless, isEffortDiscipline, isFragmentTag, isTimeLikeMetric, isWithinThreshold, levenshteinDistance, metricPresentation, mutateTimerSpans, normalizeForFuzzy, num, openSpan, outputNodeId, outputNodeIds, padRuntimeLogEvent, padRuntimeLogSubject, parseCalcLine, parseCalculateBlock, parseEffortFile, parseEquipmentFile, parseExpression, parseMetricLine, parseScript, parseSoundTrigger, printCalculation, readNestedSection, readTimer, realtimeProcessorRegistry, renderMetric, resolveDominantOrigin, resolveEntityRank, resolveEntityTier, resolveProfileRules, resolveSoundProfile, resolveSourceRank, resolveSourceTier, resolveTagContributions, slugifyRefLabel, snippetCompletions, startSpan, str, strategyRegistry, subDim, summaryProcessorRegistry, tagContributionMetrics, tagMarkerSlug, tagMarkerSlugs, tagMarkerType, toStoredOutputStatement, truthy, validateOutputUnit, parser as whiteboardParser, whiteboardScript, whiteboardScriptCompletion, whiteboardScriptCompletionSource, whiteboardScriptLanguage, whiteboardScriptSnippets, writeChoiceSelection };
15138
15449
  //# sourceMappingURL=index.mjs.map
15139
15450
  //# sourceMappingURL=index.mjs.map