feat: add ESM (.mjs) file support (#57)

resolves: #53
This commit is contained in:
Thomas M. Edwards 2023-11-06 13:09:21 -06:00 committed by GitHub
parent 9f43ea0976
commit aba7e432ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 18 deletions

View file

@ -58,7 +58,7 @@ Where <code>[options]</code> are mostly optional configuration flags—see [Opti
<p>Log various story statistics. Primarily, passage and word counts.</p> <p>Log various story statistics. Primarily, passage and word counts.</p>
<p role="note"><b>Note:</b> Unsupported when watch mode (<kbd>-w</kbd>, <kbd>--watch</kbd>) is enabled.</p> <p role="note"><b>Note:</b> Unsupported when watch mode (<kbd>-w</kbd>, <kbd>--watch</kbd>) is enabled.</p>
</dd> </dd>
<dt><kbd>-m SRC</kbd>, <kbd>--module=SRC</kbd></dt><dd>Module sources (repeatable); may consist of supported files and/or directories to recursively search for such files. Each file will be wrapped within the appropriate markup and bundled into the &lt;head&gt; element of the compiled HTML. Supported files: <code>.css</code>, <code>.js</code>, <code>.otf</code>, <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code>.</dd> <dt><kbd>-m SRC</kbd>, <kbd>--module=SRC</kbd></dt><dd>Module sources (repeatable); may consist of supported files and/or directories to recursively search for such files. Each file will be wrapped within the appropriate markup and bundled into the &lt;head&gt; element of the compiled HTML. Supported files: <code>.css</code>, <code>.js</code>, <code>.mjs</code>, <code>.otf</code>, <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code>.</dd>
<dt><kbd>--no-trim</kbd></dt><dd> <dt><kbd>--no-trim</kbd></dt><dd>
<p>Do not trim whitespace surrounding passages—i.e., whitespace preceding and trailing the actual text of the passage. By default, such whitespace is removed when processing passages.</p> <p>Do not trim whitespace surrounding passages—i.e., whitespace preceding and trailing the actual text of the passage. By default, such whitespace is removed when processing passages.</p>
<p role="note"><b>Note:</b> It is recommended that you do not disable passage trimming.</p> <p role="note"><b>Note:</b> It is recommended that you do not disable passage trimming.</p>
@ -86,7 +86,9 @@ The following extensions are supported:
<dt><code>.tw</code>, <code>.twee</code></dt> <dt><code>.tw</code>, <code>.twee</code></dt>
<dd> <dd>
<p>Twee notation source files to process for passages.</p> <p>Twee notation source files to process for passages.</p>
<p role="note"><b>Note:</b> If any of these files are in the unofficial Twee2 notation, you must manually enable the Twee2 compatibility mode via its command line option (<kbd>--twee2-compat</kbd>).</p> <p role="note"><b>Note:</b>
If any of these files are in the unofficial Twee2 notation, you must manually enable the Twee2 compatibility mode via its command line option (<kbd>--twee2-compat</kbd>).
</p>
</dd> </dd>
<dt><code>.tw2</code>, <code>.twee2</code></dt> <dt><code>.tw2</code>, <code>.twee2</code></dt>
<dd>Unofficial Twee2 notation source files to process for passages. Twee2 compatibility mode is automatically enabled for files with these extensions.</dd> <dd>Unofficial Twee2 notation source files to process for passages. Twee2 compatibility mode is automatically enabled for files with these extensions.</dd>
@ -96,6 +98,13 @@ The following extensions are supported:
<dd>CSS source files to bundle.</dd> <dd>CSS source files to bundle.</dd>
<dt><code>.js</code></dt> <dt><code>.js</code></dt>
<dd>JavaScript source files to bundle.</dd> <dd>JavaScript source files to bundle.</dd>
<dt><code>.mjs</code></dt>
<dd>
<p>JavaScript module (ESM) source files to bundle.</p>
<p role="note"><b>Note:</b>
May only be used with the module option (<kbd>-m SRC</kbd>, <kbd>--module=SRC</kbd>).
</p>
</dd>
<dt><code>.otf</code>, <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code></dt> <dt><code>.otf</code>, <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code></dt>
<dd>Font files to bundle, as <code>@font-face</code> style rules. The generated name of the font family will be the font's base filename sans its extension—e.g., the family name for <code>chinacat.tff</code> will be <code>chinacat</code>.</dd> <dd>Font files to bundle, as <code>@font-face</code> style rules. The generated name of the font family will be the font's base filename sans its extension—e.g., the family name for <code>chinacat.tff</code> will be <code>chinacat</code>.</dd>
<dt><code>.gif</code>, <code>.jpeg</code>, <code>.jpg</code>, <code>.png</code>, <code>.svg</code>, <code>.tif</code>, <code>.tiff</code>, <code>.webp</code></dt> <dt><code>.gif</code>, <code>.jpeg</code>, <code>.jpg</code>, <code>.png</code>, <code>.svg</code>, <code>.tif</code>, <code>.tiff</code>, <code>.webp</code></dt>

View file

@ -244,7 +244,7 @@ func knownFileType(filename string) bool {
"tw2", "twee2", "tw2", "twee2",
"htm", "html", "htm", "html",
"css", "css",
"js", "js", "mjs",
"otf", "ttf", "woff", "woff2", "otf", "ttf", "woff", "woff2",
"gif", "jpeg", "jpg", "png", "svg", "tif", "tiff", "webp", "gif", "jpeg", "jpg", "png", "svg", "tif", "tiff", "webp",
"aac", "flac", "m4a", "mp3", "oga", "ogg", "opus", "wav", "wave", "weba", "aac", "flac", "m4a", "mp3", "oga", "ogg", "opus", "wav", "wave", "weba",

View file

@ -1,5 +1,5 @@
/* /*
Copyright © 20142021 Thomas Michael Edwards. All rights reserved. Copyright © 20142023 Thomas Michael Edwards. All rights reserved.
Use of this source code is governed by a Simplified BSD License which Use of this source code is governed by a Simplified BSD License which
can be found in the LICENSE file. can be found in the LICENSE file.
*/ */
@ -33,9 +33,11 @@ func loadModules(filenames []string, encoding string) []byte {
switch normalizedFileExt(filename) { switch normalizedFileExt(filename) {
// NOTE: The case values here should match those in `filesystem.go:knownFileType()`. // NOTE: The case values here should match those in `filesystem.go:knownFileType()`.
case "css": case "css":
source, err = loadModuleTagged("style", filename, encoding) source, err = loadModuleByType("text/css", filename, encoding)
case "js": case "js":
source, err = loadModuleTagged("script", filename, encoding) source, err = loadModuleByType("text/javascript", filename, encoding)
case "mjs":
source, err = loadModuleByType("module", filename, encoding)
case "otf", "ttf", "woff", "woff2": case "otf", "ttf", "woff", "woff2":
source, err = loadModuleFont(filename) source, err = loadModuleFont(filename)
default: default:
@ -55,7 +57,7 @@ func loadModules(filenames []string, encoding string) []byte {
return bytes.Join(headTags, []byte("\n")) return bytes.Join(headTags, []byte("\n"))
} }
func loadModuleTagged(tag, filename, encoding string) ([]byte, error) { func loadModuleByType(typeValue, filename, encoding string) ([]byte, error) {
source, err := fileReadAllWithEncoding(filename, encoding) source, err := fileReadAllWithEncoding(filename, encoding)
if err != nil { if err != nil {
return nil, err return nil, err
@ -65,24 +67,25 @@ func loadModuleTagged(tag, filename, encoding string) ([]byte, error) {
return source, nil return source, nil
} }
var tag string
switch typeValue {
case "module", "text/javascript":
tag = "script"
case "text/css":
tag = "style"
}
var ( var (
idSlug = tag + "-module-" + slugify(strings.Split(filepath.Base(filename), ".")[0]) idSlug = tag + "-module-" + slugify(strings.Split(filepath.Base(filename), ".")[0])
mimeType string
b bytes.Buffer b bytes.Buffer
) )
switch tag {
case "script":
mimeType = "text/javascript"
case "style":
mimeType = "text/css"
}
if _, err := fmt.Fprintf( if _, err := fmt.Fprintf(
&b, &b,
`<%s id=%q type=%q>%s</%[1]s>`, `<%s id=%q type=%q>%s</%[1]s>`,
tag, tag,
idSlug, idSlug,
mimeType, typeValue,
source, source,
); err != nil { ); err != nil {
return nil, err return nil, err

View file

@ -52,6 +52,8 @@ func (s *story) load(filenames []string, c *config) {
if err := s.loadTagged("script", filename, c.encoding); err != nil { if err := s.loadTagged("script", filename, c.encoding); err != nil {
log.Fatalf("error: load %s: %s", filename, err.Error()) log.Fatalf("error: load %s: %s", filename, err.Error())
} }
case "mjs":
log.Fatalf("error: load %s: ESM files must be loaded via the module option", filename)
case "otf", "ttf", "woff", "woff2": case "otf", "ttf", "woff", "woff2":
if err := s.loadFont(filename); err != nil { if err := s.loadFont(filename); err != nil {
log.Fatalf("error: load %s: %s", filename, err.Error()) log.Fatalf("error: load %s: %s", filename, err.Error())