Skip to content

Commit 019b46b

Browse files
committed
Addressing comments.
1 parent b893441 commit 019b46b

File tree

5 files changed

+100
-102
lines changed

5 files changed

+100
-102
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import json
2+
3+
4+
DOUBLE_QUOTE = '\"'
5+
BACKSLASH = '\\'
6+
DOUBLE_SLASH = '//'
7+
MULTILINE_COMMENT_START = '/*'
8+
MULTILINE_COMMENT_END = '*/'
9+
NEW_LINE = '\n'
10+
11+
12+
def parse_json_with_comments(json_string):
13+
try:
14+
return json.loads(json_string)
15+
16+
except json.JSONDecodeError:
17+
return json.loads(__strip_json_comments(json_string))
18+
19+
20+
def __strip_json_comments(json_string):
21+
current_index = 0
22+
length = len(json_string)
23+
result = []
24+
25+
while current_index < length:
26+
# Single line comment
27+
if json_string[current_index:current_index + 2] == DOUBLE_SLASH:
28+
current_index = __find_next_newline_index(json_string, current_index, length)
29+
if current_index < length and json_string[current_index] == NEW_LINE:
30+
result.append(NEW_LINE)
31+
32+
# Multi-line comment
33+
elif json_string[current_index:current_index + 2] == MULTILINE_COMMENT_START:
34+
current_index = __find_next_multiline_comment_end(json_string, current_index + 2, length)
35+
36+
# String literal
37+
elif json_string[current_index] == DOUBLE_QUOTE:
38+
literal_start_index = current_index
39+
current_index = __find_next_double_quote_index(json_string, current_index + 1, length)
40+
41+
result.extend(json_string[literal_start_index:current_index + 1])
42+
else:
43+
result.append(json_string[current_index])
44+
45+
current_index += 1
46+
47+
return "".join(result)
48+
49+
50+
def __is_escaped(json_string, char_index):
51+
backslash_count = 0
52+
index = char_index - 1
53+
while index >= 0 and json_string[index] == BACKSLASH:
54+
backslash_count += 1
55+
index -= 1
56+
57+
return backslash_count % 2 == 1
58+
59+
60+
def __find_next_newline_index(json_string, start_index, end_index):
61+
index = start_index
62+
63+
while index < end_index:
64+
if json_string[index] == NEW_LINE:
65+
return index
66+
67+
index += 1
68+
69+
return index
70+
71+
72+
def __find_next_double_quote_index(json_string, start_index, end_index):
73+
index = start_index
74+
while index < end_index:
75+
if json_string[index] == DOUBLE_QUOTE and not __is_escaped(json_string, index):
76+
return index
77+
78+
index += 1
79+
80+
raise ValueError("Unterminated string literal")
81+
82+
83+
def __find_next_multiline_comment_end(json_string, start_index, end_index):
84+
index = start_index
85+
while index < end_index - 1:
86+
if json_string[index:index + 2] == MULTILINE_COMMENT_END:
87+
return index + 1
88+
89+
index += 1
90+
91+
raise ValueError("Unterminated multi-line comment")

src/azure-cli/azure/cli/command_modules/appconfig/_kv_import_helpers.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@
4747
ImportMode,
4848
)
4949
from ._diff_utils import KVComparer, print_preview
50+
from ._json import parse_json_with_comments
5051
from ._utils import (
5152
is_json_content_type,
52-
strip_json_comments,
5353
validate_feature_flag_name,
5454
validate_feature_flag_key,
5555
)
@@ -88,7 +88,7 @@ def __read_with_appropriate_encoding(file_path, format_):
8888
try:
8989
with io.open(file_path, "r", encoding=default_encoding) as config_file:
9090
if format_ == "json":
91-
config_data = __parse_json_file_data(config_file.read())
91+
config_data = parse_json_with_comments(config_file.read())
9292
# Only accept json objects
9393
if not isinstance(config_data, (dict, list)):
9494
raise ValueError(
@@ -113,7 +113,7 @@ def __read_with_appropriate_encoding(file_path, format_):
113113

114114
with io.open(file_path, "r", encoding=detected_encoding) as config_file:
115115
if format_ == "json":
116-
config_data = __parse_json_file_data(config_file.read())
116+
config_data = parse_json_with_comments(config_file.read())
117117

118118
elif format_ == "yaml":
119119
for yaml_data in list(yaml.safe_load_all(config_file)):
@@ -1122,11 +1122,3 @@ def __flatten_key_value(key, value, flattened_data, depth, separator):
11221122
) # Ensure boolean values are properly stringified.
11231123
else:
11241124
flattened_data[key] = value if isinstance(value, str) else json.dumps(value)
1125-
1126-
1127-
def __parse_json_file_data(json_string):
1128-
try:
1129-
return json.loads(json_string)
1130-
1131-
except json.JSONDecodeError:
1132-
return json.loads(strip_json_comments(json_string))

src/azure-cli/azure/cli/command_modules/appconfig/_utils.py

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@
2020

2121
logger = get_logger(__name__)
2222

23-
DOUBLE_QUOTE = '\"'
24-
BACKSLASH = '\\'
25-
DOUBLE_SLASH = '//'
26-
MULTILINE_COMMENT_START = '/*'
27-
MULTILINE_COMMENT_END = '*/'
28-
NEW_LINE = '\n'
29-
3023

3124
def construct_connection_string(cmd, config_store_name):
3225
connection_string_template = 'Endpoint={};Id={};Secret={}'
@@ -261,73 +254,3 @@ def parse_tags_to_dict(tags):
261254
tags_dict[tag_key] = tag_value
262255
return tags_dict
263256
return tags
264-
265-
266-
def strip_json_comments(json_string):
267-
current_index = 0
268-
length = len(json_string)
269-
result = []
270-
271-
def __is_escaped(json_string, char_index):
272-
backslash_count = 0
273-
index = char_index - 1
274-
while index >= 0 and json_string[index] == BACKSLASH:
275-
backslash_count += 1
276-
index -= 1
277-
278-
return backslash_count % 2 == 1
279-
280-
def __find_next_newline_index(json_string, start_index):
281-
index = start_index
282-
283-
while index < length:
284-
if json_string[index] == NEW_LINE:
285-
break
286-
287-
index += 1
288-
289-
return index
290-
291-
def __find_next_double_quote_index(json_string, start_index):
292-
index = start_index
293-
while index < length:
294-
if json_string[index] == DOUBLE_QUOTE and not __is_escaped(json_string, index):
295-
return index
296-
297-
index += 1
298-
299-
raise ValueError("Unterminated string literal")
300-
301-
def __find_next_multiline_comment_end(json_string, start_index):
302-
index = start_index
303-
while index < length - 1:
304-
if json_string[index:index + 2] == MULTILINE_COMMENT_END:
305-
return index + 1
306-
307-
index += 1
308-
309-
raise ValueError("Unterminated multi-line comment")
310-
311-
while current_index < length:
312-
# Single line comment
313-
if json_string[current_index:current_index + 2] == DOUBLE_SLASH:
314-
current_index = __find_next_newline_index(json_string, current_index)
315-
if current_index < length and json_string[current_index] == NEW_LINE:
316-
result.append(NEW_LINE)
317-
318-
# Multi-line comment
319-
elif json_string[current_index:current_index + 2] == MULTILINE_COMMENT_START:
320-
current_index = __find_next_multiline_comment_end(json_string, current_index + 2)
321-
322-
# String literal
323-
elif json_string[current_index] == DOUBLE_QUOTE:
324-
literal_start_index = current_index
325-
current_index = __find_next_double_quote_index(json_string, current_index + 1)
326-
327-
result.extend(json_string[literal_start_index:current_index + 1])
328-
else:
329-
result.append(json_string[current_index])
330-
331-
current_index += 1
332-
333-
return "".join(result)

src/azure-cli/azure/cli/command_modules/appconfig/keyvalue.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@
5252
ImportExportProfiles, CompareFieldsMap,
5353
JsonDiff, ImportMode)
5454
from ._featuremodels import map_keyvalue_to_featureflag
55+
from ._json import parse_json_with_comments
5556
from ._models import (convert_configurationsetting_to_keyvalue, convert_keyvalue_to_configurationsetting)
56-
from ._utils import get_appconfig_data_client, prep_filter_for_url_encoding, resolve_store_metadata, get_store_endpoint_from_connection_string, is_json_content_type, strip_json_comments
57+
from ._utils import get_appconfig_data_client, prep_filter_for_url_encoding, resolve_store_metadata, get_store_endpoint_from_connection_string, is_json_content_type
5758

5859
from ._diff_utils import print_preview, KVComparer
5960
from .feature import __list_features
@@ -510,7 +511,7 @@ def set_key(cmd,
510511
# Ensure that provided value is valid JSON and strip comments if needed.
511512
value = 'null' if value is None else value
512513

513-
__validate_json_input(value)
514+
parse_json_with_comments(value)
514515
except ValueError:
515516
raise CLIErrors.ValidationError('Value "{}" is not a valid JSON object, which conflicts with the content type "{}".'.format(value, content_type))
516517

@@ -525,7 +526,7 @@ def set_key(cmd,
525526
if is_json_content_type(content_type):
526527
try:
527528
# Ensure that provided value is valid JSON and strip comments if needed.
528-
__validate_json_input(value)
529+
parse_json_with_comments(value)
529530
except (TypeError, ValueError):
530531
raise CLIErrors.ValidationError('Value "{}" is not a valid JSON object, which conflicts with the content type "{}". Set the value again in valid JSON format.'.format(value, content_type))
531532
set_kv = ConfigurationSetting(key=key,
@@ -985,12 +986,3 @@ def list_revision(cmd,
985986
return retrieved_revisions
986987
except HttpResponseError as ex:
987988
raise CLIErrors.AzureResponseError('List revision operation failed.\n' + str(ex))
988-
989-
990-
# Helper function to validate JSON input that may contain comments
991-
def __validate_json_input(json_string):
992-
try:
993-
json.loads(json_string)
994-
995-
except json.JSONDecodeError:
996-
json.loads(strip_json_comments(json_string))

src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_json_content_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,13 @@ def test_azconfig_json_content_type(self, resource_group, location):
473473

474474
class AppConfigJsonCommentsTest(TestCase):
475475
def test_azconfig_strip_json_comments(self):
476-
from azure.cli.command_modules.appconfig._utils import strip_json_comments
476+
from azure.cli.command_modules.appconfig._json import parse_json_with_comments
477477

478478
json_with_comments_file_path = os.path.join(TEST_DIR, 'json_with_comments.json')
479479
clean_json_file_path = os.path.join(TEST_DIR, 'json_with_comments_stripped.json')
480480

481481
with open(json_with_comments_file_path) as json_file:
482-
parsed_json = json.loads(strip_json_comments(json_file.read()))
482+
parsed_json = parse_json_with_comments(json_file.read())
483483

484484
with open(clean_json_file_path) as json_file:
485485
expected_json = json.load(json_file)

0 commit comments

Comments
 (0)