aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mmmfs/conversion.moon
blob: 7f86aa4a57c8ec054c81381eca4bae771153cc3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import text, code from require 'lib.dom'
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: single markdown
    }

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
}