stacker-parser
Version:
Stacker template file parser plugin
114 lines (94 loc) • 2.92 kB
text/coffeescript
# Load and parse .stacker template files
yaml = require 'js-yaml'
EST = require 'stacker-est'
path = require 'path'
# globals
_ = require 'stacker/_'
config = require 'stacker/config'
{Promise} = require 'stacker/promise'
defaults = require('stacker/utils').object.deepDefaults
readFile = Promise.promisify require('fs').readFile
loadAndParse = (filename, opts = {}) ->
load filename, opts
.then (contents) ->
opts.filename = filename
parse contents, opts
load = (filename, opts = {}) ->
_.defaults opts, encoding: 'utf8'
readFile path.normalize(filename), opts.encoding
###*
Parse contents for stacker header, est templates, yaml, and json.
@param opts All opts are optional.
opts.filename: {String} filename used for parsing contents by file extension
opts.parse: {Bool} set to false to disable parsing of file contents by parseContents
@return [contents, input] Input is the config object passed to the template.
Contents is the parsed output.
###
parse = (contents, opts = {}) ->
[contents, header] = parseHeader contents
cfg = {}
defaults cfg, header.config
defaults cfg, opts.config or config.config
ext = fileExt opts.filename
type = fileType ext
input =
config: cfg
header: header
file:
name: opts.filename
ext: ext
type: type
# Process est template code, if any
renderer = new EST root: tpl: contents
contents = renderer.render 'tpl', input
# By default, parse contents for supported file types
unless opts.parse == false
try
contents = parseContents contents, type
catch err
throw "Parse contents error [#{opts.filename}]: #{err.message}"
[contents, input]
# @return [contents, header]
parseHeader = (contents) ->
matches = contents.match /^#!stacker\s+"""\s+((.*\s+)+?)"""\s+((.*\s+)*)/m
return [contents, {}] unless matches
[tmp, header, tmp, contents] = matches
header = yaml.safeLoad header
[contents, header]
# @throws parse error
parseContents = (contents, type) ->
if type is 'yaml'
yaml.safeLoad contents
else if type is 'json'
# Strip comments
contents = contents.replace /\s*\/\/.*/g, ''
contents = contents.replace /\s*\/\*[^\*]*\*\//m, ''
JSON.parse contents
else
contents
# Get file extension without .stack or .stacker
fileExt = (filename) ->
return null unless filename
ext = filename and path.extname filename or ''
if ext in ['.stack', '.stacker']
# Strip .stacker extension
path.extname filename[0...-ext.length]
else
ext
fileType = (ext) ->
return null unless ext
ext = ext.toLowerCase()
if ext in ['.yml', '.yaml']
'yaml'
else if ext is '.json'
'json'
else
ext.replace '.', ''
module.exports =
load: load
parse: parse
loadAndParse: loadAndParse
parseHeader: parseHeader
parseContents: parseContents
fileExt: fileExt
fileType: fileType