@karagoz/hayali 0.0.0-stage → 0.6.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/LICENSE +21 -0
- package/dist/karagoz-hayali.css +3 -0
- package/dist/karagoz-hayali.js +3869 -0
- package/dist/karagoz-hayali.umd.cjs +15 -0
- package/dist/karagoz-logo.svg +3 -0
- package/dist/parse.cjs +3 -0
- package/dist/parse.js +521 -0
- package/dist/src/App.vue.d.ts +3 -0
- package/dist/src/callouts.d.ts +28 -0
- package/dist/src/components/KrgzHayali.vue.d.ts +49 -0
- package/dist/src/components/LessonToolbar.vue.d.ts +17 -0
- package/dist/src/components/StepBody.vue.d.ts +7 -0
- package/dist/src/components/StepList.vue.d.ts +15 -0
- package/dist/src/components/StepLockAlert.vue.d.ts +8 -0
- package/dist/src/components/TocDropdown.vue.d.ts +14 -0
- package/dist/src/composables/useCounter.d.ts +4 -0
- package/dist/src/composables/useIsolationWarning.d.ts +5 -0
- package/dist/src/composables/useLessonPosition.d.ts +30 -0
- package/dist/src/composables/useLessonReset.d.ts +34 -0
- package/dist/src/composables/useStepEntry.d.ts +59 -0
- package/dist/src/composables/useStepLocks.d.ts +24 -0
- package/dist/src/examples/DefaultExample.vue.d.ts +3 -0
- package/dist/src/examples/ParserExample.vue.d.ts +3 -0
- package/dist/src/i18n.d.ts +1739 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/layout/breakpoints.d.ts +16 -0
- package/dist/src/layout/layoutCss.d.ts +5 -0
- package/dist/src/lesson.d.ts +9 -0
- package/dist/src/locales/ar.d.ts +25 -0
- package/dist/src/locales/de.d.ts +25 -0
- package/dist/src/locales/en.d.ts +25 -0
- package/dist/src/locales/index.d.ts +1743 -0
- package/dist/src/main.d.ts +3 -0
- package/dist/src/parse/blocks.d.ts +31 -0
- package/dist/src/parse/body.d.ts +7 -0
- package/dist/src/parse/fenceInfo.d.ts +8 -0
- package/dist/src/parse/fileSource.d.ts +18 -0
- package/dist/src/parse/index.d.ts +2 -0
- package/dist/src/parse/parseLesson.d.ts +3 -0
- package/dist/src/parse/resolve.d.ts +37 -0
- package/dist/src/parse/tree.d.ts +11 -0
- package/dist/src/parse/types.d.ts +32 -0
- package/dist/src/typedoc-entry.d.ts +7 -0
- package/dist/src/types.d.ts +69 -0
- package/dist/src/validateLesson.d.ts +22 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +1943 -0
- package/package.json +87 -3
- package/src/layout.css +218 -0
- package/src/lib.css +50 -0
- package/README.md +0 -3
package/dist/parse.js
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import e from "markdown-it";
|
|
2
|
+
import { LineCounter as t, isMap as n, isSeq as r, parseDocument as i } from "yaml";
|
|
3
|
+
//#region src/parse/body.ts
|
|
4
|
+
var a = (e, t, n, r) => {
|
|
5
|
+
let i = [], a = !0, o = t, s = (t) => {
|
|
6
|
+
for (; o < t; o++) {
|
|
7
|
+
let t = e[o];
|
|
8
|
+
a && t.trim() === "" || (a = !1, i.push(t));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
for (let [e, t] of [...r].sort((e, t) => e[0] - t[0])) s(e), o = t, a = i.length === 0 || i[i.length - 1].trim() === "";
|
|
12
|
+
return s(n), i.join("\n").trim();
|
|
13
|
+
}, o = "krgz-", s = "krgz-lesson", c = "krgz-step", l = (e, a, o) => {
|
|
14
|
+
let s = new t(), c = i(e, { lineCounter: s }), l = (e) => {
|
|
15
|
+
let { line: t, col: n } = s.linePos(e);
|
|
16
|
+
return {
|
|
17
|
+
line: a + t - 1,
|
|
18
|
+
column: n
|
|
19
|
+
};
|
|
20
|
+
}, u = /* @__PURE__ */ new Map(), d = (e, t) => {
|
|
21
|
+
if (n(e)) for (let n of e.items) {
|
|
22
|
+
let e = String(n.key?.value), r = t ? `${t}.${e}` : e, i = n.key?.range;
|
|
23
|
+
i && u.set(r, l(i[0])), d(n.value, r);
|
|
24
|
+
}
|
|
25
|
+
else r(e) && e.items.forEach((e, n) => {
|
|
26
|
+
let r = `${t}.${n}`, i = e?.range;
|
|
27
|
+
i && u.set(r, l(i[0])), d(e, r);
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
d(c.contents, "");
|
|
31
|
+
for (let e of c.errors) o.push({
|
|
32
|
+
rule: "malformed-yaml",
|
|
33
|
+
message: e.message.split("\n")[0],
|
|
34
|
+
...l(e.pos[0])
|
|
35
|
+
});
|
|
36
|
+
let f = (e) => u.get(e) ?? {
|
|
37
|
+
line: a,
|
|
38
|
+
column: 1
|
|
39
|
+
};
|
|
40
|
+
return c.errors.length > 0 ? {
|
|
41
|
+
data: void 0,
|
|
42
|
+
at: f
|
|
43
|
+
} : c.contents === null ? {
|
|
44
|
+
data: {},
|
|
45
|
+
at: f
|
|
46
|
+
} : n(c.contents) ? {
|
|
47
|
+
data: c.toJS(),
|
|
48
|
+
at: f
|
|
49
|
+
} : (o.push({
|
|
50
|
+
rule: "invalid-value",
|
|
51
|
+
message: "A krgz block must be a YAML mapping.",
|
|
52
|
+
...f("")
|
|
53
|
+
}), {
|
|
54
|
+
data: void 0,
|
|
55
|
+
at: f
|
|
56
|
+
});
|
|
57
|
+
}, u = (e) => typeof e == "object" && !!e && !Array.isArray(e), d = (e) => Array.isArray(e) && e.every((e) => typeof e == "string"), f = /^\d+$/, p = /^(\d+)\s*-\s*(\d+)$/, m = (e) => {
|
|
58
|
+
let t = e.split(",").map((e) => e.trim()), n = [];
|
|
59
|
+
for (let e of t) {
|
|
60
|
+
let t = p.exec(e);
|
|
61
|
+
if (f.test(e)) n.push(Number(e));
|
|
62
|
+
else if (t) n.push([Number(t[1]), Number(t[2])]);
|
|
63
|
+
else return;
|
|
64
|
+
}
|
|
65
|
+
return n.length === 1 ? n[0] : n.length === 2 && n.every((e) => typeof e == "number") ? n.map((e) => [e, e]) : n;
|
|
66
|
+
}, h = (e, t, n, r) => {
|
|
67
|
+
for (let i of Object.keys(e)) t.includes(i) || r("unknown-key", n + i, `Unknown key "${i}"; expected one of ${t.join(", ")}.`);
|
|
68
|
+
}, g = (e, t) => {
|
|
69
|
+
h(e, ["immutable"], "", t);
|
|
70
|
+
let n = {};
|
|
71
|
+
return "immutable" in e && (d(e.immutable) ? n.immutable = e.immutable : t("invalid-value", "immutable", "immutable must be a list of paths.")), n;
|
|
72
|
+
}, _ = (e, t) => {
|
|
73
|
+
if (!u(e)) {
|
|
74
|
+
t("invalid-value", "editor", "editor must be a mapping.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
h(e, [
|
|
78
|
+
"open",
|
|
79
|
+
"close",
|
|
80
|
+
"highlight"
|
|
81
|
+
], "editor.", t);
|
|
82
|
+
let n = {};
|
|
83
|
+
if ("open" in e) {
|
|
84
|
+
let r = e.open;
|
|
85
|
+
Array.isArray(r) && r.every((e) => typeof e == "string" || u(e) && typeof e.path == "string" && (e.line === void 0 || typeof e.line == "number")) ? n.open = r : t("invalid-value", "editor.open", "editor.open must be a list of paths or { path, line }.");
|
|
86
|
+
}
|
|
87
|
+
if ("close" in e && (e.close === "all" || d(e.close) ? n.close = e.close : t("invalid-value", "editor.close", "editor.close must be \"all\" or a list of paths.")), "highlight" in e) {
|
|
88
|
+
let r = e.highlight;
|
|
89
|
+
if (!Array.isArray(r)) t("invalid-value", "editor.highlight", "editor.highlight must be a list of { path, lines }.");
|
|
90
|
+
else {
|
|
91
|
+
let e = [];
|
|
92
|
+
r.forEach((n, r) => {
|
|
93
|
+
let i = `editor.highlight.${r}`;
|
|
94
|
+
if (!u(n) || typeof n.path != "string") {
|
|
95
|
+
t("invalid-value", i, "Each highlight needs a path and lines.");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
h(n, ["path", "lines"], `${i}.`, t);
|
|
99
|
+
let a = n.lines;
|
|
100
|
+
if (typeof a == "string") {
|
|
101
|
+
let e = m(a);
|
|
102
|
+
if (e === void 0) {
|
|
103
|
+
t("invalid-value", `${i}.lines`, `Cannot read "${a}" as lines; use a form like 1-7, 13-17.`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
a = e;
|
|
107
|
+
}
|
|
108
|
+
if (a === void 0) {
|
|
109
|
+
t("invalid-value", i, "Each highlight needs a path and lines.");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
e.push({
|
|
113
|
+
path: n.path,
|
|
114
|
+
lines: a
|
|
115
|
+
});
|
|
116
|
+
}), n.highlight = e;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return n;
|
|
120
|
+
}, v = (e, t) => {
|
|
121
|
+
h(e, [
|
|
122
|
+
"removals",
|
|
123
|
+
"locks",
|
|
124
|
+
"editor",
|
|
125
|
+
"preview",
|
|
126
|
+
"carry"
|
|
127
|
+
], "", t);
|
|
128
|
+
let n = {};
|
|
129
|
+
"carry" in e && (typeof e.carry == "string" && e.carry !== "" ? n.carry = e.carry : t("invalid-value", "carry", "carry must be one step reference."));
|
|
130
|
+
for (let r of ["removals", "locks"]) r in e && (d(e[r]) ? n[r] = e[r] : t("invalid-value", r, `${r} must be a list of paths.`));
|
|
131
|
+
if ("editor" in e) {
|
|
132
|
+
let r = _(e.editor, t);
|
|
133
|
+
r && (n.editor = r);
|
|
134
|
+
}
|
|
135
|
+
if ("preview" in e) {
|
|
136
|
+
let r = e.preview;
|
|
137
|
+
u(r) && typeof r.url == "string" ? (h(r, ["url"], "preview.", t), n.preview = { url: r.url }) : t("invalid-value", "preview", "preview must be { url: <string> }.");
|
|
138
|
+
}
|
|
139
|
+
return n;
|
|
140
|
+
}, y = /* @__PURE__ */ new Set([
|
|
141
|
+
"file",
|
|
142
|
+
"from",
|
|
143
|
+
"src"
|
|
144
|
+
]), b = (e) => {
|
|
145
|
+
let t = [], n = /* @__PURE__ */ new Map();
|
|
146
|
+
for (let r of e.matchAll(/([^\s=]+)(?:=(?:"([^"]*)"|'([^']*)'|(\S*)))?/g)) {
|
|
147
|
+
let [, e, i, a, o] = r;
|
|
148
|
+
r[0].includes("=") ? n.set(e, i ?? a ?? o ?? "") : y.has(e) ? n.set(e, "") : t.push(e);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
words: t,
|
|
152
|
+
attrs: n
|
|
153
|
+
};
|
|
154
|
+
}, x = (e, t, n) => Object.defineProperty(e, t, {
|
|
155
|
+
value: n,
|
|
156
|
+
enumerable: !0,
|
|
157
|
+
writable: !0,
|
|
158
|
+
configurable: !0
|
|
159
|
+
}), S = (e) => e.split("/").filter((e) => e !== "" && e !== "."), C = (e) => S(e).join("/"), w = (e, t) => {
|
|
160
|
+
for (let n of e) if (n === t || n.startsWith(`${t}/`) || t.startsWith(`${n}/`)) return !0;
|
|
161
|
+
return !1;
|
|
162
|
+
}, T = (e, t, n) => {
|
|
163
|
+
let r = S(t), i = r.pop();
|
|
164
|
+
if (i === void 0) return;
|
|
165
|
+
let a = e;
|
|
166
|
+
for (let e of r) {
|
|
167
|
+
let t = Object.getOwnPropertyDescriptor(a, e)?.value;
|
|
168
|
+
if (t && "directory" in t) {
|
|
169
|
+
a = t.directory;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
let n = {};
|
|
173
|
+
x(a, e, { directory: n }), a = n;
|
|
174
|
+
}
|
|
175
|
+
x(a, i, { file: { contents: n } });
|
|
176
|
+
}, E = (e) => {
|
|
177
|
+
if (e === "" || e.startsWith("/") || e.includes("\\") || /^[A-Za-z]:/.test(e)) return;
|
|
178
|
+
let t = [];
|
|
179
|
+
for (let n of e.split("/")) if (!(n === "" || n === ".")) if (n === "..") {
|
|
180
|
+
if (t.pop() === void 0) return;
|
|
181
|
+
} else t.push(n);
|
|
182
|
+
return t.length > 0 ? t.join("/") : void 0;
|
|
183
|
+
}, D = (e, { fail: t, resolveSrc: n, srcPaths: r }) => {
|
|
184
|
+
let { attrs: i, content: a, path: o } = e, s = i.get("from"), c = i.get("src"), l = a.trim() !== "";
|
|
185
|
+
if (s !== void 0 && c !== void 0) {
|
|
186
|
+
t("conflicting-file-source", `"${o}" cannot take its content from both from= and src=.`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (s !== void 0) {
|
|
190
|
+
if (!l) return {
|
|
191
|
+
kind: "from",
|
|
192
|
+
ref: s
|
|
193
|
+
};
|
|
194
|
+
t("ref-with-body", `"${o}" reuses another step's file, so its fence must be empty.`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (c === void 0) return {
|
|
198
|
+
kind: "literal",
|
|
199
|
+
contents: a
|
|
200
|
+
};
|
|
201
|
+
if (l) {
|
|
202
|
+
t("src-with-body", `"${o}" takes its content from src=, so its fence must be empty.`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
let u = E(c);
|
|
206
|
+
if (u === void 0) {
|
|
207
|
+
t("invalid-src", `src="${c}" must be a relative path inside the lesson's folder.`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
let d;
|
|
211
|
+
if (n) {
|
|
212
|
+
r.includes(u) || r.push(u);
|
|
213
|
+
try {
|
|
214
|
+
d = n(u);
|
|
215
|
+
} catch {
|
|
216
|
+
d = void 0;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (typeof d != "string") {
|
|
220
|
+
t("unresolved-src", `Could not read src="${u}" for "${o}".`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
kind: "literal",
|
|
225
|
+
contents: d
|
|
226
|
+
};
|
|
227
|
+
}, O = (e, t, n) => {
|
|
228
|
+
let r = /* @__PURE__ */ new Map();
|
|
229
|
+
for (let e of t) r.set(`${e.chapterId}/${e.stepId}`, e);
|
|
230
|
+
let i = (t, n, i = !0) => {
|
|
231
|
+
if (n === "base" && i) return e;
|
|
232
|
+
let a = n.split("/");
|
|
233
|
+
if (a.length === 2) return r.get(n);
|
|
234
|
+
if (a.length === 1 && t.chapterId !== void 0) return r.get(`${t.chapterId}/${n}`);
|
|
235
|
+
}, a = (e) => ({
|
|
236
|
+
chapterId: e.chapterId,
|
|
237
|
+
stepId: e.stepId,
|
|
238
|
+
column: e.carry?.column
|
|
239
|
+
});
|
|
240
|
+
for (let e of t) {
|
|
241
|
+
if (!e.carry) continue;
|
|
242
|
+
let t = i(e, e.carry.ref, !1);
|
|
243
|
+
t ? e.carryTarget = t : n("carry-unknown-step", e.carry.line, `No step "${e.carry.ref}" to carry.`, a(e));
|
|
244
|
+
}
|
|
245
|
+
let o = /* @__PURE__ */ new Set();
|
|
246
|
+
for (let e of t) {
|
|
247
|
+
let t = [], r = e;
|
|
248
|
+
for (; r && !o.has(r);) {
|
|
249
|
+
if (t.includes(r)) {
|
|
250
|
+
n("carry-cycle", r.carry?.line ?? 0, `Carrying "${r.carry?.ref}" leads back to this step.`, a(r)), r.carryTarget = void 0;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
t.push(r), r = r.carryTarget;
|
|
254
|
+
}
|
|
255
|
+
for (let e of t) o.add(e);
|
|
256
|
+
}
|
|
257
|
+
for (let e of t) {
|
|
258
|
+
let t = e.carryTarget;
|
|
259
|
+
if (!t) continue;
|
|
260
|
+
let r = new Set(e.removals), i = (t.removals ?? []).filter((e) => !r.has(e));
|
|
261
|
+
i.length > 0 && n("carry-drops-removals", e.carry?.line ?? 0, `"${e.carry?.ref}" removes ${i.join(", ")}, which this step carries back in.`, {
|
|
262
|
+
...a(e),
|
|
263
|
+
severity: "warning"
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
let s = (e, t) => {
|
|
267
|
+
let n = e.entries.get(t);
|
|
268
|
+
return n ? {
|
|
269
|
+
scope: e,
|
|
270
|
+
entry: n
|
|
271
|
+
} : e.carryTarget ? s(e.carryTarget, t) : void 0;
|
|
272
|
+
}, c = (e) => [.../* @__PURE__ */ new Set([...e.carryTarget ? c(e.carryTarget) : [], ...e.entries.keys()])], l = /* @__PURE__ */ new Map(), u = (e, t) => {
|
|
273
|
+
let r = {
|
|
274
|
+
chapterId: e.chapterId,
|
|
275
|
+
stepId: e.stepId,
|
|
276
|
+
path: t.path
|
|
277
|
+
}, a = l.get(t);
|
|
278
|
+
if (a) return a.done || n("ref-cycle", t.line, `"${t.path}" refers back to itself.`, r), a.value;
|
|
279
|
+
let o = { done: !1 };
|
|
280
|
+
if (l.set(t, o), t.source.kind === "literal") o.value = t.source.contents;
|
|
281
|
+
else {
|
|
282
|
+
let a = i(e, t.source.ref), c = a && s(a, t.path);
|
|
283
|
+
a ? c ? o.value = u(c.scope, c.entry) : n("ref-missing-path", t.line, `"${t.source.ref}" has no "${t.path}" of its own to reuse.`, r) : n("ref-unknown-step", t.line, `No step "${t.source.ref}" to reuse "${t.path}" from.`, r);
|
|
284
|
+
}
|
|
285
|
+
return o.done = !0, o.value;
|
|
286
|
+
}, d = /* @__PURE__ */ new Map();
|
|
287
|
+
for (let n of [e, ...t]) for (let e of c(n)) {
|
|
288
|
+
let t = s(n, e), r = t && u(t.scope, t.entry);
|
|
289
|
+
if (r === void 0) continue;
|
|
290
|
+
let i = d.get(n);
|
|
291
|
+
i || d.set(n, i = {}), T(i, e, r);
|
|
292
|
+
}
|
|
293
|
+
return d;
|
|
294
|
+
}, k = new e(), A = /^[A-Za-z0-9_-]+$/, j = /^(.*?)\s*\{#([^{}]*)\}\s*$/, M = (e, t) => {
|
|
295
|
+
let n = e.replace(/^(\s*>)*\s*/, "").trimEnd(), r = t[0];
|
|
296
|
+
return n.length >= t.length && [...n].every((e) => e === r);
|
|
297
|
+
}, N = (e) => e.type === "heading_open" && e.level === 0 && (e.tag === "h1" || e.tag === "h2"), P = (e, { resolveSrc: t } = {}) => {
|
|
298
|
+
let n = [], r = [], i = (e, t, r, i = {}) => n.push({
|
|
299
|
+
rule: e,
|
|
300
|
+
severity: "error",
|
|
301
|
+
message: r,
|
|
302
|
+
line: t + 1,
|
|
303
|
+
...i
|
|
304
|
+
}), u = e.split(/\r\n|\r|\n/), d = [];
|
|
305
|
+
try {
|
|
306
|
+
d = k.parse(e, {});
|
|
307
|
+
} catch {
|
|
308
|
+
d = [];
|
|
309
|
+
}
|
|
310
|
+
for (let e of d) {
|
|
311
|
+
if (e.type !== "fence" || !e.map) continue;
|
|
312
|
+
let [t, n] = e.map;
|
|
313
|
+
(n - t < 2 || !M(u[n - 1] ?? "", e.markup)) && i("unclosed-fence", t, "Code fence is never closed.");
|
|
314
|
+
}
|
|
315
|
+
let f = [];
|
|
316
|
+
d.forEach((e, t) => {
|
|
317
|
+
!N(e) || !e.map || f.push({
|
|
318
|
+
level: e.tag === "h1" ? 1 : 2,
|
|
319
|
+
line: e.map[0],
|
|
320
|
+
text: d[t + 1]?.content ?? ""
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
let p = [], m, h = !1, _ = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map();
|
|
324
|
+
f.forEach((e, t) => {
|
|
325
|
+
let n = f[t + 1], r = e.level === 1 ? "Chapter" : "Step", a = j.exec(e.text), o = m && e.level === 2 ? { chapterId: m.id } : {}, s;
|
|
326
|
+
if (a ? A.test(a[2]) ? s = a[2] : i("invalid-id", e.line, `${r} id "${a[2]}" must match [A-Za-z0-9_-]+.`, o) : i("missing-id", e.line, `${r} heading needs an {#id}.`, o), e.level === 1) {
|
|
327
|
+
if (h = s === void 0, m = void 0, s === void 0) return;
|
|
328
|
+
if (p.some((e) => e.id === s)) {
|
|
329
|
+
h = !0, i("duplicate-id", e.line, `Chapter id "${s}" is used twice.`, { chapterId: s });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
m = {
|
|
333
|
+
id: s,
|
|
334
|
+
title: a[1],
|
|
335
|
+
steps: []
|
|
336
|
+
}, p.push(m), y.set(m, e.line), S.set(e, { chapter: m });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (!m) {
|
|
340
|
+
h || i("step-outside-chapter", e.line, "Step heading comes before any chapter heading.");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (s === void 0) return;
|
|
344
|
+
if (m.steps.some((e) => e.id === s)) {
|
|
345
|
+
i("duplicate-id", e.line, `Step id "${s}" is used twice.`, {
|
|
346
|
+
chapterId: m.id,
|
|
347
|
+
stepId: s
|
|
348
|
+
});
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
let c = {
|
|
352
|
+
id: s,
|
|
353
|
+
title: a[1],
|
|
354
|
+
body: ""
|
|
355
|
+
};
|
|
356
|
+
m.steps.push(c), S.set(e, {
|
|
357
|
+
step: c,
|
|
358
|
+
chapter: m
|
|
359
|
+
}), x.set(c, {
|
|
360
|
+
chapterId: m.id,
|
|
361
|
+
stepId: c.id,
|
|
362
|
+
entries: /* @__PURE__ */ new Map()
|
|
363
|
+
}), _.set(c, {
|
|
364
|
+
start: e.line + 1,
|
|
365
|
+
end: n?.line ?? u.length
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
let T = (e) => {
|
|
369
|
+
let t = "base";
|
|
370
|
+
for (let n of f) {
|
|
371
|
+
if (n.line > e) break;
|
|
372
|
+
t = S.get(n) ?? "rejected";
|
|
373
|
+
}
|
|
374
|
+
return t;
|
|
375
|
+
}, E = { entries: /* @__PURE__ */ new Map() }, P = /* @__PURE__ */ new Map(), F = (e, t) => {
|
|
376
|
+
if (!e) return;
|
|
377
|
+
let n = P.get(e) ?? [];
|
|
378
|
+
n.push(t), P.set(e, n);
|
|
379
|
+
}, I = !1, L = /* @__PURE__ */ new Set(), R = {}, z = (e, t, r, a) => {
|
|
380
|
+
let o = e.map[0], u = r === "base" ? void 0 : r.step;
|
|
381
|
+
if (t !== "krgz-lesson" && t !== "krgz-step") {
|
|
382
|
+
i("unknown-fence", o, `Unknown fence "${t}".`, a);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (t === "krgz-lesson") {
|
|
386
|
+
if (r !== "base") {
|
|
387
|
+
i("misplaced-lesson-block", o, `${s} must come before the first chapter heading.`, a);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (I) {
|
|
391
|
+
i("duplicate-lesson-block", o, `Only one ${s} block is allowed.`);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
I = !0;
|
|
395
|
+
} else {
|
|
396
|
+
if (!u) {
|
|
397
|
+
i("misplaced-step-block", o, `${c} must sit inside a step.`, a);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (L.has(u)) {
|
|
401
|
+
i("duplicate-step-block", o, `Only one ${c} block is allowed per step.`, a);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
L.add(u);
|
|
405
|
+
}
|
|
406
|
+
let d = [], f = l(e.content, o + 1, d), p = (e, t, n) => d.push({
|
|
407
|
+
rule: e,
|
|
408
|
+
message: n,
|
|
409
|
+
...f.at(t)
|
|
410
|
+
});
|
|
411
|
+
if (f.data) if (u) {
|
|
412
|
+
let { carry: e, ...t } = v(f.data, p);
|
|
413
|
+
Object.assign(u, t);
|
|
414
|
+
let n = x.get(u);
|
|
415
|
+
n && (n.removals = (t.removals ?? []).map(C), e && (n.carry = {
|
|
416
|
+
ref: e,
|
|
417
|
+
...f.at("carry")
|
|
418
|
+
}));
|
|
419
|
+
} else R = g(f.data, p);
|
|
420
|
+
for (let e of d) n.push({
|
|
421
|
+
rule: e.rule,
|
|
422
|
+
severity: "error",
|
|
423
|
+
message: e.message,
|
|
424
|
+
line: e.line + 1,
|
|
425
|
+
column: e.column,
|
|
426
|
+
...a
|
|
427
|
+
});
|
|
428
|
+
}, B = (e, n, a, o) => {
|
|
429
|
+
let s = e.map[0], c = a === "base" ? void 0 : a.step;
|
|
430
|
+
if (a !== "base" && !c) {
|
|
431
|
+
i("file-outside-step", s, "A file fence must sit inside a step or before the first chapter.", o);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
let l = C(n.get("file") ?? "");
|
|
435
|
+
if (l === "") {
|
|
436
|
+
i("missing-file-path", s, "File fence needs file=<path>.", o);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
let u = (e, t) => i(e, s, t, {
|
|
440
|
+
...o,
|
|
441
|
+
path: l
|
|
442
|
+
}), d = c && x.get(c) || E;
|
|
443
|
+
if (w(d.entries.keys(), l)) {
|
|
444
|
+
u("duplicate-file", `File "${l}" is defined twice.`);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
let f = D({
|
|
448
|
+
attrs: n,
|
|
449
|
+
content: e.content,
|
|
450
|
+
path: l
|
|
451
|
+
}, {
|
|
452
|
+
fail: u,
|
|
453
|
+
resolveSrc: t,
|
|
454
|
+
srcPaths: r
|
|
455
|
+
});
|
|
456
|
+
f && d.entries.set(l, {
|
|
457
|
+
path: l,
|
|
458
|
+
line: s,
|
|
459
|
+
source: f
|
|
460
|
+
});
|
|
461
|
+
};
|
|
462
|
+
for (let e of d) {
|
|
463
|
+
if (e.type !== "fence" || e.level !== 0 || !e.map) continue;
|
|
464
|
+
let { words: t, attrs: n } = b(e.info), r = t.find((e) => e.startsWith(o));
|
|
465
|
+
if (!r && !n.has("file")) continue;
|
|
466
|
+
let i = T(e.map[0]);
|
|
467
|
+
if (i === "rejected") continue;
|
|
468
|
+
let a = i === "base" ? void 0 : i.step, s = i === "base" ? {} : {
|
|
469
|
+
chapterId: i.chapter.id,
|
|
470
|
+
stepId: a?.id
|
|
471
|
+
};
|
|
472
|
+
F(a, [e.map[0], e.map[1]]), r ? z(e, r, i, s) : B(e, n, i, s);
|
|
473
|
+
}
|
|
474
|
+
let V = O(E, [...x.values()], i);
|
|
475
|
+
for (let [e, { start: t, end: n }] of _) {
|
|
476
|
+
e.body = a(u, t, n, P.get(e) ?? []);
|
|
477
|
+
let r = V.get(x.get(e));
|
|
478
|
+
r && (e.adjustments = r);
|
|
479
|
+
}
|
|
480
|
+
for (let e of p) e.steps.length > 0 || i("empty-chapter", y.get(e) ?? 0, `Chapter "${e.id}" has no steps.`, { chapterId: e.id });
|
|
481
|
+
let H = {
|
|
482
|
+
chapters: p,
|
|
483
|
+
...R
|
|
484
|
+
}, U = V.get(E);
|
|
485
|
+
return U && (H.files = U), {
|
|
486
|
+
lesson: H,
|
|
487
|
+
issues: n.sort((e, t) => e.line - t.line),
|
|
488
|
+
srcPaths: r,
|
|
489
|
+
locate: ({ chapterId: e, stepId: t, path: n }) => {
|
|
490
|
+
let r = p.find((t) => t.id === e);
|
|
491
|
+
if (!r) return;
|
|
492
|
+
let i = (y.get(r) ?? 0) + 1;
|
|
493
|
+
if (t === void 0) {
|
|
494
|
+
let e = n && E.entries.get(C(n));
|
|
495
|
+
return e ? e.line + 1 : i;
|
|
496
|
+
}
|
|
497
|
+
let a = r.steps.find((e) => e.id === t), o = a && _.get(a);
|
|
498
|
+
if (!a || !o) return;
|
|
499
|
+
let s = n && x.get(a)?.entries.get(C(n));
|
|
500
|
+
return s ? s.line + 1 : o.start;
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}, F = (e, t = {}) => {
|
|
504
|
+
try {
|
|
505
|
+
return P(e, t);
|
|
506
|
+
} catch (e) {
|
|
507
|
+
return {
|
|
508
|
+
lesson: { chapters: [] },
|
|
509
|
+
issues: [{
|
|
510
|
+
rule: "parser-failure",
|
|
511
|
+
severity: "error",
|
|
512
|
+
message: `The lesson file could not be parsed: ${String(e)}`,
|
|
513
|
+
line: 1
|
|
514
|
+
}],
|
|
515
|
+
srcPaths: [],
|
|
516
|
+
locate: () => void 0
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
//#endregion
|
|
521
|
+
export { F as parseLesson };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type AlertVariants } from '@karagoz/shared';
|
|
2
|
+
import type { PluginSimple } from 'markdown-it';
|
|
3
|
+
export interface CalloutDefinition {
|
|
4
|
+
variant: NonNullable<AlertVariants['variant']>;
|
|
5
|
+
}
|
|
6
|
+
export interface CalloutRegistry {
|
|
7
|
+
/** Registers (or replaces) a callout kind, e.g. `:::tip`. */
|
|
8
|
+
register: (kind: string, definition: CalloutDefinition) => void;
|
|
9
|
+
get: (kind: string) => CalloutDefinition | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare const defaultCallouts: Record<string, CalloutDefinition>;
|
|
12
|
+
export declare function createCalloutRegistry(initial?: Record<string, CalloutDefinition>): CalloutRegistry;
|
|
13
|
+
/** Splits a container info string (`tip Custom title`) into kind and optional title. */
|
|
14
|
+
export declare function parseCalloutInfo(info: string): {
|
|
15
|
+
kind: string;
|
|
16
|
+
title: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Pure transform: callout info string → opening HTML using the shared Alert
|
|
20
|
+
* styling, or `undefined` when the kind is not registered.
|
|
21
|
+
*/
|
|
22
|
+
export declare function renderCalloutOpen(registry: CalloutRegistry, info: string, escape: (text: string) => string): string | undefined;
|
|
23
|
+
export declare const CALLOUT_CLOSE_HTML = "</div></div>";
|
|
24
|
+
/**
|
|
25
|
+
* markdown-it plugin recognising `:::kind [title]` ... `:::` blocks for every
|
|
26
|
+
* kind in the registry. Unregistered kinds are left as plain markdown.
|
|
27
|
+
*/
|
|
28
|
+
export declare function calloutPlugin(registry: CalloutRegistry): PluginSimple;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { FullLayoutFrom } from '../layout/breakpoints';
|
|
2
|
+
import type { Lesson, Position } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
lesson: Lesson;
|
|
5
|
+
/**
|
|
6
|
+
* Minimum container width for the side-by-side lesson/sandbox split; below it a single panel is shown
|
|
7
|
+
* with a Lesson/Sandbox toggle. Uses the component's own width (container query), not the viewport's.
|
|
8
|
+
* `none` always uses the single-panel layout.
|
|
9
|
+
* **Available values:** none, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl
|
|
10
|
+
*/
|
|
11
|
+
fullLayoutFrom?: FullLayoutFrom;
|
|
12
|
+
/**
|
|
13
|
+
* Forwarded to the default `KrgzSandbox` (and exposed on the `sandbox` slot) as its `multi-panel-from`,
|
|
14
|
+
* so the sandbox drops to a single panel when its pane is narrow.
|
|
15
|
+
* **Available values:** none, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl
|
|
16
|
+
*/
|
|
17
|
+
multiPanelFrom?: FullLayoutFrom;
|
|
18
|
+
};
|
|
19
|
+
type __VLS_ModelProps = {
|
|
20
|
+
/**
|
|
21
|
+
* Current step. Optional so a server render needs nothing from the consumer: it falls back to the first step of the
|
|
22
|
+
* first chapter (never restored from `localStorage`).
|
|
23
|
+
*/
|
|
24
|
+
'position'?: Position;
|
|
25
|
+
};
|
|
26
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
27
|
+
declare var __VLS_55: {
|
|
28
|
+
ready: boolean;
|
|
29
|
+
multiPanelFrom: FullLayoutFrom;
|
|
30
|
+
};
|
|
31
|
+
type __VLS_Slots = {} & {
|
|
32
|
+
sandbox?: (props: typeof __VLS_55) => any;
|
|
33
|
+
};
|
|
34
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
35
|
+
"update:position": (value: Position | undefined) => any;
|
|
36
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
37
|
+
"onUpdate:position"?: ((value: Position | undefined) => any) | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
fullLayoutFrom: FullLayoutFrom;
|
|
40
|
+
multiPanelFrom: FullLayoutFrom;
|
|
41
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
42
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
43
|
+
declare const _default: typeof __VLS_export;
|
|
44
|
+
export default _default;
|
|
45
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
46
|
+
new (): {
|
|
47
|
+
$slots: S;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { StepGroup } from '../composables/useLessonPosition';
|
|
2
|
+
import type { Position } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
prev?: Position;
|
|
5
|
+
next?: Position;
|
|
6
|
+
groups: StepGroup[];
|
|
7
|
+
current: Position;
|
|
8
|
+
chapterTitle?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
navigate: (position: Position) => any;
|
|
13
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
14
|
+
onNavigate?: ((position: Position) => any) | undefined;
|
|
15
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** Step markdown body. */
|
|
3
|
+
body: string;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PathPattern, Step } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
steps: Step[];
|
|
4
|
+
currentStepId: string;
|
|
5
|
+
/** Lock patterns of the current step. */
|
|
6
|
+
locks: PathPattern[];
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
select: (stepId: string) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onSelect?: ((stepId: string) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PathPattern } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
/** Lock patterns of the current step. */
|
|
4
|
+
locks: PathPattern[];
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StepGroup } from '../composables/useLessonPosition';
|
|
2
|
+
import type { Position } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
groups: StepGroup[];
|
|
5
|
+
current: Position;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
select: (position: Position) => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onSelect?: ((position: Position) => any) | undefined;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|