@qooxdoo/framework 7.0.0-beta.5 → 7.0.0-beta.6

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/Manifest.json +1 -1
  3. package/README.md +7 -3
  4. package/lib/compiler/compile-info.json +67 -67
  5. package/lib/compiler/index.js +2176 -1397
  6. package/lib/resource/qx/tool/loadsass.js +6 -4
  7. package/package.json +15 -2
  8. package/source/class/qx/io/__init__.js +5 -3
  9. package/source/class/qx/io/exception/Cancel.js +34 -0
  10. package/source/class/qx/io/exception/Exception.js +38 -0
  11. package/source/class/qx/io/exception/Protocol.js +26 -0
  12. package/source/class/qx/io/exception/Transport.js +39 -0
  13. package/source/class/qx/io/exception/__init__.js +4 -0
  14. package/source/class/qx/io/graphql/Client.js +112 -0
  15. package/source/class/qx/io/graphql/__init__.js +9 -0
  16. package/source/class/qx/io/graphql/protocol/Message.js +65 -0
  17. package/source/class/qx/io/graphql/protocol/Request.js +95 -0
  18. package/source/class/qx/io/graphql/protocol/Response.js +61 -0
  19. package/source/class/qx/io/graphql/protocol/__init__.js +6 -0
  20. package/source/class/qx/io/jsonrpc/Client.js +323 -0
  21. package/source/class/qx/io/jsonrpc/__init__.js +15 -0
  22. package/source/class/qx/io/jsonrpc/protocol/Batch.js +97 -0
  23. package/source/class/qx/io/jsonrpc/protocol/Error.js +63 -0
  24. package/source/class/qx/io/jsonrpc/protocol/Message.js +48 -0
  25. package/source/class/qx/io/jsonrpc/protocol/Notification.js +45 -0
  26. package/source/class/qx/io/jsonrpc/protocol/Parser.js +81 -0
  27. package/source/class/qx/io/jsonrpc/protocol/Request.js +93 -0
  28. package/source/class/qx/io/jsonrpc/protocol/Result.js +48 -0
  29. package/source/class/qx/io/jsonrpc/protocol/__init__.js +5 -0
  30. package/source/class/qx/io/request/authentication/Bearer.js +52 -0
  31. package/source/class/qx/io/transport/AbstractClient.js +100 -0
  32. package/source/class/qx/io/transport/AbstractTransport.js +41 -0
  33. package/source/class/qx/io/transport/Fetch.js +95 -0
  34. package/source/class/qx/io/transport/ITransport.js +40 -0
  35. package/source/class/qx/io/transport/PostMessage.js +55 -0
  36. package/source/class/qx/io/transport/Websocket.js +97 -0
  37. package/source/class/qx/io/transport/Xhr.js +139 -0
  38. package/source/class/qx/io/transport/__init__.js +18 -0
  39. package/source/class/qx/test/io/MAssert.js +46 -0
  40. package/source/class/qx/test/io/graphql/Client.js +169 -0
  41. package/source/class/qx/test/io/graphql/ClientFetch.js +34 -0
  42. package/source/class/qx/test/io/graphql/Request.js +42 -0
  43. package/source/class/qx/test/io/jsonrpc/Client.js +267 -0
  44. package/source/class/qx/test/io/jsonrpc/Protocol.js +80 -0
  45. package/source/class/qx/test/io/transport/PostMessage.js +56 -0
  46. package/source/class/qx/test/io/transport/Websocket.js +63 -0
  47. package/source/class/qx/test/ui/embed/Iframe.js +1 -1
  48. package/source/class/qx/test/util/DateFormat.js +45 -6
  49. package/source/class/qx/tool/cli/commands/Compile.js +3 -3
  50. package/source/class/qx/tool/cli/commands/package/Publish.js +14 -0
  51. package/source/class/qx/tool/compiler/makers/AppMaker.js +2 -1
  52. package/source/class/qx/tool/compiler/targets/Target.js +2 -1
  53. package/source/class/qx/tool/compiler/targets/meta/PolyfillJs.js +11 -3
  54. package/source/class/qx/ui/form/ComboBox.js +8 -3
  55. package/source/class/qx/ui/form/MenuButton.js +8 -4
  56. package/source/class/qx/ui/form/SelectBox.js +8 -3
  57. package/source/class/qx/ui/menu/AbstractButton.js +12 -8
  58. package/source/class/qx/ui/menu/Menu.js +18 -8
  59. package/source/class/qx/ui/table/pane/Model.js +10 -4
  60. package/source/class/qx/util/format/DateFormat.js +44 -17
  61. package/source/resource/qx/tool/loadsass.js +6 -4
  62. package/source/translation/hr.po +297 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The implementation of a HTTP Transport using the {@link qx.io.request} API,
3
+ * so any special configuration of the HTTP request must be done on the
4
+ * underlying implementation of {@link qx.io.request.AbstractRequest}.
5
+ *
6
+ * The assumption is that the payload will be JSON in both request and response.
7
+ * If that is not what you want, override the {@link #_createTransportImpl()} method.
8
+ *
9
+ */
10
+ qx.Class.define("qx.io.transport.Xhr", {
11
+ extend: qx.io.transport.AbstractTransport,
12
+ implement : qx.io.transport.ITransport,
13
+
14
+ /**
15
+ * Constructor.
16
+ *
17
+ * @param {String} url The URL of the http endpoint
18
+ */
19
+ construct(url) {
20
+ this.base(arguments, url);
21
+ },
22
+
23
+ members: {
24
+
25
+ /**
26
+ * Internal implementation of the transport
27
+ * @var {qx.io.request.Xhr}
28
+ */
29
+ __tranportImpl : null,
30
+
31
+ /**
32
+ * Returns the object which implements the transport on the
33
+ * underlying level, so that transport-specific configuration
34
+ * can be done on it. Note that since in the HTTP transport,
35
+ * this object cannot be reused, it will return a new object
36
+ * each time which will be used in the immediately next request.
37
+ *
38
+ * @return {qx.io.request.Xhr}
39
+ */
40
+ getTransportImpl() {
41
+ this.__tranportImpl = this._createTransportImpl();
42
+ return this.__tranportImpl;
43
+ },
44
+
45
+ /**
46
+ * Transport the given message to the endpoint
47
+ *
48
+ * @param {String} message
49
+ *
50
+ * @return {qx.Promise} Promise that resolves (with no data)
51
+ * when the message has been successfully sent out, and rejects
52
+ * when there is an error or a cancellation up to that point.
53
+ */
54
+ async send(message) {
55
+ qx.core.Assert.assertString(message);
56
+ const req = this.__tranportImpl || this.getTransportImpl();
57
+ req.setRequestData(message);
58
+ this.__tranportImpl = null; // free the internal reference for the next request
59
+ try {
60
+ await req.sendWithPromise();
61
+ } catch (e) {
62
+ if (e instanceof qx.type.BaseError) {
63
+ switch (e.getComment()) {
64
+ case "timeout":
65
+ throw new qx.io.exception.Transport(
66
+ e.toString(),
67
+ qx.io.exception.Transport.TIMEOUT,
68
+ {message}
69
+ );
70
+ case "parseError":
71
+ throw new qx.io.exception.Transport(
72
+ e.toString(),
73
+ qx.io.exception.Transport.INVALID_MSG_DATA,
74
+ {message}
75
+ );
76
+ case "abort":
77
+ throw new qx.io.exception.Cancel(
78
+ e.toString(),
79
+ {message}
80
+ );
81
+ case "statusError":
82
+ if (req.getStatus() === 400) {
83
+ // "400 Bad Request" is a really a protocol error (syntax error)
84
+ break;
85
+ }
86
+ // fallthrough
87
+ case "error":
88
+ throw new qx.io.exception.Transport(
89
+ e.toString(),
90
+ qx.io.exception.Transport.FAILED,
91
+ {
92
+ message,
93
+ response: req.getResponse()
94
+ }
95
+ );
96
+ default:
97
+ // unknown error
98
+ throw new qx.io.exception.Exception(
99
+ e.toString(),
100
+ undefined,
101
+ {message, error:e}
102
+ );
103
+ }
104
+ }
105
+ }
106
+ // notify listeners
107
+ this.fireDataEvent("message", req.getResponse());
108
+ // discard old object
109
+ req.dispose();
110
+ },
111
+
112
+ /**
113
+ * Factory method to create a request object. By default, a POST
114
+ * request will be made, and the expected response type will be
115
+ * "application/json", but differently to the standard behavior,
116
+ * the response will not be parsed into a javascript object.
117
+ *
118
+ * Classes extending this one may override this method to obtain
119
+ * a Request object with different parameters and/or different
120
+ * authentication settings. The object must be a subclass of {@link
121
+ * qx.io.request.AbstractRequest} or implement its public API.
122
+ *
123
+ * @return {qx.io.request.Xhr}
124
+ */
125
+ _createTransportImpl() {
126
+ const req = new qx.io.request.Xhr(this.getEndpoint(), "POST");
127
+ req.setAccept("application/json");
128
+ req.setCache(false);
129
+ req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
130
+ // disable parsing, we are going to parse the JSON ourselves
131
+ req.setParser(response => response);
132
+ return req;
133
+ }
134
+ },
135
+
136
+ defer() {
137
+ qx.io.jsonrpc.Client.registerTransport(/^http/, qx.io.transport.Xhr);
138
+ }
139
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * <p>This namespace contains an interface for and different implementations of
3
+ * a transport for higher-level protocol data.</p>
4
+ *
5
+ * <p>{@link qx.io.transport.ITransport} specifies that a
6
+ * transport has to provide for three things:</p>
7
+ * <ol>
8
+ * <li>It must have an "endpoint" property which is a representation of the
9
+ * the endpoint. In most cases, it will be an URI which identifies where the
10
+ * the server is located, but it can also be an object with which the transport
11
+ * can interact.</li>
12
+ * <li>It must have a "send" method which knows how to deliver an UTF-8
13
+ * encoded message string to the endpoint, and</li>
14
+ * <li>It must fire a "message" event when it receives such a message from
15
+ * the peer, regardless if this message is a normal "response" (like in a
16
+ * HTTP request) or an incoming message in a duplex communication channel.</li>
17
+ * </ol>
18
+ */
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Mixin containing special assert methods
3
+ */
4
+ qx.Mixin.define("qx.test.io.MAssert", {
5
+
6
+ members : {
7
+
8
+ /**
9
+ * Deep equal comparison, using Sinon's `deepEqual` comparison.
10
+ * Two values are "deep equal" if:
11
+ *
12
+ * - They are equal, according to samsam.identical
13
+ * (https://sinonjs.github.io/samsam/)
14
+ * - They are both date objects representing the same time
15
+ * - They are both arrays containing elements that are all deepEqual
16
+ * - They are objects with the same set of properties, and each property
17
+ * in obj1 is deepEqual to the corresponding property in obj2
18
+ *
19
+ * Supports cyclic objects.
20
+ * @param {*} expected
21
+ * @param {*} actual
22
+ * @param {String?} msg
23
+ */
24
+ assertDeepEquals : function(expected, actual, msg) {
25
+ if (!msg) {
26
+ msg = `Failed to assert that ${qx.lang.Json.stringify(actual)} deeply equals ${qx.lang.Json.stringify(expected)}.`;
27
+ }
28
+ this.assert(qx.dev.unit.Sinon.getSinon().deepEqual(expected, actual), msg);
29
+ },
30
+
31
+ /**
32
+ * Asserts that a string fragment is contained in a result
33
+ * @param {String} expectedFragment
34
+ * @param {String} actual
35
+ * @param {String?} msg
36
+ */
37
+ assertContains: function(expectedFragment, actual, msg) {
38
+ this.assertString(expectedFragment);
39
+ this.assertString(actual);
40
+ if (!msg) {
41
+ msg = `Failed to assert that '${actual}' contains '${expectedFragment}'.`;
42
+ }
43
+ this.assert(actual.includes(expectedFragment), msg);
44
+ }
45
+ }
46
+ });
@@ -0,0 +1,169 @@
1
+ /* ************************************************************************
2
+
3
+ qooxdoo - the new era of web development
4
+
5
+ http://qooxdoo.org
6
+
7
+ Copyright:
8
+ 2020 Christian Boulanger
9
+
10
+ License:
11
+ MIT: https://opensource.org/licenses/MIT
12
+ See the LICENSE file in the project's top-level directory for details.
13
+
14
+ Authors:
15
+ * Christian Boulanger (cboulanger)
16
+
17
+ ************************************************************************ */
18
+
19
+ /**
20
+ * @require(qx.io.transport.Xhr)
21
+ * @ignore(fetch)
22
+ */
23
+ qx.Class.define("qx.test.io.graphql.Client",
24
+ {
25
+ extend : qx.dev.unit.TestCase,
26
+ include : [qx.test.io.MAssert],
27
+ statics: {
28
+ TEST_ENDPOINT: "https://countries.trevorblades.com/"
29
+ },
30
+ construct() {
31
+ this.base(arguments);
32
+ let transport = new qx.io.transport.Xhr(this.constructor.TEST_ENDPOINT);
33
+ transport.getTransportImpl();
34
+ this.client = new qx.io.graphql.Client(transport);
35
+ },
36
+
37
+ members : {
38
+
39
+ __hasEndpoint: false,
40
+ __skipMsg: "Skipping test as endpoint is not available.",
41
+
42
+ async runQuery(query, expected) {
43
+ let req = new qx.io.graphql.protocol.Request({query});
44
+ let result = await this.client.send(req);
45
+ this.assertDeepEquals(expected, result)
46
+ },
47
+
48
+ async runQueryWithVariables(query, variables, expected) {
49
+ let req = new qx.io.graphql.protocol.Request({query});
50
+ req.setVariables(variables);
51
+ let result = await this.client.send(req);
52
+ this.assertDeepEquals(expected, result)
53
+ },
54
+
55
+ async "test: check endpoint"() {
56
+ try {
57
+ let url = this.constructor.TEST_ENDPOINT;
58
+ let body = '{"query":"{__typename}"}';
59
+ let init = {method:"POST", headers:{"Content-Type":"application/json"}, body};
60
+ let response = await fetch(url, init);
61
+ let result = await response.json();
62
+ this.assertDeepEquals({
63
+ "data": {
64
+ "__typename": "Query"
65
+ }
66
+ }, result);
67
+ this.__hasEndpoint = true;
68
+ } catch(e) {
69
+ console.error(`Endpoint ${this.constructor.TEST_ENDPOINT} is not accessible: ${e.message}`);
70
+ }
71
+ },
72
+
73
+ async "test: execute query"() {
74
+ if (!this.__hasEndpoint) {
75
+ return this.skip(this.__skipMsg);
76
+ }
77
+ await this.runQuery(`{
78
+ country(code: "BR") {
79
+ name
80
+ native
81
+ capital
82
+ currency
83
+ languages {
84
+ code
85
+ name
86
+ }
87
+ }
88
+ }`, {
89
+ "country": {
90
+ "name": "Brazil",
91
+ "native": "Brasil",
92
+ "capital": "Brasília",
93
+ "currency": "BRL",
94
+ "languages": [
95
+ {
96
+ "code": "pt",
97
+ "name": "Portuguese"
98
+ }
99
+ ]
100
+ }
101
+ });
102
+ },
103
+
104
+ async "test: execute query with variables"() {
105
+ if (!this.__hasEndpoint) {
106
+ return this.skip(this.__skipMsg);
107
+ }
108
+ await this.runQueryWithVariables(`query ($countryCode:ID!){
109
+ country(code: $countryCode) {
110
+ name
111
+ languages {
112
+ code
113
+ name
114
+ }
115
+ }
116
+ }`,
117
+ {"countryCode": "BE"},
118
+ {
119
+ "country": {
120
+ "name": "Belgium",
121
+ "languages": [
122
+ {
123
+ "code": "nl",
124
+ "name": "Dutch"
125
+ },
126
+ {
127
+ "code": "fr",
128
+ "name": "French"
129
+ },
130
+ {
131
+ "code": "de",
132
+ "name": "German"
133
+ }
134
+ ]
135
+ }
136
+ });
137
+ },
138
+
139
+ async "test: expect error after invalid query"() {
140
+ if (!this.__hasEndpoint) {
141
+ return this.skip(this.__skipMsg);
142
+ }
143
+ try {
144
+ await this.runQuery(`query { invalidSyntax }`);
145
+ } catch (e) {
146
+ this.assertInstance(e, qx.io.exception.Protocol);
147
+ this.assertContains("invalidSyntax", JSON.stringify(e.data));
148
+ return;
149
+ }
150
+ throw new Error("Query should return an error after invalid query");
151
+ },
152
+
153
+ async "test: expect transport error"() {
154
+ if (!this.__hasEndpoint) {
155
+ return this.skip(this.__skipMsg);
156
+ }
157
+ try {
158
+ const client = new qx.io.graphql.Client("https://doesnotexist.org/"+Math.random());
159
+ const query = "query { doesnotmatter }";
160
+ const request = new qx.io.graphql.protocol.Request({query});
161
+ await client.send(request);
162
+ } catch (e) {
163
+ this.assertInstance(e, qx.io.exception.Transport);
164
+ return;
165
+ }
166
+ throw new Error("Query should throw qx.io.exception.Transport");
167
+ }
168
+ }
169
+ });
@@ -0,0 +1,34 @@
1
+ /* ************************************************************************
2
+
3
+ qooxdoo - the new era of web development
4
+
5
+ http://qooxdoo.org
6
+
7
+ Copyright:
8
+ 2020 Christian Boulanger
9
+
10
+ License:
11
+ MIT: https://opensource.org/licenses/MIT
12
+ See the LICENSE file in the project's top-level directory for details.
13
+
14
+ Authors:
15
+ * Christian Boulanger (cboulanger)
16
+
17
+ ************************************************************************ */
18
+
19
+ /**
20
+ * GraphQL tests using the Fetch API
21
+ */
22
+ qx.Class.define("qx.test.io.graphql.ClientFetch",
23
+ {
24
+ extend : qx.test.io.graphql.Client,
25
+ statics: {
26
+ TEST_ENDPOINT: "https://countries.trevorblades.com/"
27
+ },
28
+ construct() {
29
+ this.base(arguments);
30
+ let transport = new qx.io.transport.Fetch(this.constructor.TEST_ENDPOINT);
31
+ transport.getTransportImpl();
32
+ this.client = new qx.io.graphql.Client(transport);
33
+ }
34
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @require(qx.io.transport.Xhr)
3
+ */
4
+ qx.Class.define("qx.test.io.graphql.Request", {
5
+ extend: qx.dev.unit.TestCase,
6
+ include: [qx.test.io.MAssert],
7
+
8
+ members: {
9
+
10
+ "test: request can be converted to json": function() {
11
+ const query = "query { SomeRandomStuff }";
12
+ const variables = {"testKey": "testValue"};
13
+
14
+ const request = new qx.io.graphql.protocol.Request({query});
15
+ request.setVariables(variables);
16
+
17
+ const expected = "{\"query\":\"query { SomeRandomStuff }\",\"variables\":{\"testKey\":\"testValue\"}}";
18
+ this.assertEquals(expected, request.toString());
19
+ },
20
+
21
+ "test: no variables in the final string": function() {
22
+ const query = "query { SomeRandomStuff }";
23
+ const request = new qx.io.graphql.protocol.Request({query});
24
+ const expected = "{\"query\":\"query { SomeRandomStuff }\"}";
25
+ this.assertEquals(expected, request.toString());
26
+ },
27
+
28
+ "test: variables can be bound": function() {
29
+ const query = "query { SomeRandomStuff }";
30
+ const variables = {"testKey": "testValue"};
31
+ const request = new qx.io.graphql.protocol.Request({query});
32
+ request.setVariables(variables);
33
+
34
+ const model = qx.data.marshal.Json.createModel({source: "test"});
35
+ model.bind("source", request, "variables.testKey");
36
+ model.setSource("newTestValue");
37
+
38
+ this.assertMatch(request.toString(), /newTestValue/);
39
+ }
40
+ }
41
+ });
42
+