1
1
module minijson.lib ;
2
2
3
3
import std : ctRegex, replaceAll, join, array, matchAll, matchFirst, RegexMatch;
4
- import automem : Vector;
5
4
6
5
const tokenizerWithComment = ctRegex! (` "|(/\*)|(\*/)|(//)|\n|\r|\[|]` , " g" );
7
6
const tokenizerNoComment = ctRegex! (` [\n\r"[]]` , " g" );
8
7
9
8
const spaceOrBreakRegex = ctRegex! (` \s` );
10
9
11
- const repeatingBackSlashRegex = ctRegex! (` (\\)*$` );
12
-
13
10
/**
14
11
Minify the given JSON string
15
12
@@ -20,12 +17,12 @@ const repeatingBackSlashRegex = ctRegex!(`(\\)*$`);
20
17
Return:
21
18
the minified json string
22
19
*/
23
- string minifyString (string jsonString, bool hasComment = false ) @trusted
20
+ string minifyString (in string jsonString, in bool hasComment = false ) @trusted
24
21
{
25
22
auto in_string = false ;
26
23
auto in_multiline_comment = false ;
27
24
auto in_singleline_comment = false ;
28
- Vector ! string new_str ;
25
+ string result ;
29
26
size_t from = 0 ;
30
27
auto rightContext = " " ;
31
28
@@ -49,22 +46,24 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
49
46
if (noCommentOrNotInComment)
50
47
{
51
48
auto leftContextSubstr = match.pre()[prevFrom .. $];
52
-
53
- if (! in_string)
49
+ if (leftContextSubstr.length != 0 )
54
50
{
55
- leftContextSubstr = leftContextSubstr.replaceAll(spaceOrBreakRegex, " " );
56
- }
57
- new_str ~= leftContextSubstr;
51
+ if (! in_string)
52
+ {
53
+ leftContextSubstr = leftContextSubstr.replaceAll(spaceOrBreakRegex, " " );
54
+ }
55
+ result ~= leftContextSubstr;
58
56
59
- if (matchFrontHit == " \" " )
60
- {
61
- if (! in_string || hasNoSlashOrEvenNumberOfSlashes(leftContextSubstr))
57
+ if (matchFrontHit == " \" " )
62
58
{
63
- // start of string with ", or unescaped " character found to end string
64
- in_string = ! in_string;
59
+ if (! in_string || hasNoSlashOrEvenNumberOfSlashes(leftContextSubstr))
60
+ {
61
+ // start of string with ", or unescaped " character found to end string
62
+ in_string = ! in_string;
63
+ }
64
+ -- from; // include " character in next catch
65
+ rightContext = jsonString[from .. $];
65
66
}
66
- -- from; // include " character in next catch
67
- rightContext = jsonString[from .. $];
68
67
}
69
68
}
70
69
// comments
@@ -82,7 +81,7 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
82
81
}
83
82
else if (notSlashAndNoSpaceOrBreak(matchFrontHit))
84
83
{
85
- new_str ~= matchFrontHit;
84
+ result ~= matchFrontHit;
86
85
}
87
86
}
88
87
else if (in_multiline_comment && ! in_singleline_comment && matchFrontHit == " */" )
@@ -94,24 +93,35 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
94
93
in_singleline_comment = false ;
95
94
}
96
95
}
97
- if (! hasComment && notSlashAndNoSpaceOrBreak(matchFrontHit))
96
+ else if (! hasComment && notSlashAndNoSpaceOrBreak(matchFrontHit))
98
97
{
99
- new_str ~= matchFrontHit;
98
+ result ~= matchFrontHit;
100
99
}
101
100
match.popFront();
102
101
}
103
- new_str ~= rightContext;
104
- return new_str.array().join( " " ) ;
102
+ result ~= rightContext;
103
+ return result ;
105
104
}
106
105
107
- private bool hasNoSlashOrEvenNumberOfSlashes (string leftContext ) @safe
106
+ private bool hasNoSlashOrEvenNumberOfSlashes (in string leftContextSubstr ) @safe @nogc
108
107
{
109
- auto leftContextMatch = leftContext.matchFirst(repeatingBackSlashRegex);
110
- // if not matched the hit length will be 0 (== leftContextMatch.empty())
111
- return leftContextMatch.hit().length % 2 == 0 ;
108
+ size_t slashCount = 0 ;
109
+
110
+ // NOTE leftContextSubstr.length is not 0 (checked outside of the function)
111
+ size_t index = leftContextSubstr.length - 1 ;
112
+
113
+ // loop over the string backwards and find `\`
114
+ while (leftContextSubstr[index] == ' \\ ' )
115
+ {
116
+ slashCount += 1 ;
117
+
118
+ index -= 1 ;
119
+ }
120
+ // no slash or even number of slashes
121
+ return slashCount % 2 == 0 ;
112
122
}
113
123
114
- private bool notSlashAndNoSpaceOrBreak (string matchFrontHit)
124
+ private bool notSlashAndNoSpaceOrBreak (in string matchFrontHit) @safe
115
125
{
116
126
return matchFrontHit != " \" " && matchFrontHit.matchFirst(spaceOrBreakRegex).empty();
117
127
}
@@ -123,7 +133,7 @@ private bool notSlashAndNoSpaceOrBreak(string matchFrontHit)
123
133
files = the paths to the files.
124
134
hasComment = a boolean to support comments in json. Default: `false`.
125
135
*/
126
- void minifyFiles (string [] files, bool hasComment = false )
136
+ void minifyFiles (in string [] files, in bool hasComment = false )
127
137
{
128
138
import std.parallelism : parallel;
129
139
import std.file : readText, write;
0 commit comments