//
// Copyright (c) 2023, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 03 May 2023 Matthew Giannini Creation
//
using compiler
**
** JsWriter
**
class JsWriter
{
//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////
new make(OutStream out, SourceMap? sourcemap := null)
{
this.out = out
this.sourcemap = sourcemap
}
private OutStream out
private SourceMap? sourcemap := null
Int line := 0 { private set }
Int col := 0 { private set }
private Bool needIndent := false
private Int indentation := 0
@NoDoc Bool trace := false
//////////////////////////////////////////////////////////////////////////
// JsWriter
//////////////////////////////////////////////////////////////////////////
** Write and then return this. If loc is not null, the text will be
** added to the generated source map.
JsWriter w(Obj o, Loc? loc := null, Str? name := null)
{
if (needIndent)
{
spaces := indentation * 2
out.writeChars(Str.spaces(spaces))
col += spaces
needIndent = false
}
str := o.toStr
if (str.containsChar('\n')) throw Err("cannot w() str with newline: ${str}")
if (loc != null) sourcemap?.add(str, Loc(loc.file, line, col), loc, name)
if (trace) Env.cur.out.print(str)
out.writeChars(str)
col += str.size
return this
}
** Convenience for 'w(o,loc,name).nl'.
JsWriter wl(Obj o, Loc? loc := null, Str? name := null)
{
this.w(o, loc, name).nl
}
** Write newline and then return this.
JsWriter nl()
{
if (trace) Env.cur.out.printLine
out.writeChar('\n')
++line
col = 0
needIndent = true
out.flush
return this
}
** Increment the indentation
JsWriter indent() { indentation++; return this }
** Decrement the indentation
JsWriter unindent()
{
indentation--
if (indentation < 0) indentation = 0
return this
}
JsWriter minify(InStream in, Bool close := true)
{
inBlock := false
in.readAllLines.each |line|
{
// TODO: temp hack for inlining already minified js
if (line.size > 1024) { w(line).nl; return }
s := line
// line comments
if (s.size > 1 && (s[0] == '/' && s[1] == '/')) return
// need to check if inside str
// i := s.index("//")
// if (i != null) s = s[0..<i]
// block comments
temp := s
a := temp.index("/*")
if (a != null)
{
s = temp[0..<a]
inBlock = true
}
if (inBlock)
{
b := temp.index("*/")
if (b != null)
{
s = (a == null) ? temp[b+2..-1] : s + temp[b+2..-1]
inBlock = false
}
}
// trim and print
s = s.trimEnd
if (inBlock) return
// if (s.size == 0) return
w(s).nl
}
if (close) in.close
return this
}
}