1 /**
2 License:
3 	Boost Software License - Version 1.0 - August 17th, 2003
4 
5 	Permission is hereby granted, free of charge, to any person or organization
6 	obtaining a copy of the software and accompanying documentation covered by
7 	this license (the "Software") to use, reproduce, display, distribute,
8 	execute, and transmit the Software, and to prepare derivative works of the
9 	Software, and to permit third-parties to whom the Software is furnished to
10 	do so, all subject to the following:
11 
12 	The copyright notices in the Software and this entire statement, including
13 	the above license grant, this restriction and the following disclaimer,
14 	must be included in all copies of the Software, in whole or in part, and
15 	all derivative works of the Software, unless such copies or derivative
16 	works are solely in the form of machine-executable object code generated by
17 	a source language processor.
18 
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28 	aermicioi
29 **/
30 module aermicioi.aedi_property_reader.json.json;
31 
32 import aermicioi.aedi.configurer.annotation.annotation;
33 import aermicioi.aedi.storage.storage;
34 import aermicioi.aedi.storage.locator;
35 import aermicioi.aedi_property_reader.json.accessor;
36 import aermicioi.aedi_property_reader.convertor.accessor;
37 import aermicioi.aedi_property_reader.core.core;
38 import aermicioi.aedi_property_reader.json.convertor;
39 import aermicioi.aedi_property_reader.json.inspector;
40 import aermicioi.aedi_property_reader.json.type_guesser;
41 import aermicioi.aedi_property_reader.convertor.convertor;
42 import aermicioi.aedi_property_reader.convertor.type_guesser;
43 import aermicioi.aedi_property_reader.core.document;
44 import aermicioi.aedi_property_reader.convertor.std_conv : StdConvStringPrebuiltConvertorsFactory;
45 import std.json;
46 import std.typecons;
47 import std.experimental.allocator;
48 import std.experimental.logger;
49 
50 auto JsonConvertors(JsonConvertor convertor, CombinedConvertor combined) {
51     combined.add(convertor);
52 };
53 
54 auto JsonArrayConvertors(CombinedConvertor convertor) {
55     import std.meta : AliasSeq;
56 
57     static foreach (FromType; AliasSeq!(JSONValue[])) {
58         static foreach (ToType; AliasSeq!(ScalarArrayConvertibleTypes, StringArrayConvertibleTypes)) {
59             convertor.add(new RangeToArrayConvertor!(ToType, FromType)(convertor));
60         }
61     }
62 };
63 
64 alias JsonDocumentContainer = PolicyDocument!(
65     JSONValue,
66     JSONValue,
67     WithContainerScanning!(
68         aermicioi.aedi_property_reader.core.config,
69         aermicioi.aedi_property_reader.json.type_guesser,
70         aermicioi.aedi_property_reader.json.accessor,
71         aermicioi.aedi_property_reader.json.setter,
72         aermicioi.aedi_property_reader.json.inspector,
73         aermicioi.aedi_property_reader.json.convertor,
74         aermicioi.aedi_property_reader.json.json
75     )(),
76     WithConvertorAggregation!CombinedConvertor(),
77     WithLocatorForUnregisteredComponents("json-document-locator"),
78     WithInitializer!(
79         StdConvStringPrebuiltConvertorsFactory
80     )(),
81     WithInitializer!(
82         JsonConvertors
83     )(),
84     WithInitializer!(
85         JsonArrayConvertors
86     )(),
87     WithDefaultRegisterers
88 );
89 
90 /**
91 Create a convertor container with data source being json document.
92 
93 Params:
94     value = source of data for container to use to construct components.
95     accessor = property accessing logic
96     guesser = type guesser based on held json value
97     allocator = allocator used to allocate converted values
98 Returns:
99     JsonConvertorContainer
100 **/
101 auto json(
102     JSONValue value = JSONValue()
103 ) {
104 
105     JsonDocumentContainer container = JsonDocumentContainer(value);
106 
107     return container;
108 }
109 
110 /**
111 Create a convertor container with data source being json document.
112 
113 Params:
114     pathOrData = path to source of data or source data itself in form of string for container to use to construct components.
115     returnEmpty = wheter to return or not a locator with empty data source
116 Returns:
117     JsonConvertorContainer
118 **/
119 auto json(string pathOrData, bool returnEmpty = true) {
120     import std.file : exists, readText;
121 
122     debug(trace) trace("Loading json document from ", pathOrData);
123     debug(trace) trace("Checking if ", pathOrData, " is a json file");
124     if (pathOrData.exists) {
125 
126         debug(trace) trace("Loading json from ", pathOrData);
127         pathOrData = pathOrData.readText();
128     }
129 
130     try {
131 
132         debug(trace) trace("Attempting to parse ", pathOrData, " as json");
133         return json(parseJSON(pathOrData));
134     } catch (Exception e) {
135 
136         debug(trace) trace("Failed to parse json");
137         if (returnEmpty) {
138 
139             debug(trace) trace("Returning empty container");
140             return json();
141         }
142 
143         throw new Exception(
144             "Could not create json convertor container from file or content passed in pathOrData: " ~ pathOrData,
145             e
146         );
147     }
148 }