WIP inheritance

This commit is contained in:
tristan 2024-01-01 03:20:59 +00:00
parent b734310051
commit 35b8cf7472
6 changed files with 169 additions and 84 deletions

View file

@ -32,14 +32,14 @@
default = nixite.serve self.packages.${system}.raw; default = nixite.serve self.packages.${system}.raw;
test = let test = import ./testing/import.nix; test = let run = import ./testing/run.nix pkgs;
in pkgs.writeShellScriptBin "test" '' in run [
${test ./testing/md.test.nix} #./testing/md.test.nix
${test ./testing/html.test.nix} ./testing/html.test.nix
${test ./testing/elems.test.nix} #./testing/elems.test.nix
${test ./testing/site.test.nix} #./testing/site.test.nix
${test ./testing/style.test.nix} ./testing/style.test.nix
''; ];
}; };
}; };
} }

View file

@ -1,7 +1,9 @@
let let
keyvalue = key: value: keyvalue = key: value:
assert builtins.isString key; assert builtins.isString key;
if value == "" || value == [ ] || value == { } then if builtins.isAttrs value then
builtins.trace "Skipping ${key} as it is a set" "" else
if value == "" || value == [ ] then
"" ""
else else
''${key}="${toString value}"''; ''${key}="${toString value}"'';
@ -26,11 +28,27 @@ in rec {
else else
keyvalue key value) attrs))); keyvalue key value) attrs)));
tag = tag: attrs: child: { tag = tag: {
inherit tag attrs child; inherit tag;
__toString = toHTML; __functor = self: attrs:
if !(builtins.isAttrs attrs) then
throw "HTML tag requires attribute set"
else {
inherit attrs;
__functor = self: child:
if !(isTag child) then
throw "tag child must be tag, list, or string"
else {
inherit tag attrs child;
__toString = toHTML;
};
};
}; };
isTag = tag:
(builtins.isString tag || builtins.isList tag
|| (tag ? toString && builtins.isFunction tag.toString));
addToHead = page: heads: addToHead = page: heads:
page // { page // {
child = map child = map

View file

@ -2,25 +2,40 @@ let
html = import ./html.nix; html = import ./html.nix;
join = { join = {
__functor = self: new: self // new // { style = self.style + new.style; }; __functor = self: new: self // new // { style = self.style // new.style; };
}; };
mkStyle = identifier: styles: mkStyle = identifier: styles: {
if styles == { } then ${identifier} = styles;
__toString = self:
toString (builtins.attrValues (builtins.mapAttrs styleToString self));
};
styleToString = identifier: styles:
if !builtins.isAttrs styles then
"" ""
else '' else if styles == { } then
${identifier} { ""
${ else
toString (builtins.attrValues assert builtins.isString identifier; ''
(builtins.mapAttrs (key: value: "${key}: ${value};") styles)) ${identifier} {
${
toString (builtins.attrValues
(builtins.mapAttrs (key: value: "${key}: ${value};") styles))
}
} }
} '';
'';
mkIdentifier = name: tag: mkIdentifier = name: tag:
{ class ? [ name ], id ? "", ... }: assert builtins.isString name;
"${tag}" + builtins.concatStringsSep "" (map (c: "." + c) class) let
elem = if builtins.isString tag then tag else tag.tag or "";
inheritClass =
if builtins.isString tag then [ ] else tag.attrs.class or [ ];
in { class ? [ name ] ++ inheritClass, id ? "", ... }:
"${elem}" + builtins.concatStringsSep "" (map (c: "." + c) class)
+ (if id != "" then "#" else "") + id; + (if id != "" then "#" else "") + id;
in { in {
styled = name: tag: cprops: styled = name: tag: cprops:
assert builtins.isString name; assert builtins.isString name;
@ -36,9 +51,9 @@ in {
if cprops.class == [ ] then [ ] else [ name ] ++ cprops.class if cprops.class == [ ] then [ ] else [ name ] ++ cprops.class
else else
[ name ]; [ name ];
}) { style = ""; }; });
self = if builtins.isFunction tag then self = if tag ? __functor && builtins.isFunction tag.__functor then
props: tag (joinProps props) props: tag (joinProps props)
else if builtins.isString tag then else if builtins.isString tag then
props: html.tag tag (joinProps props) props: html.tag tag (joinProps props)
@ -54,8 +69,14 @@ in {
(self { } (__child props)) (self { } (__child props))
else else
throw "Call element with attributes and child.")) self; throw "Call element with attributes and child.")) self;
in { in {
${name} = __self; ${name} = {
tag = (if builtins.isString tag then tag else tag.tag);
attrs =
joinProps (if builtins.isString tag then { } else tag.attrs or { });
__functor = self: __self;
};
style = mkStyle (mkIdentifier name tag cprops) (cprops.style or { }); style = mkStyle (mkIdentifier name tag cprops) (cprops.style or { });
} // join; } // join;

View file

@ -2,6 +2,19 @@ let
html = import ../nixite/html.nix; html = import ../nixite/html.nix;
it = import ./it.nix; it = import ./it.nix;
in with html; [ in with html; [
(it "keeps info in the tag" (let p = tag "p";
in {
actual = p.tag;
expected = "p";
}))
(it "keeps attr info in the tag" (let p = tag "p" { class = ""; };
in {
actual = p.attrs;
expected = { class = ""; };
}))
(it "makes a p tag" { (it "makes a p tag" {
actual = tag "p" { } "Hello"; actual = tag "p" { } "Hello";
expected = { expected = {

5
testing/run.nix Normal file
View file

@ -0,0 +1,5 @@
pkgs:
let test = import ./import.nix;
in files:
(pkgs.writeShellScriptBin "test"
(builtins.concatStringsSep "\n" (map test files)))

View file

@ -3,55 +3,61 @@ let
html = import ../nixite/html.nix; html = import ../nixite/html.nix;
it = import ./it.nix; it = import ./it.nix;
p = style.styled "generic" "p" { my = (style.styled "div" "div" {
foo = "bar"; class = [ "something" ];
forgetme = "nothing"; style = { this = "that"; };
}; }) (style.styled "s" "div" {
id = "s";
class = [ "something" ];
style = { s = "yes"; };
}) (style.styled "foobar" "div" {
class = [ "foo" "bar" ];
style = { something = "something"; };
}) (style.style "body" { foo = "bar"; }) (style.styled "list" "ul" {
__child = child:
assert builtins.isList child;
(map (html.tag "li" { }) child);
});
in [
my = (style.styled "p" "p" { style = { some-style = "some value"; }; }) (it "makes a p component" (let
(style.styled "classless" "div" { class = [ ]; }) my = (style.styled "para" "p" { style = { some-style = "some value"; }; });
(style.styled "quote" p.generic { in {
expected = html.tag "p" { class = [ "para" ]; } "yes";
actual = my.para { } "yes";
asString = true;
}))
(it "extends existing components" (let
my = (style.styled "generic" "p" {
foo = "bar";
forgetme = "nothing";
});
this = (style.styled "quote" my.generic {
baz = "baz"; baz = "baz";
forgetme = "forgotten"; forgetme = "forgotten";
}) (style.styled "div" "div" {
class = [ "something" ];
style = { this = "that"; };
}) (style.styled "s" "div" {
id = "s";
class = [ "something" ];
style = { s = "yes"; };
}) (style.styled "foobar" "div" {
class = [ "foo" "bar" ];
style = { something = "something"; };
}) (style.style "body" { foo = "bar"; }) (style.styled "list" "ul" {
__child = child:
assert builtins.isList child;
(map (html.tag "li" { }) child);
}); });
in [ in {
(it "extends existing components" {
expected = html.tag "p" { expected = html.tag "p" {
forgetme = "forgotten"; forgetme = "forgotten";
baz = "baz"; baz = "baz";
foo = "bar"; foo = "bar";
class = [ "generic" "quote" ]; class = [ "generic" "quote" ];
} "yes"; } "yes";
actual = my.quote { } "yes"; actual = this.quote { } "yes";
asString = true; asString = true;
}) }))
(it "makes a p component" {
expected = html.tag "p" { class = [ "p" ]; } "yes"; (it "makes a component with no class"
actual = my.p { } "yes"; (let my = (style.styled "classless" "div" { class = [ ]; });
asString = true; in {
}) expected = html.tag "div" { class = [ ]; } "yes";
(it "makes a component with no class" { actual = my.classless { } "yes";
expected = html.tag "div" { class = [ ]; } "yes"; asString = true;
actual = my.classless { } "yes"; }))
asString = true;
})
(it "does not error without attrs" { (it "does not error without attrs" {
expected = html.tag "p" { class = [ "p" ]; } "yes"; expected = html.tag "div" { class = [ "div" "something" ]; } "yes";
actual = my.p "yes"; actual = my.div "yes";
asString = true; asString = true;
}) })
(it "makes a component" { (it "makes a component" {
@ -88,24 +94,46 @@ in [
actual = my.div { id = "foo"; } "foobar"; actual = my.div { id = "foo"; } "foobar";
asString = true; asString = true;
}) })
(it "makes a style" { (it "makes a style"
expected = '' (let my = (style.styled "para" "p" { style = { foo = "bar"; }; });
p.p { in {
some-style: some value; expected = { "p.para" = { foo = "bar"; }; };
} actual = removeAttrs my.style [ "__toString" ];
div.something { }))
this: that;
} (it "retains tag"
div.something#s { (let p = (style.styled "para" "p" { style = { foo = "bar"; }; });
s: yes; in {
} expected = "p";
div.foo.bar { actual = p.para.tag;
something: something; }))
}
body { (it "retains attrs"
foo: bar; (let p = (style.styled "para" "p" { style = { foo = "bar"; }; });
} in {
''; expected = { foo = "bar"; };
actual = my.style; actual = p.para.attrs.style;
}) }))
(it "retains class" (let p = (style.styled "para" "p" { });
in {
expected = [ "para" ];
actual = p.para.attrs.class;
}))
(it "merges styles" (let
p = (style.styled "para" "p" { style = { foo = "bar"; }; });
d = (style.styled "para2" p.para { style = { baz = "bar"; }; });
my = p d;
in {
expected = {
"p.para" = { foo = "bar"; };
"p.para2.para" = {
foo = "bar";
baz = "bar";
};
};
actual = removeAttrs my.style [ "__toString" ];
}))
] ]