@learnmd/cli 0.0.1-beta.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/README.md +24 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +93 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/add.test.d.ts +2 -0
- package/dist/commands/add.test.d.ts.map +1 -0
- package/dist/commands/add.test.js +35 -0
- package/dist/commands/add.test.js.map +1 -0
- package/dist/commands/build.d.ts +7 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +89 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +7 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +307 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +42 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +67 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 LearnMD Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# š @learnmd/cli
|
|
2
|
+
|
|
3
|
+
The command-line tool for scaffolding and managing LearnMD projects. It streamlines the creation of multi-course workspaces and individual lessons.
|
|
4
|
+
|
|
5
|
+
## š Commands
|
|
6
|
+
|
|
7
|
+
### `learnmd create [name]`
|
|
8
|
+
Scaffolds a new LearnMD project with MDX and Vite pre-configured.
|
|
9
|
+
|
|
10
|
+
### `learnmd add course <name>`
|
|
11
|
+
Adds a new course project/module to the workspace.
|
|
12
|
+
|
|
13
|
+
### `learnmd add lesson <title>`
|
|
14
|
+
Generates a new `.mdx` lesson file with standard frontmatter in the current project.
|
|
15
|
+
|
|
16
|
+
### `learnmd dev`
|
|
17
|
+
Starts the development server for the current course.
|
|
18
|
+
|
|
19
|
+
### `learnmd build`
|
|
20
|
+
Compiles the course for production.
|
|
21
|
+
|
|
22
|
+
## šļø Scaffolding Logic
|
|
23
|
+
|
|
24
|
+
The CLI generates a optimized Vite project that uses `import.meta.glob` to automatically discover and compile MDX lessons, ensuring zero-config content management.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAeA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,iBAqBlD;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAAsB,iBA2DvF"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { writeFile, mkdir, readFile } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
async function checkIfInLearnMDWorkspace() {
|
|
5
|
+
try {
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const rootPackageJson = await readFile(join(cwd, 'package.json'), 'utf-8');
|
|
8
|
+
const pkg = JSON.parse(rootPackageJson);
|
|
9
|
+
return pkg.name === 'learnmd' || pkg.dependencies?.['@learnmd/core'] || pkg.devDependencies?.['@learnmd/core'];
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function addCourseCommand(name) {
|
|
16
|
+
console.log(chalk.blue(`\nš Adding new course: ${name}\n`));
|
|
17
|
+
const isLearnMD = await checkIfInLearnMDWorkspace();
|
|
18
|
+
if (!isLearnMD) {
|
|
19
|
+
console.warn(chalk.yellow('ā ļø Warning: This doesn\'t look like a LearnMD project. Ensure you are running this inside a LearnMD workspace.'));
|
|
20
|
+
}
|
|
21
|
+
const slug = name.toLowerCase().replace(/\s+/g, '-');
|
|
22
|
+
const coursePath = join(process.cwd(), 'courses', slug, 'lessons');
|
|
23
|
+
try {
|
|
24
|
+
await mkdir(coursePath, { recursive: true });
|
|
25
|
+
// Add an initial lesson
|
|
26
|
+
await addLessonCommand('Introduction', slug);
|
|
27
|
+
console.log(chalk.green(`ā
Course '${name}' created successfully in courses/${slug}/`));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(chalk.red('ā Failed to create course directory.'));
|
|
31
|
+
console.error(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function addLessonCommand(title, courseSlug = 'demo-course') {
|
|
35
|
+
console.log(chalk.blue(`\nš Adding new lesson: ${title} to ${courseSlug}\n`));
|
|
36
|
+
const slug = title.toLowerCase().replace(/\s+/g, '-');
|
|
37
|
+
const filePath = join(process.cwd(), 'courses', courseSlug, 'lessons', `${slug}.mdx`);
|
|
38
|
+
const content = `---
|
|
39
|
+
title:
|
|
40
|
+
en: '${title}'
|
|
41
|
+
es: '${title} (ES)'
|
|
42
|
+
description:
|
|
43
|
+
en: 'Description for ${title}'
|
|
44
|
+
es: 'Descripción para ${title}'
|
|
45
|
+
duration: '10 minutes'
|
|
46
|
+
difficulty: 'beginner'
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# ${title}
|
|
50
|
+
|
|
51
|
+
<Callout type="info">
|
|
52
|
+
Welcome to the new lesson: **${title}**!
|
|
53
|
+
</Callout>
|
|
54
|
+
|
|
55
|
+
<Paragraph i18n="intro">
|
|
56
|
+
<en>
|
|
57
|
+
This is an auto-generated lesson content.
|
|
58
|
+
</en>
|
|
59
|
+
<es>
|
|
60
|
+
Este es el contenido autogenerado de la lección.
|
|
61
|
+
</es>
|
|
62
|
+
</Paragraph>
|
|
63
|
+
|
|
64
|
+
<Quiz
|
|
65
|
+
id="${slug}-quiz"
|
|
66
|
+
questions={[
|
|
67
|
+
{
|
|
68
|
+
id: "q1",
|
|
69
|
+
type: "multiple-choice",
|
|
70
|
+
question: "Is this lesson auto-generated?",
|
|
71
|
+
options: [
|
|
72
|
+
{ id: "a", label: "Yes" },
|
|
73
|
+
{ id: "b", label: "No" }
|
|
74
|
+
],
|
|
75
|
+
correctAnswer: "a",
|
|
76
|
+
points: 10
|
|
77
|
+
}
|
|
78
|
+
]}
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
<Progress value={50} showPercentage label="Lesson Progress" />
|
|
82
|
+
`;
|
|
83
|
+
try {
|
|
84
|
+
await mkdir(join(process.cwd(), 'courses', courseSlug, 'lessons'), { recursive: true });
|
|
85
|
+
await writeFile(filePath, content);
|
|
86
|
+
console.log(chalk.green(`ā
Lesson created at: courses/${courseSlug}/lessons/${slug}.mdx`));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error(chalk.red('ā Failed to create lesson. Ensure you have permissions.'));
|
|
90
|
+
console.error(error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.test.d.ts","sourceRoot":"","sources":["../../src/commands/add.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { addLessonCommand } from './add';
|
|
3
|
+
import { writeFile, mkdir } from 'fs/promises';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
// Mock fs/promises
|
|
6
|
+
vi.mock('fs/promises', () => ({
|
|
7
|
+
writeFile: vi.fn().mockResolvedValue(undefined),
|
|
8
|
+
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
9
|
+
}));
|
|
10
|
+
describe('addLessonCommand', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
vi.stubGlobal('console', {
|
|
14
|
+
log: vi.fn(),
|
|
15
|
+
error: vi.fn(),
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
it('should create a lesson file with correct content', async () => {
|
|
19
|
+
const title = 'Test Lesson';
|
|
20
|
+
const slug = 'test-lesson';
|
|
21
|
+
const courseSlug = 'demo-course';
|
|
22
|
+
const expectedPath = join(process.cwd(), 'courses', courseSlug, 'lessons', `${slug}.mdx`);
|
|
23
|
+
await addLessonCommand(title);
|
|
24
|
+
expect(mkdir).toHaveBeenCalledWith(expect.stringContaining(join('courses', courseSlug, 'lessons')), { recursive: true });
|
|
25
|
+
expect(writeFile).toHaveBeenCalledWith(expectedPath, expect.stringContaining('title:'));
|
|
26
|
+
expect(writeFile).toHaveBeenCalledWith(expectedPath, expect.stringContaining(title));
|
|
27
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Lesson created'));
|
|
28
|
+
});
|
|
29
|
+
it('should handle errors during creation', async () => {
|
|
30
|
+
vi.mocked(writeFile).mockRejectedValueOnce(new Error('Write failed'));
|
|
31
|
+
await addLessonCommand('Fail Test');
|
|
32
|
+
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Failed to create lesson'));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=add.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.test.js","sourceRoot":"","sources":["../../src/commands/add.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,mBAAmB;AACnB,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;IAC/C,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;CAC5C,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE;YACvB,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;YACZ,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,KAAK,GAAG,aAAa,CAAC;QAC5B,MAAM,IAAI,GAAG,aAAa,CAAC;QAC3B,MAAM,UAAU,GAAG,aAAa,CAAC;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC;QAE1F,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAE9B,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzH,MAAM,CAAC,SAAS,CAAC,CAAC,oBAAoB,CACpC,YAAY,EACZ,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAClC,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,oBAAoB,CACpC,YAAY,EACZ,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAC/B,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;QAEtE,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAEpC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AASA,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE,YAAY,iBAiBxD"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { build } from 'vite';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
import { readdir, writeFile, mkdir, readFile } from 'fs/promises';
|
|
5
|
+
import { existsSync, cpSync } from 'fs';
|
|
6
|
+
import matter from 'gray-matter';
|
|
7
|
+
import { marked } from 'marked';
|
|
8
|
+
import MiniSearch from 'minisearch';
|
|
9
|
+
export async function buildCommand(options) {
|
|
10
|
+
const outDir = options?.out || 'dist';
|
|
11
|
+
const basePath = options?.base || '/';
|
|
12
|
+
console.log(chalk.blue('\nšØ Building LearnMD course...\n'));
|
|
13
|
+
try {
|
|
14
|
+
await buildFrontend(outDir, basePath);
|
|
15
|
+
await generateSearchIndex(outDir);
|
|
16
|
+
await copyStaticFiles(outDir);
|
|
17
|
+
console.log(chalk.green(`\nā
Build complete!\n`));
|
|
18
|
+
console.log(chalk.blue(`Output directory: ${outDir}\n`));
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(chalk.red('\nā Build failed:'), error);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function buildFrontend(outDir, basePath) {
|
|
26
|
+
console.log(chalk.gray('Building frontend...'));
|
|
27
|
+
const root = process.cwd();
|
|
28
|
+
const outPath = resolve(root, outDir);
|
|
29
|
+
await mkdir(outPath, { recursive: true });
|
|
30
|
+
await build({
|
|
31
|
+
root,
|
|
32
|
+
base: basePath,
|
|
33
|
+
build: {
|
|
34
|
+
outDir,
|
|
35
|
+
emptyOutDir: true,
|
|
36
|
+
rollupOptions: {
|
|
37
|
+
input: resolve(root, 'index.html'),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function generateSearchIndex(outDir) {
|
|
43
|
+
console.log(chalk.gray('Generating search index...'));
|
|
44
|
+
const miniSearch = new MiniSearch({
|
|
45
|
+
fields: ['title', 'content'],
|
|
46
|
+
storeFields: ['title', 'lessonSlug', 'moduleSlug'],
|
|
47
|
+
});
|
|
48
|
+
const coursesDir = resolve(process.cwd(), 'courses');
|
|
49
|
+
try {
|
|
50
|
+
const modules = await readdir(coursesDir);
|
|
51
|
+
for (const mod of modules) {
|
|
52
|
+
const modulePath = resolve(coursesDir, mod);
|
|
53
|
+
const lessons = await readdir(modulePath);
|
|
54
|
+
for (const lesson of lessons) {
|
|
55
|
+
if (!lesson.endsWith('.md'))
|
|
56
|
+
continue;
|
|
57
|
+
const lessonPath = resolve(modulePath, lesson);
|
|
58
|
+
const content = await readFile(lessonPath, 'utf-8');
|
|
59
|
+
const { data, content: markdown } = matter(content);
|
|
60
|
+
const html = await marked.parse(markdown);
|
|
61
|
+
miniSearch.add({
|
|
62
|
+
id: `${mod}/${lesson}`,
|
|
63
|
+
title: data.title || 'Untitled',
|
|
64
|
+
content: html.replace(/<[^>]+>/g, ' '),
|
|
65
|
+
lessonSlug: lesson.replace('.md', ''),
|
|
66
|
+
moduleSlug: mod,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const indexPath = resolve(process.cwd(), outDir, 'search-index.json');
|
|
71
|
+
await writeFile(indexPath, JSON.stringify(miniSearch.toJSON()));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.warn(chalk.yellow('No courses found to index'));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function copyStaticFiles(outDir) {
|
|
78
|
+
console.log(chalk.gray('Copying static files...'));
|
|
79
|
+
const root = process.cwd();
|
|
80
|
+
const outPath = resolve(root, outDir);
|
|
81
|
+
const staticDirs = ['public', 'static'];
|
|
82
|
+
for (const dir of staticDirs) {
|
|
83
|
+
const src = resolve(root, dir);
|
|
84
|
+
if (existsSync(src)) {
|
|
85
|
+
cpSync(src, resolve(outPath, dir), { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAIA,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,iBAqB1E"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { mkdir, writeFile, readFile } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
export async function createCommand(name, _options) {
|
|
5
|
+
const projectName = name || (await askForProjectName());
|
|
6
|
+
const isInWorkspace = await checkIfInLearnMDWorkspace();
|
|
7
|
+
console.log(chalk.blue(`\nš Creating LearnMD project: ${projectName}\n`));
|
|
8
|
+
try {
|
|
9
|
+
await mkdir(projectName, { recursive: true });
|
|
10
|
+
await createBasicStructure(projectName);
|
|
11
|
+
await updatePackageJson(projectName, projectName, isInWorkspace);
|
|
12
|
+
await createEssentialFiles(projectName, isInWorkspace);
|
|
13
|
+
console.log(chalk.green('\nā
LearnMD project created successfully!\n'));
|
|
14
|
+
console.log(chalk.blue('Next steps:'));
|
|
15
|
+
console.log(` cd ${projectName}`);
|
|
16
|
+
console.log(' pnpm install');
|
|
17
|
+
console.log(' pnpm dev\n');
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error(chalk.red('\nā Error creating project:'), error);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function checkIfInLearnMDWorkspace() {
|
|
25
|
+
try {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const rootPackageJson = await readFile(join(cwd, 'package.json'), 'utf-8');
|
|
28
|
+
const pkg = JSON.parse(rootPackageJson);
|
|
29
|
+
return pkg.name === 'learnmd' || pkg.workspaces?.length > 0;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function askForProjectName() {
|
|
36
|
+
const inquirer = await import('inquirer');
|
|
37
|
+
const { projectName } = await inquirer.default.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'input',
|
|
40
|
+
name: 'projectName',
|
|
41
|
+
message: 'What is your project name?',
|
|
42
|
+
default: 'my-course',
|
|
43
|
+
validate: (input) => {
|
|
44
|
+
if (/^[a-z0-9-]+$/.test(input))
|
|
45
|
+
return true;
|
|
46
|
+
return 'Project name must contain only lowercase letters, numbers, and hyphens';
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
return projectName;
|
|
51
|
+
}
|
|
52
|
+
async function createBasicStructure(projectPath) {
|
|
53
|
+
const dirs = ['courses/demo-course/lessons', 'public', 'src'];
|
|
54
|
+
for (const dir of dirs) {
|
|
55
|
+
await mkdir(join(projectPath, dir), { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
await writeFile(join(projectPath, 'index.html'), getIndexHtml());
|
|
58
|
+
await writeFile(join(projectPath, 'src/main.tsx'), getMainTsx());
|
|
59
|
+
await writeFile(join(projectPath, 'src/App.tsx'), getAppTsx());
|
|
60
|
+
await writeFile(join(projectPath, 'src/index.css'), getIndexCss());
|
|
61
|
+
await writeFile(join(projectPath, 'vite.config.ts'), getViteConfig());
|
|
62
|
+
await writeFile(join(projectPath, 'tsconfig.json'), getTsConfig());
|
|
63
|
+
await writeFile(join(projectPath, 'tsconfig.node.json'), getTsNodeConfig());
|
|
64
|
+
await writeFile(join(projectPath, 'learnmd.config.ts'), getLearnMdConfig());
|
|
65
|
+
await writeFile(join(projectPath, '.gitignore'), getGitIgnore());
|
|
66
|
+
await writeFile(join(projectPath, 'courses/demo-course/lessons/.gitkeep'), '');
|
|
67
|
+
}
|
|
68
|
+
async function createEssentialFiles(projectPath, _isInWorkspace) {
|
|
69
|
+
await writeFile(join(projectPath, '.npmrc'), 'auto-install-peers=true\n');
|
|
70
|
+
}
|
|
71
|
+
function getIndexHtml() {
|
|
72
|
+
return `<!DOCTYPE html>
|
|
73
|
+
<html lang="en">
|
|
74
|
+
<head>
|
|
75
|
+
<meta charset="UTF-8" />
|
|
76
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
77
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
78
|
+
<title>LearnMD Course</title>
|
|
79
|
+
</head>
|
|
80
|
+
<body>
|
|
81
|
+
<div id="root"></div>
|
|
82
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
function getMainTsx() {
|
|
88
|
+
return `import React from 'react';
|
|
89
|
+
import ReactDOM from 'react-dom/client';
|
|
90
|
+
import App from './App';
|
|
91
|
+
import '@learnmd/default-theme/styles';
|
|
92
|
+
import './index.css';
|
|
93
|
+
|
|
94
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
95
|
+
<React.StrictMode>
|
|
96
|
+
<App />
|
|
97
|
+
</React.StrictMode>
|
|
98
|
+
);
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
function getAppTsx() {
|
|
102
|
+
return `/// <reference types="vite/client" />
|
|
103
|
+
import { LearnMDProvider } from '@learnmd/core';
|
|
104
|
+
import { CatalogViewer, CourseViewer, ProfileViewer } from '@learnmd/default-theme';
|
|
105
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
106
|
+
import config from '../learnmd.config';
|
|
107
|
+
|
|
108
|
+
// Glob all markdown files dynamically across all courses
|
|
109
|
+
const lessonModules = import.meta.glob('../courses/*/lessons/*.mdx', { eager: true });
|
|
110
|
+
const allLessons = Object.entries(lessonModules).map(([path, mod]) => {
|
|
111
|
+
const parts = path.split('/');
|
|
112
|
+
const courseSlug = parts[2];
|
|
113
|
+
const lessonSlug = parts[4].replace('.mdx', '');
|
|
114
|
+
return {
|
|
115
|
+
courseSlug,
|
|
116
|
+
slug: lessonSlug,
|
|
117
|
+
Component: (mod as any).default as React.ComponentType,
|
|
118
|
+
frontmatter: (mod as any).frontmatter || {}
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
function App() {
|
|
123
|
+
return (
|
|
124
|
+
<LearnMDProvider config={config}>
|
|
125
|
+
<BrowserRouter>
|
|
126
|
+
<Routes>
|
|
127
|
+
<Route path="/" element={<CatalogViewer courses={allLessons} />} />
|
|
128
|
+
<Route path="/profile" element={<ProfileViewer />} />
|
|
129
|
+
<Route path="/courses/:courseId/*" element={<CourseViewer allLessons={allLessons} />} />
|
|
130
|
+
</Routes>
|
|
131
|
+
</BrowserRouter>
|
|
132
|
+
</LearnMDProvider>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default App;
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
function getIndexCss() {
|
|
140
|
+
return `:root {
|
|
141
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
142
|
+
line-height: 1.5;
|
|
143
|
+
font-weight: 400;
|
|
144
|
+
color-scheme: light dark;
|
|
145
|
+
color: rgba(255, 255, 255, 0.87);
|
|
146
|
+
background-color: #242424;
|
|
147
|
+
font-synthesis: none;
|
|
148
|
+
text-rendering: optimizeLegibility;
|
|
149
|
+
-webkit-font-smoothing: antialiased;
|
|
150
|
+
-moz-osx-font-smoothing: grayscale;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
body {
|
|
154
|
+
margin: 0;
|
|
155
|
+
min-width: 320px;
|
|
156
|
+
min-height: 100vh;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#root {
|
|
160
|
+
width: 100%;
|
|
161
|
+
min-height: 100vh;
|
|
162
|
+
}
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
function getViteConfig() {
|
|
166
|
+
return `import { defineConfig } from 'vite';
|
|
167
|
+
import react from '@vitejs/plugin-react';
|
|
168
|
+
import mdx from '@mdx-js/rollup';
|
|
169
|
+
import remarkGfm from 'remark-gfm';
|
|
170
|
+
import remarkFrontmatter from 'remark-frontmatter';
|
|
171
|
+
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
|
172
|
+
import { resolve } from 'path';
|
|
173
|
+
|
|
174
|
+
export default defineConfig({
|
|
175
|
+
plugins: [
|
|
176
|
+
{
|
|
177
|
+
enforce: 'pre',
|
|
178
|
+
...mdx({
|
|
179
|
+
remarkPlugins: [remarkGfm, remarkFrontmatter, remarkMdxFrontmatter],
|
|
180
|
+
providerImportSource: '@mdx-js/react'
|
|
181
|
+
})
|
|
182
|
+
},
|
|
183
|
+
react()
|
|
184
|
+
],
|
|
185
|
+
resolve: {
|
|
186
|
+
alias: {
|
|
187
|
+
'@': resolve(__dirname, './src'),
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
function getTsConfig() {
|
|
194
|
+
return `{
|
|
195
|
+
"compilerOptions": {
|
|
196
|
+
"target": "ES2020",
|
|
197
|
+
"useDefineForClassFields": true,
|
|
198
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
199
|
+
"module": "ESNext",
|
|
200
|
+
"skipLibCheck": true,
|
|
201
|
+
"moduleResolution": "bundler",
|
|
202
|
+
"allowImportingTsExtensions": true,
|
|
203
|
+
"resolveJsonModule": true,
|
|
204
|
+
"isolatedModules": true,
|
|
205
|
+
"noEmit": true,
|
|
206
|
+
"jsx": "react-jsx",
|
|
207
|
+
"strict": true,
|
|
208
|
+
"noUnusedLocals": true,
|
|
209
|
+
"noUnusedParameters": true,
|
|
210
|
+
"noFallthroughCasesInSwitch": true,
|
|
211
|
+
"baseUrl": ".",
|
|
212
|
+
"paths": {
|
|
213
|
+
"@/*": ["./src/*"]
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"include": ["src"],
|
|
217
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
function getTsNodeConfig() {
|
|
222
|
+
return `{
|
|
223
|
+
"compilerOptions": {
|
|
224
|
+
"composite": true,
|
|
225
|
+
"skipLibCheck": true,
|
|
226
|
+
"module": "ESNext",
|
|
227
|
+
"moduleResolution": "bundler",
|
|
228
|
+
"allowSyntheticDefaultImports": true,
|
|
229
|
+
"strict": true
|
|
230
|
+
},
|
|
231
|
+
"include": ["vite.config.ts"]
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
function getGitIgnore() {
|
|
236
|
+
return `node_modules/
|
|
237
|
+
dist/
|
|
238
|
+
.env
|
|
239
|
+
.env.local
|
|
240
|
+
*.log
|
|
241
|
+
.DS_Store
|
|
242
|
+
.vite/
|
|
243
|
+
.cache/
|
|
244
|
+
`;
|
|
245
|
+
}
|
|
246
|
+
async function updatePackageJson(projectPath, name, isInWorkspace) {
|
|
247
|
+
const dependencies = {
|
|
248
|
+
react: '^18.2.0',
|
|
249
|
+
'react-dom': '^18.2.0',
|
|
250
|
+
'react-router-dom': '^6.22.3',
|
|
251
|
+
'@mdx-js/react': '^3.0.1'
|
|
252
|
+
};
|
|
253
|
+
const devDependencies = {
|
|
254
|
+
'@types/react': '^18.2.0',
|
|
255
|
+
'@types/react-dom': '^18.2.0',
|
|
256
|
+
'@vitejs/plugin-react': '^4.2.0',
|
|
257
|
+
'@mdx-js/rollup': '^3.0.1',
|
|
258
|
+
'remark-gfm': '^4.0.0',
|
|
259
|
+
'remark-frontmatter': '^5.0.0',
|
|
260
|
+
'remark-mdx-frontmatter': '^4.0.0',
|
|
261
|
+
typescript: '^5.4.0',
|
|
262
|
+
vite: '^5.1.0',
|
|
263
|
+
'@learnmd/core': isInWorkspace ? 'file:../packages/core' : '^0.0.1',
|
|
264
|
+
'@learnmd/default-theme': isInWorkspace
|
|
265
|
+
? 'file:../packages/default-theme'
|
|
266
|
+
: '^0.0.1',
|
|
267
|
+
};
|
|
268
|
+
const packageJson = {
|
|
269
|
+
name: name.toLowerCase().replace(/\s+/g, '-'),
|
|
270
|
+
version: '0.0.1',
|
|
271
|
+
private: true,
|
|
272
|
+
type: 'module',
|
|
273
|
+
scripts: {
|
|
274
|
+
dev: 'vite',
|
|
275
|
+
build: 'vite build',
|
|
276
|
+
preview: 'vite preview',
|
|
277
|
+
},
|
|
278
|
+
dependencies,
|
|
279
|
+
devDependencies,
|
|
280
|
+
};
|
|
281
|
+
await writeFile(join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
282
|
+
}
|
|
283
|
+
function getLearnMdConfig() {
|
|
284
|
+
return `import { defineConfig } from '@learnmd/core';
|
|
285
|
+
|
|
286
|
+
export default defineConfig({
|
|
287
|
+
title: 'LearnMD Course',
|
|
288
|
+
description: 'An interactive course built with LearnMD',
|
|
289
|
+
defaultLanguage: 'en',
|
|
290
|
+
availableLanguages: ['en', 'es'],
|
|
291
|
+
theme: {
|
|
292
|
+
primaryColor: '#3b82f6',
|
|
293
|
+
darkMode: true,
|
|
294
|
+
},
|
|
295
|
+
gamification: {
|
|
296
|
+
pointsPerLesson: 100,
|
|
297
|
+
pointsPerQuiz: 10,
|
|
298
|
+
badges: [
|
|
299
|
+
{ id: 'first-lesson', name: 'First Steps', icon: 'š' },
|
|
300
|
+
{ id: 'quiz-master', name: 'Quiz Master', icon: 'š' },
|
|
301
|
+
{ id: 'course-complete', name: 'Course Graduate', icon: 'š' },
|
|
302
|
+
],
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAIA,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,iBAuCpD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { createServer } from 'vite';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
export async function devCommand(options) {
|
|
5
|
+
const port = parseInt(options?.port || '3000', 10);
|
|
6
|
+
const host = options?.host || 'localhost';
|
|
7
|
+
console.log(chalk.blue('\nš Starting LearnMD development server...\n'));
|
|
8
|
+
try {
|
|
9
|
+
const server = await createServer({
|
|
10
|
+
root: process.cwd(),
|
|
11
|
+
server: {
|
|
12
|
+
port,
|
|
13
|
+
host,
|
|
14
|
+
open: true,
|
|
15
|
+
},
|
|
16
|
+
plugins: [
|
|
17
|
+
{
|
|
18
|
+
name: 'learnmd-dev',
|
|
19
|
+
configureServer(server) {
|
|
20
|
+
server.httpServer?.on('listening', () => {
|
|
21
|
+
console.log(chalk.green(`\nā
Server running at:`));
|
|
22
|
+
console.log(chalk.blue(` http://${host}:${port}\n`));
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
resolve: {
|
|
28
|
+
alias: {
|
|
29
|
+
'@learnmd/core': resolve(process.cwd(), '../packages/core/src'),
|
|
30
|
+
'@learnmd/default-theme': resolve(process.cwd(), '../packages/default-theme/src'),
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
await server.listen();
|
|
35
|
+
await server.printUrls();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(chalk.red('\nā Error starting development server:'), error);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAO/B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAoB;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,WAAW,CAAC;IAE1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAEzE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;YAChC,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE;YACnB,MAAM,EAAE;gBACN,IAAI;gBACJ,IAAI;gBACJ,IAAI,EAAE,IAAI;aACX;YACD,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,aAAa;oBACnB,eAAe,CAAC,MAAM;wBACpB,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;4BACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;4BACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;wBACzD,CAAC,CAAC,CAAC;oBACL,CAAC;iBACF;aACF;YACD,OAAO,EAAE;gBACP,KAAK,EAAE;oBACL,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,sBAAsB,CAAC;oBAC/D,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,+BAA+B,CAAC;iBAClF;aACF;SACF,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,kBAsBhC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { writeFile, mkdir } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
export async function initCommand() {
|
|
5
|
+
console.log(chalk.blue('\n⨠Initializing LearnMD...\n'));
|
|
6
|
+
try {
|
|
7
|
+
const projectFiles = await getProjectFiles();
|
|
8
|
+
for (const file of projectFiles) {
|
|
9
|
+
const filePath = join(process.cwd(), file.path);
|
|
10
|
+
await mkdir(join(process.cwd(), file.dir), { recursive: true });
|
|
11
|
+
await writeFile(filePath, file.content);
|
|
12
|
+
console.log(chalk.gray(` Created: ${file.path}`));
|
|
13
|
+
}
|
|
14
|
+
console.log(chalk.green('\nā
LearnMD initialized successfully!\n'));
|
|
15
|
+
console.log(chalk.blue('Next steps:'));
|
|
16
|
+
console.log(' 1. Create your course content in the courses/ directory');
|
|
17
|
+
console.log(' 2. Customize your theme in learnmd.config.ts');
|
|
18
|
+
console.log(' 3. Run "npm run dev" to start development\n');
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(chalk.red('\nā Initialization failed:'), error);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function getProjectFiles() {
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
path: 'learnmd.config.ts',
|
|
29
|
+
dir: '.',
|
|
30
|
+
content: `import { defineConfig } from '@learnmd/core';
|
|
31
|
+
|
|
32
|
+
export default defineConfig({
|
|
33
|
+
title: 'My Course',
|
|
34
|
+
description: 'A course built with LearnMD',
|
|
35
|
+
defaultLanguage: 'en',
|
|
36
|
+
availableLanguages: ['en', 'es'],
|
|
37
|
+
theme: {
|
|
38
|
+
primaryColor: '#3b82f6',
|
|
39
|
+
darkMode: true,
|
|
40
|
+
},
|
|
41
|
+
plugins: [],
|
|
42
|
+
});
|
|
43
|
+
`,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
path: 'courses/.gitkeep',
|
|
47
|
+
dir: 'courses',
|
|
48
|
+
content: '',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
path: 'public/.gitkeep',
|
|
52
|
+
dir: 'public',
|
|
53
|
+
content: '',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: '.gitignore',
|
|
57
|
+
dir: '.',
|
|
58
|
+
content: `node_modules/
|
|
59
|
+
dist/
|
|
60
|
+
.env
|
|
61
|
+
*.log
|
|
62
|
+
.DS_Store
|
|
63
|
+
`,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAEzD,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,eAAe,EAAE,CAAC;QAE7C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAQD,KAAK,UAAU,eAAe;IAC5B,OAAO;QACL;YACE,IAAI,EAAE,mBAAmB;YACzB,GAAG,EAAE,GAAG;YACR,OAAO,EAAE;;;;;;;;;;;;;CAad;SACI;QACD;YACE,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,SAAS;YACd,OAAO,EAAE,EAAE;SACZ;QACD;YACE,IAAI,EAAE,iBAAiB;YACvB,GAAG,EAAE,QAAQ;YACb,OAAO,EAAE,EAAE;SACZ;QACD;YACE,IAAI,EAAE,YAAY;YAClB,GAAG,EAAE,GAAG;YACR,OAAO,EAAE;;;;;CAKd;SACI;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { createCommand } from './commands/create.js';
|
|
4
|
+
import { devCommand } from './commands/dev.js';
|
|
5
|
+
import { buildCommand } from './commands/build.js';
|
|
6
|
+
import { initCommand } from './commands/init.js';
|
|
7
|
+
import { addCourseCommand, addLessonCommand } from './commands/add.js';
|
|
8
|
+
const version = '0.0.1';
|
|
9
|
+
program
|
|
10
|
+
.name('learnmd')
|
|
11
|
+
.description('CLI for creating and building LearnMD courses')
|
|
12
|
+
.version(version);
|
|
13
|
+
program
|
|
14
|
+
.command('create')
|
|
15
|
+
.description('Create a new LearnMD project')
|
|
16
|
+
.argument('[name]', 'Project name')
|
|
17
|
+
.option('-t, --template <template>', 'Template to use', 'default')
|
|
18
|
+
.option('-l, --language <language>', 'Default language', 'en')
|
|
19
|
+
.action(createCommand);
|
|
20
|
+
program
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Initialize LearnMD in an existing project')
|
|
23
|
+
.action(initCommand);
|
|
24
|
+
program
|
|
25
|
+
.command('dev')
|
|
26
|
+
.description('Start development server')
|
|
27
|
+
.option('-p, --port <port>', 'Port to run on', '3000')
|
|
28
|
+
.option('-h, --host <host>', 'Host to run on', 'localhost')
|
|
29
|
+
.action(devCommand);
|
|
30
|
+
program
|
|
31
|
+
.command('build')
|
|
32
|
+
.description('Build for production')
|
|
33
|
+
.option('-o, --out <dir>', 'Output directory', 'dist')
|
|
34
|
+
.option('--base <base>', 'Base path', '/')
|
|
35
|
+
.action(buildCommand);
|
|
36
|
+
program
|
|
37
|
+
.command('add')
|
|
38
|
+
.description('Add new resources (course or lesson)')
|
|
39
|
+
.argument('<type>', 'Type of resource (course, lesson)')
|
|
40
|
+
.argument('<name>', 'Name/Title of the resource')
|
|
41
|
+
.option('-c, --course <courseName>', 'Course name to add the lesson to (defaults to demo-course)')
|
|
42
|
+
.action((type, name, options) => {
|
|
43
|
+
if (type === 'course') {
|
|
44
|
+
addCourseCommand(name);
|
|
45
|
+
}
|
|
46
|
+
else if (type === 'lesson') {
|
|
47
|
+
addLessonCommand(name, options.course || 'demo-course');
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.error('Invalid resource type. Use "course" or "lesson".');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
program.parse();
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,+CAA+C,CAAC;KAC5D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,8BAA8B,CAAC;KAC3C,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;KAClC,MAAM,CAAC,2BAA2B,EAAE,iBAAiB,EAAE,SAAS,CAAC;KACjE,MAAM,CAAC,2BAA2B,EAAE,kBAAkB,EAAE,IAAI,CAAC;KAC7D,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,CAAC;KACrD,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,WAAW,CAAC;KAC1D,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,CAAC;KACrD,MAAM,CAAC,eAAe,EAAE,WAAW,EAAE,GAAG,CAAC;KACzC,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,sCAAsC,CAAC;KACnD,QAAQ,CAAC,QAAQ,EAAE,mCAAmC,CAAC;KACvD,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,2BAA2B,EAAE,4DAA4D,CAAC;KACjG,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;IAC9B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;SAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACpE,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@learnmd/cli",
|
|
3
|
+
"version": "0.0.1-beta.0",
|
|
4
|
+
"description": "CLI for creating and building LearnMD courses",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"learnmd": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"chalk": "^5.3.0",
|
|
14
|
+
"commander": "^12.0.0",
|
|
15
|
+
"fs-extra": "^11.2.0",
|
|
16
|
+
"gray-matter": "^4.0.3",
|
|
17
|
+
"inquirer": "^9.2.0",
|
|
18
|
+
"listr2": "^8.0.0",
|
|
19
|
+
"marked": "^12.0.0",
|
|
20
|
+
"minisearch": "^6.3.0",
|
|
21
|
+
"vite": "^5.1.0",
|
|
22
|
+
"@learnmd/core": "0.0.1-beta.0",
|
|
23
|
+
"@learnmd/default-theme": "0.0.1-beta.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/fs-extra": "^11.0.4",
|
|
27
|
+
"@types/inquirer": "^9.0.7",
|
|
28
|
+
"@types/node": "^20.11.0",
|
|
29
|
+
"eslint-plugin-import": "^2.32.0",
|
|
30
|
+
"eslint-plugin-security": "^4.0.0",
|
|
31
|
+
"typescript": "^5.4.0",
|
|
32
|
+
"vitest": "^1.3.0",
|
|
33
|
+
"@vitest/coverage-v8": "^1.3.0"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"learnmd",
|
|
37
|
+
"cli",
|
|
38
|
+
"courses"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"files": [
|
|
42
|
+
"dist"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "tsc --watch",
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"lint": "eslint src",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:coverage": "vitest run --coverage",
|
|
50
|
+
"clean": "rm -rf dist"
|
|
51
|
+
}
|
|
52
|
+
}
|