diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2018-10-29 08:35:53 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2018-10-29 08:35:53 +0000 |
| commit | 27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e (patch) | |
| tree | ac703b9f84c1c8e4666d039a880a2af91c450c4a | |
| parent | move duct_tape to lib (diff) | |
| download | mmm-27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e.tar.gz mmm-27d1cf641ce3bbfe96e6fe18f24dd46f95efbe5e.zip | |
better conversion inverence for mmmfs
| -rw-r--r-- | Tupfile | 1 | ||||
| -rw-r--r-- | app/mmmfs/browser.moon | 5 | ||||
| -rw-r--r-- | app/mmmfs/conversion.moon | 121 | ||||
| -rw-r--r-- | app/mmmfs/init.moon | 221 | ||||
| -rw-r--r-- | app/mmmfs/tree/gallery.moon (renamed from app/mmmfs/gallery.moon) | 8 | ||||
| -rw-r--r-- | app/mmmfs/tree/init.moon (renamed from app/mmmfs/tree.moon) | 6 | ||||
| -rw-r--r-- | app/mmmfs/tree/twisted.moon (renamed from app/mmmfs/twisted.moon) | 0 | ||||
| -rw-r--r-- | lib/component.client.moon | 1 | ||||
| -rw-r--r-- | lib/init.client.moon | 21 | ||||
| -rw-r--r-- | lib/init.server.moon | 22 |
10 files changed, 220 insertions, 186 deletions
@@ -9,6 +9,7 @@ preload app app/tags lib CLIENT += app/*.moon CLIENT += app/tags/*.moon CLIENT += app/mmmfs/*.moon +CLIENT += app/mmmfs/tree/*.moon CLIENT += lib/*.client.moon CLIENT += lib/*.shared.moon diff --git a/app/mmmfs/browser.moon b/app/mmmfs/browser.moon index 50da38b..427d952 100644 --- a/app/mmmfs/browser.moon +++ b/app/mmmfs/browser.moon @@ -78,8 +78,9 @@ class Browser active = @active\get! ok, res = pcall -> - val, key = active\get prop.name, prop.type - CONVERT 'mmm/dom', val, key + -- val, key = active\get prop.name, prop.type + -- CONVERT 'mmm/dom', val, key + active\get prop.name, 'mmm/dom' if ok and res res diff --git a/app/mmmfs/conversion.moon b/app/mmmfs/conversion.moon new file mode 100644 index 0000000..a670e2e --- /dev/null +++ b/app/mmmfs/conversion.moon @@ -0,0 +1,121 @@ +import text, code from require 'lib.html' +import tohtml from require 'lib.component' + +-- limit function to one argument +single = (func) -> (val) -> func val + +-- list of converts +-- converts each have +-- * inp - input type. can capture subtypes using `(.+)` +-- * out - output type. can substitute subtypes from inp with %1, %2 etc. +-- * transform - function (val: inp, fileder) -> val: out +converts = { + { + inp: 'moon -> (.+)', + out: '%1', + transform: (val, fileder) -> val fileder + }, + { + inp: 'text/plain', + out: 'mmm/dom', + transform: single text + }, + { + inp: 'alpha', + out: 'mmm/dom', + transform: single code + }, + { + inp: 'URL -> .*', + out: 'mmm/dom', + transform: single code + }, + { + inp: 'mmm/component', + out: 'mmm/dom', + transform: single tohtml + }, + { + inp: 'mmm/dom', + out: 'text/html', + transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML + }, + { + inp: 'text/html', + out: 'mmm/dom', + transform: if MODE == 'SERVER' + (...) -> ... + else + (html) -> + tmp = document\createElement 'div' + tmp.innerHTML = html + if tmp.childElementCount == 1 + tmp.firstChild + else + tmp + } +} + +do + local markdown + if MODE == 'SERVER' + success, discount = pcall require, 'discount' + markdown = discount if success + else + markdown = window and window.marked and window\marked + + if markdown + table.insert converts, { + inp: 'text/markdown', + out: 'text/html', + transform: (val) -> + html = markdown val + warn html + html + } + +count = (base, pattern='->') -> select 2, base\gsub pattern, '' +escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" + +-- attempt to find a conversion path from 'have' to 'want' +-- * have - start type string or list of type strings +-- * want - stop type string +-- * limit - limit conversion amount +-- returns a list of conversion steps +get_conversions = (want, have, limit=3) -> + assert have, 'need starting type(s)' + + if 'string' == type have + have = { have } + + assert #have > 0, 'need starting type(s) (list was empty)' + + iterations = limit + math.max table.unpack [count type for type in *have] + have = [{ :start, rest: start, conversions: {} } for start in *have] + + for i=1, iterations + next_have, c = {}, 1 + for { :start, :rest, :conversions } in *have + if want == rest + return conversions, start + else + for convert in *converts + inp = escape_inp convert.inp + matches = { rest\match inp } + continue unless #matches > 0 + result = rest\gsub inp, convert.out + if result + next_have[c] = { + :start, + rest: result, + conversions: { convert, table.unpack conversions } + } + c += 1 + + have = next_have + return unless #have > 0 + +{ + :converts + :get_conversions +} diff --git a/app/mmmfs/init.moon b/app/mmmfs/init.moon index 1f2d2f6..19cb028 100644 --- a/app/mmmfs/init.moon +++ b/app/mmmfs/init.moon @@ -1,143 +1,35 @@ -export ^ - --- list of interps --- interp signature is (fileder, value) -> value -interps = { - moon: (method) => method @ -} - -split = (str, delim='->') -> - return {}, str if nil == str\find delim +require = relative ... +import get_conversions from require '.conversion' - -- @TODO interp chain? - interp, rest = str\match ' *(%w+) *-> *(.*)' - { interp }, rest +export ^ -- Key of a Fileder Property -- contains: -- * @name - key name or '' for main content --- * @type - final type after interps --- * @interps - array describing interp chain +-- * @type - type string (type -> type -> type) class Key -- instantiate from table w/ keys described above -- or string like 'name: interp -> interp -> type' (name + interps optional) - new: (opts) => - if 'string' == type opts - @name, rest = opts\match '(%w+): *(.+)' + new: (opts, second) => + if 'string' == type second + @name, @type = (opts or ''), second + elseif 'string' == type opts + @name, @type = opts\match '(%w+): *(.+)' if not @name @name = '' - rest = opts - @interps, @type = split rest, '->' + @type = opts elseif 'table' == type opts @name = opts.name - @type = assert opts.type, 'no type given' - @interps = opts.interps or {} + @type = opts.type else - error 'wrong argument type' - - -- get a function that interpretes a raw value according to @interps - -- and returns a value of @type - -- overrides is a map of interp overrides - get_interp: (overrides={}) => - return ((val) => val) if #@interps == 0 - - assert #@interps == 1, 'not supported rn' -- @TODO - _name = @interps[1] - - return overrides[_name] if overrides and overrides[_name] - - assert overrides[_name] or interps[_name], "interp not found: '#{_name}'" + error "wrong argument type: #{type opts}, #{type second}" -- format as a string (see constructor) tostring: => - list = { table.unpack @interps } - table.insert list, @type - - type = table.concat list, ' -> ' - if @name == '' - type + @type else - "#{@name}: #{type}" - - -import text, code from require 'lib.html' -import tohtml from require 'lib.component' - --- list of converts --- converts each have --- * inp - input type --- * out - output type --- * transform - function (inp) -> out -converts = { - { - inp: 'text/plain', - out: 'mmm/dom', - transform: text - }, - { - inp: 'alpha', - out: 'mmm/dom', - transform: code - }, - { - inp: 'mmm/dom', - out: 'text/html', - transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML - }, - { - inp: 'mmm/component', - out: 'mmm/dom', - transform: tohtml - }, - { - -- @TODO this chained rule *should* be inferred, but that's way too hot rn - inp: 'mmm/component', - out: 'text/html', - transform: (node) -> - node = tohtml node - if MODE == 'SERVER' then node else node.outerHTML - }, -} - -table.insert converts, { - inp: 'text/html', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (...) -> ... - else - (html) -> - tmp = document\createElement 'div' - tmp.innerHTML = html - tmp.firstChild - } - -do - local markdown - if MODE == 'SERVER' - success, discount = pcall require, 'discount' - markdown = discount if success - else - markdown = window and window\marked - - if markdown - table.insert converts, { - inp: 'text/markdown', - out: 'text/html', - transform: markdown, - } - - -- @TODO chained w above - table.insert converts, { - inp: 'text/markdown', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (md) -> markdown md - else - (md) -> - with document\createElement 'div' - .innerHTML = markdown md - } + "#{@name}: #{@type}" -- Fileder itself -- contains: @@ -158,69 +50,56 @@ class Fileder -- find property key according to criteria, nil if no value or conversion path -- * name - property name (optional: defaults to main content) -- * type - wanted result type - -- * convert - allow conversion (optional: default true) - find: (name='', type, convert=true) => - if not type - type = name - name = '' + find: (...) => + want = Key ... - -- first pass, interps only - for key, value in pairs @props - continue unless key.name == name and key.type == type + -- filter props by name + matching = [ key for key in pairs @props when key.name == want.name ] + return unless #matching > 0 - return key + -- get shortest conversion path + shortest_path, start = get_conversions want.type, [ key.type for key in *matching ] - if convert - -- second pass, interps + converts - for key, value in pairs @props - continue unless key.name == name + if start + for key in *matching + if key.type == start + return key, shortest_path - for { :inp, :out, :transform } in *converts - return key if inp == key.type and out == type + error "couldn't find key after resolution?" -- get property according to criteria, nil if no value or conversion path -- * name - property name (optional: defaults to main content) -- * type - wanted result type - -- * overrides - map of interp overrides (optional) - get: (name='', type, overrides) => - if not type - type = name - name = '' + get: (...) => + want = Key ... - key = @find name, type, not overrides + -- find matching key and shortest conversion path + key, conversions = @find want if key - interp = key\get_interp overrides - - return (interp @, @props[key]), key if key.type == type + value = @props[key] - for { :inp, :out, :transform } in *converts - return (transform interp @, @props[key]), key if inp == key.type and out == type + -- apply conversions (in reverse order) + for i=#conversions,1,-1 + { :inp, :out, :transform } = conversions[i] + value = transform value, @ - nil, nil + value, key - -- like get, throw if no value or conversion path - gett: (name='', type, overrides) => - if not type - type = name - name = '' + -- like @get, throw if no value or conversion path + gett: (...) => + want = Key ... - val, key = @get name, type, overrides - assert val, "node doesn't have value for #{name}:#{type}" - val, key + value, key = @get want + assert value, "node doesn't have value for #{want\tostring!}" + value, key -CONVERT = (type, val, key) -> - return unless val and key - - if key.type == type - val - else - for { :inp, :out, :transform } in *converts - return transform val if inp == key.type and out == type - -require = relative ... -import Browser from require '.browser' root = require '.tree' - -BROWSER = Browser root -append BROWSER.node +if MODE == 'CLIENT' + import Browser from require '.browser' + + export BROWSER + BROWSER = Browser root + append BROWSER.node +else + append root\get 'mmm/dom' diff --git a/app/mmmfs/gallery.moon b/app/mmmfs/tree/gallery.moon index e1868d1..93ca58d 100644 --- a/app/mmmfs/gallery.moon +++ b/app/mmmfs/tree/gallery.moon @@ -1,7 +1,5 @@ import div, h1, a, img, br from require 'lib.html' -URL = (url) => url - children = for i=1,100 id = math.floor math.random! * 200 Fileder { @@ -16,13 +14,13 @@ props = { 'preview: moon -> mmm/dom': => div { 'the first pic as a little taste:', br!, - img src: @children[1]\get 'preview', 'image/png', :URL + img src: @children[1]\get 'preview', 'URL -> image/png' } 'moon -> mmm/dom': => link = (child) -> a { href: '#', onclick: -> BROWSER\navigate { 'gallery', (child\get 'name', 'alpha'), nil }, - img src: child\gett 'preview', 'image/png', :URL + img src: child\gett 'preview', 'URL -> image/png' } content = [link child for child in *@children] @@ -44,7 +42,7 @@ props = { index\map (i) -> text " image ##{i} " e.a 'next', href: '#', onclick: -> index\transform next }, - index\map (i) -> img src: @children[i]\gett nil, 'image/png', :URL + index\map (i) -> img src: @children[i]\gett nil, 'URL -> image/png' } } diff --git a/app/mmmfs/tree.moon b/app/mmmfs/tree/init.moon index e270cf8..1d6a116 100644 --- a/app/mmmfs/tree.moon +++ b/app/mmmfs/tree/init.moon @@ -1,4 +1,4 @@ -require = relative ..., 1 +require = relative ... Fileder { -- main content @@ -224,9 +224,7 @@ If you are reading this in the source, then c'mon, just scroll past and give me -- preview is a lua/moonscript function that neturns an mmm/dom value 'preview: moon -> mmm/dom': => import img from require 'lib.html' - img src: @gett nil, -- look for: main content - 'image/png', -- with image type, and - URL: (url) => url -- override URL interp to get raw URL + img src: @gett nil, 'URL -> image/png' -- look for main content with 'URL to png' type } Fileder { diff --git a/app/mmmfs/twisted.moon b/app/mmmfs/tree/twisted.moon index ec3fa83..ec3fa83 100644 --- a/app/mmmfs/twisted.moon +++ b/app/mmmfs/tree/twisted.moon diff --git a/lib/component.client.moon b/lib/component.client.moon index 617deb5..af0b38a 100644 --- a/lib/component.client.moon +++ b/lib/component.client.moon @@ -102,6 +102,7 @@ class ReactiveElement @node.style[k] = v return + print "setting attr #{attr}" @node[attr] = value append: (child, last) => diff --git a/lib/init.client.moon b/lib/init.client.moon index c1aea07..d39143d 100644 --- a/lib/init.client.moon +++ b/lib/init.client.moon @@ -5,8 +5,25 @@ window = js.global { :document, :console } = window MODE = 'CLIENT' -print = console\log -warn = console\warn + +deep_tostring = (tbl, space='') -> + buf = space .. tostring tbl + + return buf unless 'table' == type tbl + + buf = buf .. ' {\n' + for k,v in pairs tbl + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space}}" + buf + +print = (...) -> + contents = [deep_tostring v for v in *{ ... } ] + console\log table.unpack contents + +warn = (...) -> + contents = [deep_tostring v for v in *{ ... } ] + console\warn table.unpack contents package.path = '/?.shared.moon.lua;/?.client.moon.lua;/?.moon.lua;/?/init.moon.lua;/?.lua;/?/init.lua' diff --git a/lib/init.server.moon b/lib/init.server.moon index a91bd52..f81a2dc 100644 --- a/lib/init.server.moon +++ b/lib/init.server.moon @@ -1,9 +1,27 @@ -export MODE, warn, relative, append, on_client +export MODE, print, warn, relative, append, on_client MODE = 'SERVER' +deep_tostring = (tbl, space='') -> + buf = space .. tostring tbl + + return buf unless 'table' == type tbl + + buf = buf .. ' {\n' + for k,v in pairs tbl + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space}}" + buf + +print = do + _print = print + (...) -> + contents = [deep_tostring v for v in *{ ... } ] + _print table.unpack contents + -- warning messages warn = (...) -> - io.stderr\write table.concat { ... }, '\t' + contents = [deep_tostring v for v in *{ ... } ] + io.stderr\write table.concat contents, '\t' io.stderr\write '\n' -- relative imports |
