@davidsouther/jiffies 1.0.0-beta.1 → 1.0.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.
Files changed (96) hide show
  1. package/build/components/button_bar.js +24 -13
  2. package/build/components/select.d.ts +1 -4
  3. package/build/display.js +9 -1
  4. package/build/dom/dom.js +1 -0
  5. package/build/dom/form/form.d.ts +9 -8
  6. package/build/dom/form/form.js +14 -5
  7. package/build/dom/provide.d.ts +3 -0
  8. package/build/dom/provide.js +7 -0
  9. package/build/equal.d.ts +5 -4
  10. package/build/equal.js +19 -4
  11. package/build/fs.d.ts +48 -0
  12. package/build/fs.js +144 -0
  13. package/build/{components/index.d.ts → fs.test.d.ts} +0 -0
  14. package/build/fs.test.js +43 -0
  15. package/build/log.js +16 -4
  16. package/build/result.d.ts +11 -11
  17. package/build/result.js +2 -2
  18. package/build/scope/execute.js +1 -1
  19. package/build/scope/expect.d.ts +1 -1
  20. package/build/scope/expect.js +4 -3
  21. package/build/server/http/css.d.ts +5 -0
  22. package/build/server/http/css.js +47 -0
  23. package/build/server/http/index.js +4 -2
  24. package/build/server/http/response.js +6 -3
  25. package/build/test_all.d.ts +7 -1
  26. package/build/test_all.js +7 -8
  27. package/package.json +5 -2
  28. package/src/components/button_bar.ts +32 -26
  29. package/src/display.ts +8 -2
  30. package/src/dom/dom.ts +1 -0
  31. package/src/dom/form/form.ts +30 -7
  32. package/src/dom/provide.ts +11 -0
  33. package/src/equal.ts +22 -11
  34. package/src/fs.test.ts +53 -0
  35. package/src/fs.ts +180 -0
  36. package/src/index.html +4 -4
  37. package/src/log.ts +8 -4
  38. package/src/pico/_variables.scss +66 -0
  39. package/src/pico/components/_accordion.scss +112 -0
  40. package/src/pico/components/_button-group.scss +51 -0
  41. package/src/pico/components/_card.scss +47 -0
  42. package/src/pico/components/_dropdown.scss +203 -0
  43. package/src/pico/components/_modal.scss +181 -0
  44. package/src/pico/components/_nav.scss +79 -0
  45. package/src/pico/components/_progress.scss +70 -0
  46. package/src/pico/components/_property.scss +34 -0
  47. package/src/pico/content/_button.scss +152 -0
  48. package/src/pico/content/_code.scss +63 -0
  49. package/src/pico/content/_embedded.scss +0 -0
  50. package/src/pico/content/_form-alt.scss +276 -0
  51. package/src/pico/content/_form.scss +259 -0
  52. package/src/pico/content/_misc.scss +0 -0
  53. package/src/pico/content/_table.scss +28 -0
  54. package/src/pico/content/_toggle.scss +132 -0
  55. package/src/pico/content/_typography.scss +232 -0
  56. package/src/pico/layout/_container.scss +40 -0
  57. package/src/pico/layout/_document.scss +0 -0
  58. package/src/pico/layout/_flex.scss +46 -0
  59. package/src/pico/layout/_grid.scss +24 -0
  60. package/src/pico/layout/_scroller.scss +16 -0
  61. package/src/pico/layout/_section.scss +8 -0
  62. package/src/pico/layout/_sectioning.scss +53 -0
  63. package/src/pico/pico.scss +60 -0
  64. package/src/pico/reset/_accessibility.scss +34 -0
  65. package/src/pico/reset/_button.scss +17 -0
  66. package/src/pico/reset/_code.scss +15 -0
  67. package/src/pico/reset/_document.scss +48 -0
  68. package/src/pico/reset/_embedded.scss +39 -0
  69. package/src/pico/reset/_form.scss +97 -0
  70. package/src/pico/reset/_misc.scss +23 -0
  71. package/src/pico/reset/_nav.scss +5 -0
  72. package/src/pico/reset/_progress.scss +4 -0
  73. package/src/pico/reset/_table.scss +8 -0
  74. package/src/pico/reset/_typography.scss +25 -0
  75. package/src/pico/themes/default/_colors.scss +65 -0
  76. package/src/pico/themes/default/_dark.scss +148 -0
  77. package/src/pico/themes/default/_light.scss +149 -0
  78. package/src/pico/themes/default/_styles.scss +272 -0
  79. package/src/pico/themes/default.scss +34 -0
  80. package/src/pico/utilities/_accessibility.scss +3 -0
  81. package/src/pico/utilities/_loading.scss +52 -0
  82. package/src/pico/utilities/_reduce-motion.scss +27 -0
  83. package/src/pico/utilities/_tooltip.scss +101 -0
  84. package/src/result.ts +16 -20
  85. package/src/scope/execute.ts +1 -1
  86. package/src/scope/expect.ts +10 -9
  87. package/src/server/http/css.ts +63 -0
  88. package/src/server/http/index.ts +4 -2
  89. package/src/server/http/response.ts +7 -4
  90. package/src/test_all.ts +7 -8
  91. package/src/zip/spec.txt +3260 -0
  92. package/build/components/index.js +0 -1
  93. package/build/index.d.ts +0 -13
  94. package/build/index.js +0 -13
  95. package/build/parcel_resolver.d.ts +0 -3
  96. package/build/parcel_resolver.js +0 -19
@@ -1,16 +1,27 @@
1
1
  import { display } from "../display.js";
2
2
  import { FC } from "../dom/fc.js";
3
- import { a, li, ul } from "../dom/html.js";
4
- const ButtonBar = FC("button-bar", (el, { value, values, events }) => ul({ class: "ButtonBar__wrapper" }, ...values.map((option) => li(a({
5
- href: "#",
6
- class: `ButtonBar__${`${option}`.replace(/\s+/g, "_").toLowerCase()}
7
- ${option === value ? "" : "secondary"}
8
- `.replace(/[\n\s]+/, " "),
9
- events: {
10
- click: (e) => {
11
- e.preventDefault();
12
- events.onSelect(option);
13
- },
14
- },
15
- }, display(option))))));
3
+ import { fieldset, input, label } from "../dom/html.js";
4
+ let buttonBarId = 1;
5
+ let nextId = () => buttonBarId++;
6
+ const ButtonBar = FC("button-bar", (el, { value, values, events }) => {
7
+ const name = `button-bar-${nextId()}`;
8
+ return fieldset({ class: "input-group" }, ...values
9
+ .map((option) => {
10
+ const opt = `${option}`.replace(/\s+/g, "_").toLowerCase();
11
+ const id = `${name}-${opt}`;
12
+ return [
13
+ label({ role: "button", htmlFor: id }, input({
14
+ type: "radio",
15
+ id,
16
+ name,
17
+ value: option,
18
+ checked: option === value,
19
+ events: {
20
+ change: () => events.onSelect(option),
21
+ },
22
+ }), display(option)),
23
+ ];
24
+ })
25
+ .flat());
26
+ });
16
27
  export default ButtonBar;
@@ -6,8 +6,5 @@ export declare const Select: import("../dom/fc.js").FCComponentCtor<{
6
6
  change: EventHandler;
7
7
  };
8
8
  disabled: boolean;
9
- options: [
10
- string,
11
- string
12
- ][];
9
+ options: [string, string][];
13
10
  }, {}>;
package/build/display.js CHANGED
@@ -1,3 +1,11 @@
1
1
  export const isDisplay = (/** @type unknown */ a) => typeof a.toString === "function" ||
2
2
  typeof a === "string";
3
- export const display = (a) => isDisplay(a) ? a.toString() : JSON.stringify(a);
3
+ export const display = (a) => {
4
+ if (isDisplay(a)) {
5
+ const str = a.toString();
6
+ if (str === "[object Object]")
7
+ return JSON.stringify(a);
8
+ return str;
9
+ }
10
+ return JSON.stringify(a);
11
+ };
package/build/dom/dom.js CHANGED
@@ -58,6 +58,7 @@ export function update(element, attrs, children) {
58
58
  .forEach((c) => element.classList.add(c));
59
59
  }
60
60
  let useAttributes = k.startsWith("aria-") ||
61
+ k == "role" ||
61
62
  element.namespaceURI != "http://www.w3.org/1999/xhtml";
62
63
  if (useAttributes) {
63
64
  switch (v) {
@@ -1,21 +1,22 @@
1
1
  import { DenormChildren } from "../dom.js";
2
2
  import { label } from "../html.js";
3
- import { FormAttributes, InputAttributes, OptionAttributes, SelectAttributes } from "../types/html.js";
3
+ import { FormAttributes, InputAttributes, LabelAttributes, OptionAttributes, SelectAttributes } from "../types/html.js";
4
4
  export declare const Form: (attrs: FormAttributes, ...children: DenormChildren[]) => import("../html.js").UHTMLElement<HTMLFormElement>;
5
5
  export declare const Input: (attrs: InputAttributes, ...children: DenormChildren[]) => import("../html.js").UHTMLElement<HTMLLabelElement>;
6
- export declare const Select: ({ options }: {
6
+ export declare const Select: (attrs: {
7
7
  options: string[] | {};
8
- }) => import("../html.js").UHTMLElement<HTMLLabelElement>;
8
+ selected?: string;
9
+ } & SelectAttributes & LabelAttributes) => import("../html.js").UHTMLElement<HTMLLabelElement>;
9
10
  export declare const Button: () => void;
10
11
  declare const prepareOptions: (attrs: string[] | Record<string, string | {
11
12
  label: string;
12
- disabled?: boolean;
13
- selected?: boolean;
14
- }>) => Parameters<typeof Option>[0][];
13
+ disabled?: boolean | undefined;
14
+ selected?: boolean | undefined;
15
+ }>, selected?: string) => Parameters<typeof Option>[0][];
15
16
  export declare const Option: (attrs: OptionAttributes) => import("../html.js").UHTMLElement<HTMLOptionElement>;
16
17
  export declare const Dropdown: (attrs: SelectAttributes | {
17
- options: Parameters<typeof prepareOptions>[0];
18
- }) => void;
18
+ selected?: string;
19
+ }, ...options: Parameters<typeof prepareOptions>[0][]) => import("../html.js").UHTMLElement<HTMLLabelElement>;
19
20
  export declare const Radios: () => void;
20
21
  export declare const Checks: () => void;
21
22
  export declare const Switches: () => void;
@@ -10,13 +10,22 @@ export const Form = (attrs, ...children) => {
10
10
  return form(attrs, ...children);
11
11
  };
12
12
  export const Input = (attrs, ...children) => label(input(attrs), ...children);
13
- export const Select = ({ options }) => label(select(...prepareOptions(options).map(Option)));
13
+ export const Select = (attrs) => label({ style: attrs.style ?? {} }, select({ events: attrs.events ?? {} }, ...prepareOptions(attrs.options, attrs.selected).map(Option)));
14
14
  export const Button = () => { };
15
- const prepareOptions = (attrs) => Array.isArray(attrs)
16
- ? attrs.map((value) => ({ value, label: value }))
17
- : Object.entries(attrs).map(([value, label]) => typeof label === "string" ? { value, label } : { value, ...label });
15
+ const prepareOptions = (attrs, selected) => Array.isArray(attrs)
16
+ ? attrs.map((value) => ({
17
+ value,
18
+ label: value,
19
+ selected: selected == value,
20
+ }))
21
+ : Object.entries(attrs).map(([value, label]) => typeof label === "string"
22
+ ? { value, label, selected: selected === value }
23
+ : { value, ...label });
18
24
  export const Option = (attrs) => option(attrs);
19
- export const Dropdown = (attrs) => { };
25
+ export const Dropdown = (attrs, ...options) => Select({
26
+ ...attrs,
27
+ options: typeof options[0] == "string" ? options : options[0],
28
+ });
20
29
  export const Radios = () => { };
21
30
  export const Checks = () => { };
22
31
  export const Switches = () => { };
@@ -0,0 +1,3 @@
1
+ import { Option } from "../result.js";
2
+ export declare function provide(items: Record<string, unknown>): void;
3
+ export declare function retrieve<T>(key: string): Option<T>;
@@ -0,0 +1,7 @@
1
+ let registry = {};
2
+ export function provide(items) {
3
+ registry = { ...registry, ...items };
4
+ }
5
+ export function retrieve(key) {
6
+ return registry[key];
7
+ }
package/build/equal.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export declare function compareArrays<T>(equal: (a: T, b: T) => boolean): (A: T[], B: T[]) => boolean;
2
- export declare const equalArrays: (A: any[], B: any[]) => boolean;
3
- export declare const matchArrays: <A>(a: A[], b: A[]) => boolean;
4
- export declare function equals<A>(a: A | A[], b: A | A[]): boolean;
1
+ export declare function compareArrays<T>(equal: (a: T, b: T, partial: boolean) => boolean): (A: T[], B: T[], partial?: boolean) => boolean;
2
+ export declare const equalArrays: (A: any[], B: any[], partial?: boolean) => boolean;
3
+ export declare const matchArrays: <A>(a: A[], b: A[], partial?: boolean) => boolean;
4
+ export declare const matchObjects: (a: {}, b: {}, partial?: boolean) => boolean;
5
+ export declare function equals<A>(a: A | A[], b: A | A[], partial?: boolean): boolean;
package/build/equal.js CHANGED
@@ -1,21 +1,36 @@
1
1
  export function compareArrays(equal) {
2
- return (a, b) => a.length === b.length && a.every((e, i) => equal(e, b[i]));
2
+ return (a, b, partial = false) => a.length === b.length && a.every((e, i) => equal(e, b[i], partial));
3
3
  }
4
4
  export const equalArrays = compareArrays(Object.is);
5
5
  export const matchArrays = compareArrays(equals);
6
6
  function asArray(a) {
7
7
  return Object.entries(a).sort((a, b) => a[0].localeCompare(b[0]));
8
8
  }
9
- export function equals(a, b) {
9
+ export const matchObjects = (a, b, partial = true) => {
10
+ for (const [k, v] of Object.entries(a)) {
11
+ if (!b.hasOwnProperty(k) && partial)
12
+ continue;
13
+ // @ts-ignore
14
+ if (!equals(v, b[k], partial))
15
+ return false;
16
+ }
17
+ return true;
18
+ };
19
+ export function equals(a, b, partial = false) {
10
20
  // runtime type checking
11
21
  switch (typeof a) {
12
22
  case "object":
23
+ if (b === undefined) {
24
+ return false;
25
+ }
13
26
  if (a instanceof Array && b instanceof Array) {
14
- return matchArrays(a, b);
27
+ return matchArrays(a, b, partial);
15
28
  }
16
29
  else {
17
- return matchArrays(asArray(a), asArray(b));
30
+ return matchObjects(a, b, partial);
18
31
  }
32
+ case "function":
33
+ return a.name == b.name;
19
34
  default:
20
35
  return Object.is(a, b);
21
36
  }
package/build/fs.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ export declare type PathLike = string;
2
+ export interface Stats {
3
+ isDirectory(): boolean;
4
+ isFile(): boolean;
5
+ }
6
+ interface FileSystemAdapter {
7
+ stat(path: PathLike): Promise<Stats>;
8
+ readdir(path: PathLike): Promise<string[]>;
9
+ copyFile(from: PathLike, to: PathLike): Promise<void>;
10
+ readFile(path: PathLike): Promise<string>;
11
+ writeFile(path: PathLike, contents: string): Promise<void>;
12
+ rm(path: PathLike): Promise<void>;
13
+ }
14
+ export declare class FileSystem implements FileSystemAdapter {
15
+ protected adapter: ObjectFileSystemAdapter;
16
+ protected wd: string;
17
+ protected stack: string[];
18
+ constructor(adapter?: ObjectFileSystemAdapter);
19
+ cwd(): string;
20
+ cd(dir: string): void;
21
+ pushd(dir: string): void;
22
+ popd(): void;
23
+ stat(path: PathLike): Promise<Stats>;
24
+ readdir(path: PathLike): Promise<string[]>;
25
+ copyFile(from: PathLike, to: PathLike): Promise<void>;
26
+ readFile(path: PathLike): Promise<string>;
27
+ writeFile(path: PathLike, contents: string): Promise<void>;
28
+ rm(path: PathLike): Promise<void>;
29
+ private p;
30
+ }
31
+ export declare class ObjectFileSystemAdapter implements FileSystemAdapter {
32
+ private fs;
33
+ constructor(fs?: Record<string, string>);
34
+ stat(path: PathLike): Promise<Stats>;
35
+ readdir(path: PathLike): Promise<string[]>;
36
+ copyFile(from: PathLike, to: PathLike): Promise<void>;
37
+ readFile(path: PathLike): Promise<string>;
38
+ writeFile(path: PathLike, contents: string): Promise<void>;
39
+ rm(path: PathLike): Promise<void>;
40
+ }
41
+ export declare class LocalStorageFileSystemAdapter extends ObjectFileSystemAdapter {
42
+ constructor();
43
+ }
44
+ export interface Tree {
45
+ [k: string]: string | Tree;
46
+ }
47
+ export declare function reset(fs: FileSystem, tree: Tree): Promise<void>;
48
+ export {};
package/build/fs.js ADDED
@@ -0,0 +1,144 @@
1
+ function join(...paths) {
2
+ const pathParts = [];
3
+ for (const path of paths) {
4
+ for (const part of path.split("/")) {
5
+ switch (part) {
6
+ case "":
7
+ case ".":
8
+ break;
9
+ case "..":
10
+ pathParts.pop();
11
+ break;
12
+ default:
13
+ pathParts.push(part);
14
+ }
15
+ }
16
+ }
17
+ return "/" + pathParts.join("/");
18
+ }
19
+ export class FileSystem {
20
+ adapter;
21
+ wd = "/";
22
+ stack = [];
23
+ constructor(adapter = new ObjectFileSystemAdapter()) {
24
+ this.adapter = adapter;
25
+ }
26
+ cwd() {
27
+ return this.wd;
28
+ }
29
+ cd(dir) {
30
+ this.wd = this.p(dir);
31
+ }
32
+ pushd(dir) {
33
+ this.stack.push(this.wd);
34
+ this.cd(dir);
35
+ }
36
+ popd() {
37
+ if (this.stack.length > 0) {
38
+ this.wd = this.stack.pop();
39
+ }
40
+ }
41
+ stat(path) {
42
+ return this.adapter.stat(join(this.cwd(), path));
43
+ }
44
+ readdir(path) {
45
+ return this.adapter.readdir(this.p(path) + "/");
46
+ }
47
+ copyFile(from, to) {
48
+ return this.adapter.copyFile(this.p(from), this.p(to));
49
+ }
50
+ readFile(path) {
51
+ return this.adapter.readFile(this.p(path));
52
+ }
53
+ writeFile(path, contents) {
54
+ return this.adapter.writeFile(this.p(path), contents);
55
+ }
56
+ rm(path) {
57
+ return this.adapter.rm(this.p(path));
58
+ }
59
+ p(path) {
60
+ return path[0] == "/" ? path : join(this.cwd(), path);
61
+ }
62
+ }
63
+ export class ObjectFileSystemAdapter {
64
+ fs;
65
+ constructor(fs = {}) {
66
+ this.fs = fs;
67
+ }
68
+ stat(path) {
69
+ return new Promise((resolve, reject) => {
70
+ if (this.fs[path] != null) {
71
+ resolve({
72
+ isDirectory() {
73
+ return false;
74
+ },
75
+ isFile() {
76
+ return true;
77
+ },
78
+ });
79
+ }
80
+ else {
81
+ reject();
82
+ }
83
+ });
84
+ }
85
+ readdir(path) {
86
+ return new Promise((resolve) => {
87
+ let dir = [];
88
+ for (const filename of Object.keys(this.fs)) {
89
+ if (filename.startsWith(path)) {
90
+ const end = filename.indexOf("/", path.length + 1);
91
+ const basename = filename.substring(path.length, end == -1 ? undefined : end);
92
+ dir.push(basename);
93
+ }
94
+ }
95
+ return resolve(dir);
96
+ });
97
+ }
98
+ copyFile(from, to) {
99
+ return new Promise((resolve) => {
100
+ this.fs[to] = this.fs[from];
101
+ resolve();
102
+ });
103
+ }
104
+ readFile(path) {
105
+ return new Promise((resolve, reject) => {
106
+ let file = this.fs[path];
107
+ if (file === undefined) {
108
+ reject();
109
+ }
110
+ else {
111
+ resolve(file);
112
+ }
113
+ });
114
+ }
115
+ writeFile(path, contents) {
116
+ return new Promise((resolve) => {
117
+ this.fs[path] = contents;
118
+ resolve();
119
+ });
120
+ }
121
+ rm(path) {
122
+ return new Promise((resolve) => {
123
+ delete this.fs[path];
124
+ resolve();
125
+ });
126
+ }
127
+ }
128
+ export class LocalStorageFileSystemAdapter extends ObjectFileSystemAdapter {
129
+ constructor() {
130
+ super(window.localStorage);
131
+ }
132
+ }
133
+ export async function reset(fs, tree) {
134
+ for (const [path, file] of Object.entries(tree)) {
135
+ if (typeof file == "string") {
136
+ await fs.writeFile(path, file);
137
+ }
138
+ else {
139
+ fs.cd(path);
140
+ await reset(fs, file);
141
+ fs.cd("..");
142
+ }
143
+ }
144
+ }
File without changes
@@ -0,0 +1,43 @@
1
+ import { FileSystem, ObjectFileSystemAdapter } from "./fs.js";
2
+ import { describe, it, expect } from "./scope/index.js";
3
+ describe("FileSystem", () => {
4
+ describe("Writing", () => {
5
+ it("Writes files", async () => {
6
+ const fsObj = {};
7
+ const fs = new FileSystem(new ObjectFileSystemAdapter(fsObj));
8
+ await fs.writeFile("hello", "world");
9
+ expect(fsObj).toEqual({ "/hello": "world" });
10
+ });
11
+ it("Writes deep files", async () => {
12
+ const fsObj = {};
13
+ const fs = new FileSystem(new ObjectFileSystemAdapter(fsObj));
14
+ await fs.writeFile("deep/hello", "world");
15
+ expect(fsObj).toEqual({ "/deep/hello": "world" });
16
+ });
17
+ it("Writes deep files from root", async () => {
18
+ const fsObj = {};
19
+ const fs = new FileSystem(new ObjectFileSystemAdapter(fsObj));
20
+ await fs.writeFile("/root/deep/hello", "world");
21
+ expect(fsObj).toEqual({ "/root/deep/hello": "world" });
22
+ });
23
+ it("Writes files after cd", async () => {
24
+ const fsObj = {};
25
+ const fs = new FileSystem(new ObjectFileSystemAdapter(fsObj));
26
+ await fs.cd("deep");
27
+ await fs.writeFile("hello", "world");
28
+ expect(fsObj).toEqual({ "/deep/hello": "world" });
29
+ });
30
+ });
31
+ describe("directory", () => {
32
+ it("returns directory listing", async () => {
33
+ const fsObj = {
34
+ "/deep/hello": "world",
35
+ "/deep/bonjour": "monde",
36
+ "/other/file": "text",
37
+ };
38
+ const fs = new FileSystem(new ObjectFileSystemAdapter(fsObj));
39
+ const dir = await fs.readdir("deep");
40
+ expect(dir.sort()).toEqual(["bonjour", "hello"]);
41
+ });
42
+ });
43
+ });
package/build/log.js CHANGED
@@ -21,14 +21,26 @@ export function getLogger(name) {
21
21
  }
22
22
  export const DEFAULT_LOGGER = getLogger("default");
23
23
  export function debug(message, data) {
24
- DEFAULT_LOGGER.debug(message, data);
24
+ if (data)
25
+ DEFAULT_LOGGER.debug(message, data);
26
+ else
27
+ DEFAULT_LOGGER.debug(message);
25
28
  }
26
29
  export function info(message, data) {
27
- DEFAULT_LOGGER.info(message, data);
30
+ if (data)
31
+ DEFAULT_LOGGER.info(message, data);
32
+ else
33
+ DEFAULT_LOGGER.info(message);
28
34
  }
29
35
  export function warn(message, data) {
30
- DEFAULT_LOGGER.warn(message, data);
36
+ if (data)
37
+ DEFAULT_LOGGER.warn(message, data);
38
+ else
39
+ DEFAULT_LOGGER.warn(message);
31
40
  }
32
41
  export function error(message, data) {
33
- DEFAULT_LOGGER.error(message, data);
42
+ if (data)
43
+ DEFAULT_LOGGER.error(message, data);
44
+ else
45
+ DEFAULT_LOGGER.error(message);
34
46
  }
package/build/result.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export declare type None = null;
2
2
  export declare type Some<T> = T;
3
3
  export declare type Option<T> = Some<T> | None;
4
- export declare type Err<E extends Error> = {
4
+ export declare type Err<E = Error> = {
5
5
  err: E;
6
6
  map: <U>(fn: (t: unknown) => Result<U>) => Result<U>;
7
7
  };
@@ -9,23 +9,23 @@ export declare type Ok<T> = {
9
9
  ok: T;
10
10
  map: <U>(fn: (t: T) => Result<U>) => Result<U>;
11
11
  };
12
- export declare type Result<T, E extends Error = Error> = Ok<T> | Err<E>;
12
+ export declare type Result<T, E = Error> = Ok<T> | Err<E>;
13
13
  export declare const isNone: <T>(s: Option<T>) => s is null;
14
14
  export declare const isSome: <T>(s: Option<T>) => s is T;
15
15
  export declare function None<T = unknown>(_?: T): Option<T>;
16
16
  export declare function Some<T>(t: Option<T>): Option<T>;
17
17
  export declare function Some<T>(t: T): Option<T>;
18
- export declare const isOk: <T, E extends Error>(t: Result<T, E>) => t is Ok<T>;
19
- export declare const isErr: <T, E extends Error>(e: Result<T, E>) => boolean;
20
- export declare const isResult: <T, E extends Error>(t: Result<T, E>) => t is Result<T, E>;
18
+ export declare const isOk: <T, E>(t: Result<T, E>) => t is Ok<T>;
19
+ export declare const isErr: <T, E>(e: Result<T, E>) => e is Err<E>;
20
+ export declare const isResult: <T, E>(t: Result<T, E>) => t is Result<T, E>;
21
21
  export declare function Ok<T>(ok: Ok<T>): T;
22
22
  export declare function Ok<T>(t: T): Ok<T>;
23
- export declare function Err<E extends Error>(e: Err<E>): E;
24
- export declare function Err<E extends Error>(e: E): Err<E>;
25
- export declare function Err<E extends Error>(e: string): Err<E>;
26
- export declare function unwrap<T, E extends Error>(result: Result<T, E>): T | never;
23
+ export declare function Err<E>(e: Err<E>): E;
24
+ export declare function Err<E>(e: E): Err<E>;
25
+ export declare function Err<E>(e: string): Err<E>;
26
+ export declare function unwrap<T, E>(result: Result<T, E>): T | never;
27
27
  export declare function unwrap<O>(some: Option<O>): O | never;
28
- export declare function unwrapOr<T, E extends Error>(result: Result<T, E>, def: T): T;
28
+ export declare function unwrapOr<T, E>(result: Result<T, E>, def: T): T;
29
29
  export declare function unwrapOr<T>(some: Some<T>, def: T): T;
30
- export declare function unwrapOrElse<T, E extends Error>(result: Result<T, Error>, def: () => T): T;
30
+ export declare function unwrapOrElse<T, E>(result: Result<T, Error>, def: () => T): T;
31
31
  export declare function unwrapOrElse<T>(some: Some<T>, def: () => T): T;
package/build/result.js CHANGED
@@ -21,8 +21,8 @@ export function Ok(t) {
21
21
  }
22
22
  export function Err(e) {
23
23
  return (e.err ?? {
24
- err: typeof e === "string" ? new Error(e) : e,
25
- map(fn) {
24
+ err: e,
25
+ map(_fn) {
26
26
  return this;
27
27
  },
28
28
  });
@@ -66,7 +66,7 @@ function makeResult(test, result) {
66
66
  stats: { executed: 1, failed: 1 },
67
67
  },
68
68
  ];
69
- if (result.passed) {
69
+ if (result.passed === true) {
70
70
  return [{ test, stats: { executed: 1, failed: 0 } }];
71
71
  }
72
72
  return flattenResults(result, test);
@@ -3,7 +3,7 @@ export declare class Matcher<T> {
3
3
  constructor(actual: T);
4
4
  get not(): Matcher<T>;
5
5
  toBe(expected: T): void;
6
- toEqual(expected: T): void;
6
+ toEqual(expected: T, partial?: boolean): void;
7
7
  toMatch(expected: RegExp | string): void;
8
8
  toMatchObject(expected: Partial<T>): void;
9
9
  toBeNull(): void;
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../assert.js";
2
+ import { display } from "../display.js";
2
3
  import { equals } from "../equal.js";
3
4
  export class Matcher {
4
5
  actual;
@@ -11,8 +12,8 @@ export class Matcher {
11
12
  toBe(expected) {
12
13
  assert(this.actual === expected, () => `${this.actual} !== ${expected}`);
13
14
  }
14
- toEqual(expected) {
15
- assert(equals(this.actual, expected), () => `Objects are not equivalent: ${JSON.stringify(this.actual)}, ${JSON.stringify(expected)}`);
15
+ toEqual(expected, partial = false) {
16
+ assert(equals(this.actual, expected, partial), () => `Objects are not equivalent: ${display(this.actual)}, ${display(expected)}`);
16
17
  }
17
18
  toMatch(expected) {
18
19
  assert(typeof this.actual === "string", () => "Must have string for regexp match");
@@ -29,7 +30,7 @@ export class Matcher {
29
30
  for (const [k, v] of Object.entries(expected)) {
30
31
  // @ts-expect-error
31
32
  const actual = this.actual[k];
32
- assert(equals(actual, v), () => `Comparing ${k}, properties not equal: ${JSON.stringify(actual)}, ${JSON.stringify(v)}`);
33
+ assert(equals(actual, v, true), () => `Comparing ${k}, properties not equal: ${display(actual)}, ${display(v)}`);
33
34
  }
34
35
  }
35
36
  toBeNull() {
@@ -0,0 +1,5 @@
1
+ import { MiddlewareFactory } from "./index.js";
2
+ /**
3
+ * Serves .css files statically. Finds .sass files and transpiles them to css.
4
+ */
5
+ export declare const cssFileServer: MiddlewareFactory;
@@ -0,0 +1,47 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { contentResponse } from "./response.js";
4
+ import sass from "sass";
5
+ const { compileStringAsync } = sass;
6
+ function render(source) {
7
+ // Replace `from "@scope` with `from "/@scope`, for browsers
8
+ // source = source
9
+ // .replaceAll(`from "@`, 'from "/@')
10
+ // .replaceAll(`import("@`, 'import("/@');
11
+ return contentResponse(source, "text/css");
12
+ }
13
+ async function compile(filename, root, vars) {
14
+ vars = vars.substring(1).replaceAll("=", ":");
15
+ const sassString = `// Using variables: ${vars}\n${vars};\n@import "${filename}";`;
16
+ return (await compileStringAsync(sassString, { loadPaths: [root] })).css;
17
+ }
18
+ /**
19
+ * Serves .css files statically. Finds .sass files and transpiles them to css.
20
+ */
21
+ export const cssFileServer = async ({ root, scopes = {} }) => async (req) => {
22
+ const Url = new URL(req.url ?? "/", `http://${req.headers.host}`);
23
+ if (Url.pathname.endsWith(".css")) {
24
+ let scope = Object.entries(scopes).find(([s]) => Url.pathname.startsWith(`/${s}`));
25
+ // Expand url with found scope
26
+ let url = scope ? Url.pathname.replace(scope[0], scope[1]) : Url.pathname;
27
+ let filename = path.join(root, url);
28
+ try {
29
+ const stat = await fs.stat(filename);
30
+ if (stat.isFile()) {
31
+ const css = (await fs.readFile(filename)).toString("utf-8");
32
+ return render(css);
33
+ }
34
+ }
35
+ catch { }
36
+ filename = filename.replace(/\.css$/, ".scss");
37
+ try {
38
+ const stat = await fs.stat(filename);
39
+ if (stat.isFile()) {
40
+ const css = await compile(filename.replace(root, "."), root, Url.search);
41
+ return render(css);
42
+ }
43
+ }
44
+ catch { }
45
+ }
46
+ return undefined;
47
+ };
@@ -3,6 +3,7 @@ import { createServer, } from "http";
3
3
  import * as path from "path";
4
4
  import { info } from "../../log.js";
5
5
  import { findIndex } from "./apps.js";
6
+ import { cssFileServer } from "./css.js";
6
7
  import { fileResponse } from "./response.js";
7
8
  import { sitemap } from "./sitemap.js";
8
9
  import { staticFileServer } from "./static.js";
@@ -13,6 +14,7 @@ path.join(root, "404.html"), undefined, 404);
13
14
  const BASE_MIDDLEWARES = [
14
15
  sitemap,
15
16
  tsFileServer,
17
+ cssFileServer,
16
18
  staticFileServer,
17
19
  findIndex,
18
20
  notFound,
@@ -25,8 +27,8 @@ const error = (res, message) => {
25
27
  return true;
26
28
  };
27
29
  const sendContent = async (res, { content, contentType, contentLength }) => {
28
- res.setHeader("content-length", `${contentLength}`);
29
- res.setHeader("content-type", contentType);
30
+ res.setHeader("Content-Length", `${contentLength}`);
31
+ res.setHeader("Content-Type", contentType);
30
32
  await res.write(content);
31
33
  res.end();
32
34
  return true;