Skip to content

Commit

Permalink
Add option to only remove comments
Browse files Browse the repository at this point in the history
  • Loading branch information
klaashoekstra94 committed May 27, 2024
1 parent 761f16e commit 9e65781
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 20 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,19 @@ heishamon-rules-minify [input_file] [output_file]

This will shorten all custom function and variable names and remove all unneeded spaces and newlines.

### Extra options
There are a couple of extra options to pass with the minifier:
* `--print` or `-p` to also print the output on the command line.
* `--comments_only` or `-c` to only remove the comments from the input file but do no further minifying.

## Release History

* 0.0.1
* [0.0.1](https://github.com/klaashoekstra94/heishamon_rules_minify/releases/tag/v0.0.1)
* Initial version
* [0.0.2](https://github.com/klaashoekstra94/heishamon_rules_minify/releases/tag/v0.0.2)
* Fix incorrect spacing for double operators, minor bugfixes
* [0.0.3](https://github.com/klaashoekstra94/heishamon_rules_minify/releases/tag/v0.0.3)
* Add option to only remove comments

## Contributing

Expand Down
3 changes: 2 additions & 1 deletion src/heishamon_rules_minify/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ def main_cli():
parser.add_argument("input", help="input rules file")
parser.add_argument("output", help="output rules file")
parser.add_argument("-p", "--print", action="store_true", help="print the output on the commandline")
parser.add_argument("-c", "--comments_only", action="store_true", help="only remove comments from the input")
args = parser.parse_args()

with open(args.input, "r") as i:
text = Minifier.minify(i.read())
text = Minifier.minify(i.read(), args.comments_only)

with open(args.output, "w") as o:
o.write(text)
Expand Down
55 changes: 40 additions & 15 deletions src/heishamon_rules_minify/minifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@
class Minifier:
_TABLE = str.maketrans("", "", string.ascii_lowercase)

@staticmethod
def _fix_spaces_around_operators(text):
# Remove extra spaces
text = re.sub(r"(?<=[;=&|<>\-+%*\/^()])[\t ]*(?=\S)(?!then)", "", text, flags=re.MULTILINE)

# Correct spaces around operators and functions
text = re.sub(
r"(?<!timer)( *(==|!=|>=|<=|\|\||&&|[=+\*\/<>^]) *)(?=-?\d|\b|[(#$@%?].+(;|then|end|$))",
r" \g<2> ",
text,
flags=re.MULTILINE,
)
text = re.sub(
r"(?<![=<>(,])(?<![=<>(,] ) *- *(?=-*\d|[(#$@%?].+(;|then|end|$))", " - ", text, flags=re.MULTILINE
)
text = re.sub(r" *% *(?=-*\d|[(#$@%?].+(;|then|end|$))", " % ", text, flags=re.MULTILINE)

return text

@classmethod
def _remove_lowercase(cls, input_dict):
for key in input_dict.keys():
Expand All @@ -22,12 +41,29 @@ def _remove_lowercase(cls, input_dict):
return input_dict

@classmethod
def minify(cls, input_text):
def minify(cls, input_text, comments_only=False):
# Remove comment blocks
text = re.sub(r"--\[\[[^\]\]]*]]", "", input_text, flags=re.MULTILINE)

# Remove single-line comments
text = re.sub(r"[ \t]*--(?!\[\[).*$", "", text, flags=re.MULTILINE)
text = re.sub(r"[ \t]*--(?!\[\[).*\r?\n", "", text, flags=re.MULTILINE)

if comments_only:
# Remove newlines at start of file
text = re.sub(r"^(\r?\n)+", "", text)

# Replace three or more newlines with two
text = re.sub(
r"(\r?\n){3,}",
lambda match: list(filter(None, re.split(r"(\r?\n)", match.group(0))))[0] * 2,
text,
flags=re.MULTILINE,
)

# Remove newline after line ending with all possible operators
text = re.sub(r"(?<=[=&|<>\-+%*\/^()])\r?\n", "", text, flags=re.MULTILINE)

return Minifier._fix_spaces_around_operators(text)

# Find all global/local variable names
found_variables = {k: "" for k in re.findall(r"(?<=\B[#$])[_A-za-z0-9]+(?=[= &|<>\-+%*\/^])", text)}
Expand All @@ -54,24 +90,13 @@ def minify(cls, input_text):
# Remove newline after line ending with 'then' or 'else'
text = re.sub(r"(?<=then|else)\r?\n", " ", text, flags=re.MULTILINE)

# Remove newline after line ending with all possible operators
# Remove newline after line ending with all possible operators and semicolon
text = re.sub(r"(?<=[;=&|<>\-+%*\/^()])\r?\n", "", text, flags=re.MULTILINE)

# Remove extra spaces that are present after removing newlines
text = re.sub(r"(?<=[;=&|<>\-+%*\/^()])[\t ]*(?=\S)(?!then)", "", text, flags=re.MULTILINE)

# Remove newline after line ending with 'end', except for last end of function
text = re.sub(r"(?<=end)\s+(?!\s*on |\Z)", " ", text, flags=re.MULTILINE)

# Correct spaces around operators and functions
text = re.sub(
r"(?<!timer)( *(==|!=|>=|<=|\|\||&&|[=+\*\/<>^]) *)(?=-?\d|\b|[(#$@%?].+(;|then|end))",
r" \g<2> ",
text,
flags=re.MULTILINE,
)
text = re.sub(r"(?<![=<>(,])(?<![=<>(,] ) *- *(?=-*\d|[(#$@%?].+(;|then|end))", " - ", text, flags=re.MULTILINE)
text = re.sub(r" *% *(?=-*\d|[(#$@%?].+(;|then|end))", " % ", text, flags=re.MULTILINE)
text = Minifier._fix_spaces_around_operators(text)

# Remove all spaces around comma signs
text = re.sub(r"(?<=[)_A-Za-z0-9]) *, *\s*(?=[$#@?_A-Za-z0-9])", ",", text, flags=re.MULTILINE)
Expand Down
101 changes: 98 additions & 3 deletions tests/test_minifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

from heishamon_rules_minify.minifier import Minifier


def test_minifier():
input_text = """
input_text = """
--[[
Multiline block comment
]]
Expand Down Expand Up @@ -123,6 +121,8 @@ def test_minifier():
end
"""


def test_minifier():
expected_output = """on System#Boot then #HWSTS = 1;#ASQM = 0;#QMH = 1;#QMP = -1;setTimer(3,60);end
on CWDC then $WTWW = 32;$OTWW = 14;$WTCW = 41;$OTCW = -4;#HWSTS = $WTWW;if @Outside_Temp >= $OTWW then #HWSTS = $WTWW;else if @Outside_Temp <= $OTCW then #HWSTS = $WTCW;else #HWSTS = $WTWW + (($OTWW - @Outside_Temp) * ($WTCW - $WTWW) / ($OTWW - $OTCW));end end end
on SQM then if #ASQM == 1 then if isset(@Outside_Temp) && isset(@Heatpump_State) then if #QMH == 1 then if @Outside_Temp < 13 then #QM = 1;else #QM = 2;end if @Outside_Temp < 8 then #QM = 0;end if @Outside_Temp < 2 then if %hour > 22 || %hour < 7 then #QM = 1;else #QM = 0;end end if #QMP != #QM && @Heatpump_State == 1 then setTimer(2,900);#QMH = 0;#QMP = #QM;@SetQuietMode = #QM;end end end end end
Expand All @@ -132,3 +132,98 @@ def test_minifier():
"""
output = Minifier.minify(input_text)
assert output == expected_output

def test_minifier_comments_only():
expected_output = """on System#Boot then
#HeatingWaterSupplyTemperatureSetpoint = 1;
#allowSetQuietMode = 0;
#quietModeHelper = 1;
#quietModePrevious = -1;
setTimer(3, 60);end
on CalculateWeatherDependentControl then
$WaterTemperatureWarmWeather = 32;
$OutsideTemperatureWarmWeather = 14;
$WaterTemperatureColdWeather = 41;
$OutsideTemperatureColdWeather = -4;
#HeatingWaterSupplyTemperatureSetpoint = $WaterTemperatureWarmWeather;
if @Outside_Temp >= $OutsideTemperatureWarmWeather then
#HeatingWaterSupplyTemperatureSetpoint = $WaterTemperatureWarmWeather;
else
if @Outside_Temp <= $OutsideTemperatureColdWeather then
#HeatingWaterSupplyTemperatureSetpoint = $WaterTemperatureColdWeather;
else
#HeatingWaterSupplyTemperatureSetpoint = $WaterTemperatureWarmWeather + (($OutsideTemperatureWarmWeather - @Outside_Temp) * ($WaterTemperatureColdWeather - $WaterTemperatureWarmWeather) / ($OutsideTemperatureWarmWeather - $OutsideTemperatureColdWeather));
end
end
end
on setQuietMode then
if #allowSetQuietMode == 1 then
if isset(@Outside_Temp) && isset(@Heatpump_State) then
if #quietModeHelper == 1 then
if @Outside_Temp < 13 then
#quietMode = 1;
else
#quietMode = 2;
end
if @Outside_Temp < 8 then
#quietMode = 0;
end
if @Outside_Temp < 2 then
if %hour > 22 || %hour < 7 then
#quietMode = 1;
else
#quietMode = 0;
end
end
if #quietModePrevious != #quietMode && @Heatpump_State == 1 then
setTimer(2, 900);
#quietModeHelper = 0;
#quietModePrevious = #quietMode;
@SetQuietMode = #quietMode;
end
end
end
end
end
on ?roomTemp then
$margin = 0.25;
$setpoint = ?roomTempSet;
if ?roomTemp > ($setpoint + $margin) then
if @Heatpump_State == 1 then
@SetHeatpump = 0;
end
else
if ?roomTemp < ($setpoint - $margin) then
if @Heatpump_State == 0 then
@SetHeatpump = 1;
end
else
@SetZ1HeatRequestTemperature = round(#HeatingWaterSupplyTemperatureSetpoint);
end
end
end
on timer=2 then
#quietModeHelper = 1;
#quietMode = 0;
end
on timer=3 then
$somevalue = 0;
$someValue = 1;
$SomeValue = 2;
$SoveValue3 = 3;
$SomeValuee = 4;
setTimer(3, 60);
end
"""
output = Minifier.minify(input_text, comments_only=True)
assert output == expected_output

0 comments on commit 9e65781

Please sign in to comment.