dsh-ensp 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Access to the curriculum index: which vendor manual chapter teaches what, and
3
+ * which commands that chapter uses to prove the result.
4
+ *
5
+ * The index holds only structure. The manuals themselves are vendor
6
+ * documentation, are hundreds of pages each, and are not redistributed with this
7
+ * package; what ships is the chapter title, the learning goals, and the
8
+ * verification commands, which is what a scenario needs to point at.
9
+ *
10
+ * @module core/curriculum
11
+ */
12
+
13
+ import { readFileSync } from 'node:fs'
14
+
15
+ let cached = null
16
+
17
+ function catalogue() {
18
+ if (!cached) {
19
+ cached = JSON.parse(readFileSync(new URL('./curriculum.json', import.meta.url), 'utf8'))
20
+ }
21
+ return cached
22
+ }
23
+
24
+ /** Levels that have chapters, in study order. */
25
+ export function curriculumLevels() {
26
+ return Object.keys(catalogue().levels)
27
+ }
28
+
29
+ /** Every chapter, optionally limited to one level. */
30
+ export function curriculumChapters(level = null) {
31
+ const { levels } = catalogue()
32
+ if (level) return [...(levels[level] || [])]
33
+ return Object.values(levels).flat()
34
+ }
35
+
36
+ /** Chapters that teach a given scenario, in study order. */
37
+ export function curriculumFor(scenarioId) {
38
+ if (!scenarioId) return []
39
+ return curriculumChapters().filter((chapter) => chapter.scenarios?.includes(scenarioId))
40
+ }
41
+
42
+ /** Chapter titles that mention a term, for a keyword search. */
43
+ export function searchCurriculum(query) {
44
+ const needle = String(query ?? '').trim().toLowerCase()
45
+ if (!needle) return []
46
+ return curriculumChapters().filter((chapter) => {
47
+ const haystack = [chapter.title, ...(chapter.goals || []), ...(chapter.verify || [])]
48
+ .join(' ')
49
+ .toLowerCase()
50
+ return haystack.includes(needle)
51
+ })
52
+ }
53
+
54
+ /**
55
+ * Markdown block for a scenario brief, or an empty string when no chapter covers
56
+ * it. Verification commands come from the manual rather than from this project,
57
+ * so they carry the authority of whatever the vendor actually checks.
58
+ */
59
+ export function renderCurriculum(scenarioId, { limit = 2 } = {}) {
60
+ const chapters = curriculumFor(scenarioId).slice(0, limit)
61
+ if (!chapters.length) return ''
62
+ const lines = ['', '## 官方教材对应章节']
63
+ for (const chapter of chapters) {
64
+ lines.push(`- ${chapter.level} · ${chapter.title}(手册第 ${chapter.page} 页)`)
65
+ if (chapter.verify?.length) {
66
+ lines.push(` 验证:${chapter.verify.slice(0, 4).join(' / ')}`)
67
+ }
68
+ }
69
+ return lines.join('\n')
70
+ }
@@ -130,6 +130,14 @@ export {
130
130
  renderKnowledge,
131
131
  } from './knowledge.mjs'
132
132
 
133
+ export {
134
+ curriculumLevels,
135
+ curriculumChapters,
136
+ curriculumFor,
137
+ searchCurriculum,
138
+ renderCurriculum,
139
+ } from './curriculum.mjs'
140
+
133
141
  export {
134
142
  resolveEnspExe,
135
143
  resolveVBoxManage,