Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 84 additions & 54 deletions source/_extensions/controls_js_sim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from pathlib import Path
from typing import Any, Dict

import os, glob
from jsmin import jsmin
from sphinx.application import Sphinx
from sphinx.util import logging

# Handle custom javascript
# Groups, sorts, merges, and minifies the JS files associated with
Expand All @@ -25,74 +25,104 @@
".",
]

LOGGER = logging.getLogger("controls_js_sim")

def mergeAndMinify(out_folder):
if not os.path.isdir(out_folder):
os.makedirs(out_folder)

outputFile = os.path.join(out_folder, "pid-tune.js")

with open(outputFile, "w") as outf:
for folder in FOLDER_INCS:
jsRoot = os.path.dirname(__file__)
# find all js files in the specific folder
inFileNames = glob.glob(os.path.join(jsRoot, folder, "*.js"))

# sort file names alphabetically
# this allows a within-folder sort by number prefix if needed.
inFileNames.sort()

for inFileName in inFileNames:
with open(inFileName, "r") as inf:
if not debugJS:
# Minify each file independently - again, low bar solution for now
minified = jsmin(inf.read())
outf.write(minified)
outf.write("\n")
else:
# Verbose, no minify, and add debug markers.
outf.write("\n\n\n")
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("//** {}\n".format(inFileName))
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("\n")
outf.write(inf.read())
outf.write("\n")

return outputFile
STATIC_DIR = Path(__file__).parent / "_static"
OUTPUT_FILE = STATIC_DIR / "pid-tune.js"


def setup(app: Sphinx) -> Dict[str, Any]:
print("Generating and adding controls javascript...")
def get_source_files():
"""Get the list of source JavaScript files to be merged and minified."""

# Perform controls js setup
static_dir = Path(__file__).parent / "_static"
js_files = []
js_root = Path(__file__).parent

for folder in FOLDER_INCS:
# find all js files in the specific folder
folder_path = js_root / folder
# sort file names alphabetically
# this allows a within-folder sort by number prefix if needed.
in_file_names = sorted(folder_path.glob("*.js"))
js_files.extend(in_file_names)

return js_files


def should_rebuild():
"""Check if JavaScript needs to be rebuilt based on source file timestamps."""

# If output doesn't exist, must rebuild
if not OUTPUT_FILE.exists():
return True

output_mtime = OUTPUT_FILE.stat().st_mtime
source_files = get_source_files()

# Check if any source file is newer than output
for source_file in source_files:
if source_file.stat().st_mtime > output_mtime:
return True

return False


def merge_and_minify():
"""Merge and minify the JavaScript source files into a single output file."""

source_files = get_source_files()

with OUTPUT_FILE.open("w") as outf:
for source_file in source_files:
with source_file.open("r") as source:
if not debugJS:
# Minify each file independently - again, low bar solution for now
minified = jsmin(source.read())
outf.write(minified)
outf.write("\n")
else:
# Verbose, no minify, and add debug markers.
outf.write("\n\n\n")
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("//** {}\n".format(source_file))
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("\n")
outf.write(source.read())
outf.write("\n")
Comment on lines +74 to +100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with OUTPUT_FILE.open("w") as outf:
for source_file in source_files:
with source_file.open("r") as source:
if not debugJS:
# Minify each file independently - again, low bar solution for now
minified = jsmin(source.read())
outf.write(minified)
outf.write("\n")
else:
# Verbose, no minify, and add debug markers.
outf.write("\n\n\n")
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("//** {}\n".format(source_file))
outf.write(
"//*******************************************************\n"
)
outf.write(
"//*******************************************************\n"
)
outf.write("\n")
outf.write(source.read())
outf.write("\n")
output_text = ""
for source_file in source_files:
text = ""
if not debugJS:
# Minify each file independently - again, low bar solution for now
minified = jsmin(source_file.read_text())
text += minified + "\n"
continue
# Verbose, no minify, and add debug markers.
text = f"""\n\n\n
//*******************************************************
//*******************************************************
//** {source_file}
//*******************************************************
//*******************************************************
{source_file.read_text()}
"""
output_text += textwrap.dedent(indented_string)
OUTPUT_FILE.write_text(output_text)

Further testing with dedent is needed, but I think it's more concise.



def generate_js_if_needed(app: Sphinx):
if should_rebuild():
LOGGER.info("Generating controls javascript...")
merge_and_minify()
LOGGER.info("Done.")
else:
LOGGER.debug("Controls javascript is up to date, skipping rebuild.")


def setup(app: Sphinx) -> Dict[str, Any]:
# Perform controls js setup
# everything written to this new static folder in this `setup` will be copied to the build static folder as is
app.connect(
"builder-inited",
(lambda app: app.config.html_static_path.append(static_dir.as_posix())),
(lambda app: app.config.html_static_path.append(STATIC_DIR.as_posix())),
)

# Generate merged/minified PID tuning source
mergeAndMinify(static_dir)
app.connect("builder-inited", generate_js_if_needed)

# Add interactive PID tuning
app.add_js_file("pid-tune.js")
app.add_css_file("pid-tune.css")

print("Done.")

return {
"parallel_read_safe": True,
"parallel_write_safe": True,
Expand Down