@zipadee/javascript 0.0.9 → 0.0.11
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/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/serve.d.ts +27 -27
- package/lib/serve.js +95 -75
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './lib/serve.js';
|
|
2
|
-
//# sourceMappingURL=index.d.ts.map
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './lib/serve.js';
|
|
2
|
-
//# sourceMappingURL=index.js.map
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
package/lib/serve.d.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type Middleware} from '@zipadee/core';
|
|
2
2
|
export interface Options {
|
|
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
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Root directory to restrict file access. Defaults to the current working
|
|
5
|
+
* directory.
|
|
6
|
+
*/
|
|
7
|
+
root?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Base path to resolve imports from. Defaults to the current working
|
|
10
|
+
* directory.
|
|
11
|
+
*/
|
|
12
|
+
base?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Imports resolved to outside of the base path will be prefixed with this
|
|
15
|
+
* string. Defaults to `/__root__`.
|
|
16
|
+
*/
|
|
17
|
+
rootPathPrefix?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Array of file extensions to transform. Defaults to `['.js', '.mjs']`.
|
|
20
|
+
*
|
|
21
|
+
* Other extensions are served as plain files.
|
|
22
|
+
*/
|
|
23
|
+
extensions?: Array<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Array of import conditions to support. Defaults to `['browser', 'import']`.
|
|
26
|
+
*/
|
|
27
|
+
conditions?: Array<string>;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Serve static JavaScript files from a `root` directory.
|
|
31
31
|
*/
|
|
32
32
|
export declare const serve: (opts: Options) => Middleware;
|
|
33
|
-
//# sourceMappingURL=serve.d.ts.map
|
|
33
|
+
//# sourceMappingURL=serve.d.ts.map
|
package/lib/serve.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import {HttpError} from '@zipadee/core';
|
|
2
|
+
import {
|
|
3
|
+
decodePath,
|
|
4
|
+
pathIsHidden,
|
|
5
|
+
resolvePath,
|
|
6
|
+
stat,
|
|
7
|
+
} from '@zipadee/static/lib/utils.js';
|
|
8
|
+
import {send} from '@zipadee/static';
|
|
4
9
|
import fs from 'node:fs/promises';
|
|
5
10
|
import path from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
11
|
+
import {parse, init} from 'es-module-lexer';
|
|
12
|
+
import {moduleResolve} from 'import-meta-resolve';
|
|
8
13
|
await init;
|
|
9
14
|
// TODO:
|
|
10
15
|
// - Add caching for both specifier resolution and files
|
|
@@ -19,77 +24,92 @@ await init;
|
|
|
19
24
|
* Serve static JavaScript files from a `root` directory.
|
|
20
25
|
*/
|
|
21
26
|
export const serve = (opts) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const root =
|
|
28
|
+
opts.root === undefined ? process.cwd() : path.resolve(opts.root);
|
|
29
|
+
const base = opts.base === undefined ? root : resolvePath(root, opts.base);
|
|
30
|
+
const rootPathPrefix = opts.rootPathPrefix ?? '/__root__';
|
|
31
|
+
const extensions = opts.extensions ?? ['.js', '.mjs'];
|
|
32
|
+
const conditionsArray = opts.conditions ?? ['browser', 'import'];
|
|
33
|
+
const conditions = new Set(conditionsArray);
|
|
34
|
+
return async (req, res, next) => {
|
|
35
|
+
if (!(req.method === 'HEAD' || req.method === 'GET')) {
|
|
36
|
+
// TODO: implement HEAD?
|
|
37
|
+
return await next();
|
|
38
|
+
}
|
|
39
|
+
let filePath = decodePath(req.path);
|
|
40
|
+
const mountedPath = req.url.pathname.substring(
|
|
41
|
+
0,
|
|
42
|
+
req.url.pathname.length - filePath.length,
|
|
43
|
+
);
|
|
44
|
+
const parsedPath = path.parse(filePath);
|
|
45
|
+
const transform = extensions.includes(parsedPath.ext);
|
|
46
|
+
if (filePath.startsWith(rootPathPrefix)) {
|
|
47
|
+
filePath = filePath.substring(rootPathPrefix.length);
|
|
48
|
+
filePath = filePath.slice(parsedPath.root.length);
|
|
49
|
+
filePath = resolvePath(root, filePath);
|
|
50
|
+
} else {
|
|
51
|
+
filePath = filePath.slice(parsedPath.root.length);
|
|
52
|
+
filePath = resolvePath(base, filePath);
|
|
53
|
+
}
|
|
54
|
+
if (pathIsHidden(root, filePath)) {
|
|
55
|
+
return await next();
|
|
56
|
+
}
|
|
57
|
+
const stats = await stat(filePath);
|
|
58
|
+
if (stats.isDirectory()) {
|
|
59
|
+
return await next();
|
|
60
|
+
}
|
|
61
|
+
if (!transform) {
|
|
62
|
+
const relativePath = path.relative(root, filePath);
|
|
63
|
+
await send(req, res, relativePath, {root});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const source = await fs.readFile(filePath, 'utf8');
|
|
67
|
+
const [imports, _exports, _facade, _hasModuleSyntax] = parse(
|
|
68
|
+
source,
|
|
69
|
+
filePath,
|
|
70
|
+
);
|
|
71
|
+
let output = '';
|
|
72
|
+
let lastIndex = 0;
|
|
73
|
+
for (const impt of imports) {
|
|
74
|
+
const {t: type, s: start, e: end, n: unescaped} = impt;
|
|
75
|
+
if (type === 1) {
|
|
76
|
+
// Static import
|
|
77
|
+
const importSpecifier = unescaped || source.substring(start, end);
|
|
78
|
+
// If the specifier is relative or absolute, we don't need to resolve it
|
|
79
|
+
if (
|
|
80
|
+
importSpecifier.startsWith('.') ||
|
|
81
|
+
importSpecifier.startsWith('/')
|
|
82
|
+
) {
|
|
83
|
+
output += `${source.substring(lastIndex, start)}${importSpecifier}`;
|
|
84
|
+
lastIndex = end;
|
|
85
|
+
continue;
|
|
32
86
|
}
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
87
|
+
const fileURL = new URL(filePath, 'file://');
|
|
88
|
+
const resolvedImportURL = moduleResolve(
|
|
89
|
+
importSpecifier,
|
|
90
|
+
fileURL,
|
|
91
|
+
conditions,
|
|
92
|
+
);
|
|
93
|
+
const resolvedImportPath = resolvedImportURL.pathname;
|
|
94
|
+
if (!resolvedImportPath.startsWith(root)) {
|
|
95
|
+
throw new HttpError(500);
|
|
41
96
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
97
|
+
let resolvedimport;
|
|
98
|
+
if (resolvedImportPath.startsWith(base)) {
|
|
99
|
+
resolvedimport = resolvedImportPath.substring(base.length);
|
|
100
|
+
} else {
|
|
101
|
+
resolvedimport = path.join(
|
|
102
|
+
mountedPath,
|
|
103
|
+
rootPathPrefix,
|
|
104
|
+
resolvedImportPath.substring(root.length),
|
|
105
|
+
);
|
|
45
106
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!transform) {
|
|
54
|
-
const relativePath = path.relative(root, filePath);
|
|
55
|
-
await send(req, res, relativePath, { root });
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const source = await fs.readFile(filePath, 'utf8');
|
|
59
|
-
const [imports, _exports, _facade, _hasModuleSyntax] = parse(source, filePath);
|
|
60
|
-
let output = '';
|
|
61
|
-
let lastIndex = 0;
|
|
62
|
-
for (const impt of imports) {
|
|
63
|
-
const { t: type, s: start, e: end, n: unescaped } = impt;
|
|
64
|
-
if (type === 1) {
|
|
65
|
-
// Static import
|
|
66
|
-
const importSpecifier = unescaped || source.substring(start, end);
|
|
67
|
-
// If the specifier is relative or absolute, we don't need to resolve it
|
|
68
|
-
if (importSpecifier.startsWith('.') ||
|
|
69
|
-
importSpecifier.startsWith('/')) {
|
|
70
|
-
output += `${source.substring(lastIndex, start)}${importSpecifier}`;
|
|
71
|
-
lastIndex = end;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const fileURL = new URL(filePath, 'file://');
|
|
75
|
-
const resolvedImportURL = moduleResolve(importSpecifier, fileURL, conditions);
|
|
76
|
-
const resolvedImportPath = resolvedImportURL.pathname;
|
|
77
|
-
if (!resolvedImportPath.startsWith(root)) {
|
|
78
|
-
throw new HttpError(500);
|
|
79
|
-
}
|
|
80
|
-
let resolvedimport;
|
|
81
|
-
if (resolvedImportPath.startsWith(base)) {
|
|
82
|
-
resolvedimport = resolvedImportPath.substring(base.length);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
resolvedimport = path.join(mountedPath, rootPathPrefix, resolvedImportPath.substring(root.length));
|
|
86
|
-
}
|
|
87
|
-
output += `${source.substring(lastIndex, start)}${resolvedimport}`;
|
|
88
|
-
lastIndex = end;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
res.type = 'text/javascript';
|
|
92
|
-
res.body = output + source.substring(lastIndex);
|
|
93
|
-
};
|
|
107
|
+
output += `${source.substring(lastIndex, start)}${resolvedimport}`;
|
|
108
|
+
lastIndex = end;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
res.type = 'text/javascript';
|
|
112
|
+
res.body = output + source.substring(lastIndex);
|
|
113
|
+
};
|
|
94
114
|
};
|
|
95
|
-
//# sourceMappingURL=serve.js.map
|
|
115
|
+
//# sourceMappingURL=serve.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zipadee/javascript",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@zipadee/core": "^0.0.
|
|
60
|
-
"@zipadee/static": "^0.0.
|
|
59
|
+
"@zipadee/core": "^0.0.11",
|
|
60
|
+
"@zipadee/static": "^0.0.11",
|
|
61
61
|
"import-meta-resolve": "^4.1.0"
|
|
62
62
|
}
|
|
63
63
|
}
|