@forwardimpact/pathway 0.25.20 → 0.25.22

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.
@@ -1,116 +0,0 @@
1
- /**
2
- * Stage formatting for microdata HTML output
3
- *
4
- * Generates clean, class-less HTML with microdata aligned with stages.schema.json
5
- * RDF vocab: https://www.forwardimpact.team/schema/rdf/
6
- */
7
-
8
- import {
9
- openTag,
10
- prop,
11
- metaTag,
12
- linkTag,
13
- section,
14
- ul,
15
- escapeHtml,
16
- htmlDocument,
17
- } from "../microdata-shared.js";
18
- import { prepareStagesList, prepareStageDetail } from "./shared.js";
19
-
20
- /**
21
- * Format stage list as microdata HTML
22
- * @param {Array} stages - Raw stage entities
23
- * @returns {string} HTML with microdata
24
- */
25
- export function stageListToMicrodata(stages) {
26
- const { items } = prepareStagesList(stages);
27
-
28
- const content = items
29
- .map((stage) => {
30
- const handoffText =
31
- stage.handoffs.length > 0
32
- ? `→ ${stage.handoffs.map((h) => h.target).join(", ")}`
33
- : "";
34
- return `${openTag("article", { itemtype: "Stage", itemid: `#${stage.id}` })}
35
- ${prop("h2", "name", `${stage.emojiIcon} ${stage.name}`)}
36
- ${prop("p", "description", stage.truncatedDescription)}
37
- ${handoffText ? `<p>Handoffs: ${handoffText}</p>` : ""}
38
- </article>`;
39
- })
40
- .join("\n");
41
-
42
- return htmlDocument(
43
- "Stages",
44
- `<main>
45
- <h1>Stages</h1>
46
- ${content}
47
- </main>`,
48
- );
49
- }
50
-
51
- /**
52
- * Format stage detail as microdata HTML
53
- * @param {Object} stage - Raw stage entity
54
- * @returns {string} HTML with microdata
55
- */
56
- export function stageToMicrodata(stage) {
57
- const view = prepareStageDetail(stage);
58
-
59
- if (!view) return "";
60
-
61
- const sections = [];
62
-
63
- // Read checklist
64
- if (view.readChecklist.length > 0) {
65
- const readItems = view.readChecklist.map((c) => escapeHtml(c));
66
- sections.push(
67
- section("Read-Then-Do Checklist", ul(readItems, "readChecklist"), 2),
68
- );
69
- }
70
-
71
- // Constraints
72
- if (view.constraints.length > 0) {
73
- const constraintItems = view.constraints.map((c) => escapeHtml(c));
74
- sections.push(
75
- section("Constraints", ul(constraintItems, "constraints"), 2),
76
- );
77
- }
78
-
79
- // Confirm checklist
80
- if (view.confirmChecklist.length > 0) {
81
- const confirmItems = view.confirmChecklist.map((c) => escapeHtml(c));
82
- sections.push(
83
- section(
84
- "Do-Then-Confirm Checklist",
85
- ul(confirmItems, "confirmChecklist"),
86
- 2,
87
- ),
88
- );
89
- }
90
-
91
- // Handoffs - using Handoff itemtype
92
- if (view.handoffs.length > 0) {
93
- const handoffItems = view.handoffs.map(
94
- (
95
- h,
96
- ) => `${openTag("article", { itemtype: "Handoff", itemprop: "handoffs" })}
97
- ${linkTag("targetStage", `#${h.target}`)}
98
- <p><strong>${prop("span", "label", h.label)}</strong> → ${escapeHtml(h.target)}</p>
99
- ${prop("p", "prompt", h.prompt)}
100
- </article>`,
101
- );
102
- sections.push(section("Handoffs", handoffItems.join("\n"), 2));
103
- }
104
-
105
- const body = `<main>
106
- ${openTag("article", { itemtype: "Stage", itemid: `#${view.id}` })}
107
- ${prop("h1", "name", view.name)}
108
- ${metaTag("id", view.id)}
109
- ${stage.emojiIcon ? metaTag("emojiIcon", stage.emojiIcon) : ""}
110
- ${prop("p", "description", view.description)}
111
- ${sections.join("\n")}
112
- </article>
113
- </main>`;
114
-
115
- return htmlDocument(view.name, body);
116
- }
@@ -1,111 +0,0 @@
1
- /**
2
- * Track formatting for microdata HTML output
3
- *
4
- * Generates clean, class-less HTML with microdata aligned with track.schema.json
5
- * RDF vocab: https://www.forwardimpact.team/schema/rdf/
6
- */
7
-
8
- import {
9
- openTag,
10
- prop,
11
- metaTag,
12
- linkTag,
13
- section,
14
- ul,
15
- escapeHtml,
16
- htmlDocument,
17
- } from "../microdata-shared.js";
18
- import { prepareTracksList, prepareTrackDetail } from "./shared.js";
19
-
20
- /**
21
- * Format track list as microdata HTML
22
- * @param {Array} tracks - Raw track entities
23
- * @returns {string} HTML with microdata
24
- */
25
- export function trackListToMicrodata(tracks) {
26
- const { items } = prepareTracksList(tracks);
27
-
28
- const content = items
29
- .map((track) => {
30
- return `${openTag("article", { itemtype: "Track", itemid: `#${track.id}` })}
31
- ${prop("h2", "name", track.name)}
32
- </article>`;
33
- })
34
- .join("\n");
35
-
36
- return htmlDocument(
37
- "Tracks",
38
- `<main>
39
- <h1>Tracks</h1>
40
- ${content}
41
- </main>`,
42
- );
43
- }
44
-
45
- /**
46
- * Format track detail as microdata HTML
47
- * @param {Object} track - Raw track entity
48
- * @param {Object} context - Additional context
49
- * @param {Array} context.skills - All skills
50
- * @param {Array} context.behaviours - All behaviours
51
- * @param {Array} context.disciplines - All disciplines
52
- * @returns {string} HTML with microdata
53
- */
54
- export function trackToMicrodata(track, { skills, behaviours, disciplines }) {
55
- const view = prepareTrackDetail(track, { skills, behaviours, disciplines });
56
-
57
- if (!view) return "";
58
-
59
- const sections = [];
60
-
61
- // Skill modifiers - using SkillModifier itemtype with targetCapability
62
- if (view.skillModifiers.length > 0) {
63
- const modifierItems = view.skillModifiers.map((m) => {
64
- const modifierStr = m.modifier > 0 ? `+${m.modifier}` : `${m.modifier}`;
65
-
66
- if (m.isCapability && m.skills && m.skills.length > 0) {
67
- // Capability with expanded skills
68
- const skillLinks = m.skills
69
- .map(
70
- (s) => `<a href="#${escapeHtml(s.id)}">${escapeHtml(s.name)}</a>`,
71
- )
72
- .join(", ");
73
- return `${openTag("div", { itemtype: "SkillModifier", itemprop: "skillModifiers" })}
74
- ${linkTag("targetCapability", `#${m.id}`)}
75
- <strong>${escapeHtml(m.name)} Capability</strong> (${openTag("span", { itemprop: "modifierValue" })}${modifierStr}</span>)
76
- <p>${skillLinks}</p>
77
- </div>`;
78
- } else {
79
- // Individual skill or capability without skills
80
- return `${openTag("span", { itemtype: "SkillModifier", itemprop: "skillModifiers" })}
81
- ${linkTag("targetCapability", `#${m.id}`)}
82
- <strong>${escapeHtml(m.name)}</strong>: ${openTag("span", { itemprop: "modifierValue" })}${modifierStr}</span>
83
- </span>`;
84
- }
85
- });
86
- sections.push(section("Skill Modifiers", modifierItems.join("\n"), 2));
87
- }
88
-
89
- // Behaviour modifiers - using BehaviourModifier itemtype
90
- if (view.behaviourModifiers.length > 0) {
91
- const modifierItems = view.behaviourModifiers.map((b) => {
92
- const modifierStr = b.modifier > 0 ? `+${b.modifier}` : `${b.modifier}`;
93
- return `${openTag("span", { itemtype: "BehaviourModifier", itemprop: "behaviourModifiers" })}
94
- ${linkTag("targetBehaviour", `#${b.id}`)}
95
- <a href="#${escapeHtml(b.id)}">${escapeHtml(b.name)}</a>: ${openTag("span", { itemprop: "modifierValue" })}${modifierStr}</span>
96
- </span>`;
97
- });
98
- sections.push(section("Behaviour Modifiers", ul(modifierItems), 2));
99
- }
100
-
101
- const body = `<main>
102
- ${openTag("article", { itemtype: "Track", itemid: `#${view.id}` })}
103
- ${prop("h1", "name", view.name)}
104
- ${metaTag("id", view.id)}
105
- ${prop("p", "description", view.description)}
106
- ${sections.join("\n")}
107
- </article>
108
- </main>`;
109
-
110
- return htmlDocument(view.name, body);
111
- }
@@ -1,89 +0,0 @@
1
- /**
2
- * Job Cache
3
- *
4
- * Centralized caching for generated job definitions.
5
- * Provides consistent key generation and get-or-create pattern.
6
- */
7
-
8
- import { deriveJob } from "@forwardimpact/libskill/derivation";
9
-
10
- /** @type {Map<string, Object>} */
11
- const cache = new Map();
12
-
13
- /**
14
- * Build a consistent cache key from job parameters
15
- * @param {string} disciplineId
16
- * @param {string} levelId
17
- * @param {string} [trackId] - Optional track ID
18
- * @returns {string}
19
- */
20
- export function buildJobKey(disciplineId, levelId, trackId = null) {
21
- if (trackId) {
22
- return `${disciplineId}_${levelId}_${trackId}`;
23
- }
24
- return `${disciplineId}_${levelId}`;
25
- }
26
-
27
- /**
28
- * Get or create a cached job definition
29
- * @param {Object} params
30
- * @param {Object} params.discipline
31
- * @param {Object} params.level
32
- * @param {Object} [params.track] - Optional track
33
- * @param {Array} params.skills
34
- * @param {Array} params.behaviours
35
- * @param {Array} [params.capabilities]
36
- * @returns {Object|null}
37
- */
38
- export function getOrCreateJob({
39
- discipline,
40
- level,
41
- track = null,
42
- skills,
43
- behaviours,
44
- capabilities,
45
- }) {
46
- const key = buildJobKey(discipline.id, level.id, track?.id);
47
-
48
- if (!cache.has(key)) {
49
- const job = deriveJob({
50
- discipline,
51
- level,
52
- track,
53
- skills,
54
- behaviours,
55
- capabilities,
56
- });
57
- if (job) {
58
- cache.set(key, job);
59
- }
60
- return job;
61
- }
62
-
63
- return cache.get(key);
64
- }
65
-
66
- /**
67
- * Clear all cached jobs
68
- */
69
- export function clearCache() {
70
- cache.clear();
71
- }
72
-
73
- /**
74
- * Invalidate a specific job from the cache
75
- * @param {string} disciplineId
76
- * @param {string} levelId
77
- * @param {string} [trackId] - Optional track ID
78
- */
79
- export function invalidateCachedJob(disciplineId, levelId, trackId = null) {
80
- cache.delete(buildJobKey(disciplineId, levelId, trackId));
81
- }
82
-
83
- /**
84
- * Get the number of cached jobs (for testing/debugging)
85
- * @returns {number}
86
- */
87
- export function getCachedJobCount() {
88
- return cache.size;
89
- }