coursecode 0.1.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 +322 -0
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/bin/cli.js +331 -0
- package/framework/assets/logo-coursecode-black.svg +14 -0
- package/framework/assets/logo-coursecode-white.svg +14 -0
- package/framework/assets/logo-coursecode.svg +14 -0
- package/framework/css/01-base.css +160 -0
- package/framework/css/02-layout.css +499 -0
- package/framework/css/accessibility.css +834 -0
- package/framework/css/components/accordions.css +710 -0
- package/framework/css/components/assessments.css +520 -0
- package/framework/css/components/audio-player.css +570 -0
- package/framework/css/components/badges.css +80 -0
- package/framework/css/components/breadcrumbs.css +87 -0
- package/framework/css/components/buttons.css +707 -0
- package/framework/css/components/callouts.css +1280 -0
- package/framework/css/components/cards.css +475 -0
- package/framework/css/components/carousel.css +193 -0
- package/framework/css/components/checkbox-group.css +123 -0
- package/framework/css/components/checklist.css +203 -0
- package/framework/css/components/collapse.css +96 -0
- package/framework/css/components/comparison.css +33 -0
- package/framework/css/components/content-image.css +36 -0
- package/framework/css/components/document-gallery.css +425 -0
- package/framework/css/components/dropdown.css +115 -0
- package/framework/css/components/embed-frame.css +142 -0
- package/framework/css/components/engagement.css +412 -0
- package/framework/css/components/features.css +35 -0
- package/framework/css/components/flip-cards.css +253 -0
- package/framework/css/components/footer.css +353 -0
- package/framework/css/components/forms.css +294 -0
- package/framework/css/components/hero.css +216 -0
- package/framework/css/components/images.css +528 -0
- package/framework/css/components/interactive-timeline.css +274 -0
- package/framework/css/components/intro-cards.css +30 -0
- package/framework/css/components/lightbox.css +666 -0
- package/framework/css/components/loading.css +65 -0
- package/framework/css/components/modals.css +235 -0
- package/framework/css/components/notifications.css +107 -0
- package/framework/css/components/quote.css +150 -0
- package/framework/css/components/sidebar.css +684 -0
- package/framework/css/components/slide-header.css +52 -0
- package/framework/css/components/spinner.css +62 -0
- package/framework/css/components/stats.css +44 -0
- package/framework/css/components/steps.css +232 -0
- package/framework/css/components/tables.css +90 -0
- package/framework/css/components/tabs.css +347 -0
- package/framework/css/components/timeline.css +154 -0
- package/framework/css/components/toggle.css +95 -0
- package/framework/css/components/tooltip.css +226 -0
- package/framework/css/components/video-player.css +438 -0
- package/framework/css/design-tokens.css +707 -0
- package/framework/css/framework.css +86 -0
- package/framework/css/interactions/accessibility.css +75 -0
- package/framework/css/interactions/base.css +92 -0
- package/framework/css/interactions/drag-drop.css +295 -0
- package/framework/css/interactions/fill-in-the-blank.css +236 -0
- package/framework/css/interactions/hotspots.css +69 -0
- package/framework/css/interactions/index.css +45 -0
- package/framework/css/interactions/interactive-image.css +359 -0
- package/framework/css/interactions/likert.css +126 -0
- package/framework/css/interactions/matching.css +354 -0
- package/framework/css/interactions/numeric-input.css +78 -0
- package/framework/css/interactions/sequencing.css +378 -0
- package/framework/css/interactions/true-false.css +177 -0
- package/framework/css/layouts/article.css +258 -0
- package/framework/css/layouts/base.css +30 -0
- package/framework/css/layouts/canvas.css +38 -0
- package/framework/css/layouts/focused.css +236 -0
- package/framework/css/layouts/index.css +29 -0
- package/framework/css/layouts/presentation.css +191 -0
- package/framework/css/layouts/traditional.css +52 -0
- package/framework/css/responsive.css +439 -0
- package/framework/css/utilities/accessibility-utils.css +59 -0
- package/framework/css/utilities/animations.css +419 -0
- package/framework/css/utilities/borders.css +72 -0
- package/framework/css/utilities/colors.css +76 -0
- package/framework/css/utilities/container.css +46 -0
- package/framework/css/utilities/decorative.css +442 -0
- package/framework/css/utilities/display.css +257 -0
- package/framework/css/utilities/flexbox.css +80 -0
- package/framework/css/utilities/grid.css +69 -0
- package/framework/css/utilities/icons.css +534 -0
- package/framework/css/utilities/lists.css +190 -0
- package/framework/css/utilities/spacing.css +167 -0
- package/framework/css/utilities/tables.css +81 -0
- package/framework/css/utilities/typography.css +159 -0
- package/framework/css/utilities/visibility.css +117 -0
- package/framework/docs/COURSE_AUTHORING_GUIDE.md +1773 -0
- package/framework/docs/COURSE_OUTLINE_GUIDE.md +725 -0
- package/framework/docs/COURSE_OUTLINE_TEMPLATE.md +161 -0
- package/framework/docs/DATA_MODEL.md +409 -0
- package/framework/docs/FRAMEWORK_GUIDE.md +1088 -0
- package/framework/docs/USER_GUIDE.md +583 -0
- package/framework/docs/examples/cloudflare-channel-relay.js +169 -0
- package/framework/docs/examples/cloudflare-data-worker.js +102 -0
- package/framework/docs/examples/cloudflare-error-worker.js +228 -0
- package/framework/index.html +175 -0
- package/framework/js/app/AppActions.js +410 -0
- package/framework/js/app/AppState.js +225 -0
- package/framework/js/app/AppUI.js +616 -0
- package/framework/js/assessment/AssessmentActions.js +615 -0
- package/framework/js/assessment/AssessmentFactory.js +471 -0
- package/framework/js/assessment/AssessmentState.js +322 -0
- package/framework/js/assessment/AssessmentUI.js +451 -0
- package/framework/js/automation/api-engagement.js +196 -0
- package/framework/js/automation/api-interactions.js +167 -0
- package/framework/js/automation/api.js +242 -0
- package/framework/js/automation/index.js +41 -0
- package/framework/js/components/interactions/drag-drop.js +884 -0
- package/framework/js/components/interactions/fill-in.js +535 -0
- package/framework/js/components/interactions/hotspot.js +702 -0
- package/framework/js/components/interactions/interaction-base.js +511 -0
- package/framework/js/components/interactions/likert.js +301 -0
- package/framework/js/components/interactions/matching.js +699 -0
- package/framework/js/components/interactions/multiple-choice.js +377 -0
- package/framework/js/components/interactions/numeric.js +271 -0
- package/framework/js/components/interactions/sequencing.js +423 -0
- package/framework/js/components/interactions/true-false.js +241 -0
- package/framework/js/components/ui-components/accordion.js +442 -0
- package/framework/js/components/ui-components/alert.js +88 -0
- package/framework/js/components/ui-components/audio-player.js +1193 -0
- package/framework/js/components/ui-components/callout.js +121 -0
- package/framework/js/components/ui-components/carousel.js +145 -0
- package/framework/js/components/ui-components/checkbox-group.js +87 -0
- package/framework/js/components/ui-components/checklist.js +40 -0
- package/framework/js/components/ui-components/collapse.js +114 -0
- package/framework/js/components/ui-components/comparison.js +30 -0
- package/framework/js/components/ui-components/conditional-display.js +150 -0
- package/framework/js/components/ui-components/content-image.js +41 -0
- package/framework/js/components/ui-components/dropdown.js +262 -0
- package/framework/js/components/ui-components/embed-frame.js +274 -0
- package/framework/js/components/ui-components/features.js +33 -0
- package/framework/js/components/ui-components/flip-card.js +230 -0
- package/framework/js/components/ui-components/form-validator.js +76 -0
- package/framework/js/components/ui-components/hero.js +49 -0
- package/framework/js/components/ui-components/index.js +12 -0
- package/framework/js/components/ui-components/interactive-image.js +235 -0
- package/framework/js/components/ui-components/interactive-timeline.js +285 -0
- package/framework/js/components/ui-components/intro-cards.js +35 -0
- package/framework/js/components/ui-components/lightbox.js +652 -0
- package/framework/js/components/ui-components/modal.js +386 -0
- package/framework/js/components/ui-components/notifications.js +145 -0
- package/framework/js/components/ui-components/progress.js +88 -0
- package/framework/js/components/ui-components/quote.js +41 -0
- package/framework/js/components/ui-components/stats.js +33 -0
- package/framework/js/components/ui-components/steps.js +41 -0
- package/framework/js/components/ui-components/tabs.js +255 -0
- package/framework/js/components/ui-components/timeline.js +42 -0
- package/framework/js/components/ui-components/toggle-group.js +73 -0
- package/framework/js/components/ui-components/tooltip.js +458 -0
- package/framework/js/components/ui-components/value-display.js +133 -0
- package/framework/js/components/ui-components/video-player.js +686 -0
- package/framework/js/core/component-catalog.js +121 -0
- package/framework/js/core/event-bus.js +178 -0
- package/framework/js/core/interaction-catalog.js +149 -0
- package/framework/js/dev/runtime-linter.js +1725 -0
- package/framework/js/drivers/cmi5-driver.js +768 -0
- package/framework/js/drivers/driver-factory.js +77 -0
- package/framework/js/drivers/driver-interface.js +110 -0
- package/framework/js/drivers/http-driver-base.js +241 -0
- package/framework/js/drivers/lti-driver.js +508 -0
- package/framework/js/drivers/proxy-driver.js +444 -0
- package/framework/js/drivers/scorm-12-driver.js +560 -0
- package/framework/js/drivers/scorm-2004-driver.js +775 -0
- package/framework/js/drivers/scorm-driver-base.js +112 -0
- package/framework/js/engagement/engagement-manager.js +404 -0
- package/framework/js/engagement/engagement-progress.js +191 -0
- package/framework/js/engagement/engagement-trackers.js +215 -0
- package/framework/js/engagement/requirement-strategies.js +268 -0
- package/framework/js/main.js +727 -0
- package/framework/js/managers/accessibility-manager.js +499 -0
- package/framework/js/managers/assessment-manager.js +230 -0
- package/framework/js/managers/audio-manager.js +944 -0
- package/framework/js/managers/comment-manager.js +88 -0
- package/framework/js/managers/flag-manager.js +86 -0
- package/framework/js/managers/interaction-manager.js +254 -0
- package/framework/js/managers/interaction-registry.js +96 -0
- package/framework/js/managers/objective-manager.js +423 -0
- package/framework/js/managers/score-manager.js +441 -0
- package/framework/js/managers/video-manager.js +536 -0
- package/framework/js/navigation/Breadcrumbs.js +234 -0
- package/framework/js/navigation/NavigationActions.js +1132 -0
- package/framework/js/navigation/NavigationState.js +276 -0
- package/framework/js/navigation/NavigationUI.js +574 -0
- package/framework/js/navigation/document-gallery.js +357 -0
- package/framework/js/navigation/navigation-helpers.js +175 -0
- package/framework/js/navigation/navigation-validators.js +174 -0
- package/framework/js/state/index.js +8 -0
- package/framework/js/state/lms-connection.js +482 -0
- package/framework/js/state/lms-error-utils.js +58 -0
- package/framework/js/state/state-commits.js +200 -0
- package/framework/js/state/state-domains.js +86 -0
- package/framework/js/state/state-manager.js +502 -0
- package/framework/js/state/state-validation.js +311 -0
- package/framework/js/state/transaction-log.js +41 -0
- package/framework/js/state/xapi-statement-service.js +325 -0
- package/framework/js/utilities/access-control.js +99 -0
- package/framework/js/utilities/breakpoint-manager.js +315 -0
- package/framework/js/utilities/canvas-slide.js +35 -0
- package/framework/js/utilities/conditional-display.js +388 -0
- package/framework/js/utilities/course-channel.js +214 -0
- package/framework/js/utilities/course-helpers.js +420 -0
- package/framework/js/utilities/data-reporter.js +273 -0
- package/framework/js/utilities/error-reporter.js +313 -0
- package/framework/js/utilities/hotspot-helper.js +341 -0
- package/framework/js/utilities/icons.js +348 -0
- package/framework/js/utilities/logger.js +92 -0
- package/framework/js/utilities/markdown-renderer.js +45 -0
- package/framework/js/utilities/scroll-tracker.js +68 -0
- package/framework/js/utilities/ui-initializer.js +146 -0
- package/framework/js/utilities/utilities.js +293 -0
- package/framework/js/utilities/view-manager.js +227 -0
- package/framework/js/validation/html-validators.js +422 -0
- package/framework/js/validation/scorm-validators.js +438 -0
- package/framework/js/vendor/pipwerks.js +931 -0
- package/framework/scripts/generate-narration.js +629 -0
- package/framework/scripts/tts-providers/azure-provider.js +178 -0
- package/framework/scripts/tts-providers/base-provider.js +81 -0
- package/framework/scripts/tts-providers/deepgram-provider.js +135 -0
- package/framework/scripts/tts-providers/elevenlabs-provider.js +148 -0
- package/framework/scripts/tts-providers/google-provider.js +272 -0
- package/framework/scripts/tts-providers/index.js +158 -0
- package/framework/scripts/tts-providers/openai-provider.js +143 -0
- package/framework/version.json +63 -0
- package/lib/authoring-api.js +919 -0
- package/lib/build-linter.js +450 -0
- package/lib/build-packaging.js +186 -0
- package/lib/build.js +88 -0
- package/lib/cloud.js +691 -0
- package/lib/convert.js +341 -0
- package/lib/course-parser.js +936 -0
- package/lib/course-writer.js +258 -0
- package/lib/create.js +248 -0
- package/lib/css-index.js +237 -0
- package/lib/dev.js +51 -0
- package/lib/export-content.js +1246 -0
- package/lib/headless-browser.js +413 -0
- package/lib/import.js +377 -0
- package/lib/index.js +80 -0
- package/lib/info.js +79 -0
- package/lib/interaction-formatters.js +568 -0
- package/lib/manifest/cmi5-manifest.js +63 -0
- package/lib/manifest/lti-tool-config.js +53 -0
- package/lib/manifest/manifest-factory.js +99 -0
- package/lib/manifest/scorm-12-manifest.js +61 -0
- package/lib/manifest/scorm-2004-manifest.js +94 -0
- package/lib/manifest/scorm-proxy-manifest.js +104 -0
- package/lib/manifest-parser.js +96 -0
- package/lib/mcp-prompts.js +753 -0
- package/lib/mcp-server.js +316 -0
- package/lib/narration.js +53 -0
- package/lib/pdf-structure.js +142 -0
- package/lib/preview-export.js +231 -0
- package/lib/preview-routes-api.js +662 -0
- package/lib/preview-routes-editing.js +159 -0
- package/lib/preview-routes-lms.js +230 -0
- package/lib/preview-server.js +564 -0
- package/lib/project-utils.js +269 -0
- package/lib/proxy-templates/proxy.html +68 -0
- package/lib/proxy-templates/scorm-bridge.js +112 -0
- package/lib/scaffold.js +193 -0
- package/lib/schema-extractor.js +361 -0
- package/lib/slide-source-editor.js +586 -0
- package/lib/stub-player/app-viewer.js +195 -0
- package/lib/stub-player/app.js +370 -0
- package/lib/stub-player/catalog-panel.js +312 -0
- package/lib/stub-player/config-panel.js +1303 -0
- package/lib/stub-player/content-generator.js +586 -0
- package/lib/stub-player/content-viewer.js +173 -0
- package/lib/stub-player/debug-panel.js +420 -0
- package/lib/stub-player/edit-mode.js +922 -0
- package/lib/stub-player/edit-utils.js +400 -0
- package/lib/stub-player/header-bar.js +354 -0
- package/lib/stub-player/interaction-editor.js +210 -0
- package/lib/stub-player/interactions-panel.js +565 -0
- package/lib/stub-player/lms-api.js +1094 -0
- package/lib/stub-player/login-screen.js +74 -0
- package/lib/stub-player/outline-mode.js +689 -0
- package/lib/stub-player/styles/_assessments-panel.css +245 -0
- package/lib/stub-player/styles/_base.css +89 -0
- package/lib/stub-player/styles/_catalog-icons.css +96 -0
- package/lib/stub-player/styles/_catalog-panel.css +291 -0
- package/lib/stub-player/styles/_config-panel.css +636 -0
- package/lib/stub-player/styles/_content-viewer.css +834 -0
- package/lib/stub-player/styles/_debug-panel.css +576 -0
- package/lib/stub-player/styles/_edit-mode.css +128 -0
- package/lib/stub-player/styles/_header-bar.css +343 -0
- package/lib/stub-player/styles/_interaction-editor.css +140 -0
- package/lib/stub-player/styles/_interactions-panel.css +1038 -0
- package/lib/stub-player/styles/_login-screen.css +102 -0
- package/lib/stub-player/styles/_outline-mode.css +752 -0
- package/lib/stub-player/styles.css +15 -0
- package/lib/stub-player.js +160 -0
- package/lib/test-data-reporting.js +176 -0
- package/lib/test-error-reporting.js +146 -0
- package/lib/token.js +86 -0
- package/lib/upgrade.js +257 -0
- package/lib/validation-rules.js +517 -0
- package/lib/vite-plugin-content-discovery.js +296 -0
- package/package.json +108 -0
- package/schemas/XMLSchema.dtd +402 -0
- package/schemas/adlcp_v1p3.xsd +111 -0
- package/schemas/adlnav_v1p3.xsd +61 -0
- package/schemas/adlseq_v1p3.xsd +93 -0
- package/schemas/common/anyElement.xsd +27 -0
- package/schemas/common/dataTypes.xsd +138 -0
- package/schemas/common/elementNames.xsd +767 -0
- package/schemas/common/elementTypes.xsd +786 -0
- package/schemas/common/rootElement.xsd +31 -0
- package/schemas/common/vocabTypes.xsd +345 -0
- package/schemas/common/vocabValues.xsd +257 -0
- package/schemas/datatypes.dtd +203 -0
- package/schemas/ims_xml.xsd +35 -0
- package/schemas/imscp_v1p1.xsd +368 -0
- package/schemas/imsss_v1p0.xsd +67 -0
- package/schemas/imsss_v1p0auxresource.xsd +19 -0
- package/schemas/imsss_v1p0control.xsd +20 -0
- package/schemas/imsss_v1p0delivery.xsd +17 -0
- package/schemas/imsss_v1p0limit.xsd +47 -0
- package/schemas/imsss_v1p0objective.xsd +67 -0
- package/schemas/imsss_v1p0random.xsd +16 -0
- package/schemas/imsss_v1p0rollup.xsd +46 -0
- package/schemas/imsss_v1p0seqrule.xsd +108 -0
- package/schemas/imsss_v1p0util.xsd +94 -0
- package/schemas/license.txt +17 -0
- package/schemas/lom.xsd +102 -0
- package/schemas/lomCustom.xsd +62 -0
- package/schemas/lomLoose.xsd +62 -0
- package/schemas/lomStrict.xsd +62 -0
- package/schemas/xml.xsd +81 -0
- package/template/.env.example +92 -0
- package/template/course/assets/audio/example-intro.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--compact-player.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--demo-modal.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--full-player.mp3 +0 -0
- package/template/course/assets/docs/example_md_1.md +39 -0
- package/template/course/assets/docs/example_md_2.md +41 -0
- package/template/course/assets/docs/example_pdf_1_thumbnail.png +0 -0
- package/template/course/assets/docs/example_pdf_2.pdf +0 -0
- package/template/course/assets/images/course-architecture.svg +36 -0
- package/template/course/assets/images/logo.svg +14 -0
- package/template/course/assets/widgets/counter-demo.html +190 -0
- package/template/course/assets/widgets/gravity-painter.html +384 -0
- package/template/course/course-config.js +539 -0
- package/template/course/icons.js +19 -0
- package/template/course/interactions/PLUGIN_GUIDE.md +97 -0
- package/template/course/slides/example-course-structure.js +138 -0
- package/template/course/slides/example-final-exam.js +144 -0
- package/template/course/slides/example-finishing.js +127 -0
- package/template/course/slides/example-interactions-showcase.js +615 -0
- package/template/course/slides/example-preview-tour.js +129 -0
- package/template/course/slides/example-remedial.js +143 -0
- package/template/course/slides/example-summary.js +103 -0
- package/template/course/slides/example-ui-showcase.js +1805 -0
- package/template/course/slides/example-welcome.js +123 -0
- package/template/course/slides/example-workflow.js +140 -0
- package/template/course/theme.css +165 -0
- package/template/eslint.config.js +47 -0
- package/template/package.json +28 -0
- package/template/vite.config.js +339 -0
package/lib/convert.js
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Command
|
|
3
|
+
*
|
|
4
|
+
* Converts docx, pptx, pdf, and md files to the converted references directory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
|
|
10
|
+
const SUPPORTED_EXTENSIONS = ['.docx', '.pptx', '.pdf', '.md'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main convert function
|
|
14
|
+
*/
|
|
15
|
+
export async function convert(source, options) {
|
|
16
|
+
const {
|
|
17
|
+
output = './course/references/converted',
|
|
18
|
+
format = 'all',
|
|
19
|
+
dryRun = false,
|
|
20
|
+
overwrite = false,
|
|
21
|
+
flatten = false
|
|
22
|
+
} = options;
|
|
23
|
+
|
|
24
|
+
console.log('\n📄 Converting documents to markdown...\n');
|
|
25
|
+
|
|
26
|
+
// Resolve paths
|
|
27
|
+
const sourcePath = path.resolve(source);
|
|
28
|
+
const outputPath = path.resolve(output);
|
|
29
|
+
|
|
30
|
+
// Check if source exists
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(sourcePath);
|
|
33
|
+
} catch {
|
|
34
|
+
console.error(`❌ Source path not found: ${sourcePath}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Determine if source is file or directory
|
|
39
|
+
const sourceStat = await fs.stat(sourcePath);
|
|
40
|
+
const isDirectory = sourceStat.isDirectory();
|
|
41
|
+
|
|
42
|
+
// Find files to convert
|
|
43
|
+
let files = [];
|
|
44
|
+
if (isDirectory) {
|
|
45
|
+
files = await findFiles(sourcePath, format);
|
|
46
|
+
} else {
|
|
47
|
+
const ext = path.extname(sourcePath).toLowerCase();
|
|
48
|
+
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
49
|
+
if (format === 'all' || format === ext.slice(1)) {
|
|
50
|
+
files = [sourcePath];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Filter by format if specified
|
|
56
|
+
if (format !== 'all') {
|
|
57
|
+
const targetExt = `.${format}`;
|
|
58
|
+
files = files.filter(f => path.extname(f).toLowerCase() === targetExt);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (files.length === 0) {
|
|
62
|
+
console.log(` Source: ${sourcePath}\n`);
|
|
63
|
+
console.log(' No supported files found (.docx, .pptx, .pdf, .md)\n');
|
|
64
|
+
console.log(` Place source documents in ${source} and try again.\n`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(` Source: ${sourcePath}`);
|
|
69
|
+
console.log(` Output: ${outputPath}\n`);
|
|
70
|
+
|
|
71
|
+
if (dryRun) {
|
|
72
|
+
console.log(' Would convert:');
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
const _relativeSrc = path.relative(sourcePath, file);
|
|
75
|
+
const outputName = getOutputName(file, sourcePath, outputPath, flatten, isDirectory);
|
|
76
|
+
const relativeOut = path.relative(outputPath, outputName);
|
|
77
|
+
const exists = await fileExists(outputName);
|
|
78
|
+
const suffix = exists ? ' (exists, would skip)' : '';
|
|
79
|
+
console.log(` ${path.basename(file)} → ${relativeOut}${suffix}`);
|
|
80
|
+
}
|
|
81
|
+
const wouldConvert = await countConvertible(files, sourcePath, outputPath, flatten, isDirectory, overwrite);
|
|
82
|
+
console.log(`\n ${files.length} files found, ${wouldConvert} would be converted.\n`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Create output directory
|
|
87
|
+
await fs.mkdir(outputPath, { recursive: true });
|
|
88
|
+
|
|
89
|
+
// Convert files
|
|
90
|
+
let converted = 0;
|
|
91
|
+
let skipped = 0;
|
|
92
|
+
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
const outputFile = getOutputName(file, sourcePath, outputPath, flatten, isDirectory);
|
|
95
|
+
const ext = path.extname(file).toLowerCase();
|
|
96
|
+
const exists = await fileExists(outputFile);
|
|
97
|
+
|
|
98
|
+
if (exists && !overwrite) {
|
|
99
|
+
console.log(` ⊘ ${path.basename(file)} → skipped (already exists, use --overwrite)`);
|
|
100
|
+
skipped++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const result = await convertFile(file);
|
|
106
|
+
|
|
107
|
+
// Ensure output directory exists
|
|
108
|
+
await fs.mkdir(path.dirname(outputFile), { recursive: true });
|
|
109
|
+
|
|
110
|
+
// Write output
|
|
111
|
+
// Write output
|
|
112
|
+
await fs.writeFile(outputFile, result.markdown, 'utf-8');
|
|
113
|
+
|
|
114
|
+
// Write structured data if available (for AI analysis)
|
|
115
|
+
if (result.data) {
|
|
116
|
+
const jsonPath = outputFile.replace(/\.md$/, '.json');
|
|
117
|
+
await fs.writeFile(jsonPath, JSON.stringify(result.data, null, 2), 'utf-8');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let suffix = '';
|
|
121
|
+
if (ext === '.md') {
|
|
122
|
+
suffix = ' (copied)';
|
|
123
|
+
} else if (ext === '.pptx' && result.slideCount) {
|
|
124
|
+
suffix = ` (${result.slideCount} slides)`;
|
|
125
|
+
}
|
|
126
|
+
if (result.warnings?.length > 0) {
|
|
127
|
+
console.log(` ⚠ ${path.basename(file)} → ${path.basename(outputFile)}${suffix} (review recommended)`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(` ✓ ${path.basename(file)} → ${path.basename(outputFile)}${suffix}`);
|
|
130
|
+
}
|
|
131
|
+
converted++;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.log(` ✗ ${path.basename(file)} → failed: ${error.message}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(`\nDone! ${converted} converted, ${skipped} skipped.`);
|
|
138
|
+
|
|
139
|
+
// Show next steps only if we converted files
|
|
140
|
+
if (converted > 0) {
|
|
141
|
+
printNextSteps(outputPath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Find all supported files in a directory recursively
|
|
147
|
+
*/
|
|
148
|
+
async function findFiles(dir, format) {
|
|
149
|
+
const files = [];
|
|
150
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
151
|
+
|
|
152
|
+
for (const entry of entries) {
|
|
153
|
+
const fullPath = path.join(dir, entry.name);
|
|
154
|
+
|
|
155
|
+
if (entry.isDirectory()) {
|
|
156
|
+
// Skip md output directory to avoid confusion
|
|
157
|
+
if (entry.name === 'converted') continue;
|
|
158
|
+
const subFiles = await findFiles(fullPath, format);
|
|
159
|
+
files.push(...subFiles);
|
|
160
|
+
} else if (entry.isFile()) {
|
|
161
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
162
|
+
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
163
|
+
files.push(fullPath);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return files;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get output filename for a source file
|
|
173
|
+
*/
|
|
174
|
+
function getOutputName(file, sourcePath, outputPath, flatten, isSourceDir) {
|
|
175
|
+
const baseName = path.basename(file, path.extname(file)) + '.md';
|
|
176
|
+
|
|
177
|
+
if (flatten || !isSourceDir) {
|
|
178
|
+
return path.join(outputPath, baseName);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Preserve directory structure
|
|
182
|
+
const relativePath = path.relative(sourcePath, file);
|
|
183
|
+
const relativeDir = path.dirname(relativePath);
|
|
184
|
+
return path.join(outputPath, relativeDir, baseName);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check if file exists
|
|
189
|
+
*/
|
|
190
|
+
async function fileExists(filePath) {
|
|
191
|
+
try {
|
|
192
|
+
await fs.access(filePath);
|
|
193
|
+
return true;
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Count how many files would be converted (for dry run)
|
|
201
|
+
*/
|
|
202
|
+
async function countConvertible(files, sourcePath, outputPath, flatten, isSourceDir, overwrite) {
|
|
203
|
+
let count = 0;
|
|
204
|
+
for (const file of files) {
|
|
205
|
+
const outputFile = getOutputName(file, sourcePath, outputPath, flatten, isSourceDir);
|
|
206
|
+
const exists = await fileExists(outputFile);
|
|
207
|
+
if (!exists || overwrite) {
|
|
208
|
+
count++;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return count;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Convert a single file based on its extension
|
|
216
|
+
*/
|
|
217
|
+
async function convertFile(filePath) {
|
|
218
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
219
|
+
|
|
220
|
+
switch (ext) {
|
|
221
|
+
case '.docx':
|
|
222
|
+
return await convertDocx(filePath);
|
|
223
|
+
case '.pptx':
|
|
224
|
+
return await convertPptx(filePath);
|
|
225
|
+
case '.pdf':
|
|
226
|
+
return await convertPdf(filePath);
|
|
227
|
+
case '.md':
|
|
228
|
+
return await copyMd(filePath);
|
|
229
|
+
default:
|
|
230
|
+
throw new Error(`Unsupported format: ${ext}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Convert DOCX to markdown using mammoth
|
|
236
|
+
*/
|
|
237
|
+
async function convertDocx(filePath) {
|
|
238
|
+
const mammoth = await import('mammoth');
|
|
239
|
+
const result = await mammoth.convertToMarkdown({ path: filePath });
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
markdown: result.value,
|
|
243
|
+
warnings: result.messages.filter(m => m.type === 'warning')
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Convert PPTX to markdown using node-pptx-parser
|
|
249
|
+
*/
|
|
250
|
+
async function convertPptx(filePath) {
|
|
251
|
+
const PptxParser = (await import('node-pptx-parser')).default;
|
|
252
|
+
|
|
253
|
+
const parser = new PptxParser(filePath);
|
|
254
|
+
const textContent = await parser.extractText();
|
|
255
|
+
|
|
256
|
+
let markdown = '';
|
|
257
|
+
let slideNum = 0;
|
|
258
|
+
|
|
259
|
+
for (const slide of textContent) {
|
|
260
|
+
slideNum++;
|
|
261
|
+
markdown += `# Slide ${slideNum}\n\n`;
|
|
262
|
+
|
|
263
|
+
// Add slide text content
|
|
264
|
+
if (slide.text && slide.text.length > 0) {
|
|
265
|
+
for (const text of slide.text) {
|
|
266
|
+
if (text && text.trim()) {
|
|
267
|
+
markdown += `${text.trim()}\n\n`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
markdown += '---\n\n';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
markdown: markdown.trim(),
|
|
277
|
+
slideCount: slideNum,
|
|
278
|
+
warnings: []
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Convert PDF to markdown/json using pdf2json custom parser
|
|
284
|
+
*/
|
|
285
|
+
async function convertPdf(filePath) {
|
|
286
|
+
const { parsePdfStructure } = await import('./pdf-structure.js');
|
|
287
|
+
const structure = await parsePdfStructure(filePath);
|
|
288
|
+
|
|
289
|
+
// Convert structure to Markdown
|
|
290
|
+
let markdown = '';
|
|
291
|
+
for (const element of structure.elements) {
|
|
292
|
+
if (element.type.startsWith('h')) {
|
|
293
|
+
const level = element.type.substring(1);
|
|
294
|
+
markdown += `${'#'.repeat(parseInt(level))} ${element.text}\n\n`;
|
|
295
|
+
} else {
|
|
296
|
+
markdown += `${element.text}\n\n`;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
markdown: markdown.trim(),
|
|
302
|
+
data: structure, // Return structured data for JSON output if needed
|
|
303
|
+
warnings: []
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Copy markdown files directly (they're already in the right format)
|
|
309
|
+
*/
|
|
310
|
+
async function copyMd(filePath) {
|
|
311
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
312
|
+
return {
|
|
313
|
+
markdown: content,
|
|
314
|
+
warnings: []
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Print next steps for AI-assisted workflow
|
|
320
|
+
*/
|
|
321
|
+
function printNextSteps(outputPath) {
|
|
322
|
+
const relativeOutput = path.relative(process.cwd(), outputPath);
|
|
323
|
+
|
|
324
|
+
console.log(`
|
|
325
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
326
|
+
📋 Next steps (AI-assisted workflow):
|
|
327
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
328
|
+
|
|
329
|
+
1. CREATE OUTLINE: Ask your AI assistant to reference:
|
|
330
|
+
- framework/docs/COURSE_OUTLINE_GUIDE.md
|
|
331
|
+
- framework/docs/COURSE_AUTHORING_GUIDE.md
|
|
332
|
+
- ${relativeOutput}/*.md (your converted files)
|
|
333
|
+
|
|
334
|
+
2. IMPLEMENT COURSE: Then reference:
|
|
335
|
+
- framework/docs/COURSE_AUTHORING_GUIDE.md
|
|
336
|
+
- your-outline.md
|
|
337
|
+
|
|
338
|
+
Attach files using your AI tool's method (drag-drop, @file, #file, etc.)
|
|
339
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
340
|
+
`);
|
|
341
|
+
}
|