de4debe9981f013a2b6be72e683db8b78842708d — Zach Smith 10 months ago 792db94
Add some comments
1 files changed, 61 insertions(+), 13 deletions(-)

M main.janet
M main.janet => main.janet +61 -13
@@ 2,10 2,25 @@
(import path)
(import util)

(def bagatto (require "bagatto-require"))
(def bagatto
  An environment populated by the "stdlib" we want to expose to
  template and index module authors.
  (require "bagatto-require"))

# Monkey-patch the temple environment with our additional functions.
(merge-into temple/base-env bagatto)

(defn load-file [index]
  Given the filename of our index module, evaluate it in the execution
  environment with our "stdlib" in it. This will give index module
  authors access to its additional namespaces without having to import
  them (and, as the environment was created at compile time, without
  those libraries having to be present when the index module is
  (dofile index :env bagatto))

@@ 22,26 37,45 @@
    (f ;args)

(defn main [& [_ index]]
  (let [env (load-file index)
        site ((env 'site) :value)
        config ((env 'config) :value)
        pending (gensym)
        site-plan (table ;(mapcat (fn [k] [k pending]) (keys site)))
(defn produce-writers [site config]
  Main business logic: given a site definition and a global config,
  produce a sequence of fibers that represent all of the files to be
  generated for this site.

  This function handles the definitions contained in `site` one by
  one. Site definition entries can declare dependencies on each other,
  so we have a very naive implementation of dependency management
  where we follow the dependency tree and eagerly attempt to generate
  writers, tracking which entries have been handled by populating
  (let [pending (gensym)
        site-plan (table ;(mapcat |[$0 pending] (keys site)))
        writers @[]]
    (defn get-plans [req-or-reqs]
      Return the generated page attributes (or the absence thereof)
      for one or many entry dependencies.
        (nil? req-or-reqs) []
        (nil? req-or-reqs) @{}
        (tuple? req-or-reqs) (table ;(mapcat |[$0 (site-plan $0)] req-or-reqs))
        true @{req-or-reqs (site-plan req-or-reqs)}))
    (defn write-plan [name entry]
      Given a site entry whose requirements have all been populated
      (or that has none), generate writer fiber for all of its output
      files and write to the site-plan with all the page attributes.
      (def plans @[])
      (def required (get-plans (entry :requires)))
      (match entry
        # Handle generation of files from user-managed source files
        # (eg, render markdown files into HTML
        {:src filenames
         :attrs attr-f
         :path path-f

@@ 49,16 83,17 @@
          (loop [file :generate filenames]
            (let [attrs (maybe-apply attr-f [file])
                  args (case required
                         [] [config attrs]
                         _ [config attrs required])
                  args (case (length required)
                         0 [config attrs]
                         [config attrs required])
                  path (maybe-apply path-f args)
                  contents (maybe-apply content-f args)
                  writer (new-writer path contents)]
              (array/push plans attrs)
              (array/push writers writer)))
          (put site-plan name plans))
        # Handle generation of "synthetic" files that are built from
        # templates or other functions, but have no user input files
        {:path path-f :contents content-f}
        (let [args (case (length required)
                     0 [config]

@@ 70,6 105,10 @@
          (array/push writers writer))))
    (defn handle-entry [[name entry]]
      Attempt to populate the site plan and generate writers for a
      site entry. If necessary, force all of its dependencies first.
      (->> (entry :requires)

@@ 78,8 117,17 @@
           (map handle-entry))
      (write-plan name entry))
    # Trigger population of the site plan.
    (loop [[name entry] :pairs site]
      (if (= pending (site-plan name))
        (handle-entry [name entry])))

(defn main [& [_ index]]
  (let [env (load-file index)
        site ((env 'site) :value)
        config ((env 'config) :value)
        writers (produce-writers site config)]
    (each writer writers (resume writer))))