@litexa/core
Version:
Litexa, a programming language for writing Alexa skills
273 lines (211 loc) • 7.03 kB
text/coffeescript
###
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
###
###
This file collects documentation sources from around the
module and creates two outputs:
* documentation.html at the module root
this contains all the documentation in a single file
* additional .md files in the documentation directory
this contains materials scraped from other sources
The goal is to have documentation visible in source control
places that handle .md files elegantly, and to have an easy
to search local reference once you've pulled the repo.
###
path = require 'path'
fs = require 'fs'
chalk = require 'chalk'
render = ->
moduleRoot = path.join __dirname, '..', '..'
makeLinkName = (s) ->
# convert human readable names into valid url links
s.replace /\s+/g, '_'
isCodeLink = (name) ->
return false unless name[0].toLowerCase() == name[0]
return true
# customize marked to collect heading info
markedLib = require 'marked'
headings = []
marked = null
do ->
renderer = new markedLib.Renderer()
renderer.heading = (text, level) ->
link = makeLinkName text
headings.push
level: level
text: text
link: link
return "<h#{level} id='#{link}'>#{text}</h#{level}>"
markedLib.marked.setOptions { renderer: renderer }
marked = (text) -> markedLib.marked.parse(text)
entries = {}
entryNames = []
do ->
pegFilename = path.join moduleRoot, 'parser', 'litexa.pegjs'
pegSource = fs.readFileSync pegFilename, 'utf8'
test = /\/\*\s*litexa\s+\[([^\]]+)\]\s+([^*]*\*+(?:[^/*][^*]*\*+)*)\//g
match = test.exec pegSource
while match
name = match[1]
comment = match[2][0...-1]
if name of entries
throw "You have duplicate entry names: #{name}"
entries[name] =
text: comment
name: name
match = test.exec pegSource
html = fs.readFileSync path.join(__dirname, 'template.html'), 'utf8'
do ->
pages = []
source = fs.readFileSync path.join(moduleRoot, '..', 'README.md'), 'utf8'
pages.push marked source
docsRoot = path.join moduleRoot, 'documentation'
for file in fs.readdirSync docsRoot
continue if file == 'reference.md'
filename = path.join docsRoot, file
continue if fs.statSync(filename).isDirectory()
source = fs.readFileSync filename, 'utf8'
pages.push marked source
html = html.replace '{pages}', pages.join '\n'
do ->
entryHTML = ""
entryNames = ( n for n of entries )
entries = ( e for n, e of entries )
entries.sort (a, b) -> a.name.localeCompare(b.name)
substituteLinks = (text) ->
test = /\[([a-zA-Z$@ ]+)\]/
match = test.exec text
while match
name = match[1]
unless name in entryNames
console.error chalk.red "missing link [#{name}] in `#{text[0...25]}`"
link = "<a href='##{makeLinkName name}'>#{name}</a>"
if isCodeLink name
link = "<code>#{link}</code>"
text = text.replace match[0], link
match = test.exec text
return text
headings.push
level: 1
text: "Language Reference"
link: "Language_Reference"
class: "toc-language-reference"
for e in entries
linkName = makeLinkName e.name
headings.push
level: 2
text: e.name
link: linkName
contents = e.text
contents = marked contents
contents = substituteLinks contents
namePart = e.name
if isCodeLink e.name
namePart = "<code>#{namePart}</code>"
entryHTML += "
<tr class='entry'>
<td id='#{linkName}'
class='entry-cell entry-name'>#{namePart}</td>
<td class='entry-cell entry-text'>#{contents}</td>
</tr>
"
html = html.replace '{entries}', entryHTML
do ->
tocHTML = []
links = {}
level = 1
for h in headings
opening = false
if h.level > level
tocHTML.push "<ul>"
opening = true
else if h.level < level
tocHTML.push "</ul></li>"
level = h.level
if h.link of links
console.error chalk.red "DUPLICATE LINK detected: #{h.link}"
links[h.link] = true
link = "<a href='##{h.link}'>#{h.text}</a>"
#if isCodeLink h.text
# link = "<code>#{link}</code>"
if opening
terminator = '</li>'
else
terminator = ''
if h.class?
tocHTML.push "<li class='#{h.class}'>#{link}#{terminator}"
else
tocHTML.push "<li>#{link}#{terminator}"
while level > 1
tocHTML.push "</ul></li>"
level -= 1
html = html.replace '{toc}', tocHTML.join '\n'
do ->
# write HTML version, intentionally disabled right now
###
outputFilename = path.join moduleRoot, '..', 'documentation.html'
fs.writeFileSync outputFilename, html, 'utf8'
console.log ''
console.log chalk.green "Wrote #{outputFilename}"
###
do ->
# instructions to vuepress, where the docs are hosted
frontMatter = """
---
sidebarDepth: 1
---
"""
markdownEntries = [
frontMatter
"# Language Reference\n"
]
substituteLinks = (text) ->
test = /\[([^\]]+)\]/
match = test.exec text
while match
name = match[1]
text = text.replace match[0], match[1]
match = test.exec text
return text
for e in entries
contents = e.text
#(don't need to do this now) contents = substituteLinks contents
markdownEntries.push """
## #{e.name}
#{contents}
"""
outputFilename = path.join moduleRoot, 'documentation', 'reference.md'
fs.writeFileSync outputFilename, markdownEntries.join('\n'), 'utf8'
console.log ''
console.log chalk.green (new Date).toLocaleString()
render()
if process.argv[2] == 'watch'
docsDir = path.join(__dirname, '../')
fileCache = {}
# Takes a string and generates a 32-bit integer
hash = (contents) ->
hashedInt = 0
return hashedInt if contents.length == 0
for i in [0..contents.length - 1]
char = contents.charCodeAt(i)
hashedInt = ((hashedInt << 5) - hashedInt) + char
hashedInt = hashedInt || 0
hashedInt
# Watches for changes
fs.watch docsDir, (event, file) ->
filePath = path.join(docsDir, file)
fileExists = fs.existsSync filePath
# Ignores extraneous temp data
if fileExists
format = 'utf8'
# hash the file
data = hash(fs.readFileSync filePath, format)
# Caches the fingerprint of the data
fileCache[file] = data unless fileCache[file]?
# If the contents change, cache contents then re-render the documentation
if fileCache[file] != data
fileCache[file] = data
render()