-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathloader.js
103 lines (87 loc) · 2.89 KB
/
loader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const path = require('path')
const fs = require('fs')
const fm = require('formality-lang')
const withLocalFiles = require('formality-lang/dist/fs-local.js')
.with_local_files
const withFileSystemCache = require('formality-lang/dist/fs-cache.js')
.with_file_system_cache
module.exports = function formalityLoader(content) {
const loader = withLocalFiles(getFromCache, this.context)
const file = path.basename(this.resourcePath, '.fm')
return fm
.parse(content, { loader, file })
.then(({ defs, open_imports }) => {
// Adding local imports as a file dependency
getDependentFiles(open_imports, this.context).forEach(this.addDependency)
const name = (this.resourceQuery || '?@').slice(1)
const term = `${file}/${name}`
const { typeCheckMode = 'all' } = this.query
const shouldCheckTypes =
typeCheckMode === 'all' || typeCheckMode === this.mode
if (shouldCheckTypes) typeCheck(term, defs)
const js = fm.js.compile(term, defs)
return 'module.exports = ' + js
})
.catch(err => {
throw new Error(err)
})
}
module.exports.resolver = {
apply(resolver) {
resolver
.getHook('described-resolve')
.tapAsync('formalityResolver', (req, resolveContext, callback) => {
if (!req.request.includes('.fm') || req.resolved) return callback()
const request = path.resolve(
req.module ? cachePath : req.path,
req.request.replace('.fm/', '.fm?')
)
const [filePath] = request.split('?')
const resolve = () =>
resolver.doResolve(
resolver.ensureHook('resolve'),
{ ...req, request, resolved: true },
null,
resolveContext,
callback
)
if (req.module)
fs.exists(filePath, fileExits =>
fileExits
? resolve()
: getFromCache(path.basename(filePath, '.fm')).then(resolve)
)
else resolve()
})
}
}
const cachePath = path.join(__dirname, 'fm_modules')
const getFromCache = withFileSystemCache(
withDownloadWarning(fm.loader.load_file),
cachePath
)
function typeCheck(term, defs) {
if (term.endsWith('/@')) {
const file = term.slice(0, -1)
Object.keys(defs)
.filter(defName => defName.startsWith(file))
.forEach(defName => fm.core.typecheck(defName, null, defs))
} else fm.core.typecheck(term, null, defs)
}
function getDependentFiles(imports, filesPath) {
return Object.entries(imports)
.filter(([name, value]) => value && !name.includes('#'))
.map(([name]) => path.join(filesPath, name + '.fm'))
}
let warned_about_downloading = false
function withDownloadWarning(loader) {
return file => {
if (!warned_about_downloading) {
console.info(
'Downloading files to `fm_modules`. This may take a while...'
)
warned_about_downloading = true
}
return loader(file)
}
}