• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

source-academy / js-slang / 5406352152

pending completion
5406352152

Pull #1428

github

web-flow
Merge 0380f5ed7 into 8618e26e4
Pull Request #1428: Further Enhancements to the Module System

3611 of 4728 branches covered (76.37%)

Branch coverage included in aggregate %.

831 of 831 new or added lines in 50 files covered. (100.0%)

10852 of 12603 relevant lines covered (86.11%)

93898.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.76
/src/modules/moduleLoaderAsync.ts
1
import type { Node } from 'estree'
2
import { memoize } from 'lodash'
1✔
3

4
import type { Context } from '..'
5
import { timeoutPromise } from '../utils'
1✔
6
import { wrapSourceModule } from '../utils/operators'
1✔
7
import { ModuleConnectionError, ModuleInternalError, ModuleNotFoundError } from './errors'
1✔
8
import { MODULES_STATIC_URL } from './moduleLoader'
1✔
9
import type { ModuleBundle, ModuleDocumentation, ModuleManifest } from './moduleTypes'
10
import { getRequireProvider } from './requireProvider'
1✔
11

12
export function httpGetAsync(path: string, type: 'json'): Promise<object>
13
export function httpGetAsync(path: string, type: 'text'): Promise<string>
14
export async function httpGetAsync(path: string, type: 'json' | 'text') {
1✔
15
  try {
12✔
16
    const resp = await fetch(path, {
12✔
17
      method: 'GET'
18
    })
19

20
    if (resp.status !== 200 && resp.status !== 304) {
11✔
21
      throw new ModuleConnectionError()
1✔
22
    }
23

24
    const promise = type === 'text' ? resp.text() : resp.json()
10✔
25
    if (typeof window === 'undefined') {
10!
26
      return timeoutPromise(promise, 10000)
×
27
    }
28
    return promise
10✔
29
  } catch (error) {
30
    if (error instanceof TypeError) throw new ModuleConnectionError()
2✔
31
    if (!(error instanceof ModuleConnectionError)) throw new ModuleInternalError(path, error)
1!
32
    throw error
1✔
33
  }
34
}
35

36
/**
37
 * Send a HTTP GET request to the modules endpoint to retrieve the manifest
38
 * @return Modules
39
 */
40
export const memoizedGetModuleManifestAsync = memoize(getModuleManifestAsync)
1✔
41
function getModuleManifestAsync(): Promise<ModuleManifest> {
42
  return httpGetAsync(`${MODULES_STATIC_URL}/modules.json`, 'json') as Promise<ModuleManifest>
2✔
43
}
44

45
async function checkModuleExists(moduleName: string, node?: Node) {
46
  const modules = await memoizedGetModuleManifestAsync()
1✔
47
  // Check if the module exists
48
  if (!(moduleName in modules)) throw new ModuleNotFoundError(moduleName, node)
1!
49

50
  return modules[moduleName]
1✔
51
}
52

53
export const memoizedGetModuleBundleAsync = memoize(getModuleBundleAsync)
1✔
54
async function getModuleBundleAsync(moduleName: string): Promise<string> {
55
  return httpGetAsync(`${MODULES_STATIC_URL}/bundles/${moduleName}.js`, 'text')
3✔
56
}
57

58
export const memoizedGetModuleTabAsync = memoize(getModuleTabAsync)
1✔
59
function getModuleTabAsync(tabName: string): Promise<string> {
60
  return httpGetAsync(`${MODULES_STATIC_URL}/tabs/${tabName}.js`, 'text')
3✔
61
}
62

63
export const memoizedGetModuleDocsAsync = memoize(getModuleDocsAsync)
1✔
64
async function getModuleDocsAsync(moduleName: string): Promise<ModuleDocumentation | null> {
65
  try {
×
66
    const result = await httpGetAsync(`${MODULES_STATIC_URL}/jsons/${moduleName}.json`, 'json')
×
67
    return result as ModuleDocumentation
×
68
  } catch (error) {
69
    console.warn(`Failed to load documentation for ${moduleName}:`, error)
×
70
    return null
×
71
  }
72
}
73

74
export async function loadModuleTabsAsync(moduleName: string, node?: Node) {
1✔
75
  const moduleInfo = await checkModuleExists(moduleName, node)
1✔
76

77
  // Load the tabs for the current module
78
  return Promise.all(
1✔
79
    moduleInfo.tabs.map(async path => {
2✔
80
      const rawTabFile = await memoizedGetModuleTabAsync(path)
2✔
81
      try {
2✔
82
        return eval(rawTabFile)
2✔
83
      } catch (error) {
84
        // console.error('tab error:', error);
85
        throw new ModuleInternalError(path, error, node)
2✔
86
      }
87
    })
88
  )
89
}
90

91
export async function loadModuleBundleAsync(
1✔
92
  moduleName: string,
93
  context: Context,
94
  wrapModule: boolean,
95
  node?: Node
96
) {
97
  // await checkModuleExists(moduleName, node)
98
  const moduleText = await memoizedGetModuleBundleAsync(moduleName)
2✔
99
  try {
2✔
100
    const moduleBundle: ModuleBundle = eval(moduleText)
2✔
101

102
    if (wrapModule) return wrapSourceModule(moduleName, moduleBundle, getRequireProvider(context))
1!
103
    return moduleBundle(getRequireProvider(context))
1✔
104
  } catch (error) {
105
    // console.error("bundle error: ", error)
106
    throw new ModuleInternalError(moduleName, error, node)
1✔
107
  }
108
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc