Skip to content

Commit

Permalink
Included a build script for sanitizing the items data file.
Browse files Browse the repository at this point in the history
This script currently escapes unescaped quotation marks, as well as removes the trailing comma in the `items` array, if present.
  • Loading branch information
SirRandoo committed Sep 11, 2024
1 parent f207f19 commit 2691e72
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 240 deletions.
32 changes: 2 additions & 30 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
source "https://rubygems.org"
# Hello! This is where you manage which Jekyll version is used to run.
# When you want to use a different version, change it below, save the
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
#
# bundle exec jekyll serve
#
# This will help ensure the proper Jekyll version is running.
# Happy Jekylling!
gem "jekyll", "~> 4.0.0"
gem "jekyll-remote-theme"
gem "jekyll-feed"
gem "jekyll-paginate"
gem "jekyll-seo-tag"
# This is the default theme for new Jekyll sites. You may change this to anything you like.
# gem "minima", "~> 2.5"
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
# gem "github-pages", group: :jekyll_plugins
# If you have any plugins, put them here!
group :jekyll_plugins do
# gem "jekyll-feed", "~> 0.12"
end

# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
# and associated library.
install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
gem "tzinfo", "~> 1.2"
gem "tzinfo-data"
end
gem "jekyll", "~> 4.3"

# Performance-booster for watching directories on Windows
gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?
gem "type-on-strap", "~> 2.4"
90 changes: 42 additions & 48 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
bigdecimal (3.1.8)
colorator (1.1.0)
concurrent-ruby (1.2.3)
concurrent-ruby (1.3.4)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
eventmachine (1.2.7-x64-mingw32)
ffi (1.16.3)
ffi (1.16.3-x64-mingw32)
ffi (1.17.0)
forwardable-extended (2.6.0)
google-protobuf (4.28.0)
bigdecimal
rake (>= 13)
http_parser.rb (0.8.0)
i18n (1.14.4)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
jekyll (4.0.1)
jekyll (4.3.3)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (>= 0.9.5, < 2)
jekyll-sass-converter (~> 2.0)
i18n (~> 1.0)
jekyll-sass-converter (>= 2.0, < 4.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.1)
kramdown (~> 2.3, >= 2.3.1)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (~> 0.3.3)
mercenary (>= 0.3.6, < 0.5)
pathutil (~> 0.9)
rouge (~> 3.0)
rouge (>= 3.0, < 5.0)
safe_yaml (~> 1.0)
terminal-table (~> 1.8)
jekyll-feed (0.15.1)
terminal-table (>= 1.8, < 4.0)
webrick (~> 1.7)
jekyll-feed (0.17.0)
jekyll (>= 3.7, < 5.0)
jekyll-paginate (1.1.0)
jekyll-remote-theme (0.4.3)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (2.2.0)
sassc (> 2.0.1, < 3.0)
jekyll-sass-converter (3.0.0)
sass-embedded (~> 1.54)
jekyll-seo-tag (2.8.0)
jekyll (>= 3.8, < 5.0)
jekyll-watch (2.2.1)
Expand All @@ -53,44 +52,39 @@ GEM
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mercenary (0.4.0)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.0.5)
public_suffix (6.0.1)
rake (13.2.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
rb-inotify (0.11.1)
ffi (~> 1.0)
rexml (3.2.6)
rouge (3.30.0)
rubyzip (2.3.2)
rexml (3.3.7)
rouge (4.3.0)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
sassc (2.4.0-x64-mingw32)
ffi (~> 1.9)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
tzinfo (1.2.11)
thread_safe (~> 0.1)
tzinfo-data (1.2024.1)
tzinfo (>= 1.0.0)
unicode-display_width (1.8.0)
wdm (0.1.1)
sass-embedded (1.78.0)
google-protobuf (~> 4.27)
rake (>= 13)
sass-embedded (1.78.0-x64-mingw32)
google-protobuf (~> 4.27)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
type-on-strap (2.4.10)
jekyll (>= 3.8, < 5.0)
jekyll-feed (>= 0.15.1, <= 0.17)
jekyll-paginate (~> 1.1.0)
jekyll-seo-tag (>= 2.7.1, <= 2.8)
unicode-display_width (2.5.0)
webrick (1.8.1)

PLATFORMS
ruby
x64-mingw32

DEPENDENCIES
jekyll (~> 4.0.0)
jekyll-feed
jekyll-paginate
jekyll-remote-theme
jekyll-seo-tag
tzinfo (~> 1.2)
tzinfo-data
wdm (~> 0.1.1)
jekyll (~> 4.3)
type-on-strap (~> 2.4)

BUNDLED WITH
2.4.5
11 changes: 4 additions & 7 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,12 @@ mods:
author: true

# Build settings
remote_theme: sylhare/Type-on-Strap
plugins:
- jekyll-remote-theme
- jekyll-feed
- jekyll-paginate
- jekyll-seo-tag

theme: type-on-strap
markdown: kramdown
sass:
style: compressed

permalink: pretty

exclude:
- build-scripts
111 changes: 111 additions & 0 deletions build-scripts/sanitize_items.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""
A build script for escaping unescaped quotation marks in the "StoreItems.json"
file that Twitch Toolkit writes to disk. This script also removes the trailing
comma from the last item in the "items" JSON array.
The initial step of this build script is to read and parse the "StoreItems.json"
file. Should the file be valid JSON, the script will abort early as there's no
sanitization that needs to be done.
Should the initial parse fail, the script will go through the raw file contents
line by line, looking for lines that indicate it's describing an item's
abbreviation ("abr" in the file). The line is then split by the ':' separator,
with the "key" half being written immediately to an intermediate buffer. The
value half is then iterated, looking for any unescaped quotation marks. Should
any be found, they are escaped to the buffer.
A part of this "line-by-line" iteration is watching for the closing array
character (']'). Should this line be encountered, the script will walk back up
the buffer to the final object in the `items` array, just before the final comma
was written, then write the expected closing object character ('}') and then
the closing array character, effectively removing any trailing comma that may
have been present in the file.
The final step is to reparse the sanitized result. Should it fail, the contents
will be written to disk anyway as a "best attempt." Should it succeed, the
script will use Python's `json.dump` method to serialize it to disk, unindented.
"""
import io
import os
import sys
from json import dump
from json import loads
from json import JSONDecodeError

with open("_data/StoreItems.json", "r") as file:
contents: str = file.read()

try:
loads(contents)

print("Store items is already valid json; aborting...")

sys.exit(0)
except JSONDecodeError:
print("Store items was not valid json; attempting to sanitize...")

if not contents:
print("There are no items available in the store. Aborting...")

sys.exit(1)

buffer = io.StringIO()
last_position_cookie: int = 0

for line in contents.split("\n"):
trimmed = line.strip()

if line.endswith("],"):
buffer.seek(last_position_cookie)
buffer.write("\t\t}\n")
buffer.write("\t],\n")

continue

if not trimmed.startswith('"abr"'):
last_position_cookie = buffer.tell()
buffer.write(line)
buffer.write("\n")

continue

if trimmed.count('"') > 4:
key, value = line.split(":")
buffer.write(key)
buffer.write(": ")

first_quote_index = value.index('"')
last_quote_index = value.rindex('"')

buffer.write('"')

last_char: str | None = None
for char in value[first_quote_index + 1 : last_quote_index]:
if char == '"' and last_char != "\\":
buffer.write("\\")

buffer.write(char)
last_char = char

last_position_cookie = buffer.tell()
buffer.write('",')
else:
last_position_cookie = buffer.tell()
buffer.write(line)

last_position_cookie = buffer.tell()
buffer.write("\n")

with open("_data/StoreItems.json", "w") as file:
buffer.seek(0)
buffer.truncate(last_position_cookie)

try:
data = loads(buffer.getvalue())
dump(data, file)
except ValueError:
print(
"Finished sanitizing items, but result isn't valid json; writing sanitized results anyway..."
)

file.write(buffer.getvalue())
Loading

0 comments on commit 2691e72

Please sign in to comment.