@liascript/exporter 3.0.0--1.0.3 → 3.0.1--1.0.3
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/dist/assets/capacitor/{index.bfe7363b.js → index.a7f021f7.js} +1 -1
- package/dist/assets/capacitor/index.html +1 -1
- package/dist/assets/capacitor/{jszip.min.f6eda75b.js → jszip.min.43389eb1.js} +1 -1
- package/dist/assets/capacitor/{trystero-ipfs.min.b27a61d7.js → trystero-ipfs.min.f25fe3e7.js} +1 -1
- package/dist/assets/indexeddb/{index.599a57d6.js → index.4aceca2f.js} +1 -1
- package/dist/assets/indexeddb/index.html +1 -1
- package/dist/assets/indexeddb/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
- package/dist/assets/scorm2004/{index.7a5820ab.js → index.33bec53a.js} +1 -1
- package/dist/assets/scorm2004/index.html +1 -1
- package/dist/assets/scorm2004/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
- package/dist/assets/xapi/{index.018a032a.js → index.f2e89e49.js} +1 -1
- package/dist/assets/xapi/index.html +1 -1
- package/dist/assets/xapi/{jszip.min.eaecf580.js → jszip.min.19c66d77.js} +1 -1
- package/dist/index.js +47 -47
- package/dist/server/presets.json +94 -0
- package/dist/server/presets.yaml +120 -0
- package/dist/server/public/app.js +1 -0
- package/dist/server/public/assets/android.svg +38 -0
- package/dist/server/public/assets/cmi.svg +154 -0
- package/dist/server/public/assets/docx.svg +20 -0
- package/dist/server/public/assets/edX.svg +75 -0
- package/dist/server/public/assets/edx.svg +75 -0
- package/dist/server/public/assets/epub.svg +18 -0
- package/dist/server/public/assets/icon.svg +82 -0
- package/dist/server/public/assets/ilias.png +0 -0
- package/dist/server/public/assets/json.svg +4 -0
- package/dist/server/public/assets/learnworlds.png +0 -0
- package/dist/server/public/assets/moodle.svg +190 -0
- package/dist/server/public/assets/opal.png +0 -0
- package/dist/server/public/assets/openolat.png +0 -0
- package/dist/server/public/assets/pdf.svg +4 -0
- package/dist/server/public/assets/rdf.svg +4 -0
- package/dist/server/public/assets/scorm.png +0 -0
- package/dist/server/public/assets/web.png +0 -0
- package/dist/server/public/assets/xapi.png +0 -0
- package/dist/server/public/i18n.js +1 -0
- package/dist/server/public/index.html +1587 -0
- package/dist/server/public/locales/de.json +247 -0
- package/dist/server/public/locales/en.json +247 -0
- package/dist/server/public/status.html +251 -0
- package/dist/server/public/styles.css +712 -0
- package/package.json +5 -1
- package/.parcelrc +0 -3
- package/DESKTOP_APP_README.md +0 -58
- package/DOCKERHUB_DESCRIPTION.md +0 -52
- package/Dockerfile +0 -129
- package/PLAYSTORE_GUIDE.md +0 -172
- package/action.yml +0 -157
- package/custom.css +0 -10
- package/electron-builder.json +0 -149
- package/src/cli.ts +0 -69
- package/src/colorize.ts +0 -115
- package/src/export/android.ts +0 -419
- package/src/export/docx.ts +0 -1025
- package/src/export/epub.ts +0 -1306
- package/src/export/h5p.ts +0 -390
- package/src/export/helper.ts +0 -360
- package/src/export/ims.ts +0 -191
- package/src/export/pdf.ts +0 -406
- package/src/export/presets.ts +0 -220
- package/src/export/project.ts +0 -829
- package/src/export/rdf.ts +0 -551
- package/src/export/scorm12.ts +0 -167
- package/src/export/scorm2004.ts +0 -140
- package/src/export/web.ts +0 -306
- package/src/export/xapi.ts +0 -424
- package/src/exporter.ts +0 -296
- package/src/index.ts +0 -96
- package/src/parser.ts +0 -373
- package/src/presets.yaml +0 -219
- package/src/types.ts +0 -82
- package/tsconfig.json +0 -24
package/src/export/helper.ts
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
import fetch from 'node-fetch'
|
|
4
|
-
import * as temp from 'temp'
|
|
5
|
-
import * as fs from 'fs-extra'
|
|
6
|
-
import * as path from 'path'
|
|
7
|
-
const archiver = require('archiver')
|
|
8
|
-
const beautify = require('simply-beautiful')
|
|
9
|
-
|
|
10
|
-
// Constants
|
|
11
|
-
const TEMP_DIR_PREFIX = 'lia'
|
|
12
|
-
const DIST_DIR_RELATIVE_PATH = '../../dist'
|
|
13
|
-
const ZIP_COMPRESSION_LEVEL = 9
|
|
14
|
-
const RANDOM_STRING_LENGTH = 16
|
|
15
|
-
const RANDOM_CHARS =
|
|
16
|
-
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
17
|
-
const BEAUTIFY_OPTIONS = {
|
|
18
|
-
indent_size: 4,
|
|
19
|
-
space_before_conditional: true,
|
|
20
|
-
jslint_happy: true,
|
|
21
|
-
max_char: 0,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Creates a temporary directory with a unique name.
|
|
26
|
-
* @returns Promise that resolves to the path of the created temporary directory
|
|
27
|
-
*/
|
|
28
|
-
export function tmpDir(): Promise<string> {
|
|
29
|
-
return new Promise((resolve, reject) => {
|
|
30
|
-
temp.mkdir(TEMP_DIR_PREFIX, function (err: Error | null, tmpPath: string) {
|
|
31
|
-
if (err) reject(err)
|
|
32
|
-
else resolve(tmpPath)
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Returns the absolute path to the distribution directory.
|
|
39
|
-
* @returns The path to the dist directory (where index.js is located)
|
|
40
|
-
*/
|
|
41
|
-
export function dirname(): string {
|
|
42
|
-
// Get the directory where the main entry point (index.js) is located
|
|
43
|
-
// This works both in Docker and locally because it's relative to the actual running file
|
|
44
|
-
const mainFile = require.main?.filename || process.argv[1]
|
|
45
|
-
|
|
46
|
-
return path.dirname(mainFile)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Delays execution for a specified number of milliseconds.
|
|
51
|
-
* @param ms - Number of milliseconds to sleep
|
|
52
|
-
* @returns Promise that resolves after the specified delay
|
|
53
|
-
*/
|
|
54
|
-
export function sleep(ms: number): Promise<void> {
|
|
55
|
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Writes content to a file.
|
|
60
|
-
* @param filename - Path to the file to write
|
|
61
|
-
* @param content - Content to write to the file
|
|
62
|
-
* @returns Promise that resolves when the file is written
|
|
63
|
-
*/
|
|
64
|
-
export function writeFile(filename: string, content: string): Promise<string> {
|
|
65
|
-
return new Promise((resolve, reject) => {
|
|
66
|
-
fs.writeFile(filename, content, function (err: Error | null) {
|
|
67
|
-
if (err) reject(err)
|
|
68
|
-
else resolve('ok')
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates a filter function to exclude hidden folders and node_modules during copy operations.
|
|
75
|
-
* @param sourceDir - The source directory being copied
|
|
76
|
-
* @returns A filter function that returns false for hidden folders and node_modules
|
|
77
|
-
*/
|
|
78
|
-
export function filterHidden(
|
|
79
|
-
sourceDir: string,
|
|
80
|
-
): (src: string, dest: string) => boolean {
|
|
81
|
-
return function (src: string, dest: string): boolean {
|
|
82
|
-
// Get the relative path of the source folder being copied
|
|
83
|
-
const relPath = path.relative(path.resolve(sourceDir), src)
|
|
84
|
-
|
|
85
|
-
// Split the relative path into its components
|
|
86
|
-
const components = relPath.split(path.sep)
|
|
87
|
-
|
|
88
|
-
// Check each component for hidden folders
|
|
89
|
-
for (const component of components) {
|
|
90
|
-
// Check if the component starts with a dot (i.e., hidden folder)
|
|
91
|
-
if (component.startsWith('.')) {
|
|
92
|
-
return false // Exclude the folder from the copy
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Check if the current folder being copied is the "node_modules" folder
|
|
96
|
-
if (component === 'node_modules') {
|
|
97
|
-
return false // Exclude the folder from the copy
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return true // Include the folder in the copy
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Injects ResponsiveVoice script tag into an HTML string.
|
|
107
|
-
* @param key - ResponsiveVoice API key
|
|
108
|
-
* @param into - HTML content to inject the script into
|
|
109
|
-
* @returns Modified HTML content with the ResponsiveVoice script
|
|
110
|
-
*/
|
|
111
|
-
export function injectResponsivevoice(key: string, into: string): string {
|
|
112
|
-
return inject(
|
|
113
|
-
`<script src="https://code.responsivevoice.org/responsivevoice.js?key=${key}"></script>`,
|
|
114
|
-
into,
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Inject an arbitrary tag into HTML content.
|
|
120
|
-
* @param element - new tag to be added
|
|
121
|
-
* @param into - old index.html content
|
|
122
|
-
* @param tag - Tag to inject at. Can be:
|
|
123
|
-
* - boolean: true for after `<head>`, false for before `</head>` (backward compatibility)
|
|
124
|
-
* - string: opening tag like `<body>` (injects after) or closing tag like `</body>` (injects before)
|
|
125
|
-
* @returns - new index.html content
|
|
126
|
-
*/
|
|
127
|
-
export function inject(
|
|
128
|
-
element: string,
|
|
129
|
-
into: string,
|
|
130
|
-
tag: string | boolean = false,
|
|
131
|
-
): string {
|
|
132
|
-
// Backward compatibility: handle boolean parameter
|
|
133
|
-
if (typeof tag === 'boolean') {
|
|
134
|
-
return tag
|
|
135
|
-
? into.replace('<head>', '<head>' + element)
|
|
136
|
-
: into.replace('</head>', element + '</head>')
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// New string-based tag injection
|
|
140
|
-
if (tag.startsWith('</')) {
|
|
141
|
-
// Closing tag: inject before it
|
|
142
|
-
return into.replace(tag, element + tag)
|
|
143
|
-
} else {
|
|
144
|
-
// Opening tag: inject after it
|
|
145
|
-
return into.replace(tag, tag + element)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Checks if a string is a valid URL (http, https, or file protocol).
|
|
151
|
-
* @param uri - The string to check
|
|
152
|
-
* @returns True if the string is a URL, false otherwise
|
|
153
|
-
*/
|
|
154
|
-
export function isURL(uri: string): boolean {
|
|
155
|
-
return (
|
|
156
|
-
uri.startsWith('http://') ||
|
|
157
|
-
uri.startsWith('https://') ||
|
|
158
|
-
uri.startsWith('file://')
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Creates an HTML iframe wrapper file for embedding LiaScript content.
|
|
164
|
-
* @param tmpPath - Path to the temporary directory
|
|
165
|
-
* @param filename - Name of the file to create
|
|
166
|
-
* @param readme - Path to the README file
|
|
167
|
-
* @param jsonLD - JSON-LD metadata to inject
|
|
168
|
-
* @param style - Optional custom CSS styles for the iframe
|
|
169
|
-
* @param index - Optional custom index.html filename
|
|
170
|
-
* @returns Promise that resolves when the file is written
|
|
171
|
-
*/
|
|
172
|
-
export async function iframe(
|
|
173
|
-
tmpPath: string,
|
|
174
|
-
filename: string,
|
|
175
|
-
readme: string,
|
|
176
|
-
jsonLD: string,
|
|
177
|
-
style?: string,
|
|
178
|
-
index?: string,
|
|
179
|
-
): Promise<string> {
|
|
180
|
-
await writeFile(
|
|
181
|
-
path.join(tmpPath, filename),
|
|
182
|
-
prettify(`<!DOCTYPE html>
|
|
183
|
-
<html style="height:100%; overflow: hidden">
|
|
184
|
-
<head>
|
|
185
|
-
${jsonLD}
|
|
186
|
-
</head>
|
|
187
|
-
<body style="height:100%; margin: 0px">
|
|
188
|
-
|
|
189
|
-
<iframe id="lia-container" src="" style="${
|
|
190
|
-
style || 'border: 0px; width: 100%; height: 100%'
|
|
191
|
-
}"></iframe>
|
|
192
|
-
|
|
193
|
-
<script>
|
|
194
|
-
let path = window.location.pathname.replace("start.html", "")
|
|
195
|
-
let iframe = document.getElementById("lia-container")
|
|
196
|
-
|
|
197
|
-
if (iframe) {
|
|
198
|
-
const src = path + "${
|
|
199
|
-
index || 'index.html'
|
|
200
|
-
}?" + path + "${readme.replace('./', '')}"
|
|
201
|
-
iframe.src = src
|
|
202
|
-
}
|
|
203
|
-
</script>
|
|
204
|
-
|
|
205
|
-
</body>
|
|
206
|
-
</html>
|
|
207
|
-
`),
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
return 'ok'
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Creates a ZIP archive from a directory.
|
|
215
|
-
* @param dir - Directory to archive
|
|
216
|
-
* @param filename - Base filename for the ZIP archive (without .zip extension)
|
|
217
|
-
* @returns Promise that resolves when the archive is finalized
|
|
218
|
-
*/
|
|
219
|
-
export async function zip(dir: string, filename: string): Promise<void> {
|
|
220
|
-
return new Promise((resolve, reject) => {
|
|
221
|
-
const output = fs.createWriteStream(
|
|
222
|
-
path.dirname(filename) + '/' + path.basename(filename + '.zip'),
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
const archive = archiver('zip', {
|
|
226
|
-
zlib: { level: ZIP_COMPRESSION_LEVEL }, // Sets the compression level.
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
// listen for all archive data to be written
|
|
230
|
-
// 'close' event is fired only when a file descriptor is involved
|
|
231
|
-
output.on('close', function () {
|
|
232
|
-
console.log(archive.pointer() + ' total bytes')
|
|
233
|
-
console.log(
|
|
234
|
-
'archiver has been finalized and the output file descriptor has closed.',
|
|
235
|
-
)
|
|
236
|
-
resolve()
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
// This event is fired when the data source is drained no matter what was the data source.
|
|
240
|
-
// It is not part of this library but rather from the NodeJS Stream API.
|
|
241
|
-
// @see: https://nodejs.org/api/stream.html#stream_event_end
|
|
242
|
-
output.on('end', function () {
|
|
243
|
-
console.log('Data has been drained')
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
// good practice to catch warnings (ie stat failures and other non-blocking errors)
|
|
247
|
-
archive.on('warning', function (err: any) {
|
|
248
|
-
if (err.code === 'ENOENT') {
|
|
249
|
-
console.warn('Archive warning:', err)
|
|
250
|
-
} else {
|
|
251
|
-
reject(err)
|
|
252
|
-
}
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
// good practice to catch this error explicitly
|
|
256
|
-
archive.on('error', function (err: Error) {
|
|
257
|
-
reject(err)
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
// pipe archive data to the file
|
|
261
|
-
archive.pipe(output)
|
|
262
|
-
|
|
263
|
-
archive.directory(dir, false)
|
|
264
|
-
archive.finalize()
|
|
265
|
-
})
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Generates a random alphanumeric string.
|
|
270
|
-
* Note: Uses Math.random() - not cryptographically secure.
|
|
271
|
-
* @param length - Length of the random string to generate (default: 16)
|
|
272
|
-
* @returns Random alphanumeric string
|
|
273
|
-
*/
|
|
274
|
-
export function random(length: number = RANDOM_STRING_LENGTH): string {
|
|
275
|
-
// Pick characters randomly
|
|
276
|
-
let str = ''
|
|
277
|
-
for (let i = 0; i < length; i++) {
|
|
278
|
-
str += RANDOM_CHARS.charAt(Math.floor(Math.random() * RANDOM_CHARS.length))
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return str
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Parses a raw GitHub URL and extracts repository information.
|
|
286
|
-
* Supports URLs in format: raw.githubusercontent.com/org/repo/branch/path or raw.githubusercontent.com/org/repo/refs/heads/branch/path
|
|
287
|
-
* @param raw_url - Raw GitHub URL to parse
|
|
288
|
-
* @returns Object with repository information or null if URL doesn't match
|
|
289
|
-
*/
|
|
290
|
-
export function getRepository(raw_url: string): {
|
|
291
|
-
url: string
|
|
292
|
-
branch: string
|
|
293
|
-
path: string
|
|
294
|
-
cmd: string
|
|
295
|
-
} | null {
|
|
296
|
-
const match = raw_url.match(
|
|
297
|
-
/raw\.githubusercontent\.com\/([^\/]+)\/([^\/]+)\/(?:refs\/heads\/)?([^\/]+)\/(.*)/i,
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
if (match?.length === 5) {
|
|
301
|
-
const [_, organization, repository, branch, filePath] = match
|
|
302
|
-
|
|
303
|
-
const url = `https://github.com/${organization}/${repository}`
|
|
304
|
-
|
|
305
|
-
return {
|
|
306
|
-
url,
|
|
307
|
-
branch,
|
|
308
|
-
path: filePath,
|
|
309
|
-
cmd: `git clone --branch ${branch} ${url} tmp`,
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return null
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Checks if a LICENSE file exists at the given base URL.
|
|
318
|
-
* @param baseURL - Base URL to check for LICENSE file
|
|
319
|
-
* @returns Promise that resolves to true if LICENSE exists, false otherwise
|
|
320
|
-
*/
|
|
321
|
-
export async function checkLicense(baseURL: string): Promise<boolean> {
|
|
322
|
-
const url = new URL('LICENSE', baseURL).href
|
|
323
|
-
|
|
324
|
-
return await checkFileExists(url)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Extracts the base URL by removing the last path segment.
|
|
329
|
-
* @param url - URL to extract base from
|
|
330
|
-
* @returns Base URL without the last path segment
|
|
331
|
-
*/
|
|
332
|
-
export function baseURL(url: string): string {
|
|
333
|
-
const pathSegments = url.split('/')
|
|
334
|
-
pathSegments.pop()
|
|
335
|
-
return pathSegments.join('/')
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Checks if a file exists at the given URL using a HEAD request.
|
|
340
|
-
* @param fileUrl - URL of the file to check
|
|
341
|
-
* @returns Promise that resolves to true if file exists (200 status), false otherwise
|
|
342
|
-
*/
|
|
343
|
-
async function checkFileExists(fileUrl: string): Promise<boolean> {
|
|
344
|
-
try {
|
|
345
|
-
const response = await fetch(fileUrl, { method: 'HEAD' })
|
|
346
|
-
return response.status === 200
|
|
347
|
-
} catch (error) {
|
|
348
|
-
console.warn(`Error checking if file exists: ${error}`)
|
|
349
|
-
return false
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Prettifies HTML content using beautification options.
|
|
355
|
-
* @param html - HTML string to prettify
|
|
356
|
-
* @returns Prettified HTML string
|
|
357
|
-
*/
|
|
358
|
-
export function prettify(html: string): string {
|
|
359
|
-
return beautify.html(html, BEAUTIFY_OPTIONS)
|
|
360
|
-
}
|
package/src/export/ims.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import * as helper from './helper'
|
|
2
|
-
import * as RDF from './rdf'
|
|
3
|
-
import * as COLOR from '../colorize'
|
|
4
|
-
|
|
5
|
-
const path = require('path')
|
|
6
|
-
const fs = require('fs-extra')
|
|
7
|
-
|
|
8
|
-
export function help() {
|
|
9
|
-
console.log('')
|
|
10
|
-
console.log(COLOR.heading('IMS settings:'), '\n')
|
|
11
|
-
|
|
12
|
-
COLOR.info(
|
|
13
|
-
'IMS (Instructional Management Systems) Content Package is an interoperable standard format for packaging learning content between different LMSes.',
|
|
14
|
-
)
|
|
15
|
-
console.log(
|
|
16
|
-
'\nLearn more: https://www.imsglobal.org/content/packaging/index.html\n',
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
COLOR.command(
|
|
20
|
-
null,
|
|
21
|
-
'--ims-indexeddb',
|
|
22
|
-
' Use IndexedDB to store data persistently',
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
console.log('')
|
|
26
|
-
console.log(COLOR.heading('WEB settings:'), '\n')
|
|
27
|
-
|
|
28
|
-
COLOR.info(
|
|
29
|
-
'Pack the project into a self contained web project that can be hosted everywhere.',
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
console.log('')
|
|
33
|
-
|
|
34
|
-
COLOR.command(
|
|
35
|
-
null,
|
|
36
|
-
'--web-iframe',
|
|
37
|
-
' Use an iframed version to hide the course URL.',
|
|
38
|
-
)
|
|
39
|
-
COLOR.command(
|
|
40
|
-
null,
|
|
41
|
-
'--web-indexeddb',
|
|
42
|
-
' This will allow to store data within the browser using indexeddb, you can optionally pass a unique key (by default one is generated randomly).',
|
|
43
|
-
)
|
|
44
|
-
COLOR.command(
|
|
45
|
-
null,
|
|
46
|
-
'--web-zip',
|
|
47
|
-
' By default the result is not zipped, you can change this with this parameter.',
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface ImsExportArguments {
|
|
52
|
-
input: string
|
|
53
|
-
readme: string
|
|
54
|
-
output: string
|
|
55
|
-
format: string
|
|
56
|
-
path: string
|
|
57
|
-
key?: string
|
|
58
|
-
style?: string
|
|
59
|
-
'ims-indexeddb'?: boolean
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const format = 'ims'
|
|
63
|
-
|
|
64
|
-
export async function exporter(argument: ImsExportArguments, json: any) {
|
|
65
|
-
if (typeof json === 'string') {
|
|
66
|
-
json = JSON.parse(json)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const dirname = helper.dirname()
|
|
70
|
-
|
|
71
|
-
// make temp folder
|
|
72
|
-
let tmp = await helper.tmpDir()
|
|
73
|
-
|
|
74
|
-
let tmpPath = path.join(tmp, 'pro')
|
|
75
|
-
|
|
76
|
-
// copy assets to temp
|
|
77
|
-
await fs.copy(
|
|
78
|
-
path.join(
|
|
79
|
-
dirname,
|
|
80
|
-
argument['ims-indexeddb'] ? './assets/indexeddb' : './assets/web',
|
|
81
|
-
),
|
|
82
|
-
tmpPath,
|
|
83
|
-
)
|
|
84
|
-
await fs.copy(path.join(dirname, './assets/common'), tmpPath)
|
|
85
|
-
|
|
86
|
-
let index = fs.readFileSync(path.join(tmpPath, 'index.html'), 'utf8')
|
|
87
|
-
|
|
88
|
-
// change responsive key
|
|
89
|
-
if (argument.key) {
|
|
90
|
-
index = helper.injectResponsivevoice(argument.key, index)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
await helper.writeFile(path.join(tmpPath, 'index.html'), index)
|
|
95
|
-
} catch (e) {
|
|
96
|
-
console.warn(e)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
await manifest(tmpPath, json.lia)
|
|
101
|
-
|
|
102
|
-
// copy base path or readme-directory into temp
|
|
103
|
-
await fs.copy(argument.path, tmpPath, {
|
|
104
|
-
filter: helper.filterHidden(argument.path),
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
if (argument['ims-indexeddb']) {
|
|
108
|
-
let newReadme = helper.random(20) + '.md'
|
|
109
|
-
|
|
110
|
-
let old_ = path.join(tmpPath, argument.readme)
|
|
111
|
-
let new_ = path.join(path.dirname(old_), newReadme)
|
|
112
|
-
|
|
113
|
-
argument.readme = argument.readme.replace(
|
|
114
|
-
path.basename(argument.readme),
|
|
115
|
-
newReadme,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
await fs.move(old_, new_)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const jsonLD = await RDF.script(argument, json)
|
|
122
|
-
|
|
123
|
-
await helper.iframe(
|
|
124
|
-
tmpPath,
|
|
125
|
-
'start.html',
|
|
126
|
-
argument.readme,
|
|
127
|
-
jsonLD,
|
|
128
|
-
argument.style,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
await helper.zip(tmpPath, argument.output)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async function manifest(tmpPath: any, meta: any) {
|
|
135
|
-
let keywords = ''
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
const tags = meta.definition.macro.tags
|
|
139
|
-
.split(',')
|
|
140
|
-
.map((e: string) => e.trim())
|
|
141
|
-
|
|
142
|
-
for (let i = 0; i < tags.length; i++) {
|
|
143
|
-
keywords += `<imsmd:langstring xml:lang="${meta.definition.language}">${tags[i]}</imsmd:langstring>`
|
|
144
|
-
}
|
|
145
|
-
} catch (e) {}
|
|
146
|
-
|
|
147
|
-
await helper.writeFile(
|
|
148
|
-
path.join(tmpPath, 'imsmanifest.xml'),
|
|
149
|
-
`<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"
|
|
150
|
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
151
|
-
xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/imscp_v1p1.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 http://www.imsglobal.org/xsd/imsmd_v1p2.xsd "
|
|
152
|
-
identifier="Manifest5-CEC3D3-3201-DF8E-8F42-3CEED12F4197" version="IMS CP 1.1.4">
|
|
153
|
-
<metadata>
|
|
154
|
-
<schema>IMS Content</schema>
|
|
155
|
-
<schemaversion>1.1.4</schemaversion>
|
|
156
|
-
<imsmd:lom>
|
|
157
|
-
<imsmd:general>
|
|
158
|
-
<imsmd:title>
|
|
159
|
-
<imsmd:langstring xml:lang="${meta.definition.language}">${meta.str_title}</imsmd:langstring>
|
|
160
|
-
</imsmd:title>
|
|
161
|
-
<imsmd:language>${meta.definition.language}</imsmd:language>
|
|
162
|
-
<imsmd:description>
|
|
163
|
-
<imsmd:langstring xml:lang="${meta.definition.language}">${meta.comment}</imsmd:langstring>
|
|
164
|
-
</imsmd:description>
|
|
165
|
-
<imsmd:keyword>
|
|
166
|
-
${keywords}
|
|
167
|
-
</imsmd:keyword>
|
|
168
|
-
</imsmd:general>
|
|
169
|
-
<imsmd:lifecycle>
|
|
170
|
-
<imsmd:version>
|
|
171
|
-
<imsmd:langstring xml:lang="${meta.definition.language}">${meta.definition.version}</imsmd:langstring>
|
|
172
|
-
</imsmd:version>
|
|
173
|
-
</imsmd:lifecycle>
|
|
174
|
-
</imsmd:lom>
|
|
175
|
-
</metadata>
|
|
176
|
-
<organizations default="TOC1">
|
|
177
|
-
<organization identifier="TOC1" structure="hierarchical">
|
|
178
|
-
<title>All Lessons</title>
|
|
179
|
-
<item identifier="ITEM1" identifierref="LIASCRIPT">
|
|
180
|
-
<title>LiaScript - Course</title>
|
|
181
|
-
</item>
|
|
182
|
-
</organization>
|
|
183
|
-
</organizations>
|
|
184
|
-
<resources>
|
|
185
|
-
<resource identifier="LIASCRIPT" type="webcontent" href="start.html">
|
|
186
|
-
<file href="start.html" />
|
|
187
|
-
</resource>
|
|
188
|
-
</resources>
|
|
189
|
-
</manifest>`,
|
|
190
|
-
)
|
|
191
|
-
}
|