@matdata/yasr 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -0
- package/build/ts/src/bindingsToCsv.d.ts +2 -0
- package/build/ts/src/defaults.d.ts +2 -0
- package/build/ts/src/helpers/addCSS.d.ts +1 -0
- package/build/ts/src/helpers/addScript.d.ts +1 -0
- package/build/ts/src/helpers/index.d.ts +3 -0
- package/build/ts/src/helpers/sanitize.d.ts +2 -0
- package/build/ts/src/imgs.d.ts +4 -0
- package/build/ts/src/index.d.ts +130 -0
- package/build/ts/src/parsers/csv.d.ts +2 -0
- package/build/ts/src/parsers/index.d.ts +68 -0
- package/build/ts/src/parsers/json.d.ts +2 -0
- package/build/ts/src/parsers/tsv.d.ts +2 -0
- package/build/ts/src/parsers/turtleFamily.d.ts +4 -0
- package/build/ts/src/parsers/xml.d.ts +2 -0
- package/build/ts/src/plugins/boolean/index.d.ts +13 -0
- package/build/ts/src/plugins/error/index.d.ts +13 -0
- package/build/ts/src/plugins/index.d.ts +19 -0
- package/build/ts/src/plugins/response/index.d.ts +28 -0
- package/build/ts/src/plugins/table/index.d.ts +49 -0
- package/build/yasr.html +32 -0
- package/build/yasr.min.css +2 -0
- package/build/yasr.min.css.map +1 -0
- package/build/yasr.min.js +3 -0
- package/build/yasr.min.js.LICENSE.txt +34 -0
- package/build/yasr.min.js.map +1 -0
- package/package.json +56 -0
- package/src/bin/takeScreenshot.js +373 -0
- package/src/bindingsToCsv.ts +18 -0
- package/src/defaults.ts +28 -0
- package/src/helpers/addCSS.ts +7 -0
- package/src/helpers/addScript.ts +12 -0
- package/src/helpers/index.ts +3 -0
- package/src/helpers/sanitize.ts +11 -0
- package/src/imgs.ts +7 -0
- package/src/index.ts +688 -0
- package/src/jquery/extendJquery.js +1 -0
- package/src/jquery/tableToCsv.js +88 -0
- package/src/main.scss +229 -0
- package/src/parsers/csv.ts +30 -0
- package/src/parsers/index.ts +311 -0
- package/src/parsers/json.ts +22 -0
- package/src/parsers/tsv.ts +43 -0
- package/src/parsers/turtleFamily.ts +60 -0
- package/src/parsers/xml.ts +79 -0
- package/src/plugins/boolean/index.scss +11 -0
- package/src/plugins/boolean/index.ts +42 -0
- package/src/plugins/error/index.scss +57 -0
- package/src/plugins/error/index.ts +124 -0
- package/src/plugins/index.ts +24 -0
- package/src/plugins/response/index.scss +63 -0
- package/src/plugins/response/index.ts +170 -0
- package/src/plugins/table/index.scss +154 -0
- package/src/plugins/table/index.ts +437 -0
- package/src/scss/global.scss +10 -0
- package/src/scss/variables.scss +2 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var $ = require("jquery");
|
|
3
|
+
|
|
4
|
+
$.fn.tableToCsv = function (config) {
|
|
5
|
+
var csvString = "";
|
|
6
|
+
config = $.extend(
|
|
7
|
+
{
|
|
8
|
+
quote: '"',
|
|
9
|
+
delimiter: ",",
|
|
10
|
+
lineBreak: "\n",
|
|
11
|
+
},
|
|
12
|
+
config
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
var needToQuoteString = function (value) {
|
|
16
|
+
//quote when it contains whitespace or the delimiter
|
|
17
|
+
var needQuoting = false;
|
|
18
|
+
if (value.match("[\\w|" + config.delimiter + "|" + config.quote + "]")) {
|
|
19
|
+
needQuoting = true;
|
|
20
|
+
}
|
|
21
|
+
return needQuoting;
|
|
22
|
+
};
|
|
23
|
+
var addValueToString = function (value) {
|
|
24
|
+
//Quotes in the string need to be escaped
|
|
25
|
+
value.replace(config.quote, config.quote + config.quote);
|
|
26
|
+
if (needToQuoteString(value)) {
|
|
27
|
+
value = config.quote + value + config.quote;
|
|
28
|
+
}
|
|
29
|
+
csvString += " " + value + " " + config.delimiter;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
var addRowToString = function (rowArray) {
|
|
33
|
+
rowArray.forEach(function (val) {
|
|
34
|
+
addValueToString(val);
|
|
35
|
+
});
|
|
36
|
+
csvString += config.lineBreak;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
var tableArrays = [];
|
|
40
|
+
var $el = $(this);
|
|
41
|
+
var rowspans = {};
|
|
42
|
+
|
|
43
|
+
var totalColCount = 0;
|
|
44
|
+
$el.find("tr:first *").each(function () {
|
|
45
|
+
if ($(this).attr("colspan")) {
|
|
46
|
+
totalColCount += +$(this).attr("colspan");
|
|
47
|
+
} else {
|
|
48
|
+
totalColCount++;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
$el.find("tr").each(function (rowId, tr) {
|
|
53
|
+
var $tr = $(tr);
|
|
54
|
+
var rowArray = [];
|
|
55
|
+
|
|
56
|
+
var htmlColId = 0;
|
|
57
|
+
var actualColId = 0;
|
|
58
|
+
while (actualColId < totalColCount) {
|
|
59
|
+
if (rowspans[actualColId]) {
|
|
60
|
+
rowArray.push(rowspans[actualColId].text);
|
|
61
|
+
rowspans[actualColId].rowSpan--;
|
|
62
|
+
if (!rowspans[actualColId].rowSpan) rowspans[actualColId] = null;
|
|
63
|
+
actualColId++;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var $cell = $tr.find(":nth-child(" + (htmlColId + 1) + ")");
|
|
68
|
+
if (!$cell) break;
|
|
69
|
+
var colspan = $cell.attr("colspan") || 1;
|
|
70
|
+
var rowspan = $cell.attr("rowspan") || 1;
|
|
71
|
+
|
|
72
|
+
for (var i = 0; i < colspan; i++) {
|
|
73
|
+
rowArray.push($cell.text());
|
|
74
|
+
if (rowspan > 1) {
|
|
75
|
+
rowspans[actualColId] = {
|
|
76
|
+
rowSpan: rowspan - 1,
|
|
77
|
+
text: $cell.text(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
actualColId++;
|
|
81
|
+
}
|
|
82
|
+
htmlColId++;
|
|
83
|
+
}
|
|
84
|
+
addRowToString(rowArray);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return csvString;
|
|
88
|
+
};
|
package/src/main.scss
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
@use "scss/variables.scss";
|
|
2
|
+
.yasr {
|
|
3
|
+
.yasr_btn {
|
|
4
|
+
border: none;
|
|
5
|
+
background: inherit;
|
|
6
|
+
}
|
|
7
|
+
.svgImg {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
svg {
|
|
11
|
+
max-width: 100%;
|
|
12
|
+
max-height: 100%;
|
|
13
|
+
width: 15px;
|
|
14
|
+
height: 15px;
|
|
15
|
+
align-self: center;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
.yasr_btn.yasr_external_ref_btn {
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
user-select: none;
|
|
21
|
+
// Active and focus shouldn't color the button since it'll open a new page
|
|
22
|
+
&:active,
|
|
23
|
+
&:focus {
|
|
24
|
+
color: inherit;
|
|
25
|
+
text-decoration-color: inherit;
|
|
26
|
+
}
|
|
27
|
+
.svgImg svg {
|
|
28
|
+
width: 18px;
|
|
29
|
+
height: 18px;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
a {
|
|
33
|
+
color: #428bca;
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
&:hover,
|
|
36
|
+
&:active {
|
|
37
|
+
outline: 0;
|
|
38
|
+
color: #2a6496;
|
|
39
|
+
text-decoration: underline;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
.yasr_btnGroup {
|
|
43
|
+
margin: 0;
|
|
44
|
+
padding: 0;
|
|
45
|
+
list-style: none;
|
|
46
|
+
display: flex;
|
|
47
|
+
overflow-x: auto;
|
|
48
|
+
overflow-y: hidden; // We shouldn't wrap, and therefore never draw a vertical scrollBar
|
|
49
|
+
.plugin_icon {
|
|
50
|
+
height: 15px;
|
|
51
|
+
width: 15px;
|
|
52
|
+
margin-right: 5px;
|
|
53
|
+
text-align: center;
|
|
54
|
+
}
|
|
55
|
+
.yasr_btn {
|
|
56
|
+
// redeclared here to target yasr_btns in btnGroup
|
|
57
|
+
border-bottom: 2px solid transparent;
|
|
58
|
+
&.selected {
|
|
59
|
+
border-bottom: 2px solid #337ab7;
|
|
60
|
+
}
|
|
61
|
+
padding-left: 6px;
|
|
62
|
+
padding-right: 6px;
|
|
63
|
+
margin-left: 6px;
|
|
64
|
+
margin-right: 6px;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Default med screen +
|
|
69
|
+
@media (max-width: 768px) {
|
|
70
|
+
.yasr_btn {
|
|
71
|
+
span {
|
|
72
|
+
display: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.plugin_icon {
|
|
76
|
+
margin-right: 0px;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.yasr_header {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-wrap: wrap;
|
|
84
|
+
}
|
|
85
|
+
.yasr_fallback_info:not(:empty) {
|
|
86
|
+
margin-top: 5px;
|
|
87
|
+
border: 1px solid #d1d1d1;
|
|
88
|
+
padding: 0.5rem;
|
|
89
|
+
background: #f7f7f7;
|
|
90
|
+
p {
|
|
91
|
+
margin: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
.yasr_help_variable {
|
|
95
|
+
background: #dff0ff;
|
|
96
|
+
color: #428bca;
|
|
97
|
+
}
|
|
98
|
+
.yasr_response_chip {
|
|
99
|
+
color: #505050;
|
|
100
|
+
background: #f5f5f5;
|
|
101
|
+
border-radius: 6px;
|
|
102
|
+
display: flex;
|
|
103
|
+
font-size: 11pt;
|
|
104
|
+
max-height: 16pt;
|
|
105
|
+
align-self: center;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
padding: 6px 6px;
|
|
110
|
+
margin-left: 5px;
|
|
111
|
+
overflow: visible;
|
|
112
|
+
box-sizing: border-box;
|
|
113
|
+
&.empty {
|
|
114
|
+
display: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
.yasr_plugin_control {
|
|
118
|
+
display: flex;
|
|
119
|
+
margin-left: auto;
|
|
120
|
+
align-items: center;
|
|
121
|
+
&:empty {
|
|
122
|
+
display: none;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
.yasr_btn {
|
|
126
|
+
color: #505050;
|
|
127
|
+
fill: #505050;
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
|
|
132
|
+
cursor: pointer;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
padding: 6px 12px;
|
|
135
|
+
// border-radius: 4px;
|
|
136
|
+
overflow: visible;
|
|
137
|
+
box-sizing: border-box;
|
|
138
|
+
&.btn_icon {
|
|
139
|
+
padding: 4px 8px;
|
|
140
|
+
}
|
|
141
|
+
&[disabled],
|
|
142
|
+
&.disabled {
|
|
143
|
+
cursor: default;
|
|
144
|
+
opacity: 0.5;
|
|
145
|
+
box-shadow: none;
|
|
146
|
+
}
|
|
147
|
+
&:not(.disabled):hover {
|
|
148
|
+
fill: black;
|
|
149
|
+
color: black;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.yasr_fullscreenButton {
|
|
154
|
+
border: none;
|
|
155
|
+
background: none;
|
|
156
|
+
|
|
157
|
+
svg {
|
|
158
|
+
height: 20px;
|
|
159
|
+
width: 20px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.fullscreenExitIcon {
|
|
163
|
+
display: none;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
&.fullscreen {
|
|
168
|
+
position: fixed;
|
|
169
|
+
top: 0;
|
|
170
|
+
left: 0;
|
|
171
|
+
right: 0;
|
|
172
|
+
bottom: 0;
|
|
173
|
+
z-index: 9999;
|
|
174
|
+
background: white;
|
|
175
|
+
margin: 0;
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
|
|
179
|
+
.yasr_fullscreenButton {
|
|
180
|
+
.fullscreenIcon {
|
|
181
|
+
display: none;
|
|
182
|
+
}
|
|
183
|
+
.fullscreenExitIcon {
|
|
184
|
+
display: block;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.yasr_results {
|
|
189
|
+
flex: 1;
|
|
190
|
+
overflow: auto;
|
|
191
|
+
}
|
|
192
|
+
&:focus,
|
|
193
|
+
&.selected {
|
|
194
|
+
color: #337ab7;
|
|
195
|
+
fill: #337ab7;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.yasr_loading_indicator {
|
|
200
|
+
display: none;
|
|
201
|
+
align-items: center;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
padding: 4px 8px;
|
|
204
|
+
margin-left: 5px;
|
|
205
|
+
|
|
206
|
+
.yasr_loading_spinner {
|
|
207
|
+
width: 20px;
|
|
208
|
+
height: 20px;
|
|
209
|
+
border: 3px solid #f3f3f3;
|
|
210
|
+
border-top: 3px solid #337ab7;
|
|
211
|
+
border-radius: 50%;
|
|
212
|
+
animation: yasr_spin 0.8s linear infinite;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@keyframes yasr_spin {
|
|
216
|
+
0% {
|
|
217
|
+
transform: rotate(0deg);
|
|
218
|
+
}
|
|
219
|
+
100% {
|
|
220
|
+
transform: rotate(360deg);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.space_element {
|
|
226
|
+
flex-grow: 1;
|
|
227
|
+
min-width: 10px;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Parser from "./";
|
|
2
|
+
import * as Papa from "papaparse";
|
|
3
|
+
|
|
4
|
+
export default function (csvString: string) {
|
|
5
|
+
const csvStringToJsonObject = Papa.parse(csvString, { header: true, skipEmptyLines: true });
|
|
6
|
+
if (csvStringToJsonObject.meta.fields === undefined) {
|
|
7
|
+
throw new Error("Could not parse CSV, no headers found!");
|
|
8
|
+
}
|
|
9
|
+
const header = csvStringToJsonObject.meta.fields;
|
|
10
|
+
const lines = csvStringToJsonObject.data as Record<string, string>[];
|
|
11
|
+
|
|
12
|
+
const sparqlData = lines.map((row) => {
|
|
13
|
+
const bindingObject: Parser.Binding = {};
|
|
14
|
+
for (const variable in row) {
|
|
15
|
+
bindingObject[variable] = { value: row[variable], type: "literal" };
|
|
16
|
+
}
|
|
17
|
+
return bindingObject;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const sparqlResults: Parser.SparqlResults = {
|
|
21
|
+
head: {
|
|
22
|
+
vars: header,
|
|
23
|
+
},
|
|
24
|
+
results: {
|
|
25
|
+
bindings: sparqlData,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return sparqlResults;
|
|
30
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import SparqlJsonParser from "./json";
|
|
2
|
+
import TurtleParser, { getTurtleAsStatements } from "./turtleFamily";
|
|
3
|
+
import SparqlXmlParser from "./xml";
|
|
4
|
+
import SparqlCsvParser from "./csv";
|
|
5
|
+
import SparqlTsvParser from "./tsv";
|
|
6
|
+
import bindingsToCsv from "../bindingsToCsv";
|
|
7
|
+
import { cloneDeep } from "lodash-es";
|
|
8
|
+
import N3 from "n3";
|
|
9
|
+
|
|
10
|
+
namespace Parser {
|
|
11
|
+
export interface ErrorSummary {
|
|
12
|
+
status?: number;
|
|
13
|
+
text: string;
|
|
14
|
+
statusText?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface BindingValue {
|
|
17
|
+
value: string;
|
|
18
|
+
type: "uri" | "literal" | "typed-literal" | "bnode";
|
|
19
|
+
datatype?: string;
|
|
20
|
+
"xml:lang"?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface Binding {
|
|
23
|
+
[varname: string]: BindingValue;
|
|
24
|
+
}
|
|
25
|
+
export interface SparqlResults {
|
|
26
|
+
head: {
|
|
27
|
+
vars: string[];
|
|
28
|
+
};
|
|
29
|
+
boolean?: boolean;
|
|
30
|
+
results?: {
|
|
31
|
+
bindings: Binding[];
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//a json response summary, that we can store in localstorage
|
|
35
|
+
export interface ResponseSummary {
|
|
36
|
+
data?: any;
|
|
37
|
+
error?: ErrorSummary;
|
|
38
|
+
status?: number;
|
|
39
|
+
contentType?: string;
|
|
40
|
+
executionTime?: number;
|
|
41
|
+
}
|
|
42
|
+
export type PostProcessBinding = (binding: Binding) => Binding;
|
|
43
|
+
}
|
|
44
|
+
const applyMustacheToLiterals: Parser.PostProcessBinding = (binding: Parser.Binding) => {
|
|
45
|
+
for (const lit in binding) {
|
|
46
|
+
if (binding[lit].type === "uri") continue;
|
|
47
|
+
binding[lit].value = binding[lit].value.replace(/{{(.*?)}}/g, (variable) => {
|
|
48
|
+
variable = variable.substring(2, variable.length - 2).trim();
|
|
49
|
+
if (binding[variable]) {
|
|
50
|
+
return binding[variable].value;
|
|
51
|
+
} else {
|
|
52
|
+
return variable;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return binding;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Response object from a fetch request with an additional `.content` property containing the awaited response content
|
|
61
|
+
*/
|
|
62
|
+
type QueryResponse = Response & {
|
|
63
|
+
content: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parser class for handling query responses from various formats.
|
|
68
|
+
*
|
|
69
|
+
* This class processes responses from SPARQL endpoints and converts them into standardized formats for further processing.
|
|
70
|
+
* It can handle JSON, XML, CSV, TSV, and Turtle responses, detecting the format either from content-type headers
|
|
71
|
+
* or by attempting to parse the content.
|
|
72
|
+
*
|
|
73
|
+
* The parser can process:
|
|
74
|
+
* - Direct `QueryResponse` objects (regular fetch response with additional content property with the awaited response content)
|
|
75
|
+
* - ResponseSummary objects
|
|
76
|
+
* - Error objects
|
|
77
|
+
* - Raw response data
|
|
78
|
+
*
|
|
79
|
+
* It provides methods to access parsed data in standardized formats, error information,
|
|
80
|
+
* and utilities to convert the data for storage or export.
|
|
81
|
+
*/
|
|
82
|
+
class Parser {
|
|
83
|
+
private res: QueryResponse | undefined;
|
|
84
|
+
private summary: Parser.ResponseSummary | undefined;
|
|
85
|
+
private errorSummary: Parser.ErrorSummary | undefined;
|
|
86
|
+
private error: Error | undefined;
|
|
87
|
+
private type: "json" | "xml" | "csv" | "tsv" | "ttl" | undefined;
|
|
88
|
+
private executionTime: number | undefined;
|
|
89
|
+
|
|
90
|
+
constructor(responseOrObject: Parser.ResponseSummary | QueryResponse | Error | any, executionTime?: number) {
|
|
91
|
+
if (responseOrObject.executionTime) this.executionTime = responseOrObject.executionTime;
|
|
92
|
+
if (executionTime) this.executionTime = executionTime; // Parameter has priority
|
|
93
|
+
if (responseOrObject instanceof Error) {
|
|
94
|
+
this.error = responseOrObject;
|
|
95
|
+
} else if ((<any>responseOrObject).content) {
|
|
96
|
+
this.setResponse(<QueryResponse>responseOrObject);
|
|
97
|
+
} else {
|
|
98
|
+
this.setSummary(<Parser.ResponseSummary>responseOrObject);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
public setResponse(res: QueryResponse) {
|
|
102
|
+
this.res = res;
|
|
103
|
+
}
|
|
104
|
+
public setSummary(summary: Parser.ResponseSummary | any) {
|
|
105
|
+
if (!summary.data && !summary.error) {
|
|
106
|
+
//This isnt a summary object, just try to recreate a summary object ourselves (assuming we're just passed a sparql-result object directly)
|
|
107
|
+
this.summary = {
|
|
108
|
+
data: summary,
|
|
109
|
+
};
|
|
110
|
+
} else {
|
|
111
|
+
this.summary = summary;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public hasError() {
|
|
116
|
+
if (this.res && this.res.status >= 400) return true;
|
|
117
|
+
if (this.errorSummary) return true;
|
|
118
|
+
if (this.error) return true;
|
|
119
|
+
if (this.summary && this.summary.error) return true;
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
public getError() {
|
|
123
|
+
if (!this.errorSummary) {
|
|
124
|
+
if (this.res && this.res.status >= 400) {
|
|
125
|
+
this.errorSummary = {
|
|
126
|
+
text: this.res.statusText,
|
|
127
|
+
status: this.res.status,
|
|
128
|
+
statusText: !this.res.ok ? this.res.statusText : undefined,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (this.summary && this.summary.error) {
|
|
132
|
+
this.errorSummary = this.summary.error;
|
|
133
|
+
}
|
|
134
|
+
if (this.error) {
|
|
135
|
+
this.errorSummary = {
|
|
136
|
+
text: this.error.message,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return this.errorSummary;
|
|
141
|
+
}
|
|
142
|
+
public getContentType() {
|
|
143
|
+
if (this.res) return this.res.headers.get("content-type") || undefined;
|
|
144
|
+
if (this.summary) return this.summary.contentType;
|
|
145
|
+
}
|
|
146
|
+
private json: false | Parser.SparqlResults | undefined;
|
|
147
|
+
getAsJson() {
|
|
148
|
+
if (this.json) return this.json;
|
|
149
|
+
if (this.json === false || this.hasError()) return; //already tried parsing this, and failed. do not try again...
|
|
150
|
+
if (this.getParserFromContentType()) return this.json;
|
|
151
|
+
if (this.doLuckyGuess()) return this.json;
|
|
152
|
+
|
|
153
|
+
if (!this.json) this.json = false; //explicitly set to false, so we don't try to parse this thing again..
|
|
154
|
+
return this.json;
|
|
155
|
+
}
|
|
156
|
+
private getData(): any {
|
|
157
|
+
if (this.res) {
|
|
158
|
+
if (this.res.content) return this.res.content;
|
|
159
|
+
if (this.res.body) return this.res.body;
|
|
160
|
+
if (this.res.text) return this.res.text; //probably a construct or something
|
|
161
|
+
}
|
|
162
|
+
if (this.summary) return this.summary.data;
|
|
163
|
+
}
|
|
164
|
+
public getResponseTime() {
|
|
165
|
+
return this.executionTime;
|
|
166
|
+
}
|
|
167
|
+
private getParserFromContentType(): boolean {
|
|
168
|
+
const contentType = this.getContentType();
|
|
169
|
+
if (contentType) {
|
|
170
|
+
const data = cloneDeep(this.getData());
|
|
171
|
+
try {
|
|
172
|
+
if (contentType.indexOf("json") > -1) {
|
|
173
|
+
if (contentType.indexOf("sparql-results+json") >= 0) {
|
|
174
|
+
this.json = SparqlJsonParser(data, applyMustacheToLiterals);
|
|
175
|
+
this.type = "json";
|
|
176
|
+
return true;
|
|
177
|
+
} else if (contentType.indexOf("application/rdf+json") > -1) {
|
|
178
|
+
this.type = "json";
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
this.type = "json";
|
|
182
|
+
} else if (contentType.indexOf("xml") > -1) {
|
|
183
|
+
this.json = SparqlXmlParser(data, applyMustacheToLiterals);
|
|
184
|
+
this.type = "xml";
|
|
185
|
+
return true;
|
|
186
|
+
} else if (contentType.indexOf("csv") > -1) {
|
|
187
|
+
this.json = SparqlCsvParser(data);
|
|
188
|
+
this.type = "csv";
|
|
189
|
+
return true;
|
|
190
|
+
} else if (contentType.indexOf("tab-separated") > -1) {
|
|
191
|
+
this.json = SparqlTsvParser(data);
|
|
192
|
+
this.type = "tsv";
|
|
193
|
+
return true;
|
|
194
|
+
} else if (
|
|
195
|
+
contentType.indexOf("turtle") > 0 ||
|
|
196
|
+
contentType.indexOf("trig") > 0 ||
|
|
197
|
+
contentType.indexOf("triple") > 0 ||
|
|
198
|
+
contentType.indexOf("quad") > 0
|
|
199
|
+
) {
|
|
200
|
+
this.json = TurtleParser(data);
|
|
201
|
+
this.type = "ttl";
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
if (e instanceof Error) {
|
|
206
|
+
this.errorSummary = { text: e.message };
|
|
207
|
+
} else {
|
|
208
|
+
this.errorSummary = { text: e as any };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
private doLuckyGuess(): boolean {
|
|
215
|
+
const data = cloneDeep(this.getData());
|
|
216
|
+
try {
|
|
217
|
+
this.json = SparqlJsonParser(data, applyMustacheToLiterals);
|
|
218
|
+
this.type = "json";
|
|
219
|
+
return true;
|
|
220
|
+
} catch {}
|
|
221
|
+
try {
|
|
222
|
+
this.json = SparqlXmlParser(data, applyMustacheToLiterals);
|
|
223
|
+
this.type = "xml";
|
|
224
|
+
return true;
|
|
225
|
+
} catch {}
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public getVariables(): string[] {
|
|
230
|
+
const json = this.getAsJson();
|
|
231
|
+
|
|
232
|
+
if (json && json.head) return json.head.vars;
|
|
233
|
+
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
public getBoolean(): boolean | undefined {
|
|
238
|
+
const json = this.getAsJson();
|
|
239
|
+
if (json && "boolean" in json) return json.boolean;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public getBindings() {
|
|
243
|
+
const json = this.getAsJson();
|
|
244
|
+
if (json && json.results) return json.results.bindings;
|
|
245
|
+
else return null;
|
|
246
|
+
}
|
|
247
|
+
private statements: false | N3.Quad[] | undefined;
|
|
248
|
+
public getStatements() {
|
|
249
|
+
if (!this.statements && this.type === "ttl") {
|
|
250
|
+
this.statements = getTurtleAsStatements(this.getData());
|
|
251
|
+
}
|
|
252
|
+
if (this.statements) return this.statements;
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
getOriginalResponseAsString(): string {
|
|
256
|
+
const data = this.getData();
|
|
257
|
+
if (typeof data === "string") {
|
|
258
|
+
return data;
|
|
259
|
+
} else if (this.type === "json") {
|
|
260
|
+
return JSON.stringify(data, undefined, 2);
|
|
261
|
+
}
|
|
262
|
+
return data;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
getType() {
|
|
266
|
+
if (!this.type) this.getAsJson(); //detects type as well
|
|
267
|
+
return this.type;
|
|
268
|
+
}
|
|
269
|
+
getStatus(): number | undefined {
|
|
270
|
+
if (this.res) return this.res.status;
|
|
271
|
+
if (this.summary) return this.summary.status;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
//process the input parameters in such a way that we can store it in local storage (i.e., no function)
|
|
275
|
+
//and, make sure we can easily pass it on back to this wrapper function when loading it again from storage
|
|
276
|
+
//When an object is too large to store, this method returns undefined
|
|
277
|
+
public getAsStoreObject(maxResponseSize: number): Parser.ResponseSummary | undefined {
|
|
278
|
+
let summary = this.summary;
|
|
279
|
+
if (!summary && this.res) {
|
|
280
|
+
summary = {
|
|
281
|
+
contentType: this.getContentType(),
|
|
282
|
+
data: this.getOriginalResponseAsString(),
|
|
283
|
+
error: this.getError(),
|
|
284
|
+
status: this.getStatus(),
|
|
285
|
+
executionTime: this.getResponseTime(),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (summary) {
|
|
289
|
+
//if data is set, it should be less than max limit. If not set, it's probably a response error that we'd like to store as well
|
|
290
|
+
if (summary.data && summary.data.length > maxResponseSize) {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
return summary;
|
|
294
|
+
}
|
|
295
|
+
if (this.error) {
|
|
296
|
+
return {
|
|
297
|
+
error: this.getError(),
|
|
298
|
+
executionTime: this.getResponseTime(),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public asCsv() {
|
|
304
|
+
const json = this.getAsJson();
|
|
305
|
+
if (this.type === "csv") return this.getOriginalResponseAsString();
|
|
306
|
+
if (json && json.results) {
|
|
307
|
+
return bindingsToCsv(json);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
export default Parser;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Parser from "./";
|
|
2
|
+
export default function (queryResponse: any, postProcessBinding: Parser.PostProcessBinding): Parser.SparqlResults {
|
|
3
|
+
if (typeof queryResponse == "string") {
|
|
4
|
+
const json = JSON.parse(queryResponse);
|
|
5
|
+
if (postProcessBinding) {
|
|
6
|
+
for (const binding in json.results.bindings) {
|
|
7
|
+
json.results.bindings[binding] = postProcessBinding(json.results.bindings[binding]);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return json;
|
|
11
|
+
}
|
|
12
|
+
if (typeof queryResponse == "object" && queryResponse.constructor === {}.constructor) {
|
|
13
|
+
// an ASK-query only returns a "boolean" field so we should check if are undefined here
|
|
14
|
+
if (postProcessBinding && queryResponse.results) {
|
|
15
|
+
for (const binding in queryResponse.results.bindings) {
|
|
16
|
+
queryResponse.results.bindings[binding] = postProcessBinding(queryResponse.results.bindings[binding]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return queryResponse;
|
|
20
|
+
}
|
|
21
|
+
throw new Error("Could not parse json");
|
|
22
|
+
}
|