diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2018-11-01 10:17:55 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2018-11-01 10:17:55 +0000 |
| commit | 30fb0dc40d595b9e0b7747ad8e5c4e8cf7e3023b (patch) | |
| tree | dc56f20ec4d78115e15761c402589b5aec94ef55 | |
| parent | defer all scripts (diff) | |
| download | mmm-30fb0dc40d595b9e0b7747ad8e5c4e8cf7e3023b.tar.gz mmm-30fb0dc40d595b9e0b7747ad8e5c4e8cf7e3023b.zip | |
move mmm code from lib to mmm etc
| -rw-r--r-- | Tupfile | 10 | ||||
| -rw-r--r-- | app/init.moon | 158 | ||||
| -rw-r--r-- | app/test_component.moon | 212 | ||||
| -rw-r--r-- | app/todo.moon | 35 | ||||
| -rw-r--r-- | lib/duct_tape.server.moon | 130 | ||||
| -rw-r--r-- | mmm/canvasapp.client.moon (renamed from lib/canvasapp.client.moon) | 2 | ||||
| -rw-r--r-- | mmm/color.moon (renamed from lib/color.moon) | 0 | ||||
| -rw-r--r-- | mmm/component/init.client.moon (renamed from lib/component.client.moon) | 6 | ||||
| -rw-r--r-- | mmm/component/init.server.moon (renamed from lib/component.server.moon) | 9 | ||||
| -rw-r--r-- | mmm/dom/init.client.moon (renamed from lib/dom.client.moon) | 0 | ||||
| -rw-r--r-- | mmm/dom/init.server.moon (renamed from lib/dom.server.moon) | 2 | ||||
| -rw-r--r-- | mmm/init.client.moon (renamed from lib/init.client.moon) | 0 | ||||
| -rw-r--r-- | mmm/init.server.moon (renamed from lib/init.server.moon) | 14 | ||||
| -rw-r--r-- | mmm/mmmfs/browser.moon (renamed from lib/mmmfs/browser.moon) | 2 | ||||
| -rw-r--r-- | mmm/mmmfs/conversion.moon (renamed from lib/mmmfs/conversion.moon) | 4 | ||||
| -rw-r--r-- | mmm/mmmfs/fileder.moon (renamed from lib/mmmfs/fileder.moon) | 0 | ||||
| -rw-r--r-- | mmm/mmmfs/init.moon (renamed from lib/mmmfs/init.moon) | 26 | ||||
| -rw-r--r-- | mmm/ordered.moon (renamed from lib/ordered.moon) | 0 | ||||
| -rw-r--r-- | render.moon | 21 | ||||
| -rw-r--r-- | root/animations/init.moon | 4 | ||||
| -rw-r--r-- | root/animations/koch.moon | 6 | ||||
| -rw-r--r-- | root/animations/twisted.moon | 6 | ||||
| -rw-r--r-- | root/articles/init.moon | 4 | ||||
| -rw-r--r-- | root/articles/mmmfs/gallery.moon | 6 | ||||
| -rw-r--r-- | root/articles/mmmfs/init.moon | 8 | ||||
| -rw-r--r-- | root/articles/realities.moon | 4 | ||||
| -rw-r--r-- | root/experiments/center_of_mass.moon | 8 | ||||
| -rw-r--r-- | root/experiments/init.moon | 4 | ||||
| -rw-r--r-- | root/experiments/tags/init.moon | 6 | ||||
| -rw-r--r-- | root/init.moon | 7 | ||||
| -rw-r--r-- | root/meta/init.moon | 27 | ||||
| -rw-r--r-- | root/meta/test_component.moon | 224 | ||||
| -rw-r--r-- | root/meta/todo.moon | 42 | ||||
| -rw-r--r-- | tup.moon | 13 |
34 files changed, 373 insertions, 627 deletions
@@ -11,14 +11,20 @@ # render stylesheet : scss/main.scss |> !sassc |> dist/main.css -preload lib -preload lib/mmmfs +# preload full mmmfs tree preload root preload root/animations preload root/articles preload root/articles/mmmfs preload root/experiments preload root/experiments/tags +preload root/meta + +# preload all of mmm +preload mmm +preload mmm/dom +preload mmm/mmmfs +preload mmm/component # render static content and compile sources run moon tup.moon diff --git a/app/init.moon b/app/init.moon deleted file mode 100644 index 8bc95e3..0000000 --- a/app/init.moon +++ /dev/null @@ -1,158 +0,0 @@ -require = relative ... - -union = (...) -> with res = {} - c = 1 - for i = 1, select '#', ... - tbl = select i, ... - for val in *tbl - res[c] = val - c += 1 - -map = (f, list) -> [f val for val in *list] - -patch_redirs = -> - redirs = - 'center-of-mass': 'center_of_mass', - 'test-component': 'test_component', - 'play-tags': 'tags', - - { :location } = window - if (not location.search\find '=') and #location.search > 1 - name = location.search\sub 2 - location.href = redirs[name] or name - -client_goto = -> - { :location } = window - if module = location.search\match 'client=([%w_]+)' - document.body.innerHTML = '' - require "app.#{module}" - -articles = { - { - name: 'realities' - desc: 'exploring the nesting relationships of virtual and other realities' - }, - { - name: 'mmmfs' - desc: 'a file and operating system to live in (wip)' - }, -} - -animations = { - { - name: 'twisted' - desc: 'pseudo 3d animation' - }, - { - name: 'koch' - desc: "lil' fractal thing" - }, -} - -experiments = { - { - name: 'center_of_mass' - desc: 'aligning characters by their centers of mass' - }, - { - name: 'tags' - desc: 'organizing files with Functional Tags' - }, -} - -meta = { - { - name: 'todo' - desc: 'Todo MVC with the mmm UI framework' - }, - { - name: 'test_component' - desc: 'test suite for the mmm reactive UI framework' - }, -} - -content = { - { 'articles', articles } - { 'animations', animations } - { 'experiments', experiments } - { 'meta', meta } -} - -index = { - name: 'index' - route: '' - dest: 'index.html' - render: => - import h1, h3, div, b, p, a, br, ul, tt, li, img from require 'lib.dom' - import opairs from require 'lib.ordered' - - moon = '\xe2\x98\xbd' - - -- redirects for old-style URIs - on_client patch_redirs - - iconlink = (href, src, alt, style) -> a { - class: 'iconlink', - :href, - target: '_blank', - img :src, :alt, :style - } - - -- menu - append h1 { - style: { - position: 'relative', - 'border-bottom': '1px solid #000' - }, - 'mmm', - div { - class: 'icons', - iconlink 'https://github.com/s-ol/mmm', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', - iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', - iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', - { height: '0.9em', 'margin-left': '.04em' } - } - } - - append p { - tt 'mmm' - ' is not the ' - tt 'www' - ', because it runs on ' - a { 'MoonScript', href: 'https://moonscript.org' } - '.' - br! - 'You can find the source code of everything ' - a { 'here', href: 'https://github.com/s-ol/mmm' } - '.' - } - - for { category, routes } in *content - append h3 category, style: { 'margin-bottom': '-.5em' } - append ul for { :name, :desc, :route } in *routes - li (a name, href: route), ': ', desc - - append p { - "made with #{moon} by " - a { 's-ol', href: 'https://twitter.com/S0lll0s' } - } - - on_client client_goto -} - -load = (module) -> require "app.#{module}" - -destify = (route) -> with route - .route or= .name - .dest or= "#{.route}/index.html" - - if .render == 'client' - .render = -> on_client load, .name - .render or= -> require '.' .. .name - -routes = map destify, union articles, animations, experiments, meta, { index } -{ - :routes, - indexed: { r.name, r for r in *routes } - render: (name) -> require ".#{name}" -} diff --git a/app/test_component.moon b/app/test_component.moon deleted file mode 100644 index d3f1489..0000000 --- a/app/test_component.moon +++ /dev/null @@ -1,212 +0,0 @@ -on_client -> - import div, h1, ul, li, pre from require 'lib.dom' - - last = nil - test_group = (name) -> - if last - append div (h1 name), ul last - - last = {} - (name, test) -> - ok, err = pcall test - table.insert last, li if ok - "passed '#{name}'" - else - "failed '#{name}'", pre err - - expect = (expected, note, ...) -> - ok, msg = pcall ... - print ok, msg\find expected - if ok or not msg\find expected - error note - - run_test = test_group 'component.moon' - - local ReactiveVar, ReactiveElement - run_test "exports ReactiveVar, ReactiveElement", -> - import ReactiveVar, ReactiveElement from require 'lib.component' - assert ReactiveVar, "ReactiveVar not exported" - assert ReactiveElement, "ReactiveElement not exported" - - run_test "exports tohtml helper", -> - import tohtml from require 'lib.component' - assert 'function' == (type tohtml), "tohtml not exported" - - run_test "exports append helper", -> - import append from require 'lib.component' - assert 'function' == (type append), "append not exported" - - run_test "exports text helper", -> - import text from require 'lib.component' - assert 'function' == (type text), "text not exported" - - node = text 'a test string' - assert (js.instanceof node, js.global.Node), "expected text to generate a Node" - assert node.data == 'a test string', "expected text to store the string" - - run_test "text joins multiple arguments", -> - import text from require 'lib.component' - - node = text 'a', 'test', 'string' - assert node.data == 'a test string', "expected text to join arguments with spaces" - - run_test "exports elements table", -> - import elements from require 'lib.component' - - assert (type elements.div!) == 'table', "expected to build element with elements.div!" - assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!" - - run_test = test_group 'ReactiveVar' - - run_test "stores a value", -> - reactive = ReactiveVar 'test' - assert 'test' == reactive\get!, "expected x to be 'test'" - - run_test "propagates updates", -> - local done - - reactive = ReactiveVar 'test' - reactive\subscribe coroutine.wrap (next) -> - assert next == 'toast', "expected next to be 'toast'" - assert coroutine.yield! == 'cheese', "expected next to be 'cheese'" - done = true - - reactive\set 'toast' - assert 'toast' == reactive\get!, "expected #get to return 'toast'" - reactive\set 'cheese' - assert done, "expected to reach the end" - - run_test "passed old value as well", -> - local done - - reactive = ReactiveVar 1 - reactive\subscribe coroutine.wrap (next, last) -> - assert last == 1, "expected last:1 to be 1" - next, last = coroutine.yield! - assert last == 2, "expected last:2 to be 2" - done = true - - reactive\set 2 - reactive\set 3 - assert done, "expected to reach the end" - - run_test "provides transform shorthand", -> - local done - - reactive = ReactiveVar 1 - reactive\subscribe coroutine.wrap (next, last) -> - assert last == 1, "expected last:1 to be 1" - next, last = coroutine.yield! - assert last == 2, "expected last:2 to be 2" - done = true - - add_one = (a) -> a + 1 - reactive\transform add_one - reactive\transform add_one - assert done, "expected to reach the end" - - run_test "#subscribe returns function to unsubscribe", -> - calls = 0 - - reactive = ReactiveVar 1 - unsub = reactive\subscribe coroutine.wrap () -> - calls += 1 - coroutine.yield! - calls += 1 - coroutine.yield! - calls += 1 - - assert 'function' == (type unsub), "expected to receive a function" - - reactive\set 2 - reactive\set 3 - assert calls == 2, "wat" - - unsub! - reactive\set 4 - assert calls == 2, "expected to stop receiving updates" - - run_test "tracks multiple subscriptions at once", -> - reactive = ReactiveVar 'test' - unsub = reactive\subscribe coroutine.wrap (next) -> - assert next == 'toast', "expected next to be toast" - next = coroutine.yield! - assert next == 'cheese', "expected next to be cheese" - coroutine.yield! - error "expected not to get here" - - reactive\set 'toast' - - local done - reactive\subscribe coroutine.wrap (next) -> - assert next == 'cheese', "expected next to be cheese" - next = coroutine.yield! - assert next == 'test', "expected next to be test" - done = true - - reactive\set 'cheese' - unsub! - reactive\set 'test' - assert done, "expected to reach the end" - - run_test = test_group 'ReactiveElement' - - run_test "creates a HTML element", -> - elem = ReactiveElement 'span' - assert elem.node and elem.node.localName == 'span', "expected Node to be a <span>" - - run_test "sets attributes from a table arg", -> - elem = ReactiveElement 'span', class: 'never' - assert elem.node.class == 'never', "expected class to be 'never'" - - run_test "appends Nodes from arguments", -> - e_div, e_pre = div!, pre! - elem = ReactiveElement 'span', e_div, e_pre - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" - - run_test "can append ReactiveElements and text", -> - e_div = ReactiveElement 'div' - elem = ReactiveElement 'div', e_div, 'testtext' - assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem" - assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'" - - run_test "accepts attributes after children", -> - e_div = div! - elem = ReactiveElement 'div', e_div, class: 'test' - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.class == 'test', "expected class to be 'test'" - - run_test "allows mixing attributes and children in a single table", -> - e_div, e_pre = div!, pre! - elem = ReactiveElement 'div', { class: 'test', e_div, e_pre } - assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" - assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" - assert elem.node.class == 'test', "expected class to be 'test'" - - run_test "can unwrap and track attributes from ReactiveVars", -> - klass = ReactiveVar 'test' - elem = ReactiveElement 'div', class: klass - assert elem.node.class == 'test', "expected class to be 'test'" - klass\set 'toast' - assert elem.node.class == 'toast', "expected class to be 'toast'" - - run_test "can unwrap and track children from ReactiveVars", -> - child = ReactiveVar h1 'test' - elem = ReactiveElement 'div', child, pre 'fixed' - assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1" - assert elem.node.childElementCount == 2, "expected node to have two children" - child\set div 'toast' - assert elem.node.firstElementChild.localName == 'div', "expected first child to be div" - assert elem.node.childElementCount == 2, "expected node to have two children" - - run_test "warns when appending a string from a ReactiveVar", -> - import text from require 'lib.component' - - str = ReactiveVar 'test' - elem = ReactiveElement 'div', str - expect 'cannot replace string node', 'expected error', str\set, 'string too' - elem\destroy! - - elem = ReactiveElement 'div', str\map text - str\set 'this is text' diff --git a/app/todo.moon b/app/todo.moon deleted file mode 100644 index f2baa50..0000000 --- a/app/todo.moon +++ /dev/null @@ -1,35 +0,0 @@ -on_client -> - import ReactiveVar, append, text, elements from require 'lib.component' - import div, form, span, h3, a, input, textarea, button from elements - - parent = div! - todoItem = (desc, done) -> - -- convert into reactive data sources - desc, done = (ReactiveVar desc), ReactiveVar done - with me = div style: - margin: '8px' - padding: '8px' - background: '#eeeeee' - \append h3 (desc\map text), style: 'margin: 0;' - \append span done\map (done) -> text if done then 'done' else 'not done yet' - \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked - \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me - - parent\append todoItem 'write a Component System' - parent\append todoItem 'eat Lasagna', true - - desc = ReactiveVar 'start' - form = with form { - action: '' - style: - margin: '2px' - onsubmit: (e) => - e\preventDefault! - parent\append todoItem desc\get! - desc\set '' - } - \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value - \append input type: 'submit', value: 'add' - - append parent - append form diff --git a/lib/duct_tape.server.moon b/lib/duct_tape.server.moon deleted file mode 100644 index b019ac8..0000000 --- a/lib/duct_tape.server.moon +++ /dev/null @@ -1,130 +0,0 @@ -package.noompath = './?.moon;./?/init.moon' - -export __FNDEF_NOOM_CACHE -__FNDEF_NOOM_CACHE = setmetatable {}, __mode: 'k' - -assert MODE == 'SERVER', "duct_tape only works on the server" - -compile = require 'moonscript.compile' -parse = require 'moonscript.parse' - -import smart_node, build from require 'moonscript.types' -import dirsep from require 'moonscript.base' -import get_options, unpack from require 'moonscript.util' - -line_tables = require 'moonscript.line_tables' -lua = :loadstring, :load - -local * - -escape_str = (str) -> (str\gsub('\\', '\\\\')\gsub '"', '\\"'), nil - -deep_clone = (value) -> - if 'table' == type value - { deep_clone(k), deep_clone(v) for k,v in pairs value } - else -- number, string, boolean, etc - value - -transform_fndef = (fndef, parent, i) -> - -- compile the function to Lua separately - code, ltable, pos = compile.tree { deep_clone fndef } - if not code - return compile.format_error(ltable, pos, text) - - code = "(function() #{code} end)()" - - -- assign the lua code to __FNDEF_NOOM_CACHE[function] so it can be retrieved by `compile` - fn = -> { 'ref', 'fn' } - cache = build.chain { - base: '__FNDEF_NOOM_CACHE', - { 'index', fn! } - } - - parent[i] = build.do { - { 'declare_with_shadows', { 'fn' } } - build.assign_one fn!, fndef - build.assign_one cache, { 'string', '"', escape_str code } - -- build.assign_one cache, { 'string', '[[', code } - fn! - } - - nil - -find_fndefs = (node, p, i) -> - if node[1] == "fndef" - transform_fndef node, p, i - else - for i = 1,#node - v = node[i] - find_fndefs v, node, i if 'table' == type v - -to_lua = (text, options={}) -> - if "string" != type text - t = type text - return nil, "expecting string (got ".. t ..")" - - tree, err = parse.string text - if not tree - return nil, err - - find_fndefs tree - - code, ltable, pos = compile.tree tree, options - if not code - return nil, compile.format_error(ltable, pos, text) - - code, ltable - -noom_loader = (name, ...) -> - name_path = name\gsub "%.", dirsep - - local file, file_path - for path in package.noompath\gmatch "[^;]+" - file_path = path\gsub "?", name_path - file = io.open file_path - break if file - - if file - text = file\read "*a" - file\close! - res, err = loadstring text, "@#{file_path}" - if not res - error file_path .. ": " .. err - - return res - - return nil, "Could not find noom file" - -loadstring = (...) -> - options, str, chunk_name, mode, env = get_options ... - chunk_name or= "=(noom.loadstring)" - - code, ltable_or_err = to_lua str, options - unless code - return nil, ltable_or_err - - line_tables[chunk_name] = ltable_or_err if chunk_name - - -- the unpack prevents us from passing nil - (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } - -do - local compile - insert_loader = (pos=2) -> - -- if not package.moonpath - -- package.moonpath = create_moonpath package.path - - loaders = package.loaders or package.searchers - for loader in *loaders - return false if loader == noom_loader - - table.insert loaders, pos, noom_loader - true - - compile = (fn) -> with code = __FNDEF_NOOM_CACHE[fn] - assert code, 'cannot compile function not loaded from noomscript source.' - - { - :insert_loader - :compile - } diff --git a/lib/canvasapp.client.moon b/mmm/canvasapp.client.moon index 71ffa59..40f2423 100644 --- a/lib/canvasapp.client.moon +++ b/mmm/canvasapp.client.moon @@ -1,7 +1,7 @@ window = js.global js = require 'js' -import a, canvas, div, button, script from require 'lib.dom' +import a, canvas, div, button, script from require 'mmm.dom' class CanvasApp width: 500 diff --git a/lib/color.moon b/mmm/color.moon index 6233b47..6233b47 100644 --- a/lib/color.moon +++ b/mmm/color.moon diff --git a/lib/component.client.moon b/mmm/component/init.client.moon index ffeb084..193fd94 100644 --- a/lib/component.client.moon +++ b/mmm/component/init.client.moon @@ -16,11 +16,6 @@ tohtml = (val) -> else error "not a Node: #{val}, #{type val}" --- overloaded append --- see tohtml for acceptable values -g_append = append -append = (value) -> g_append tohtml value - -- shorthand to form a text node from strings text = (...) -> document\createTextNode table.concat { ... }, ' ' @@ -152,7 +147,6 @@ elements = setmetatable {}, __index: (name) => :get_or_create, -- :join, :tohtml, - :append, :text, :elements, } diff --git a/lib/component.server.moon b/mmm/component/init.server.moon index 0026d32..b84b8d5 100644 --- a/lib/component.server.moon +++ b/mmm/component/init.server.moon @@ -1,4 +1,4 @@ -import opairs from require 'lib.ordered' +import opairs from require 'mmm.ordered' void_tags = { 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr' } void_tags = { t,t for t in *void_tags } @@ -16,11 +16,6 @@ tohtml = (val) -> else error "not a Node: #{val}, #{type val}" --- overloaded append --- see tohtml for acceptable values -g_append = append -append = (value) -> g_append tohtml value - -- shorthand to form a text node from strings text = (...) -> table.concat { ... }, ' ' @@ -123,8 +118,6 @@ get_or_create = (elem, id, ...) -> :ReactiveElement, :get_or_create, :tohtml, - :flush, - :append, :text, :elements, } diff --git a/lib/dom.client.moon b/mmm/dom/init.client.moon index acdbfa4..acdbfa4 100644 --- a/lib/dom.client.moon +++ b/mmm/dom/init.client.moon diff --git a/lib/dom.server.moon b/mmm/dom/init.server.moon index fe6b60c..b0a8c85 100644 --- a/lib/dom.server.moon +++ b/mmm/dom/init.server.moon @@ -1,4 +1,4 @@ -import opairs from require 'lib.ordered' +import opairs from require 'mmm.ordered' void_tags = { 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr' } void_tags = { t,t for t in *void_tags } diff --git a/lib/init.client.moon b/mmm/init.client.moon index 144543b..144543b 100644 --- a/lib/init.client.moon +++ b/mmm/init.client.moon diff --git a/lib/init.server.moon b/mmm/init.server.moon index cc3851d..f87596e 100644 --- a/lib/init.server.moon +++ b/mmm/init.server.moon @@ -38,20 +38,6 @@ relative = do name = base .. name if '.' == name\sub 1, 1 _require name -import compile, insert_loader from require 'lib.duct_tape' -insert_loader! - -on_client = (fn, ...) -> - args = {...} - -- warn code - "<script type=\"application/lua\"> - local fn = #{compile fn} - on_load = on_load or {} - table.insert(on_load, function() - fn(#{table.concat [string.format '%q', v for v in *args ], ', '}) - end) - </script>" - { -- access / flush the appended data flush: -> diff --git a/lib/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index ce7709f..b057573 100644 --- a/lib/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,7 +1,7 @@ require = relative ..., 1 import Key from require '.fileder' import get_conversions from require '.conversion' -import ReactiveVar, get_or_create, text, elements from require 'lib.component' +import ReactiveVar, get_or_create, text, elements from require 'mmm.component' import div, span, a, select, option from elements class Browser diff --git a/lib/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 7f86aa4..5fdb4c2 100644 --- a/lib/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -1,5 +1,5 @@ -import text, code from require 'lib.dom' -import tohtml from require 'lib.component' +import text, code from require 'mmm.dom' +import tohtml from require 'mmm.component' -- limit function to one argument single = (func) -> (val) -> func val diff --git a/lib/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index c3e40f7..c3e40f7 100644 --- a/lib/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon diff --git a/lib/mmmfs/init.moon b/mmm/mmmfs/init.moon index d0de45b..52d5da8 100644 --- a/lib/mmmfs/init.moon +++ b/mmm/mmmfs/init.moon @@ -1,7 +1,7 @@ require = relative ... import Key, Fileder from require '.fileder' import Browser from require '.browser' -import tohtml from require 'lib.component' +import tohtml from require 'mmm.component' define_fileders = (...) -> source_module = ... @@ -10,24 +10,30 @@ define_fileders = (...) -> with fileder = Fileder ... .source_module = source_module -rehydrate = (path) -> - import Browser from require 'lib.mmmfs.browser' - root = require 'root' - root\mount! - - export BROWSER - BROWSER = Browser root, path, true - render = (root, path) -> export BROWSER BROWSER = Browser root, path content = tohtml BROWSER - content, on_client rehydrate, path + + rehydrate = " +<script type=\"application/lua\"> + on_load = on_load or {} + table.insert(on_load, function() + local path = #{string.format '%q', path} + local browser = require 'mmm.mmmfs.browser' + local root = require 'root' + root:mount() + + BROWSER = browser.Browser(root, path, true) + end) +</script>" + content, rehydrate { :Key :Fileder + :Browser :render :define_fileders :module_roots diff --git a/lib/ordered.moon b/mmm/ordered.moon index 59c07bf..59c07bf 100644 --- a/lib/ordered.moon +++ b/mmm/ordered.moon diff --git a/render.moon b/render.moon index 1246999..8098ba7 100644 --- a/render.moon +++ b/render.moon @@ -1,13 +1,11 @@ -package.moonpath = './?.server.moon;' .. package.moonpath -import flush from require 'lib.init' -import render from require 'lib.mmmfs' +package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath +import flush from require 'mmm.init' +import render from require 'mmm.mmmfs' -- usage: -- moon render.moon <output> <fileder_path> [<prefix module> <prefix path>] - { output_name, path, prefix_mod, prefix_path } = arg --- output_name = assert arg[1], "please specify the output filename as an argument" --- path = assert arg[2], "please specify the path name to build as an argument" + assert output_name, "please specify the output filename as an argument" assert path, "please specify the path name to build as an argument" @@ -32,10 +30,11 @@ with io.open output_name, 'w' <title>MMM: lunar low-gravity scripting playground</title> <link rel=\"stylesheet\" type=\"text/css\" href=\"/main.css\" /> <!-- - <link rel=\"preload\" as=\"fetch\" href=\"/lib/dom.lua\" /> - <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/init.lua\" /> - <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/fileder.lua\" /> - <link rel=\"preload\" as=\"fetch\" href=\"/lib/mmmfs/browser.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/mmm/dom/init.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/mmm/component/init.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/mmm/mmmfs/init.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/mmm/mmmfs/fileder.lua\" /> + <link rel=\"preload\" as=\"fetch\" href=\"/mmm/mmmfs/browser.lua\" /> --> </head> <body> @@ -45,7 +44,7 @@ with io.open output_name, 'w' <script defer src=\"/highlight.pack.js\"></script> <script defer src=\"//cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js\"></script> <script defer src=\"//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js\"></script> - <script defer type=\"application/lua\" src=\"/lib/init.lua\"></script> + <script defer type=\"application/lua\" src=\"/mmm/init.lua\"></script> #{rehydrate} </body> diff --git a/root/animations/init.moon b/root/animations/init.moon index ba8cb91..c968cfd 100644 --- a/root/animations/init.moon +++ b/root/animations/init.moon @@ -1,5 +1,5 @@ -import div, h3, ul, li, a from require 'lib.dom' -import define_fileders from require 'lib.mmmfs' +import div, h3, ul, li, a from require 'mmm.dom' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... diff --git a/root/animations/koch.moon b/root/animations/koch.moon index 9b8217d..4d16b8a 100644 --- a/root/animations/koch.moon +++ b/root/animations/koch.moon @@ -1,4 +1,4 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... with Fileder { @@ -9,8 +9,8 @@ with Fileder { if MODE == 'CLIENT' Math = window.Math - import CanvasApp from require 'lib.canvasapp' - import hsl from require 'lib.color' + import CanvasApp from require 'mmm.canvasapp' + import hsl from require 'mmm.color' class KochDemo extends CanvasApp width: 600 diff --git a/root/animations/twisted.moon b/root/animations/twisted.moon index 9e97738..68bdac6 100644 --- a/root/animations/twisted.moon +++ b/root/animations/twisted.moon @@ -1,4 +1,4 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... with Fileder { @@ -7,8 +7,8 @@ with Fileder { } if MODE == 'CLIENT' - import CanvasApp from require 'lib.canvasapp' - import hsl from require 'lib.color' + import CanvasApp from require 'mmm.canvasapp' + import hsl from require 'mmm.color' Math = window.Math diff --git a/root/articles/init.moon b/root/articles/init.moon index b706f7c..483aa32 100644 --- a/root/articles/init.moon +++ b/root/articles/init.moon @@ -1,5 +1,5 @@ -import div, h3, ul, li, a from require 'lib.dom' -import define_fileders from require 'lib.mmmfs' +import div, h3, ul, li, a from require 'mmm.dom' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... diff --git a/root/articles/mmmfs/gallery.moon b/root/articles/mmmfs/gallery.moon index e132f42..3abad43 100644 --- a/root/articles/mmmfs/gallery.moon +++ b/root/articles/mmmfs/gallery.moon @@ -1,5 +1,5 @@ -import define_fileders from require 'lib.mmmfs' -import div, h1, a, img, br from require 'lib.dom' +import define_fileders from require 'mmm.mmmfs' +import div, h1, a, img, br from require 'mmm.dom' Fileder = define_fileders ... @@ -23,7 +23,7 @@ with Fileder { div content 'slideshow: moon -> mmm/dom': => - import ReactiveVar, text, elements from require 'lib.component' + import ReactiveVar, text, elements from require 'mmm.component' index = ReactiveVar 1 diff --git a/root/articles/mmmfs/init.moon b/root/articles/mmmfs/init.moon index 2b3ef5e..8b1ce01 100644 --- a/root/articles/mmmfs/init.moon +++ b/root/articles/mmmfs/init.moon @@ -1,4 +1,4 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... @@ -11,7 +11,7 @@ Fileder { -- uses the 'moon ->' conversion to execute the lua/pre moon function on get -- resolves to a value of type mmm/dom 'moon -> mmm/dom': () => - html = require 'lib.dom' + html = require 'mmm.dom' import article, h1, h2, h3, p, div, a, sup, ol, li, span, code, pre, br from html moon = if MODE == 'SERVER' @@ -235,7 +235,7 @@ Fileder { 'title: text/plain': "Hey I'm like a link to picture or smth", 'URL -> image/png': 'https://picsum.photos/200?random', 'preview: moon -> mmm/dom': => - import img from require 'lib.dom' + import img from require 'mmm.dom' img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type } ]] @@ -264,7 +264,7 @@ If you are reading this in the source, then c'mon, just scroll past and give me -- preview is a lua/pre moon function that neturns an mmm/dom value 'preview: moon -> mmm/dom': => - import img from require 'lib.dom' + import img from require 'mmm.dom' img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type } diff --git a/root/articles/realities.moon b/root/articles/realities.moon index 05c0c03..78d7bae 100644 --- a/root/articles/realities.moon +++ b/root/articles/realities.moon @@ -1,11 +1,11 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... Fileder { 'name: alpha': 'realities' 'description: text/plain': 'exploring the nesting relationships of virtual and other realities' 'moon -> mmm/component': => - import elements from require 'lib.component' + import elements from require 'mmm.component' import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements _content = div! diff --git a/root/experiments/center_of_mass.moon b/root/experiments/center_of_mass.moon index 641fc5a..3d0e924 100644 --- a/root/experiments/center_of_mass.moon +++ b/root/experiments/center_of_mass.moon @@ -1,4 +1,4 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... with Fileder { @@ -7,9 +7,9 @@ with Fileder { } if MODE == 'CLIENT' - import CanvasApp from require 'lib.canvasapp' - import rgb from require 'lib.color' - import article, h1, p, div, span, input, button from require 'lib.dom' + import CanvasApp from require 'mmm.canvasapp' + import rgb from require 'mmm.color' + import article, h1, p, div, span, input, button from require 'mmm.dom' fast = true center = true diff --git a/root/experiments/init.moon b/root/experiments/init.moon index d9f4938..65f3852 100644 --- a/root/experiments/init.moon +++ b/root/experiments/init.moon @@ -1,5 +1,5 @@ -import div, h3, ul, li, a from require 'lib.dom' -import define_fileders from require 'lib.mmmfs' +import div, h3, ul, li, a from require 'mmm.dom' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... diff --git a/root/experiments/tags/init.moon b/root/experiments/tags/init.moon index f113e74..611d722 100644 --- a/root/experiments/tags/init.moon +++ b/root/experiments/tags/init.moon @@ -1,5 +1,5 @@ -import div, h3, ul, li, a from require 'lib.dom' -import define_fileders from require 'lib.mmmfs' +import div, h3, ul, li, a from require 'mmm.dom' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... @@ -8,7 +8,7 @@ Fileder { 'description: text/plain': 'defining toggles, categories etc. with only tags and functional hooks', 'moon -> mmm/component': if MODE == 'CLIENT' then => import add_tag, rmv_tag, Node, Hierarchy, Toggle, NamespacedToggle from require '.tags' - import ReactiveVar, tohtml, text, elements from require 'lib.component' + import ReactiveVar, tohtml, text, elements from require 'mmm.component' import article, div, form, span, h3, a, input, textarea, button from elements clone = (set) -> diff --git a/root/init.moon b/root/init.moon index a2eab3b..8639f50 100644 --- a/root/init.moon +++ b/root/init.moon @@ -1,12 +1,12 @@ -import define_fileders from require 'lib.mmmfs' +import define_fileders from require 'mmm.mmmfs' Fileder = define_fileders ... require = relative ... Fileder { 'name: alpha': '', 'moon -> mmm/dom': => - import article, h1, h3, div, b, p, a, br, ul, tt, li, img from require 'lib.dom' - import opairs from require 'lib.ordered' + import article, h1, h3, div, b, p, a, br, ul, tt, li, img from require 'mmm.dom' + import opairs from require 'mmm.ordered' append, finish = do content = {} @@ -65,4 +65,5 @@ Fileder { require '.articles' require '.animations' require '.experiments' + require '.meta' } diff --git a/root/meta/init.moon b/root/meta/init.moon new file mode 100644 index 0000000..cd2baed --- /dev/null +++ b/root/meta/init.moon @@ -0,0 +1,27 @@ +import div, h3, ul, li, a from require 'mmm.dom' +import define_fileders from require 'mmm.mmmfs' +Fileder = define_fileders ... +require = relative ... + +Fileder { + 'name: alpha': 'meta', + 'title: text/plain': 'about mmm', + 'moon -> mmm/dom': (path) => div { + h3 @gett 'title: text/plain', style: { 'margin-bottom': '-.5em' }, + ul for child in *@children + name = child\gett 'name: alpha' + desc = child\gett 'description: text/plain' + li { + a name, { + href: child.path, + onclick: (e) => + e\preventDefault! + BROWSER\navigate child.path + }, + ': ', desc + } + } + + require '.todo' + require '.test_component' +} diff --git a/root/meta/test_component.moon b/root/meta/test_component.moon new file mode 100644 index 0000000..c1c766e --- /dev/null +++ b/root/meta/test_component.moon @@ -0,0 +1,224 @@ +import define_fileders from require 'mmm.mmmfs' +Fileder = define_fileders ... + +Fileder { + 'name: alpha': 'mmm.component_test' + 'description: text/plain': 'Tests for mmm.component' + 'moon -> mmm/dom': => + import article, div, h1, ul, li, pre from require 'mmm.dom' + + _content = {} + append = (stuff) -> table.insert _content, stuff + + last = nil + test_group = (name) -> + if last + append div (h1 name), ul last + + last = {} + (name, test) -> + ok, err = pcall test + table.insert last, li if ok + "passed '#{name}'" + else + "failed '#{name}'", pre err + + expect = (expected, note, ...) -> + ok, msg = pcall ... + print ok, msg\find expected + if ok or not msg\find expected + error note + + run_test = test_group 'component.moon' + + local ReactiveVar, ReactiveElement + run_test "exports ReactiveVar, ReactiveElement", -> + import ReactiveVar, ReactiveElement from require 'mmm.component' + assert ReactiveVar, "ReactiveVar not exported" + assert ReactiveElement, "ReactiveElement not exported" + + run_test "exports tohtml helper", -> + import tohtml from require 'mmm.component' + assert 'function' == (type tohtml), "tohtml not exported" + + -- @TODO: get_or_create + + run_test "exports text helper", -> + import text from require 'mmm.component' + assert 'function' == (type text), "text not exported" + + node = text 'a test string' + assert (js.instanceof node, js.global.Node), "expected text to generate a Node" + assert node.data == 'a test string', "expected text to store the string" + + run_test "text joins multiple arguments", -> + import text from require 'mmm.component' + + node = text 'a', 'test', 'string' + assert node.data == 'a test string', "expected text to join arguments with spaces" + + run_test "exports elements table", -> + import elements from require 'mmm.component' + + assert (type elements.div!) == 'table', "expected to build element with elements.div!" + assert (type elements.madeup!) == 'table', "expected to build element with elements.madeup!" + + run_test = test_group 'ReactiveVar' + + run_test "stores a value", -> + reactive = ReactiveVar 'test' + assert 'test' == reactive\get!, "expected x to be 'test'" + + run_test "propagates updates", -> + local done + + reactive = ReactiveVar 'test' + reactive\subscribe coroutine.wrap (next) -> + assert next == 'toast', "expected next to be 'toast'" + assert coroutine.yield! == 'cheese', "expected next to be 'cheese'" + done = true + + reactive\set 'toast' + assert 'toast' == reactive\get!, "expected #get to return 'toast'" + reactive\set 'cheese' + assert done, "expected to reach the end" + + run_test "passed old value as well", -> + local done + + reactive = ReactiveVar 1 + reactive\subscribe coroutine.wrap (next, last) -> + assert last == 1, "expected last:1 to be 1" + next, last = coroutine.yield! + assert last == 2, "expected last:2 to be 2" + done = true + + reactive\set 2 + reactive\set 3 + assert done, "expected to reach the end" + + run_test "provides transform shorthand", -> + local done + + reactive = ReactiveVar 1 + reactive\subscribe coroutine.wrap (next, last) -> + assert last == 1, "expected last:1 to be 1" + next, last = coroutine.yield! + assert last == 2, "expected last:2 to be 2" + done = true + + add_one = (a) -> a + 1 + reactive\transform add_one + reactive\transform add_one + assert done, "expected to reach the end" + + run_test "#subscribe returns function to unsubscribe", -> + calls = 0 + + reactive = ReactiveVar 1 + unsub = reactive\subscribe coroutine.wrap () -> + calls += 1 + coroutine.yield! + calls += 1 + coroutine.yield! + calls += 1 + + assert 'function' == (type unsub), "expected to receive a function" + + reactive\set 2 + reactive\set 3 + assert calls == 2, "wat" + + unsub! + reactive\set 4 + assert calls == 2, "expected to stop receiving updates" + + run_test "tracks multiple subscriptions at once", -> + reactive = ReactiveVar 'test' + unsub = reactive\subscribe coroutine.wrap (next) -> + assert next == 'toast', "expected next to be toast" + next = coroutine.yield! + assert next == 'cheese', "expected next to be cheese" + coroutine.yield! + error "expected not to get here" + + reactive\set 'toast' + + local done + reactive\subscribe coroutine.wrap (next) -> + assert next == 'cheese', "expected next to be cheese" + next = coroutine.yield! + assert next == 'test', "expected next to be test" + done = true + + reactive\set 'cheese' + unsub! + reactive\set 'test' + assert done, "expected to reach the end" + + run_test = test_group 'ReactiveElement' + + run_test "creates a HTML element", -> + elem = ReactiveElement 'span' + assert elem.node and elem.node.localName == 'span', "expected Node to be a <span>" + + -- @TODO: can take over a DOM Node + + run_test "sets attributes from a table arg", -> + elem = ReactiveElement 'span', class: 'never' + assert elem.node.class == 'never', "expected class to be 'never'" + + run_test "appends Nodes from arguments", -> + e_div, e_pre = div!, pre! + elem = ReactiveElement 'span', e_div, e_pre + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" + + run_test "can append ReactiveElements and text", -> + e_div = ReactiveElement 'div' + elem = ReactiveElement 'div', e_div, 'testtext' + assert elem.node.firstElementChild == e_div.node, "expected div to be the first child of elem" + assert elem.node.lastChild.data == 'testtext', "expected last child of elem to be 'testtext'" + + run_test "accepts attributes after children", -> + e_div = div! + elem = ReactiveElement 'div', e_div, class: 'test' + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.class == 'test', "expected class to be 'test'" + + run_test "allows mixing attributes and children in a single table", -> + e_div, e_pre = div!, pre! + elem = ReactiveElement 'div', { class: 'test', e_div, e_pre } + assert elem.node.firstElementChild == e_div, "expected div to be the first child of elem" + assert elem.node.lastElementChild == e_pre, "expected pre to be the last child of elem" + assert elem.node.class == 'test', "expected class to be 'test'" + + run_test "can unwrap and track attributes from ReactiveVars", -> + klass = ReactiveVar 'test' + elem = ReactiveElement 'div', class: klass + assert elem.node.class == 'test', "expected class to be 'test'" + klass\set 'toast' + assert elem.node.class == 'toast', "expected class to be 'toast'" + + run_test "can unwrap and track children from ReactiveVars", -> + child = ReactiveVar h1 'test' + elem = ReactiveElement 'div', child, pre 'fixed' + assert elem.node.firstElementChild.localName == 'h1', "expected first child to be h1" + assert elem.node.childElementCount == 2, "expected node to have two children" + child\set div 'toast' + assert elem.node.firstElementChild.localName == 'div', "expected first child to be div" + assert elem.node.childElementCount == 2, "expected node to have two children" + + run_test "warns when appending a string from a ReactiveVar", -> + import text from require 'mmm.component' + + str = ReactiveVar 'test' + elem = ReactiveElement 'div', str + expect 'cannot replace string node', 'expected error', str\set, 'string too' + elem\destroy! + + elem = ReactiveElement 'div', str\map text + str\set 'this is text' + + article _content +} diff --git a/root/meta/todo.moon b/root/meta/todo.moon new file mode 100644 index 0000000..eb6fc0d --- /dev/null +++ b/root/meta/todo.moon @@ -0,0 +1,42 @@ +import define_fileders from require 'mmm.mmmfs' +Fileder = define_fileders ... + +Fileder { + 'name: alpha': 'todo' + 'description: text/plain': 'TodoMVC using mmm.component' + 'moon -> mmm/component': => + import ReactiveVar, text, elements from require 'mmm.component' + import article, div, form, span, h3, a, input, textarea, button from elements + + parent = div! + todoItem = (desc, done) -> + -- convert into reactive data sources + desc, done = (ReactiveVar desc), ReactiveVar done + with me = div style: + margin: '8px' + padding: '8px' + background: '#eeeeee' + \append h3 (desc\map text), style: 'margin: 0;' + \append span done\map (done) -> text if done then 'done' else 'not done yet' + \append input type: 'checkbox', checked: done, onchange: (e) => done\set e.target.checked + \append a (text 'delete'), href: '#', onclick: (e) => parent\remove me + + parent\append todoItem 'write a Component System', true + parent\append todoItem 'eat Lasagna', true + parent\append todoItem 'do other things' + + desc = ReactiveVar 'start' + form = with form { + action: '' + style: + margin: '2px' + onsubmit: (e) => + e\preventDefault! + parent\append todoItem desc\get! + desc\set '' + } + \append input type: 'text', value: desc, onchange: (e) => desc\set e.target.value + \append input type: 'submit', value: 'add' + + article parent, form +} @@ -1,6 +1,6 @@ -package.moonpath = './?.server.moon;' .. package.moonpath +package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath require 'lfs' -require 'lib.init' +require 'mmm.init' -- enumerate moonscript source files enum_dir = do @@ -19,18 +19,21 @@ enum_dir = do coroutine.wrap -> yieldtree dir +-- COMPILE MOONSCRIPT +-- mmmfs tree for file in enum_dir 'root' basename = assert file\match '(.*)%.moon$' print ": #{file} |> ^ MOON %b > %o^ moonc -o %o %f |> dist/#{basename}.lua" -for file in enum_dir 'lib' +-- mmm +for file in enum_dir 'mmm' continue if file\match '%.server%.moon$' basename = assert file\match '(.*)%.moon$' basename = (file\match '(.*)%.client') or basename print ": #{file} |> ^ MOON %b > %o^ moonc -o %o %f |> dist/#{basename}.lua" --- add rules for each fileder -import module_roots from require 'lib.mmmfs' +-- PRE-RENDER MMMFS +import module_roots from require 'mmm.mmmfs' root = require 'root' root\mount! |
