primate 0.27.5 → 0.28.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/package.json +5 -3
- package/src/app.js +10 -10
- package/src/cwd.js +2 -2
- package/src/errors.js +2 -2
- package/src/hooks/copy_includes.js +2 -2
- package/src/hooks/parse.js +5 -9
- package/src/hooks/publish.js +2 -2
- package/src/hooks/register.js +6 -6
- package/src/hooks/respond/respond.js +2 -2
- package/src/loaders/common.js +4 -4
- package/src/loaders/routes/load.js +2 -2
- package/src/loaders/types.js +2 -2
- package/src/run.js +2 -2
- package/types/index.d.ts +64 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Polymorphic development platform",
|
|
5
5
|
"homepage": "https://primatejs.com",
|
|
6
6
|
"bugs": "https://github.com/primatejs/primate/issues",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"src/**/*.js",
|
|
10
10
|
"src/errors.json",
|
|
11
11
|
"src/defaults/*.html",
|
|
12
|
-
"!src/**/*.spec.js"
|
|
12
|
+
"!src/**/*.spec.js",
|
|
13
|
+
"types/*.ts"
|
|
13
14
|
],
|
|
14
15
|
"bin": "src/bin.js",
|
|
15
16
|
"repository": {
|
|
@@ -18,11 +19,12 @@
|
|
|
18
19
|
"directory": "packages/primate"
|
|
19
20
|
},
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"rcompat": "^0.
|
|
22
|
+
"rcompat": "^0.7.2"
|
|
22
23
|
},
|
|
23
24
|
"engines": {
|
|
24
25
|
"node": ">=18"
|
|
25
26
|
},
|
|
26
27
|
"type": "module",
|
|
28
|
+
"types": "./types/index.d.ts",
|
|
27
29
|
"exports": "./src/exports.js"
|
|
28
30
|
}
|
package/src/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "rcompat/crypto";
|
|
2
2
|
import { tryreturn } from "rcompat/async";
|
|
3
|
-
import {
|
|
3
|
+
import { File } from "rcompat/fs";
|
|
4
4
|
import { is } from "rcompat/invariant";
|
|
5
5
|
import { transform, valmap, to } from "rcompat/object";
|
|
6
6
|
import { globify } from "rcompat/string";
|
|
@@ -15,8 +15,8 @@ const { DoubleFileExtension } = errors;
|
|
|
15
15
|
|
|
16
16
|
// use user-provided file or fall back to default
|
|
17
17
|
const index = (base, page, fallback) =>
|
|
18
|
-
tryreturn(_ =>
|
|
19
|
-
.orelse(_ =>
|
|
18
|
+
tryreturn(_ => File.text(`${base.join(page)}`))
|
|
19
|
+
.orelse(_ => File.text(`${base.join(fallback)}`));
|
|
20
20
|
|
|
21
21
|
const encoder = new TextEncoder();
|
|
22
22
|
|
|
@@ -51,7 +51,7 @@ const render_head = (assets, head) =>
|
|
|
51
51
|
: tags.script({ inline, code, type, integrity, src }),
|
|
52
52
|
).join("\n").concat("\n", head ?? "");
|
|
53
53
|
|
|
54
|
-
const { name, version } = await new
|
|
54
|
+
const { name, version } = await new File(import.meta.url).up(2)
|
|
55
55
|
.join(runtime.manifest).json();
|
|
56
56
|
|
|
57
57
|
export default async (log, root, config) => {
|
|
@@ -100,7 +100,7 @@ export default async (log, root, config) => {
|
|
|
100
100
|
|
|
101
101
|
await Promise.all((await source.collect(filter)).map(async path => {
|
|
102
102
|
const debased = path.debase(this.root).path.slice(1);
|
|
103
|
-
const filename =
|
|
103
|
+
const filename = File.join(directory, path.debase(source));
|
|
104
104
|
const target = await target_base.join(filename.debase(directory));
|
|
105
105
|
await target.directory.create();
|
|
106
106
|
await (regexs.some(regex => regex.test(debased))
|
|
@@ -177,7 +177,7 @@ export default async (log, root, config) => {
|
|
|
177
177
|
}
|
|
178
178
|
if (inline || type === "style") {
|
|
179
179
|
this.assets.push({
|
|
180
|
-
src:
|
|
180
|
+
src: File.join(http.static.root, src ?? "").path,
|
|
181
181
|
code: inline ? code : "",
|
|
182
182
|
type,
|
|
183
183
|
inline,
|
|
@@ -203,7 +203,7 @@ export default async (log, root, config) => {
|
|
|
203
203
|
|
|
204
204
|
const parts = module.split("/");
|
|
205
205
|
const path = [this.library, ...parts];
|
|
206
|
-
const pkg = await
|
|
206
|
+
const pkg = await File.resolve().join(...path, this.manifest).json();
|
|
207
207
|
const exports = pkg.exports === undefined
|
|
208
208
|
? { [module]: `/${module}/${pkg.main}` }
|
|
209
209
|
: transform(pkg.exports, entry => entry
|
|
@@ -220,11 +220,11 @@ export default async (log, root, config) => {
|
|
|
220
220
|
?? value.default?.replace(".", `./${module}`)
|
|
221
221
|
?? value.import?.replace(".", `./${module}`),
|
|
222
222
|
]));
|
|
223
|
-
const dependency =
|
|
224
|
-
const target =
|
|
223
|
+
const dependency = File.resolve().join(...path);
|
|
224
|
+
const target = File.join(this.runpath(client), this.library, ...parts);
|
|
225
225
|
await dependency.copy(target);
|
|
226
226
|
this.importmaps = {
|
|
227
|
-
...valmap(exports, value =>
|
|
227
|
+
...valmap(exports, value => File.join(root, this.library, value).path),
|
|
228
228
|
...this.importmaps };
|
|
229
229
|
},
|
|
230
230
|
};
|
package/src/cwd.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
|
|
3
|
-
export default (meta, up = 1) => new
|
|
3
|
+
export default (meta, up = 1) => new File(meta.url).up(up);
|
package/src/errors.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import Logger from "./Logger.js";
|
|
3
3
|
|
|
4
|
-
const json = await new
|
|
4
|
+
const json = await new File(import.meta.url).up(1).join("errors.json").json();
|
|
5
5
|
|
|
6
6
|
const errors = Logger.err(json.errors, json.module);
|
|
7
7
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
|
|
3
3
|
export default async (app, type, post = () => undefined) => {
|
|
4
4
|
const { config } = app;
|
|
@@ -14,7 +14,7 @@ export default async (app, type, post = () => undefined) => {
|
|
|
14
14
|
.map(async include => {
|
|
15
15
|
const path = app.root.join(include);
|
|
16
16
|
if (await path.exists()) {
|
|
17
|
-
const target =
|
|
17
|
+
const target = File.join(type, include);
|
|
18
18
|
await app.stage(path, target);
|
|
19
19
|
await post(target);
|
|
20
20
|
}
|
package/src/hooks/parse.js
CHANGED
|
@@ -5,21 +5,17 @@ import errors from "../errors.js";
|
|
|
5
5
|
|
|
6
6
|
const deslash = url => url.replaceAll(/(?<!http:)\/{2,}/gu, _ => "/");
|
|
7
7
|
|
|
8
|
-
const parse_body = (
|
|
9
|
-
tryreturn(async _ => {
|
|
10
|
-
|
|
11
|
-
return Body.parse(body, headers.get("content-type")) ?? {};
|
|
12
|
-
}).orelse(error => errors.MismatchedBody.throw(url.pathname, error.message));
|
|
8
|
+
const parse_body = (request, url) =>
|
|
9
|
+
tryreturn(async _ => await Body.parse(request) ?? {})
|
|
10
|
+
.orelse(error => errors.MismatchedBody.throw(url.pathname, error.message));
|
|
13
11
|
|
|
14
12
|
export default dispatch => async original => {
|
|
15
13
|
const { headers } = original;
|
|
16
14
|
const url = new URL(deslash(globalThis.decodeURIComponent(original.url)));
|
|
17
15
|
const cookies = headers.get("cookie");
|
|
18
|
-
const body = await parse_body(original
|
|
16
|
+
const body = await parse_body(original, url);
|
|
19
17
|
|
|
20
|
-
return { original, url, body,
|
|
21
|
-
async_function: async () => "1",
|
|
22
|
-
...valmap({
|
|
18
|
+
return { original, url, body, ...valmap({
|
|
23
19
|
query: [from(url.searchParams), url.search],
|
|
24
20
|
headers: [from(headers), headers, false],
|
|
25
21
|
cookies: [from(cookies?.split(";").map(cookie =>
|
package/src/hooks/publish.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import { cascade } from "rcompat/async";
|
|
3
3
|
import { stringify } from "rcompat/object";
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ const post = async app => {
|
|
|
7
7
|
|
|
8
8
|
{
|
|
9
9
|
// after hook, publish a zero assumptions app.js (no css imports)
|
|
10
|
-
const src =
|
|
10
|
+
const src = File.join(root, app.config.build.index);
|
|
11
11
|
|
|
12
12
|
await app.publish({
|
|
13
13
|
code: app.exports.filter(({ type }) => type === "script")
|
package/src/hooks/register.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import { cascade } from "rcompat/async";
|
|
3
3
|
import cwd from "../cwd.js";
|
|
4
4
|
import copy_includes from "./copy_includes.js";
|
|
@@ -17,7 +17,7 @@ const pre = async app => {
|
|
|
17
17
|
if (await path.components.exists()) {
|
|
18
18
|
// copy .js files from components to build/client/components, since
|
|
19
19
|
// frontend frameworks handle non-js files
|
|
20
|
-
const target =
|
|
20
|
+
const target = File.join(client, components);
|
|
21
21
|
await app.stage(path.components, target, /^.*.js$/u);
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -29,13 +29,13 @@ const post = async app => {
|
|
|
29
29
|
|
|
30
30
|
if (await path.static.exists()) {
|
|
31
31
|
// copy static files to build/server/static
|
|
32
|
-
await app.stage(path.static,
|
|
32
|
+
await app.stage(path.static, File.join(location.server, location.static));
|
|
33
33
|
|
|
34
34
|
// copy static files to build/client/static
|
|
35
|
-
await app.stage(path.static,
|
|
35
|
+
await app.stage(path.static, File.join(location.client, location.static));
|
|
36
36
|
|
|
37
37
|
// publish JavaScript and CSS files
|
|
38
|
-
const imports = await
|
|
38
|
+
const imports = await File.collect(path.static, /\.(?:js|css)$/u);
|
|
39
39
|
await Promise.all(imports.map(async file => {
|
|
40
40
|
const code = await file.text();
|
|
41
41
|
const src = file.debase(path.static);
|
|
@@ -54,7 +54,7 @@ const post = async app => {
|
|
|
54
54
|
const client = app.runpath(location.client);
|
|
55
55
|
await copy_includes(app, location.client, async to =>
|
|
56
56
|
Promise.all((await to.collect(/\.js$/u)).map(async script => {
|
|
57
|
-
const src =
|
|
57
|
+
const src = File.join(root, script.path.replace(client, _ => ""));
|
|
58
58
|
await app.publish({ src, code: await script.text(), type: "module" });
|
|
59
59
|
})),
|
|
60
60
|
);
|
|
@@ -15,10 +15,10 @@ const is_object = value => is_non_null_object(value)
|
|
|
15
15
|
? json(value) : is_text(value);
|
|
16
16
|
const is_response = value => is_response_duck(value)
|
|
17
17
|
? _ => value : is_object(value);
|
|
18
|
-
const
|
|
18
|
+
const is_stream = value => value instanceof ReadableStream
|
|
19
19
|
? stream(value) : is_response(value);
|
|
20
20
|
const is_blob = value => value instanceof Blob
|
|
21
|
-
|
|
21
|
+
? stream(value.stream()) : is_stream(value);
|
|
22
22
|
const is_URL = value => value instanceof URL
|
|
23
23
|
? redirect(value.href) : is_blob(value);
|
|
24
24
|
const guess = value => is_URL(value);
|
package/src/loaders/common.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import { identity } from "rcompat/function";
|
|
3
3
|
import errors from "../errors.js";
|
|
4
4
|
|
|
@@ -17,13 +17,13 @@ export default async ({
|
|
|
17
17
|
warn = true,
|
|
18
18
|
} = {}) => {
|
|
19
19
|
const objects = directory === undefined ? [] : await Promise.all(
|
|
20
|
-
(await
|
|
20
|
+
(await File.collect(directory, /^.*.js$/u, { recursive }))
|
|
21
21
|
.filter(filter)
|
|
22
22
|
.map(async path => [
|
|
23
23
|
`${path}`.replace(directory, _ => "").slice(1, -ending.length),
|
|
24
|
-
|
|
24
|
+
await import(path),
|
|
25
25
|
]));
|
|
26
|
-
warn && await
|
|
26
|
+
warn && await directory.exists() && empty(log)(objects, name, directory);
|
|
27
27
|
|
|
28
28
|
return objects;
|
|
29
29
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import errors from "../../errors.js";
|
|
3
3
|
import to_sorted from "../../to_sorted.js";
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ export default type => async (log, directory, load) => {
|
|
|
10
10
|
.map(([name, object]) => [name.replace(replace, () => ""), object]),
|
|
11
11
|
([a], [b]) => a.length - b.length);
|
|
12
12
|
|
|
13
|
-
const resolve = name =>
|
|
13
|
+
const resolve = name => File.join(directory, name, `+${type}.js`);
|
|
14
14
|
objects.some(([name, value]) => typeof value.default !== "function"
|
|
15
15
|
&& errors.InvalidDefaultExport.throw(resolve(name)));
|
|
16
16
|
|
package/src/loaders/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { File } from "rcompat/fs";
|
|
2
2
|
import { is } from "rcompat/invariant";
|
|
3
3
|
import { tryreturn } from "rcompat/sync";
|
|
4
4
|
import errors from "../errors.js";
|
|
@@ -10,7 +10,7 @@ export default async (log, directory, load = fs) => {
|
|
|
10
10
|
const types = (await load({ log, directory, name: "types", filter }))
|
|
11
11
|
.map(([name, type]) => [name, type.default]);
|
|
12
12
|
|
|
13
|
-
const resolve = name =>
|
|
13
|
+
const resolve = name => File.join(directory, name);
|
|
14
14
|
types.every(([name, type]) => tryreturn(_ => {
|
|
15
15
|
is(type).object();
|
|
16
16
|
is(type.base).string();
|
package/src/run.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tryreturn } from "rcompat/async";
|
|
2
|
-
import {
|
|
2
|
+
import { File } from "rcompat/fs";
|
|
3
3
|
import { extend } from "rcompat/object";
|
|
4
4
|
import app from "./app.js";
|
|
5
5
|
import { default as Logger, bye } from "./Logger.js";
|
|
@@ -28,7 +28,7 @@ const get_config = async root => {
|
|
|
28
28
|
|
|
29
29
|
export default async name => tryreturn(async _ => {
|
|
30
30
|
// use module root if possible, fall back to current directory
|
|
31
|
-
const root = await tryreturn(_ =>
|
|
31
|
+
const root = await tryreturn(_ => File.root()).orelse(_ => File.resolve());
|
|
32
32
|
const config = await get_config(root);
|
|
33
33
|
logger = new Logger(config.logger);
|
|
34
34
|
await command(name)(await app(logger, root, config));
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
declare module "primate" {
|
|
2
|
+
type App = any;
|
|
3
|
+
|
|
4
|
+
interface MinOptions {
|
|
5
|
+
status: number,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ErrorOptions extends MinOptions {
|
|
9
|
+
page: string,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Options extends ErrorOptions {
|
|
13
|
+
placeholders: {},
|
|
14
|
+
headers: Headers | {},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type Dispatcher = {
|
|
18
|
+
get(property: string): string,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type RequestFacade = {
|
|
22
|
+
body: {}
|
|
23
|
+
path: Dispatcher,
|
|
24
|
+
query: Dispatcher,
|
|
25
|
+
cookies: Dispatcher,
|
|
26
|
+
headers: Dispatcher,
|
|
27
|
+
original: Request,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type ResponseFn = (app: App, ...rest: any) => Response;
|
|
31
|
+
type ResponseFacade =
|
|
32
|
+
string
|
|
33
|
+
| object
|
|
34
|
+
| URL
|
|
35
|
+
| Blob
|
|
36
|
+
| ReadableStream
|
|
37
|
+
| Response
|
|
38
|
+
| ResponseFn;
|
|
39
|
+
|
|
40
|
+
type RouteFunction = (request?: RequestFacade) => ResponseFacade;
|
|
41
|
+
|
|
42
|
+
type Streamable = ReadableStream | Blob;
|
|
43
|
+
|
|
44
|
+
export type Route = {
|
|
45
|
+
get?: RouteFunction,
|
|
46
|
+
post?: RouteFunction,
|
|
47
|
+
put?: RouteFunction,
|
|
48
|
+
delete?: RouteFunction,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export function text(body: string, options?: MinOptions): ResponseFn;
|
|
52
|
+
|
|
53
|
+
export function json(body: {}, options?: MinOptions): ResponseFn;
|
|
54
|
+
|
|
55
|
+
export function stream(body: Streamable, options?: MinOptions): ResponseFn;
|
|
56
|
+
|
|
57
|
+
export function redirect(location: string, options?: MinOptions): ResponseFn;
|
|
58
|
+
|
|
59
|
+
export function html(name: string, options?: MinOptions): ResponseFn;
|
|
60
|
+
|
|
61
|
+
export function view(name: string, props: {}, options?: Options): ResponseFn;
|
|
62
|
+
|
|
63
|
+
export function error(body: string, options?: ErrorOptions): ResponseFn;
|
|
64
|
+
}
|