UNPKG

3.5 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3'use strict'
4
5const fs = require('fs')
6const path = require('path')
7const transformer = require('jstransformer')
8
9const ymd = transformer(require('jstransformer-ymd'))
10const coffee = transformer(require('jstransformer-coffee-script'))
11const scss = transformer(require('jstransformer-scss'))
12const marked = transformer(require('jstransformer-marked'))
13const minify = transformer(require('jstransformer-html-minifier'))
14const uglify = transformer(require('jstransformer-uglify-js'))
15
16function move_match(state, reg) {
17 reg.lastIndex = state.i
18 const token = reg.exec(state.str)
19 state.i += token[0].length
20 return token
21}
22
23const helpers = {
24 nattoppet_dir: __dirname,
25
26 nattoppet_parse(hascontent = false) {
27 const opts = [], args = []
28 const parse_option = () => {
29 const token = move_match(this.state, /\.([\w\-]+)/g)
30 opts.push(token[1])
31 }
32 const parse_argument = () => {
33 const token = move_match(this.state, /\((.*?)\)|{(.*?)}/g)
34 args.push(token[1] || token[2])
35 }
36 const parse_block = () => {
37 const token = move_match(this.state, />+/g)
38 return this.capture_until('<'.repeat(token[0].length))
39 }
40
41 while (true) {
42 switch (this.peek()) {
43 case '.':
44 parse_option()
45 break
46 case '(':
47 case '{':
48 parse_argument()
49 break
50 case '>':
51 return { opts, args, block: parse_block() }
52 case ' ':
53 if (hascontent)
54 return { opts, args, block: this.capture_line() }
55 default:
56 return { opts, args }
57 }
58 }
59 },
60
61 read(file, type='utf8') {
62 if (file.startsWith('@nattoppet')) {
63 file = path.join(this.nattoppet_dir, file.substring(10))
64 } else if (!file.startsWith('/')) {
65 file = path.join(this.base_dir, file)
66 }
67 return fs.readFileSync(file, type)
68 },
69
70 extname(file) {
71 return path.extname(file).slice(1)
72 },
73
74 basename(file) {
75 return path.basename(file)
76 },
77
78 render_coffee(str) {
79 return uglify.render(coffee.render(str).body).body
80 },
81
82 render_scss(str) {
83 return scss.render(str, {outputStyle: 'compressed'}).body
84 },
85
86 render_markdown(str) {
87 return marked.render(str).body
88 }
89}
90
91function render_files(env, ...files) {
92 const str = files.map(x=>fs.readFileSync(x, 'utf8')).reduce((x, y) => x + y)
93 return ymd.render(str, null, env).body
94}
95
96const rpath = (...x) => path.join(__dirname, ...x)
97
98const render = file => {
99 const seg = path.basename(file).split('.')
100 const theme = seg[seg.length-2]
101 const base_dir = path.dirname(path.resolve(file))
102 const env = {base_dir, ...helpers}
103 const html = ['koa', 'ppt', 'vue', 'tml'].includes(theme)
104 ? render_files(env, rpath(theme, 'before.ymd'), file, rpath(theme, 'after.ymd'), rpath('nattoppet.ymd'))
105 : render_files(env, file, rpath('nattoppet.ymd'))
106 return minify.render(html, { removeAttributeQuotes:true, removeComments:true }).body.trim()
107}
108
109const file = process.argv[2]
110
111if (process.argv.length != 3 || file == "--help")
112 return console.log("Usage: nattoppet file.{koa,ppt,vue,tml}.ymd > file.html")
113
114process.stdout.write(render(file))