bare-stow 0.1.9 → 0.3.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/README.md +92 -111
- package/bin.js +142 -53
- package/index.d.ts +318 -82
- package/index.js +163 -207
- package/lib/assets.js +54 -0
- package/lib/fs.js +2 -4
- package/lib/graph.js +94 -0
- package/lib/language/javascript.js +74 -0
- package/lib/language/kotlin.js +139 -0
- package/lib/language/python.js +65 -0
- package/lib/language/swift.js +111 -0
- package/lib/language.js +18 -0
- package/lib/link.js +149 -0
- package/lib/provider.js +33 -0
- package/lib/rpc/bare-rpc.js +147 -15
- package/lib/rpc.js +6 -18
- package/lib/shim.js +24 -31
- package/lib/target/bare-kit.js +238 -0
- package/lib/target/bare-sidecar.js +86 -53
- package/lib/target/bare-worker.js +18 -72
- package/lib/target/javascript.js +63 -0
- package/lib/target/swift.js +57 -0
- package/lib/target.js +43 -12
- package/package.json +20 -36
- package/lib/host.d.ts +0 -64
- package/lib/host.js +0 -114
- package/lib/protocol.d.ts +0 -46
- package/lib/protocol.js +0 -139
- package/lib/runtime.d.ts +0 -29
- package/lib/runtime.js +0 -92
package/index.js
CHANGED
|
@@ -1,89 +1,111 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
|
-
const { fileURLToPath } = require('url')
|
|
3
2
|
const pack = require('bare-pack')
|
|
4
3
|
const id = require('bare-bundle-id')
|
|
5
|
-
const strip = require('bare-type-stripper')
|
|
6
|
-
const { resolve } = require('bare-module-traverse')
|
|
7
|
-
const lex = require('bare-module-lexer')
|
|
8
4
|
const fs = require('./lib/fs')
|
|
5
|
+
const assets = require('./lib/assets')
|
|
9
6
|
const shim = require('./lib/shim')
|
|
10
|
-
const
|
|
11
|
-
const
|
|
7
|
+
const graph = require('./lib/graph')
|
|
8
|
+
const rpcs = require('./lib/rpc')
|
|
9
|
+
const { select } = require('./lib/provider')
|
|
12
10
|
|
|
13
|
-
module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
11
|
+
module.exports = exports = async function* stow(entry, target, out, opts = {}) {
|
|
14
12
|
if (!target) throw new Error("'target' is required")
|
|
15
13
|
if (!out) throw new Error("'out' is required")
|
|
16
14
|
|
|
17
|
-
let {
|
|
15
|
+
let {
|
|
16
|
+
language,
|
|
17
|
+
languageOptions,
|
|
18
|
+
targetOptions,
|
|
19
|
+
client,
|
|
20
|
+
server,
|
|
21
|
+
base,
|
|
22
|
+
hosts,
|
|
23
|
+
resolveTarget,
|
|
24
|
+
resolveRPC,
|
|
25
|
+
resolveLanguage,
|
|
26
|
+
readModule = fs.readModule,
|
|
27
|
+
listPrefix = fs.listPrefix,
|
|
28
|
+
resolveModule = fs.resolveModule,
|
|
29
|
+
...packOpts
|
|
30
|
+
} = opts
|
|
31
|
+
|
|
32
|
+
entry = await resolveModule(new URL(entry))
|
|
33
|
+
out = new URL(out)
|
|
18
34
|
|
|
19
|
-
|
|
35
|
+
if (!out.pathname.endsWith('/')) out.pathname += '/'
|
|
20
36
|
|
|
21
|
-
const
|
|
37
|
+
const resolved = graph.providers(target, {
|
|
38
|
+
language,
|
|
39
|
+
languageOptions,
|
|
40
|
+
targetOptions,
|
|
41
|
+
hosts,
|
|
42
|
+
resolveTarget,
|
|
43
|
+
resolveLanguage
|
|
44
|
+
})
|
|
22
45
|
|
|
23
|
-
|
|
24
|
-
out = new URL(out)
|
|
46
|
+
const { harness, options } = resolved
|
|
25
47
|
|
|
26
|
-
|
|
27
|
-
|
|
48
|
+
target = resolved.target
|
|
49
|
+
language = resolved.language
|
|
50
|
+
hosts = resolved.hosts
|
|
28
51
|
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
52
|
+
if (client) client = select('RPC library', rpcs(client, resolveRPC), language.name)
|
|
53
|
+
if (server) server = rpcs(server, resolveRPC)
|
|
54
|
+
|
|
55
|
+
const layout = language.layout(out, options)
|
|
56
|
+
|
|
57
|
+
const bundleURL = new URL('index' + target.extension, layout.artifacts ?? layout.harness)
|
|
58
|
+
|
|
59
|
+
// Linked bundles leave their assets out, as files that the runtime loads from
|
|
60
|
+
// next to the bundle or from the application.
|
|
61
|
+
const resources = target.linked && target.linking === 'app' ? assets.app : null
|
|
62
|
+
const name = resources ?? 'index'
|
|
63
|
+
|
|
64
|
+
if (client) {
|
|
65
|
+
client = {
|
|
66
|
+
url: language.sibling(layout.harness, 'client'),
|
|
67
|
+
...client.generate({ role: 'client', options })
|
|
34
68
|
}
|
|
35
|
-
} else {
|
|
36
|
-
hosts = t.hosts
|
|
37
69
|
}
|
|
38
70
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}),
|
|
51
|
-
null
|
|
52
|
-
)
|
|
53
|
-
: null
|
|
71
|
+
const files = [
|
|
72
|
+
{
|
|
73
|
+
url: layout.harness,
|
|
74
|
+
...harness.generate({
|
|
75
|
+
bundle: language.reference(layout.harness, bundleURL),
|
|
76
|
+
client: client && language.reference(layout.harness, client.url),
|
|
77
|
+
resources,
|
|
78
|
+
options
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
]
|
|
54
82
|
|
|
55
|
-
|
|
83
|
+
if (client) files.push(client)
|
|
56
84
|
|
|
57
|
-
const
|
|
85
|
+
const main = shim(entry, target.isolation, server)
|
|
58
86
|
|
|
59
|
-
const
|
|
60
|
-
|
|
87
|
+
const hooks = {
|
|
88
|
+
readModule: graph.readModule(main.modules, readModule),
|
|
89
|
+
listPrefix,
|
|
90
|
+
resolveModule
|
|
91
|
+
}
|
|
61
92
|
|
|
62
93
|
const offloaded = []
|
|
63
94
|
|
|
64
95
|
let writeFile
|
|
65
96
|
|
|
66
|
-
if (isOffloadEnabled(
|
|
97
|
+
if (isOffloadEnabled(target.offload)) writeFile = collectOffloaded(offloaded)
|
|
98
|
+
|
|
99
|
+
const traversal = graph.traversal(packOpts, hosts)
|
|
67
100
|
|
|
68
101
|
// The base of the bundle depends on where its modules live, so the graph is
|
|
69
102
|
// packed unbased and unmounted once that is known.
|
|
70
103
|
let bundle = await pack(
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
'.ts': '.js',
|
|
77
|
-
'.mts': '.mjs',
|
|
78
|
-
'.cts': '.cjs'
|
|
79
|
-
},
|
|
80
|
-
hosts,
|
|
81
|
-
linked: t.linked,
|
|
82
|
-
offload: t.offload
|
|
83
|
-
},
|
|
84
|
-
readModule,
|
|
85
|
-
fs.listPrefix,
|
|
86
|
-
fs.resolveModule,
|
|
104
|
+
main.url,
|
|
105
|
+
{ ...traversal, linked: target.linked, offload: target.offload },
|
|
106
|
+
hooks.readModule,
|
|
107
|
+
hooks.listPrefix,
|
|
108
|
+
hooks.resolveModule,
|
|
87
109
|
writeFile
|
|
88
110
|
)
|
|
89
111
|
|
|
@@ -91,50 +113,72 @@ module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
|
91
113
|
|
|
92
114
|
bundle = rerootOffloaded(bundle.unmount(base), base, bundleURL, offloaded)
|
|
93
115
|
|
|
116
|
+
let unpacked = []
|
|
117
|
+
|
|
118
|
+
if (target.linked) {
|
|
119
|
+
const result = await assets.unpack(bundle, base, name, hooks.readModule)
|
|
120
|
+
|
|
121
|
+
bundle = result.bundle
|
|
122
|
+
|
|
123
|
+
// Assets left to the application are written by `link()` instead.
|
|
124
|
+
if (resources === null) unpacked = result.assets
|
|
125
|
+
}
|
|
126
|
+
|
|
94
127
|
bundle.id = id(bundle).toString('hex')
|
|
95
128
|
|
|
96
|
-
// The
|
|
97
|
-
|
|
98
|
-
// into both channels before handing it to the target.
|
|
99
|
-
let clientSetup = null
|
|
129
|
+
// The manifest lists the offloaded files only once it's known there are any.
|
|
130
|
+
const artifacts = offloaded.length > 0 ? [bundleURL, offloadURL(bundleURL)] : [bundleURL]
|
|
100
131
|
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
module
|
|
107
|
-
})
|
|
132
|
+
if (unpacked.length > 0) {
|
|
133
|
+
artifacts.push(new URL(name + '/', bundleURL), new URL(name + '.assets', bundleURL))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (layout.listing) artifacts.push(listingURL(bundleURL))
|
|
108
137
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
138
|
+
const addons = []
|
|
139
|
+
|
|
140
|
+
// Targets that leave linking to the application use `link()` instead.
|
|
141
|
+
if (target.linked && target.linking === 'package') {
|
|
142
|
+
if (!layout.addons) {
|
|
143
|
+
throw new Error(`Language '${language.name}' does not support linked addons`)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for await (const url of graph.link([main.url], layout.addons, traversal, hooks)) {
|
|
147
|
+
addons.push(url)
|
|
148
|
+
yield { url }
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
151
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
files.push({
|
|
153
|
+
url: layout.manifest,
|
|
154
|
+
source: language.manifest({
|
|
155
|
+
name: layout.name,
|
|
156
|
+
dependencies: Object.assign({}, ...files.map((file) => file.dependencies)),
|
|
157
|
+
options,
|
|
158
|
+
hosts,
|
|
159
|
+
artifacts: artifacts.map((url) => language.reference(layout.manifest, url)),
|
|
160
|
+
addons: addons.map((url) => language.reference(layout.manifest, url))
|
|
161
|
+
})
|
|
121
162
|
})
|
|
122
163
|
|
|
123
|
-
for (const
|
|
124
|
-
|
|
125
|
-
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
await fs.writeFile(file.url, file.source)
|
|
166
|
+
yield { url: file.url }
|
|
126
167
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
for (const artifact of artifacts) {
|
|
130
|
-
const url = artifact.extension ? siblingURL(out, artifact.extension) : out
|
|
168
|
+
if (file.types) {
|
|
169
|
+
const typesURL = language.types(file.url)
|
|
131
170
|
|
|
132
|
-
|
|
133
|
-
|
|
171
|
+
await fs.writeFile(typesURL, file.types)
|
|
172
|
+
yield { url: typesURL }
|
|
173
|
+
}
|
|
134
174
|
}
|
|
135
175
|
|
|
136
|
-
await fs.writeFile(bundleURL, encodeBundle(bundle,
|
|
137
|
-
yield { url: bundleURL }
|
|
176
|
+
await fs.writeFile(bundleURL, encodeBundle(bundle, target.format, target.encoding ?? 'utf8'))
|
|
177
|
+
yield { url: bundleURL, base }
|
|
178
|
+
|
|
179
|
+
if (unpacked.length > 0) {
|
|
180
|
+
for await (const url of assets.write(new URL('./', bundleURL), name, unpacked)) yield { url }
|
|
181
|
+
}
|
|
138
182
|
|
|
139
183
|
// Offloaded files are collected in the order their reads complete, so they
|
|
140
184
|
// are sorted to keep the output stable.
|
|
@@ -144,10 +188,29 @@ module.exports = async function* stow(entry, target, out, opts = {}) {
|
|
|
144
188
|
await fs.writeFile(artifact.url, artifact.source)
|
|
145
189
|
yield { url: artifact.url }
|
|
146
190
|
}
|
|
191
|
+
|
|
192
|
+
if (layout.listing) {
|
|
193
|
+
const url = listingURL(bundleURL)
|
|
194
|
+
const dir = path.posix.dirname(bundleURL.pathname)
|
|
195
|
+
|
|
196
|
+
const listing = offloaded.map(
|
|
197
|
+
(artifact) => '/' + decodeURIComponent(path.posix.relative(dir, artifact.url.pathname)) + '\n'
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
await fs.writeFile(url, listing.join(''))
|
|
201
|
+
yield { url }
|
|
202
|
+
}
|
|
147
203
|
}
|
|
148
204
|
|
|
149
|
-
|
|
150
|
-
|
|
205
|
+
// Languages that package the bundle where the runtime can't read it, such as
|
|
206
|
+
// in a jar, list the files beside it, one `/<path>` per line, for the harness to
|
|
207
|
+
// extract along with the bundle.
|
|
208
|
+
function listingURL(bundleURL) {
|
|
209
|
+
return new URL(path.basename(bundleURL.pathname) + '.files', bundleURL)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function resolveBase(base, bundle) {
|
|
213
|
+
const modules = [...bundle.keys()].map((href) => new URL(href))
|
|
151
214
|
|
|
152
215
|
if (base) {
|
|
153
216
|
base = new URL(base)
|
|
@@ -191,20 +254,6 @@ function isOffloadEnabled(offload) {
|
|
|
191
254
|
return false
|
|
192
255
|
}
|
|
193
256
|
|
|
194
|
-
function wrapReadModule(readModule, shimURL, shimSource) {
|
|
195
|
-
return async function (url) {
|
|
196
|
-
if (url.href === shimURL.href) return shimSource
|
|
197
|
-
|
|
198
|
-
const source = await readModule(url)
|
|
199
|
-
|
|
200
|
-
if (source === null) return null
|
|
201
|
-
|
|
202
|
-
if (/\.(c|m)?ts$/.test(url.pathname)) return strip(source)
|
|
203
|
-
|
|
204
|
-
return source
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
257
|
function collectOffloaded(sink) {
|
|
209
258
|
return function writeFile(url, source) {
|
|
210
259
|
sink.push({ url, source })
|
|
@@ -217,11 +266,15 @@ function collectOffloaded(sink) {
|
|
|
217
266
|
// next to the harness, as a mirrored `node_modules` beside the harness would
|
|
218
267
|
// shadow the packages it imports. Their resolutions are rewritten to point into
|
|
219
268
|
// that directory, along with the directories that hold them.
|
|
269
|
+
function offloadURL(bundleURL) {
|
|
270
|
+
return new URL(path.basename(bundleURL.pathname) + '.d/', bundleURL)
|
|
271
|
+
}
|
|
272
|
+
|
|
220
273
|
function rerootOffloaded(bundle, base, bundleURL, offloaded) {
|
|
221
274
|
if (offloaded.length === 0) return bundle
|
|
222
275
|
|
|
223
|
-
const
|
|
224
|
-
const
|
|
276
|
+
const dir = offloadURL(bundleURL)
|
|
277
|
+
const name = path.basename(dir.pathname)
|
|
225
278
|
const rewrites = new Map()
|
|
226
279
|
|
|
227
280
|
for (const file of offloaded) {
|
|
@@ -288,107 +341,6 @@ function isTerminator(input) {
|
|
|
288
341
|
return input === '' || input.endsWith('/') || input.endsWith(':')
|
|
289
342
|
}
|
|
290
343
|
|
|
291
|
-
async function assertImportsResolve(source, out) {
|
|
292
|
-
for (const entry of lex(source).imports) {
|
|
293
|
-
const { specifier } = entry
|
|
294
|
-
|
|
295
|
-
if (specifier.startsWith('.') || specifier.startsWith('/')) continue
|
|
296
|
-
|
|
297
|
-
if (await resolves(entry, out)) continue
|
|
298
|
-
|
|
299
|
-
throw new Error(
|
|
300
|
-
`Harness '${fileURLToPath(out)}' imports '${specifier}', which the package containing it does not depend on`
|
|
301
|
-
)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async function resolves(entry, parentURL) {
|
|
306
|
-
const resolver = resolve.bare(entry, parentURL)
|
|
307
|
-
|
|
308
|
-
let next = resolver.next()
|
|
309
|
-
|
|
310
|
-
while (next.done !== true) {
|
|
311
|
-
const value = next.value
|
|
312
|
-
|
|
313
|
-
if (value.package) {
|
|
314
|
-
const source = await fs.readModule(value.package)
|
|
315
|
-
|
|
316
|
-
next = resolver.next(source === null ? null : JSON.parse(source))
|
|
317
|
-
} else {
|
|
318
|
-
const exists = await fs.isFile(value.resolution)
|
|
319
|
-
|
|
320
|
-
if (exists) return true
|
|
321
|
-
|
|
322
|
-
next = resolver.next(false)
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return false
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async function resolveModule(out) {
|
|
330
|
-
switch (path.extname(out.pathname)) {
|
|
331
|
-
case '.mjs':
|
|
332
|
-
return 'esm'
|
|
333
|
-
case '.cjs':
|
|
334
|
-
return 'cjs'
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// For an ambiguous extension (e.g. '.js') the module system follows the
|
|
338
|
-
// `type` of the closest enclosing `package.json`, defaulting to CommonJS.
|
|
339
|
-
return (await packageType(new URL('./', out))) === 'module' ? 'esm' : 'cjs'
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
async function packageType(dir) {
|
|
343
|
-
while (true) {
|
|
344
|
-
let source = null
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
source = await fs.readFile(new URL('package.json', dir))
|
|
348
|
-
} catch {
|
|
349
|
-
// No `package.json` in this directory; keep searching upwards.
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (source !== null) return JSON.parse(source).type ?? null
|
|
353
|
-
|
|
354
|
-
const parent = new URL('../', dir)
|
|
355
|
-
|
|
356
|
-
if (parent.pathname === dir.pathname) return null
|
|
357
|
-
|
|
358
|
-
dir = parent
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function siblingURL(out, extension) {
|
|
363
|
-
const dir = new URL('./', out)
|
|
364
|
-
const base = path.basename(out.pathname, path.extname(out.pathname))
|
|
365
|
-
|
|
366
|
-
return new URL(base + extension, dir)
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function fragment(artifacts, extension) {
|
|
370
|
-
for (const artifact of artifacts) {
|
|
371
|
-
if ((artifact.extension ?? null) === extension) return artifact.source
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return null
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function relativeSpecifier(from, to) {
|
|
378
|
-
if (from.protocol === 'file:' && to.protocol === 'file:') {
|
|
379
|
-
const fromDir = path.dirname(fileURLToPath(from))
|
|
380
|
-
const toPath = fileURLToPath(to)
|
|
381
|
-
|
|
382
|
-
let relative = path.relative(fromDir, toPath).split(path.sep).join('/')
|
|
383
|
-
|
|
384
|
-
if (!relative.startsWith('.')) relative = './' + relative
|
|
385
|
-
|
|
386
|
-
return relative
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return to.href
|
|
390
|
-
}
|
|
391
|
-
|
|
392
344
|
function encodeBundle(bundle, format, encoding) {
|
|
393
345
|
const data = bundle.toBuffer()
|
|
394
346
|
|
|
@@ -405,3 +357,7 @@ function encodeBundle(bundle, format, encoding) {
|
|
|
405
357
|
throw new Error(`Unknown format '${format}'`)
|
|
406
358
|
}
|
|
407
359
|
}
|
|
360
|
+
|
|
361
|
+
exports.link = require('./lib/link')
|
|
362
|
+
|
|
363
|
+
exports.resources = assets.app
|
package/lib/assets.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const unpack = require('bare-unpack')
|
|
2
|
+
const fs = require('./fs')
|
|
3
|
+
|
|
4
|
+
// The assets of bundles linked by the application share one directory, named
|
|
5
|
+
// after the bundle that Bare Kit starts them as.
|
|
6
|
+
exports.app = 'bare-stow'
|
|
7
|
+
|
|
8
|
+
// Assets are laid out the way Bare Kit expects: the assets of `<name>.bundle`
|
|
9
|
+
// live in `<name>/`, listed in `<name>.assets` for platforms that extract them.
|
|
10
|
+
exports.unpack = async function (bundle, base, name, readModule) {
|
|
11
|
+
const assets = []
|
|
12
|
+
|
|
13
|
+
bundle = await unpack(bundle, { files: false, assets: true }, async (key) => {
|
|
14
|
+
const relative = await exports.path(new URL('.' + key, base), readModule)
|
|
15
|
+
|
|
16
|
+
assets.push({ path: relative, source: bundle.read(key) })
|
|
17
|
+
|
|
18
|
+
return '/../' + name + '/' + relative
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
return { bundle, assets }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Assets of dependencies keep their path from `node_modules`, and others their
|
|
25
|
+
// path within their package, so that every bundle places an asset alike.
|
|
26
|
+
exports.path = async function (url, readModule) {
|
|
27
|
+
const nm = url.pathname.indexOf('/node_modules/')
|
|
28
|
+
|
|
29
|
+
if (nm >= 0) return url.pathname.slice(nm + 1)
|
|
30
|
+
|
|
31
|
+
for (let dir = new URL('./', url); ; dir = new URL('../', dir)) {
|
|
32
|
+
if ((await readModule(new URL('package.json', dir))) !== null) {
|
|
33
|
+
return url.pathname.slice(dir.pathname.length)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (dir.pathname === '/') throw new Error(`Asset '${url.href}' is not part of a package`)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.write = async function* (dir, name, assets) {
|
|
41
|
+
assets = [...assets].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))
|
|
42
|
+
|
|
43
|
+
for (const asset of assets) {
|
|
44
|
+
const url = new URL(name + '/' + asset.path, dir)
|
|
45
|
+
|
|
46
|
+
await fs.writeFile(url, asset.source)
|
|
47
|
+
yield url
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const listing = new URL(name + '.assets', dir)
|
|
51
|
+
|
|
52
|
+
await fs.writeFile(listing, assets.map((asset) => '/' + asset.path + '\n').join(''))
|
|
53
|
+
yield listing
|
|
54
|
+
}
|
package/lib/fs.js
CHANGED
|
@@ -43,7 +43,7 @@ exports.readModule = async function readModule(url) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
function isFile(url) {
|
|
46
|
+
exports.isFile = function isFile(url) {
|
|
47
47
|
return new Promise((resolve) => {
|
|
48
48
|
fs.stat(fileURLToPath(url), (err, stat) => {
|
|
49
49
|
resolve(err === null && stat.isFile())
|
|
@@ -60,7 +60,7 @@ function isDir(url) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
exports.listPrefix = async function* listPrefix(url) {
|
|
63
|
-
if (await isFile(url)) return yield url
|
|
63
|
+
if (await exports.isFile(url)) return yield url
|
|
64
64
|
|
|
65
65
|
if (url.pathname[url.pathname.length - 1] !== '/') {
|
|
66
66
|
url.pathname += '/'
|
|
@@ -77,6 +77,4 @@ exports.listPrefix = async function* listPrefix(url) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
exports.isFile = isFile
|
|
81
|
-
|
|
82
80
|
exports.resolveModule = require('bare-pack/fs').resolveModule
|
package/lib/graph.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const { fileURLToPath, pathToFileURL } = require('url')
|
|
2
|
+
const bareLink = require('bare-link')
|
|
3
|
+
const strip = require('bare-type-stripper')
|
|
4
|
+
const { resolve } = require('bare-module-traverse')
|
|
5
|
+
const targets = require('./target')
|
|
6
|
+
const languages = require('./language')
|
|
7
|
+
const { select } = require('./provider')
|
|
8
|
+
|
|
9
|
+
exports.providers = function providers(target, opts = {}) {
|
|
10
|
+
let {
|
|
11
|
+
language = 'javascript',
|
|
12
|
+
languageOptions,
|
|
13
|
+
targetOptions,
|
|
14
|
+
hosts,
|
|
15
|
+
resolveTarget,
|
|
16
|
+
resolveLanguage
|
|
17
|
+
} = opts
|
|
18
|
+
|
|
19
|
+
target = targets(target, resolveTarget)
|
|
20
|
+
language = languages(language, resolveLanguage)
|
|
21
|
+
|
|
22
|
+
const harness = select('Target', target, language.name)
|
|
23
|
+
|
|
24
|
+
// A target may pin options that it can't do without, overriding those given.
|
|
25
|
+
const options = { ...language.options(languageOptions), ...harness.options }
|
|
26
|
+
|
|
27
|
+
targetOptions = targets.options(target, targetOptions)
|
|
28
|
+
|
|
29
|
+
target = targets.resolve(target, { language: language.name, options, targetOptions })
|
|
30
|
+
|
|
31
|
+
hosts = resolveHosts(hosts, target.hosts, target.name)
|
|
32
|
+
|
|
33
|
+
return { target, language, harness, options, targetOptions, hosts }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveHosts(hosts, supported, name) {
|
|
37
|
+
if (!hosts) return supported
|
|
38
|
+
|
|
39
|
+
for (const host of hosts) {
|
|
40
|
+
if (!supported.includes(host)) {
|
|
41
|
+
throw new Error(`Host '${host}' is not supported by target '${name}'`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return hosts
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// The graph is traversed the same way when packing it as when linking its
|
|
49
|
+
// addons.
|
|
50
|
+
exports.traversal = function traversal(opts, hosts) {
|
|
51
|
+
return {
|
|
52
|
+
...opts,
|
|
53
|
+
resolve: resolve.bare,
|
|
54
|
+
aliases: {
|
|
55
|
+
'.ts': '.js',
|
|
56
|
+
'.mts': '.mjs',
|
|
57
|
+
'.cts': '.cjs',
|
|
58
|
+
...opts.aliases
|
|
59
|
+
},
|
|
60
|
+
hosts
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exports.readModule = function readModule(modules, read) {
|
|
65
|
+
return async function (url) {
|
|
66
|
+
if (modules.has(url.href)) return modules.get(url.href)
|
|
67
|
+
|
|
68
|
+
const source = await read(url)
|
|
69
|
+
|
|
70
|
+
if (source === null) return null
|
|
71
|
+
|
|
72
|
+
if (/\.(c|m)?ts$/.test(url.pathname)) return strip(source)
|
|
73
|
+
|
|
74
|
+
return source
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// The layout must not depend on the hosts, as Swift packages only accept
|
|
79
|
+
// XCFrameworks. Resources linked outside of the directory are intermediate.
|
|
80
|
+
exports.link = async function* link(entries, dir, traversal, hooks) {
|
|
81
|
+
for await (const resource of bareLink(
|
|
82
|
+
entries.map((url) => fileURLToPath(url)),
|
|
83
|
+
{
|
|
84
|
+
...traversal,
|
|
85
|
+
out: fileURLToPath(dir),
|
|
86
|
+
alwaysMultiHost: true,
|
|
87
|
+
...hooks
|
|
88
|
+
}
|
|
89
|
+
)) {
|
|
90
|
+
const url = pathToFileURL(resource)
|
|
91
|
+
|
|
92
|
+
if (url.href.startsWith(dir.href)) yield url
|
|
93
|
+
}
|
|
94
|
+
}
|