on develop help sign in
Updating
a6b3ec1Brendan Hay
gen/gozen-gen.cabal+10−2
@@ -21,11 +21,15 @@ executable gozen-gen
21 main-is: Main.hs
21 main-is: Main.hs
22
22
23 other-modules:
23 other-modules:
24+ Gen.AST
24− Gen.Formatting
25+ , Gen.Formatting
25 , Gen.IO
26 , Gen.IO
26 , Gen.JSON
27 , Gen.JSON
27− , Gen.Types
28+ , Gen.Syntax
29+ , Gen.Text
28 , Gen.Tree
30 , Gen.Tree
31+ , Gen.Types
32+ , Gen.Types.Map
29 , Gen.Types.NS
33 , Gen.Types.NS
30
34
31 ghc-options: -Wall -threaded
35 ghc-options: -Wall -threaded
@@ -40,7 +44,11 @@ executable gozen-gen
40 , ede
44 , ede
41 , errors
45 , errors
42 , formatting
46 , formatting
47+ , hashable
48+ , haskell-src-exts
49+ , hindent
43 , lens
50 , lens
51+ , mmorph
44 , mtl
52 , mtl
45 , optparse-applicative
53 , optparse-applicative
46 , semigroups
54 , semigroups
gen/model/youtubeanalytics/youtubeanalytics/v1beta1/youtubeanalytics-api.json+724−724
@@ -1,727 +1,727 @@
1{
1{
2− "kind": "discovery#restDescription",
2+ "kind": "discovery#restDescription",
3− "etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/wzHkxHWEX9PcW7ZnULAilfkQsbM\"",
3+ "etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/wzHkxHWEX9PcW7ZnULAilfkQsbM\"",
4− "discoveryVersion": "v1",
4+ "discoveryVersion": "v1",
5− "id": "youtubeAnalytics:v1beta1",
5+ "id": "youtubeAnalytics:v1beta1",
6− "name": "youtubeAnalytics",
6+ "name": "youtubeAnalytics",
7− "canonicalName": "YouTube Analytics",
7+ "canonicalName": "YouTube Analytics",
8− "version": "v1beta1",
8+ "version": "v1beta1",
9− "revision": "20150304",
9+ "revision": "20150304",
10− "title": "YouTube Analytics API",
10+ "title": "YouTube Analytics API",
11− "description": "Retrieve your YouTube Analytics reports.",
11+ "description": "Retrieve your YouTube Analytics reports.",
12− "ownerDomain": "google.com",
12+ "ownerDomain": "google.com",
13− "ownerName": "Google",
13+ "ownerName": "Google",
14− "icons": {
14+ "icons": {
15− "x16": "https://www.google.com/images/icons/product/youtube-16.png",
15+ "x16": "https://www.google.com/images/icons/product/youtube-16.png",
16− "x32": "https://www.google.com/images/icons/product/youtube-32.png"
16+ "x32": "https://www.google.com/images/icons/product/youtube-32.png"
17− },
17+ },
18− "documentationLink": "http://developers.google.com/youtube/analytics/",
18+ "documentationLink": "http://developers.google.com/youtube/analytics/",
19− "labels": [
19+ "labels": [
20− "deprecated"
20+ "deprecated"
21− ],
21+ ],
22− "protocol": "rest",
22+ "protocol": "rest",
23− "baseUrl": "https://www.googleapis.com/youtube/analytics/v1beta1/",
23+ "baseUrl": "https://www.googleapis.com/youtube/analytics/v1beta1/",
24− "basePath": "/youtube/analytics/v1beta1/",
24+ "basePath": "/youtube/analytics/v1beta1/",
25− "rootUrl": "https://www.googleapis.com/",
25+ "rootUrl": "https://www.googleapis.com/",
26− "servicePath": "youtube/analytics/v1beta1/",
26+ "servicePath": "youtube/analytics/v1beta1/",
27− "batchPath": "batch",
27+ "batchPath": "batch",
28− "parameters": {
28+ "parameters": {
29− "alt": {
29+ "alt": {
30− "type": "string",
30+ "type": "string",
31− "description": "Data format for the response.",
31+ "description": "Data format for the response.",
32− "default": "json",
32+ "default": "json",
33− "enum": [
33+ "enum": [
34− "csv",
34+ "csv",
35− "json"
35+ "json"
36− ],
36+ ],
37− "enumDescriptions": [
37+ "enumDescriptions": [
38− "Responses with Content-Type of text/csv",
38+ "Responses with Content-Type of text/csv",
39− "Responses with Content-Type of application/json"
39+ "Responses with Content-Type of application/json"
40− ],
40+ ],
41− "location": "query"
41+ "location": "query"
42− },
42+ },
43− "fields": {
43+ "fields": {
44− "type": "string",
44+ "type": "string",
45− "description": "Selector specifying which fields to include in a partial response.",
45+ "description": "Selector specifying which fields to include in a partial response.",
46− "location": "query"
46+ "location": "query"
47− },
47+ },
48− "key": {
48+ "key": {
49− "type": "string",
49+ "type": "string",
50− "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
50+ "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.",
51− "location": "query"
51+ "location": "query"
52− },
52+ },
53− "oauth_token": {
53+ "oauth_token": {
54− "type": "string",
54+ "type": "string",
55− "description": "OAuth 2.0 token for the current user.",
55+ "description": "OAuth 2.0 token for the current user.",
56− "location": "query"
56+ "location": "query"
57− },
57+ },
58− "prettyPrint": {
58+ "prettyPrint": {
59− "type": "boolean",
59+ "type": "boolean",
60− "description": "Returns response with indentations and line breaks.",
60+ "description": "Returns response with indentations and line breaks.",
61− "default": "true",
61+ "default": "true",
62− "location": "query"
62+ "location": "query"
63− },
63+ },
64− "quotaUser": {
64+ "quotaUser": {
65− "type": "string",
65+ "type": "string",
66− "description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
66+ "description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided.",
67− "location": "query"
67+ "location": "query"
68− },
68+ },
69− "userIp": {
69+ "userIp": {
70− "type": "string",
70+ "type": "string",
71− "description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
71+ "description": "IP address of the site where the request originates. Use this if you want to enforce per-user limits.",
72− "location": "query"
72+ "location": "query"
73− }
73+ }
74− },
74+ },
75− "auth": {
75+ "auth": {
76− "oauth2": {
76+ "oauth2": {
77− "scopes": {
77+ "scopes": {
78− "https://www.googleapis.com/auth/youtube": {
78+ "https://www.googleapis.com/auth/youtube": {
79− "description": "Manage your YouTube account"
79+ "description": "Manage your YouTube account"
80− },
80+ },
81− "https://www.googleapis.com/auth/youtube.readonly": {
81+ "https://www.googleapis.com/auth/youtube.readonly": {
82− "description": "View your YouTube account"
82+ "description": "View your YouTube account"
83− },
83+ },
84− "https://www.googleapis.com/auth/youtubepartner": {
84+ "https://www.googleapis.com/auth/youtubepartner": {
85− "description": "View and manage your assets and associated content on YouTube"
85+ "description": "View and manage your assets and associated content on YouTube"
86− },
86+ },
87− "https://www.googleapis.com/auth/yt-analytics-monetary.readonly": {
87+ "https://www.googleapis.com/auth/yt-analytics-monetary.readonly": {
88− "description": "View monetary and non-monetary YouTube Analytics reports for your YouTube content"
88+ "description": "View monetary and non-monetary YouTube Analytics reports for your YouTube content"
89− },
89+ },
90− "https://www.googleapis.com/auth/yt-analytics.readonly": {
90+ "https://www.googleapis.com/auth/yt-analytics.readonly": {
91− "description": "View YouTube Analytics reports for your YouTube content"
91+ "description": "View YouTube Analytics reports for your YouTube content"
92− }
92+ }
93− }
93+ }
94− }
94+ }
95− },
95+ },
96− "schemas": {
96+ "schemas": {
97− "BatchReport": {
97+ "BatchReport": {
98− "id": "BatchReport",
98+ "id": "BatchReport",
99− "type": "object",
99+ "type": "object",
100− "description": "Contains single batchReport resource.",
100+ "description": "Contains single batchReport resource.",
101− "properties": {
101+ "properties": {
102− "id": {
102+ "id": {
103− "type": "string",
103+ "type": "string",
104− "description": "The ID that YouTube assigns and uses to uniquely identify the report."
104+ "description": "The ID that YouTube assigns and uses to uniquely identify the report."
105− },
105+ },
106− "kind": {
106+ "kind": {
107− "type": "string",
107+ "type": "string",
108− "description": "This value specifies the type of data of this item. For batch report the kind property value is youtubeAnalytics#batchReport.",
108+ "description": "This value specifies the type of data of this item. For batch report the kind property value is youtubeAnalytics#batchReport.",
109− "default": "youtubeAnalytics#batchReport"
109+ "default": "youtubeAnalytics#batchReport"
110− },
110+ },
111− "outputs": {
111+ "outputs": {
112− "type": "array",
112+ "type": "array",
113− "description": "Report outputs.",
113+ "description": "Report outputs.",
114− "items": {
114+ "items": {
115− "type": "object",
115+ "type": "object",
116− "properties": {
116+ "properties": {
117− "downloadUrl": {
117+ "downloadUrl": {
118− "type": "string",
118+ "type": "string",
119− "description": "Cloud storage URL to download this report. This URL is valid for 30 minutes."
119+ "description": "Cloud storage URL to download this report. This URL is valid for 30 minutes."
120− },
120+ },
121− "format": {
121+ "format": {
122− "type": "string",
122+ "type": "string",
123− "description": "Format of the output."
123+ "description": "Format of the output."
124− },
124+ },
125− "type": {
125+ "type": {
126− "type": "string",
126+ "type": "string",
127− "description": "Type of the output.",
127+ "description": "Type of the output.",
128− "default": "cloudStorageOutput"
128+ "default": "cloudStorageOutput"
129− }
129+ }
130− }
130+ }
131− }
131+ }
132− },
132+ },
133− "reportId": {
133+ "reportId": {
134− "type": "string",
134+ "type": "string",
135− "description": "The ID of the the report definition."
135+ "description": "The ID of the the report definition."
136− },
136+ },
137− "timeSpan": {
137+ "timeSpan": {
138− "type": "object",
138+ "type": "object",
139− "description": "Period included in the report. For reports containing all entities endTime is not set. Both startTime and endTime are inclusive.",
139+ "description": "Period included in the report. For reports containing all entities endTime is not set. Both startTime and endTime are inclusive.",
140− "properties": {
140+ "properties": {
141− "endTime": {
141+ "endTime": {
142− "type": "string",
142+ "type": "string",
143− "description": "End of the period included in the report. Inclusive. For reports containing all entities endTime is not set.",
143+ "description": "End of the period included in the report. Inclusive. For reports containing all entities endTime is not set.",
144− "format": "date-time"
144+ "format": "date-time"
145− },
145+ },
146− "startTime": {
146+ "startTime": {
147− "type": "string",
147+ "type": "string",
148− "description": "Start of the period included in the report. Inclusive.",
148+ "description": "Start of the period included in the report. Inclusive.",
149− "format": "date-time"
149+ "format": "date-time"
150− }
150+ }
151− }
151+ }
152− },
152+ },
153− "timeUpdated": {
153+ "timeUpdated": {
154− "type": "string",
154+ "type": "string",
155− "description": "The time when the report was updated.",
155+ "description": "The time when the report was updated.",
156− "format": "date-time"
156+ "format": "date-time"
157− }
157+ }
158− }
158+ }
159− },
159+ },
160− "BatchReportDefinition": {
160+ "BatchReportDefinition": {
161− "id": "BatchReportDefinition",
161+ "id": "BatchReportDefinition",
162− "type": "object",
162+ "type": "object",
163− "description": "Contains single batchReportDefinition resource.",
163+ "description": "Contains single batchReportDefinition resource.",
164− "properties": {
164+ "properties": {
165− "id": {
165+ "id": {
166− "type": "string",
166+ "type": "string",
167− "description": "The ID that YouTube assigns and uses to uniquely identify the report definition."
167+ "description": "The ID that YouTube assigns and uses to uniquely identify the report definition."
168− },
168+ },
169− "kind": {
169+ "kind": {
170− "type": "string",
170+ "type": "string",
171− "description": "This value specifies the type of data of this item. For batch report definition the kind property value is youtubeAnalytics#batchReportDefinition.",
171+ "description": "This value specifies the type of data of this item. For batch report definition the kind property value is youtubeAnalytics#batchReportDefinition.",
172− "default": "youtubeAnalytics#batchReportDefinition"
172+ "default": "youtubeAnalytics#batchReportDefinition"
173− },
173+ },
174− "name": {
174+ "name": {
175− "type": "string",
175+ "type": "string",
176− "description": "Name of the report definition."
176+ "description": "Name of the report definition."
177− },
177+ },
178− "status": {
178+ "status": {
179− "type": "string",
179+ "type": "string",
180− "description": "Status of the report definition."
180+ "description": "Status of the report definition."
181− },
181+ },
182− "type": {
182+ "type": {
183− "type": "string",
183+ "type": "string",
184− "description": "Type of the report definition."
184+ "description": "Type of the report definition."
185− }
185+ }
186− }
186+ }
187− },
187+ },
188− "BatchReportDefinitionList": {
188+ "BatchReportDefinitionList": {
189− "id": "BatchReportDefinitionList",
189+ "id": "BatchReportDefinitionList",
190− "type": "object",
190+ "type": "object",
191− "description": "A paginated list of batchReportDefinition resources returned in response to a youtubeAnalytics.batchReportDefinitions.list request.",
191+ "description": "A paginated list of batchReportDefinition resources returned in response to a youtubeAnalytics.batchReportDefinitions.list request.",
192− "properties": {
192+ "properties": {
193− "items": {
193+ "items": {
194− "type": "array",
194+ "type": "array",
195− "description": "A list of batchReportDefinition resources that match the request criteria.",
195+ "description": "A list of batchReportDefinition resources that match the request criteria.",
196− "items": {
196+ "items": {
197− "$ref": "BatchReportDefinition"
197+ "$ref": "BatchReportDefinition"
198− }
198+ }
199− },
199+ },
200− "kind": {
200+ "kind": {
201− "type": "string",
201+ "type": "string",
202− "description": "This value specifies the type of data included in the API response. For the list method, the kind property value is youtubeAnalytics#batchReportDefinitionList.",
202+ "description": "This value specifies the type of data included in the API response. For the list method, the kind property value is youtubeAnalytics#batchReportDefinitionList.",
203− "default": "youtubeAnalytics#batchReportDefinitionList"
203+ "default": "youtubeAnalytics#batchReportDefinitionList"
204− }
204+ }
205− }
205+ }
206− },
206+ },
207− "BatchReportList": {
207+ "BatchReportList": {
208− "id": "BatchReportList",
208+ "id": "BatchReportList",
209− "type": "object",
209+ "type": "object",
210− "description": "A paginated list of batchReport resources returned in response to a youtubeAnalytics.batchReport.list request.",
210+ "description": "A paginated list of batchReport resources returned in response to a youtubeAnalytics.batchReport.list request.",
211− "properties": {
211+ "properties": {
212− "items": {
212+ "items": {
213− "type": "array",
213+ "type": "array",
214− "description": "A list of batchReport resources that match the request criteria.",
214+ "description": "A list of batchReport resources that match the request criteria.",
215− "items": {
215+ "items": {
216− "$ref": "BatchReport"
216+ "$ref": "BatchReport"
217− }
217+ }
218− },
218+ },
219− "kind": {
219+ "kind": {
220− "type": "string",
220+ "type": "string",
221− "description": "This value specifies the type of data included in the API response. For the list method, the kind property value is youtubeAnalytics#batchReportList.",
221+ "description": "This value specifies the type of data included in the API response. For the list method, the kind property value is youtubeAnalytics#batchReportList.",
222− "default": "youtubeAnalytics#batchReportList"
222+ "default": "youtubeAnalytics#batchReportList"
223− }
223+ }
224− }
224+ }
225− },
225+ },
226− "Group": {
226+ "Group": {
227− "id": "Group",
227+ "id": "Group",
228− "type": "object",
228+ "type": "object",
229− "properties": {
229+ "properties": {
230− "contentDetails": {
230+ "contentDetails": {
231− "type": "object",
231+ "type": "object",
232− "properties": {
232+ "properties": {
233− "itemCount": {
233+ "itemCount": {
234− "type": "string",
234+ "type": "string",
235− "format": "uint64"
235+ "format": "uint64"
236− },
236+ },
237− "itemType": {
237+ "itemType": {
238− "type": "string"
238+ "type": "string"
239− }
239+ }
240− }
240+ }
241− },
241+ },
242− "etag": {
242+ "etag": {
243− "type": "string"
243+ "type": "string"
244− },
244+ },
245− "id": {
245+ "id": {
246− "type": "string"
246+ "type": "string"
247− },
247+ },
248− "kind": {
248+ "kind": {
249− "type": "string",
249+ "type": "string",
250− "default": "youtube#group"
250+ "default": "youtube#group"
251− },
251+ },
252− "snippet": {
252+ "snippet": {
253− "type": "object",
253+ "type": "object",
254− "properties": {
254+ "properties": {
255− "publishedAt": {
255+ "publishedAt": {
256− "type": "string",
256+ "type": "string",
257− "format": "date-time"
257+ "format": "date-time"
258− },
258+ },
259− "title": {
259+ "title": {
260− "type": "string"
260+ "type": "string"
261− }
261+ }
262− }
262+ }
263− }
263+ }
264− }
264+ }
265− },
265+ },
266− "GroupItem": {
266+ "GroupItem": {
267− "id": "GroupItem",
267+ "id": "GroupItem",
268− "type": "object",
268+ "type": "object",
269− "properties": {
269+ "properties": {
270− "etag": {
270+ "etag": {
271− "type": "string"
271+ "type": "string"
272− },
272+ },
273− "groupId": {
273+ "groupId": {
274− "type": "string"
274+ "type": "string"
275− },
275+ },
276− "id": {
276+ "id": {
277− "type": "string"
277+ "type": "string"
278− },
278+ },
279− "kind": {
279+ "kind": {
280− "type": "string",
280+ "type": "string",
281− "default": "youtube#groupItem"
281+ "default": "youtube#groupItem"
282− },
282+ },
283− "resource": {
283+ "resource": {
284− "type": "object",
284+ "type": "object",
285− "properties": {
285+ "properties": {
286− "id": {
286+ "id": {
287− "type": "string"
287+ "type": "string"
288− },
288+ },
289− "kind": {
289+ "kind": {
290− "type": "string"
290+ "type": "string"
291− }
291+ }
292− }
292+ }
293− }
293+ }
294− }
294+ }
295− },
295+ },
296− "GroupItemListResponse": {
296+ "GroupItemListResponse": {
297− "id": "GroupItemListResponse",
297+ "id": "GroupItemListResponse",
298− "type": "object",
298+ "type": "object",
299− "description": "A paginated list of grouList resources returned in response to a youtubeAnalytics.groupApi.list request.",
299+ "description": "A paginated list of grouList resources returned in response to a youtubeAnalytics.groupApi.list request.",
300− "properties": {
300+ "properties": {
301− "etag": {
301+ "etag": {
302− "type": "string"
302+ "type": "string"
303− },
303+ },
304− "items": {
304+ "items": {
305− "type": "array",
305+ "type": "array",
306− "items": {
306+ "items": {
307− "$ref": "GroupItem"
307+ "$ref": "GroupItem"
308− }
308+ }
309− },
309+ },
310− "kind": {
310+ "kind": {
311− "type": "string",
311+ "type": "string",
312− "default": "youtube#groupItemListResponse"
312+ "default": "youtube#groupItemListResponse"
313− }
313+ }
314− }
314+ }
315− },
315+ },
316− "GroupListResponse": {
316+ "GroupListResponse": {
317− "id": "GroupListResponse",
317+ "id": "GroupListResponse",
318− "type": "object",
318+ "type": "object",
319− "description": "A paginated list of grouList resources returned in response to a youtubeAnalytics.groupApi.list request.",
319+ "description": "A paginated list of grouList resources returned in response to a youtubeAnalytics.groupApi.list request.",
320− "properties": {
320+ "properties": {
321− "etag": {
321+ "etag": {
322− "type": "string"
322+ "type": "string"
323− },
323+ },
324− "items": {
324+ "items": {
325− "type": "array",
325+ "type": "array",
326− "items": {
326+ "items": {
327− "$ref": "Group"
327+ "$ref": "Group"
328− }
328+ }
329− },
329+ },
330− "kind": {
330+ "kind": {
331− "type": "string",
331+ "type": "string",
332− "default": "youtube#groupListResponse"
332+ "default": "youtube#groupListResponse"
333− }
333+ }
334− }
334+ }
335− },
335+ },
336− "ResultTable": {
336+ "ResultTable": {
337− "id": "ResultTable",
337+ "id": "ResultTable",
338− "type": "object",
338+ "type": "object",
339− "description": "Contains a single result table. The table is returned as an array of rows that contain the values for the cells of the table. Depending on the metric or dimension, the cell can contain a string (video ID, country code) or a number (number of views or number of likes).",
339+ "description": "Contains a single result table. The table is returned as an array of rows that contain the values for the cells of the table. Depending on the metric or dimension, the cell can contain a string (video ID, country code) or a number (number of views or number of likes).",
340− "properties": {
340+ "properties": {
341− "columnHeaders": {
341+ "columnHeaders": {
342− "type": "array",
342+ "type": "array",
343− "description": "This value specifies information about the data returned in the rows fields. Each item in the columnHeaders list identifies a field returned in the rows value, which contains a list of comma-delimited data. The columnHeaders list will begin with the dimensions specified in the API request, which will be followed by the metrics specified in the API request. The order of both dimensions and metrics will match the ordering in the API request. For example, if the API request contains the parameters dimensions=ageGroup,gender&metrics=viewerPercentage, the API response will return columns in this order: ageGroup,gender,viewerPercentage.",
343+ "description": "This value specifies information about the data returned in the rows fields. Each item in the columnHeaders list identifies a field returned in the rows value, which contains a list of comma-delimited data. The columnHeaders list will begin with the dimensions specified in the API request, which will be followed by the metrics specified in the API request. The order of both dimensions and metrics will match the ordering in the API request. For example, if the API request contains the parameters dimensions=ageGroup,gender&metrics=viewerPercentage, the API response will return columns in this order: ageGroup,gender,viewerPercentage.",
344− "items": {
344+ "items": {
345− "type": "object",
345+ "type": "object",
346− "properties": {
346+ "properties": {
347− "columnType": {
347+ "columnType": {
348− "type": "string",
348+ "type": "string",
349− "description": "The type of the column (DIMENSION or METRIC)."
349+ "description": "The type of the column (DIMENSION or METRIC)."
350− },
350+ },
351− "dataType": {
351+ "dataType": {
352− "type": "string",
352+ "type": "string",
353− "description": "The type of the data in the column (STRING, INTEGER, FLOAT, etc.)."
353+ "description": "The type of the data in the column (STRING, INTEGER, FLOAT, etc.)."
354− },
354+ },
355− "name": {
355+ "name": {
356− "type": "string",
356+ "type": "string",
357− "description": "The name of the dimension or metric."
357+ "description": "The name of the dimension or metric."
358− }
358+ }
359− }
359+ }
360− }
360+ }
361− },
361+ },
362− "kind": {
362+ "kind": {
363− "type": "string",
363+ "type": "string",
364− "description": "This value specifies the type of data included in the API response. For the query method, the kind property value will be youtubeAnalytics#resultTable.",
364+ "description": "This value specifies the type of data included in the API response. For the query method, the kind property value will be youtubeAnalytics#resultTable.",
365− "default": "youtubeAnalytics#resultTable"
365+ "default": "youtubeAnalytics#resultTable"
366− },
366+ },
367− "rows": {
367+ "rows": {
368− "type": "array",
368+ "type": "array",
369− "description": "The list contains all rows of the result table. Each item in the list is an array that contains comma-delimited data corresponding to a single row of data. The order of the comma-delimited data fields will match the order of the columns listed in the columnHeaders field. If no data is available for the given query, the rows element will be omitted from the response. The response for a query with the day dimension will not contain rows for the most recent days.",
369+ "description": "The list contains all rows of the result table. Each item in the list is an array that contains comma-delimited data corresponding to a single row of data. The order of the comma-delimited data fields will match the order of the columns listed in the columnHeaders field. If no data is available for the given query, the rows element will be omitted from the response. The response for a query with the day dimension will not contain rows for the most recent days.",
370− "items": {
370+ "items": {
371− "type": "array",
371+ "type": "array",
372− "items": {
372+ "items": {
373− "type": "any"
373+ "type": "any"
374− }
374+ }
375− }
375+ }
376− }
376+ }
377− }
377+ }
378− }
378+ }
379− },
379+ },
380− "resources": {
380+ "resources": {
381− "batchReportDefinitions": {
381+ "batchReportDefinitions": {
382− "methods": {
382+ "methods": {
383− "list": {
383+ "list": {
384− "id": "youtubeAnalytics.batchReportDefinitions.list",
384+ "id": "youtubeAnalytics.batchReportDefinitions.list",
385− "path": "batchReportDefinitions",
385+ "path": "batchReportDefinitions",
386− "httpMethod": "GET",
386+ "httpMethod": "GET",
387− "description": "Retrieves a list of available batch report definitions.",
387+ "description": "Retrieves a list of available batch report definitions.",
388− "parameters": {
388+ "parameters": {
389− "onBehalfOfContentOwner": {
389+ "onBehalfOfContentOwner": {
390− "type": "string",
390+ "type": "string",
391− "description": "The onBehalfOfContentOwner parameter identifies the content owner that the user is acting on behalf of.",
391+ "description": "The onBehalfOfContentOwner parameter identifies the content owner that the user is acting on behalf of.",
392− "required": true,
392+ "required": true,
393− "location": "query"
393+ "location": "query"
394− }
394+ }
395− },
395+ },
396− "parameterOrder": [
396+ "parameterOrder": [
397− "onBehalfOfContentOwner"
397+ "onBehalfOfContentOwner"
398− ],
398+ ],
399− "response": {
399+ "response": {
400− "$ref": "BatchReportDefinitionList"
400+ "$ref": "BatchReportDefinitionList"
401− },
401+ },
402− "scopes": [
402+ "scopes": [
403− "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
403+ "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
404− "https://www.googleapis.com/auth/yt-analytics.readonly"
404+ "https://www.googleapis.com/auth/yt-analytics.readonly"
405− ]
405+ ]
406− }
406+ }
407− }
407+ }
408− },
408+ },
409− "batchReports": {
409+ "batchReports": {
410− "methods": {
410+ "methods": {
411− "list": {
411+ "list": {
412− "id": "youtubeAnalytics.batchReports.list",
412+ "id": "youtubeAnalytics.batchReports.list",
413− "path": "batchReports",
413+ "path": "batchReports",
414− "httpMethod": "GET",
414+ "httpMethod": "GET",
415− "description": "Retrieves a list of processed batch reports.",
415+ "description": "Retrieves a list of processed batch reports.",
416− "parameters": {
416+ "parameters": {
417− "batchReportDefinitionId": {
417+ "batchReportDefinitionId": {
418− "type": "string",
418+ "type": "string",
419− "description": "The batchReportDefinitionId parameter specifies the ID of the batch reportort definition for which you are retrieving reports.",
419+ "description": "The batchReportDefinitionId parameter specifies the ID of the batch reportort definition for which you are retrieving reports.",
420− "required": true,
420+ "required": true,
421− "location": "query"
421+ "location": "query"
422− },
422+ },
423− "onBehalfOfContentOwner": {
423+ "onBehalfOfContentOwner": {
424− "type": "string",
424+ "type": "string",
425− "description": "The onBehalfOfContentOwner parameter identifies the content owner that the user is acting on behalf of.",
425+ "description": "The onBehalfOfContentOwner parameter identifies the content owner that the user is acting on behalf of.",
426− "required": true,
426+ "required": true,
427− "location": "query"
427+ "location": "query"
428− }
428+ }
429− },
429+ },
430− "parameterOrder": [
430+ "parameterOrder": [
431− "batchReportDefinitionId",
431+ "batchReportDefinitionId",
432− "onBehalfOfContentOwner"
432+ "onBehalfOfContentOwner"
433− ],
433+ ],
434− "response": {
434+ "response": {
435− "$ref": "BatchReportList"
435+ "$ref": "BatchReportList"
436− },
436+ },
437− "scopes": [
437+ "scopes": [
438− "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
438+ "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
439− "https://www.googleapis.com/auth/yt-analytics.readonly"
439+ "https://www.googleapis.com/auth/yt-analytics.readonly"
440− ]
440+ ]
441− }
441+ }
442− }
442+ }
443− },
443+ },
444− "groupItems": {
444+ "groupItems": {
445− "methods": {
445+ "methods": {
446− "delete": {
446+ "delete": {
447− "id": "youtubeAnalytics.groupItems.delete",
447+ "id": "youtubeAnalytics.groupItems.delete",
448− "path": "groupItems",
448+ "path": "groupItems",
449− "httpMethod": "DELETE",
449+ "httpMethod": "DELETE",
450− "description": "Removes an item from a group.",
450+ "description": "Removes an item from a group.",
451− "parameters": {
451+ "parameters": {
452− "id": {
452+ "id": {
453− "type": "string",
453+ "type": "string",
454− "description": "The id parameter specifies the YouTube group item ID for the group that is being deleted.",
454+ "description": "The id parameter specifies the YouTube group item ID for the group that is being deleted.",
455− "required": true,
455+ "required": true,
456− "location": "query"
456+ "location": "query"
457− },
457+ },
458− "onBehalfOfContentOwner": {
458+ "onBehalfOfContentOwner": {
459− "type": "string",
459+ "type": "string",
460− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
460+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
461− "location": "query"
461+ "location": "query"
462− }
462+ }
463− },
463+ },
464− "parameterOrder": [
464+ "parameterOrder": [
465− "id"
465+ "id"
466− ],
466+ ],
467− "scopes": [
467+ "scopes": [
468− "https://www.googleapis.com/auth/youtube",
468+ "https://www.googleapis.com/auth/youtube",
469− "https://www.googleapis.com/auth/youtubepartner"
469+ "https://www.googleapis.com/auth/youtubepartner"
470− ]
470+ ]
471− },
471+ },
472− "insert": {
472+ "insert": {
473− "id": "youtubeAnalytics.groupItems.insert",
473+ "id": "youtubeAnalytics.groupItems.insert",
474− "path": "groupItems",
474+ "path": "groupItems",
475− "httpMethod": "POST",
475+ "httpMethod": "POST",
476− "description": "Creates a group item.",
476+ "description": "Creates a group item.",
477− "parameters": {
477+ "parameters": {
478− "onBehalfOfContentOwner": {
478+ "onBehalfOfContentOwner": {
479− "type": "string",
479+ "type": "string",
480− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
480+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
481− "location": "query"
481+ "location": "query"
482− }
482+ }
483− },
483+ },
484− "request": {
484+ "request": {
485− "$ref": "GroupItem"
485+ "$ref": "GroupItem"
486− },
486+ },
487− "response": {
487+ "response": {
488− "$ref": "GroupItem"
488+ "$ref": "GroupItem"
489− },
489+ },
490− "scopes": [
490+ "scopes": [
491− "https://www.googleapis.com/auth/youtube",
491+ "https://www.googleapis.com/auth/youtube",
492− "https://www.googleapis.com/auth/youtubepartner"
492+ "https://www.googleapis.com/auth/youtubepartner"
493− ]
493+ ]
494− },
494+ },
495− "list": {
495+ "list": {
496− "id": "youtubeAnalytics.groupItems.list",
496+ "id": "youtubeAnalytics.groupItems.list",
497− "path": "groupItems",
497+ "path": "groupItems",
498− "httpMethod": "GET",
498+ "httpMethod": "GET",
499− "description": "Returns a collection of group items that match the API request parameters.",
499+ "description": "Returns a collection of group items that match the API request parameters.",
500− "parameters": {
500+ "parameters": {
501− "groupId": {
501+ "groupId": {
502− "type": "string",
502+ "type": "string",
503− "description": "The id parameter specifies the unique ID of the group for which you want to retrieve group items.",
503+ "description": "The id parameter specifies the unique ID of the group for which you want to retrieve group items.",
504− "required": true,
504+ "required": true,
505− "location": "query"
505+ "location": "query"
506− },
506+ },
507− "onBehalfOfContentOwner": {
507+ "onBehalfOfContentOwner": {
508− "type": "string",
508+ "type": "string",
509− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
509+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
510− "location": "query"
510+ "location": "query"
511− }
511+ }
512− },
512+ },
513− "parameterOrder": [
513+ "parameterOrder": [
514− "groupId"
514+ "groupId"
515− ],
515+ ],
516− "response": {
516+ "response": {
517− "$ref": "GroupItemListResponse"
517+ "$ref": "GroupItemListResponse"
518− },
518+ },
519− "scopes": [
519+ "scopes": [
520− "https://www.googleapis.com/auth/youtube",
520+ "https://www.googleapis.com/auth/youtube",
521− "https://www.googleapis.com/auth/youtube.readonly",
521+ "https://www.googleapis.com/auth/youtube.readonly",
522− "https://www.googleapis.com/auth/youtubepartner",
522+ "https://www.googleapis.com/auth/youtubepartner",
523− "https://www.googleapis.com/auth/yt-analytics.readonly"
523+ "https://www.googleapis.com/auth/yt-analytics.readonly"
524− ]
524+ ]
525− }
525+ }
526− }
526+ }
527− },
527+ },
528− "groups": {
528+ "groups": {
529− "methods": {
529+ "methods": {
530− "delete": {
530+ "delete": {
531− "id": "youtubeAnalytics.groups.delete",
531+ "id": "youtubeAnalytics.groups.delete",
532− "path": "groups",
532+ "path": "groups",
533− "httpMethod": "DELETE",
533+ "httpMethod": "DELETE",
534− "description": "Deletes a group.",
534+ "description": "Deletes a group.",
535− "parameters": {
535+ "parameters": {
536− "id": {
536+ "id": {
537− "type": "string",
537+ "type": "string",
538− "description": "The id parameter specifies the YouTube group ID for the group that is being deleted.",
538+ "description": "The id parameter specifies the YouTube group ID for the group that is being deleted.",
539− "required": true,
539+ "required": true,
540− "location": "query"
540+ "location": "query"
541− },
541+ },
542− "onBehalfOfContentOwner": {
542+ "onBehalfOfContentOwner": {
543− "type": "string",
543+ "type": "string",
544− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
544+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
545− "location": "query"
545+ "location": "query"
546− }
546+ }
547− },
547+ },
548− "parameterOrder": [
548+ "parameterOrder": [
549− "id"
549+ "id"
550− ],
550+ ],
551− "scopes": [
551+ "scopes": [
552− "https://www.googleapis.com/auth/youtube",
552+ "https://www.googleapis.com/auth/youtube",
553− "https://www.googleapis.com/auth/youtubepartner"
553+ "https://www.googleapis.com/auth/youtubepartner"
554− ]
554+ ]
555− },
555+ },
556− "insert": {
556+ "insert": {
557− "id": "youtubeAnalytics.groups.insert",
557+ "id": "youtubeAnalytics.groups.insert",
558− "path": "groups",
558+ "path": "groups",
559− "httpMethod": "POST",
559+ "httpMethod": "POST",
560− "description": "Creates a group.",
560+ "description": "Creates a group.",
561− "parameters": {
561+ "parameters": {
562− "onBehalfOfContentOwner": {
562+ "onBehalfOfContentOwner": {
563− "type": "string",
563+ "type": "string",
564− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
564+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
565− "location": "query"
565+ "location": "query"
566− }
566+ }
567− },
567+ },
568− "request": {
568+ "request": {
569− "$ref": "Group"
569+ "$ref": "Group"
570− },
570+ },
571− "response": {
571+ "response": {
572− "$ref": "Group"
572+ "$ref": "Group"
573− },
573+ },
574− "scopes": [
574+ "scopes": [
575− "https://www.googleapis.com/auth/youtube",
575+ "https://www.googleapis.com/auth/youtube",
576− "https://www.googleapis.com/auth/youtubepartner"
576+ "https://www.googleapis.com/auth/youtubepartner"
577− ]
577+ ]
578− },
578+ },
579− "list": {
579+ "list": {
580− "id": "youtubeAnalytics.groups.list",
580+ "id": "youtubeAnalytics.groups.list",
581− "path": "groups",
581+ "path": "groups",
582− "httpMethod": "GET",
582+ "httpMethod": "GET",
583− "description": "Returns a collection of groups that match the API request parameters. For example, you can retrieve all groups that the authenticated user owns, or you can retrieve one or more groups by their unique IDs.",
583+ "description": "Returns a collection of groups that match the API request parameters. For example, you can retrieve all groups that the authenticated user owns, or you can retrieve one or more groups by their unique IDs.",
584− "parameters": {
584+ "parameters": {
585− "id": {
585+ "id": {
586− "type": "string",
586+ "type": "string",
587− "description": "The id parameter specifies a comma-separated list of the YouTube group ID(s) for the resource(s) that are being retrieved. In a group resource, the id property specifies the group's YouTube group ID.",
587+ "description": "The id parameter specifies a comma-separated list of the YouTube group ID(s) for the resource(s) that are being retrieved. In a group resource, the id property specifies the group's YouTube group ID.",
588− "location": "query"
588+ "location": "query"
589− },
589+ },
590− "mine": {
590+ "mine": {
591− "type": "boolean",
591+ "type": "boolean",
592− "description": "Set this parameter's value to true to instruct the API to only return groups owned by the authenticated user.",
592+ "description": "Set this parameter's value to true to instruct the API to only return groups owned by the authenticated user.",
593− "location": "query"
593+ "location": "query"
594− },
594+ },
595− "onBehalfOfContentOwner": {
595+ "onBehalfOfContentOwner": {
596− "type": "string",
596+ "type": "string",
597− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
597+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
598− "location": "query"
598+ "location": "query"
599− }
599+ }
600− },
600+ },
601− "response": {
601+ "response": {
602− "$ref": "GroupListResponse"
602+ "$ref": "GroupListResponse"
603− },
603+ },
604− "scopes": [
604+ "scopes": [
605− "https://www.googleapis.com/auth/youtube",
605+ "https://www.googleapis.com/auth/youtube",
606− "https://www.googleapis.com/auth/youtube.readonly",
606+ "https://www.googleapis.com/auth/youtube.readonly",
607− "https://www.googleapis.com/auth/youtubepartner",
607+ "https://www.googleapis.com/auth/youtubepartner",
608− "https://www.googleapis.com/auth/yt-analytics.readonly"
608+ "https://www.googleapis.com/auth/yt-analytics.readonly"
609− ]
609+ ]
610− },
610+ },
611− "update": {
611+ "update": {
612− "id": "youtubeAnalytics.groups.update",
612+ "id": "youtubeAnalytics.groups.update",
613− "path": "groups",
613+ "path": "groups",
614− "httpMethod": "PUT",
614+ "httpMethod": "PUT",
615− "description": "Modifies a group. For example, you could change a group's title.",
615+ "description": "Modifies a group. For example, you could change a group's title.",
616− "parameters": {
616+ "parameters": {
617− "onBehalfOfContentOwner": {
617+ "onBehalfOfContentOwner": {
618− "type": "string",
618+ "type": "string",
619− "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
619+ "description": "Note: This parameter is intended exclusively for YouTube content partners.\n\nThe onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value. This parameter is intended for YouTube content partners that own and manage many different YouTube channels. It allows content owners to authenticate once and get access to all their video and channel data, without having to provide authentication credentials for each individual channel. The CMS account that the user authenticates with must be linked to the specified YouTube content owner.",
620− "location": "query"
620+ "location": "query"
621− }
621+ }
622− },
622+ },
623− "request": {
623+ "request": {
624− "$ref": "Group"
624+ "$ref": "Group"
625− },
625+ },
626− "response": {
626+ "response": {
627− "$ref": "Group"
627+ "$ref": "Group"
628− },
628+ },
629− "scopes": [
629+ "scopes": [
630− "https://www.googleapis.com/auth/youtube",
630+ "https://www.googleapis.com/auth/youtube",
631− "https://www.googleapis.com/auth/youtubepartner"
631+ "https://www.googleapis.com/auth/youtubepartner"
632− ]
632+ ]
633− }
633+ }
634− }
634+ }
635− },
635+ },
636− "reports": {
636+ "reports": {
637− "methods": {
637+ "methods": {
638− "query": {
638+ "query": {
639− "id": "youtubeAnalytics.reports.query",
639+ "id": "youtubeAnalytics.reports.query",
640− "path": "reports",
640+ "path": "reports",
641− "httpMethod": "GET",
641+ "httpMethod": "GET",
642− "description": "Retrieve your YouTube Analytics reports.",
642+ "description": "Retrieve your YouTube Analytics reports.",
643− "parameters": {
643+ "parameters": {
644− "currency": {
644+ "currency": {
645− "type": "string",
645+ "type": "string",
646− "description": "The currency to which financial metrics should be converted. The default is US Dollar (USD). If the result contains no financial metrics, this flag will be ignored. Responds with an error if the specified currency is not recognized.",
646+ "description": "The currency to which financial metrics should be converted. The default is US Dollar (USD). If the result contains no financial metrics, this flag will be ignored. Responds with an error if the specified currency is not recognized.",
647− "pattern": "[A-Z]{3}",
647+ "pattern": "[A-Z]{3}",
648− "location": "query"
648+ "location": "query"
649− },
649+ },
650− "dimensions": {
650+ "dimensions": {
651− "type": "string",
651+ "type": "string",
652− "description": "A comma-separated list of YouTube Analytics dimensions, such as views or ageGroup,gender. See the Available Reports document for a list of the reports that you can retrieve and the dimensions used for those reports. Also see the Dimensions document for definitions of those dimensions.",
652+ "description": "A comma-separated list of YouTube Analytics dimensions, such as views or ageGroup,gender. See the Available Reports document for a list of the reports that you can retrieve and the dimensions used for those reports. Also see the Dimensions document for definitions of those dimensions.",
653− "pattern": "[0-9a-zA-Z,]+",
653+ "pattern": "[0-9a-zA-Z,]+",
654− "location": "query"
654+ "location": "query"
655− },
655+ },
656− "end-date": {
656+ "end-date": {
657− "type": "string",
657+ "type": "string",
658− "description": "The end date for fetching YouTube Analytics data. The value should be in YYYY-MM-DD format.",
658+ "description": "The end date for fetching YouTube Analytics data. The value should be in YYYY-MM-DD format.",
659− "required": true,
659+ "required": true,
660− "pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}",
660+ "pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}",
661− "location": "query"
661+ "location": "query"
662− },
662+ },
663− "filters": {
663+ "filters": {
664− "type": "string",
664+ "type": "string",
665− "description": "A list of filters that should be applied when retrieving YouTube Analytics data. The Available Reports document identifies the dimensions that can be used to filter each report, and the Dimensions document defines those dimensions. If a request uses multiple filters, join them together with a semicolon (;), and the returned result table will satisfy both filters. For example, a filters parameter value of video==dMH0bHeiRNg;country==IT restricts the result set to include data for the given video in Italy.",
665+ "description": "A list of filters that should be applied when retrieving YouTube Analytics data. The Available Reports document identifies the dimensions that can be used to filter each report, and the Dimensions document defines those dimensions. If a request uses multiple filters, join them together with a semicolon (;), and the returned result table will satisfy both filters. For example, a filters parameter value of video==dMH0bHeiRNg;country==IT restricts the result set to include data for the given video in Italy.",
666− "location": "query"
666+ "location": "query"
667− },
667+ },
668− "ids": {
668+ "ids": {
669− "type": "string",
669+ "type": "string",
670− "description": "Identifies the YouTube channel or content owner for which you are retrieving YouTube Analytics data.\n- To request data for a YouTube user, set the ids parameter value to channel==CHANNEL_ID, where CHANNEL_ID specifies the unique YouTube channel ID.\n- To request data for a YouTube CMS content owner, set the ids parameter value to contentOwner==OWNER_NAME, where OWNER_NAME is the CMS name of the content owner.",
670+ "description": "Identifies the YouTube channel or content owner for which you are retrieving YouTube Analytics data.\n- To request data for a YouTube user, set the ids parameter value to channel==CHANNEL_ID, where CHANNEL_ID specifies the unique YouTube channel ID.\n- To request data for a YouTube CMS content owner, set the ids parameter value to contentOwner==OWNER_NAME, where OWNER_NAME is the CMS name of the content owner.",
671− "required": true,
671+ "required": true,
672− "pattern": "[a-zA-Z]+==[a-zA-Z0-9_+-]+",
672+ "pattern": "[a-zA-Z]+==[a-zA-Z0-9_+-]+",
673− "location": "query"
673+ "location": "query"
674− },
674+ },
675− "max-results": {
675+ "max-results": {
676− "type": "integer",
676+ "type": "integer",
677− "description": "The maximum number of rows to include in the response.",
677+ "description": "The maximum number of rows to include in the response.",
678− "format": "int32",
678+ "format": "int32",
679− "minimum": "1",
679+ "minimum": "1",
680− "location": "query"
680+ "location": "query"
681− },
681+ },
682− "metrics": {
682+ "metrics": {
683− "type": "string",
683+ "type": "string",
684− "description": "A comma-separated list of YouTube Analytics metrics, such as views or likes,dislikes. See the Available Reports document for a list of the reports that you can retrieve and the metrics available in each report, and see the Metrics document for definitions of those metrics.",
684+ "description": "A comma-separated list of YouTube Analytics metrics, such as views or likes,dislikes. See the Available Reports document for a list of the reports that you can retrieve and the metrics available in each report, and see the Metrics document for definitions of those metrics.",
685− "required": true,
685+ "required": true,
686− "pattern": "[0-9a-zA-Z,]+",
686+ "pattern": "[0-9a-zA-Z,]+",
687− "location": "query"
687+ "location": "query"
688− },
688+ },
689− "sort": {
689+ "sort": {
690− "type": "string",
690+ "type": "string",
691− "description": "A comma-separated list of dimensions or metrics that determine the sort order for YouTube Analytics data. By default the sort order is ascending. The '-' prefix causes descending sort order.",
691+ "description": "A comma-separated list of dimensions or metrics that determine the sort order for YouTube Analytics data. By default the sort order is ascending. The '-' prefix causes descending sort order.",
692− "pattern": "[-0-9a-zA-Z,]+",
692+ "pattern": "[-0-9a-zA-Z,]+",
693− "location": "query"
693+ "location": "query"
694− },
694+ },
695− "start-date": {
695+ "start-date": {
696− "type": "string",
696+ "type": "string",
697− "description": "The start date for fetching YouTube Analytics data. The value should be in YYYY-MM-DD format.",
697+ "description": "The start date for fetching YouTube Analytics data. The value should be in YYYY-MM-DD format.",
698− "required": true,
698+ "required": true,
699− "pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}",
699+ "pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}",
700− "location": "query"
700+ "location": "query"
701− },
701+ },
702− "start-index": {
702+ "start-index": {
703− "type": "integer",
703+ "type": "integer",
704− "description": "An index of the first entity to retrieve. Use this parameter as a pagination mechanism along with the max-results parameter (one-based, inclusive).",
704+ "description": "An index of the first entity to retrieve. Use this parameter as a pagination mechanism along with the max-results parameter (one-based, inclusive).",
705− "format": "int32",
705+ "format": "int32",
706− "minimum": "1",
706+ "minimum": "1",
707− "location": "query"
707+ "location": "query"
708− }
708+ }
709− },
709+ },
710− "parameterOrder": [
710+ "parameterOrder": [
711− "ids",
711+ "ids",
712− "start-date",
712+ "start-date",
713− "end-date",
713+ "end-date",
714− "metrics"
714+ "metrics"
715− ],
715+ ],
716− "response": {
716+ "response": {
717− "$ref": "ResultTable"
717+ "$ref": "ResultTable"
718− },
718+ },
719− "scopes": [
719+ "scopes": [
720− "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
720+ "https://www.googleapis.com/auth/yt-analytics-monetary.readonly",
721− "https://www.googleapis.com/auth/yt-analytics.readonly"
721+ "https://www.googleapis.com/auth/yt-analytics.readonly"
722− ]
722+ ]
723+ }
724+ }
725+ }
723 }
726 }
724− }
725− }
726− }
727}
727}
gen/src/Gen/AST.hs+116−116
@@ -22,114 +22,37 @@ module Gen.AST where
22import Control.Applicative
22import Control.Applicative
23import Control.Error
23import Control.Error
24import Control.Lens
24import Control.Lens
25+import Control.Monad.Except
26+import Control.Monad.Morph
25import Control.Monad.State
27import Control.Monad.State
26−import Data.Aeson hiding (String)
28+import Data.Aeson hiding (String)
27import Data.Aeson.TH
29import Data.Aeson.TH
28−import qualified Data.Attoparsec.Text as A
30+import qualified Data.Attoparsec.Text as A
29import Data.Char
31import Data.Char
30−import Data.Function (on)
32+import Data.Function (on)
31−import qualified Data.HashMap.Strict as Map
33+import qualified Data.HashMap.Strict as Map
32−import Data.List (groupBy, intersect, nub, sort)
34+import Data.List (groupBy, intersect, nub, sort)
33−import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
35+import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
34−import qualified Data.List.NonEmpty as NE
36+import qualified Data.List.NonEmpty as NE
35import Data.Ord
37import Data.Ord
36−import Data.Semigroup
38+import Data.Semigroup hiding (Sum)
37−import Data.Text (Text)
39+import Data.Text (Text)
38−import qualified Data.Text as Text
40+import qualified Data.Text as Text
39−import qualified Data.Text.Lazy as LText
41+import qualified Data.Text.Lazy as LText
40−import qualified Data.Text.Lazy.Builder as Build
42+import qualified Data.Text.Lazy.Builder as Build
41import Data.Text.Manipulate
43import Data.Text.Manipulate
44+import Debug.Trace
42−import qualified Filesystem.Path.CurrentOS as Path
45+import qualified Filesystem.Path.CurrentOS as Path
43import Formatting
46import Formatting
44import Gen.Formatting
47import Gen.Formatting
48+import Gen.Solve
49+import Gen.Syntax
45import Gen.Text
50import Gen.Text
46import Gen.Types
51import Gen.Types
52+import HIndent
53+import Language.Haskell.Exts.Pretty
54+import Prelude hiding (sum)
47−import Text.EDE (Template)
55+import Text.EDE (Template)
48−
49−-- Just use hashmaps to lookup refs etc, and hide all the mutation
50−-- behind a StateT interface.
51−
52−data TType
53− = TType Ref
54− | TLit Lit
55− | TMaybe TType
56− | TEither TType TType
57− | TList TType
58−
59−data Derive
60− = DEq
61− | DOrd
62− | DRead
63− | DShow
64− | DEnum
65− | DNum
66− | DIntegral
67− | DReal
68− | DMonoid
69− | DIsString
70− | DData
71− | DTypeable
72− | DGeneric
73− deriving (Eq)
74−
75−data Memo = Memo
76− { _typed :: Map Ref TType
77− , _derived :: Map Ref [Derive]
78− , _schemas :: Map Ref (Schema Ref)
79− }
80−
81−makeLenses ''Memo
82−
83−type AST = ExceptT Error (State Memo)
84−
85−schema :: Ref -> AST (Schema Ref)
86−schema k = do
87− m <- gets (Map.lookup k . view schemas)
88− case m of
89− Nothing -> failure ("Missing Schema: " % ref) k
90− Just v -> pure v
91−
92−memo :: Lens' Memo (Map Ref v) -> Ref -> (Schema Ref -> AST v) -> AST v
93−memo l k f = do
94− m <- gets (Map.lookup k . view l)
95− case m of
96− Just x -> return x
97− Nothing -> do
98− x <- f =<< schema k
99− l %= Map.insert k x
100− return x
101−
102−typeOf :: Ref -> AST TType
103−typeOf k = memo typed k go
104− where
105− go = \case
106− Obj {} -> pure (TType k)
107− Arr _ r -> typeOf r
108− Enum {} -> pure (TType k)
109− Ref r -> typeOf r
110− Any' -> pure (TEither (TLit String) (TLit Integer))
111− Lit _ l -> pure (TLit l)
112−
113−derive :: Ref -> AST [Derive]
114−derive k = memo derived k go
115− where
116− go = \case
117− Obj _ rs -> foldM props base (Map.keys rs)
118− Arr _ r -> mappend monoid . intersect base <$> derive r
119− Enum {} -> pure enum
120− Ref r -> derive r
121− Any' -> pure base
122− Lit _ l -> pure $
123− case l of
124− String -> base <> [DOrd, DIsString]
125− Boolean -> base <> enum
126− Integer -> base <> [DNum, DIntegral, DReal] <> enum
127−
128− props ds x = intersect ds <$> derive x
129−
130− monoid = [DMonoid]
131− enum = [DOrd, DEnum]
132− base = [DEq, DRead, DShow, DData, DTypeable, DGeneric]
133
56
134-- mapM isn't lazy here and I don't care!
57-- mapM isn't lazy here and I don't care!
135flatten :: Map Ref (Fix Schema) -> Map Ref (Schema Ref)
58flatten :: Map Ref (Fix Schema) -> Map Ref (Schema Ref)
@@ -142,31 +65,108 @@ flatten m = execState (mapM_ (uncurry (prop Nothing)) (Map.toList m)) mempty
142 res o
65 res o
143
66
144 Arr i e -> do
67 Arr i e -> do
145− e' <- prop Nothing ref e
68+ e' <- prop (Just ref) "item" e
146 res (Arr i e')
69 res (Arr i e')
147
70
148 Enum i vs ds -> res (Enum i vs ds)
71 Enum i vs ds -> res (Enum i vs ds)
149 Lit i l -> res (Lit i l)
72 Lit i l -> res (Lit i l)
150− Ref r -> res (Ref r) -- blow up if r == ref ?
73+ Ref r -> pure r
151 Any' -> res Any'
74 Any' -> res Any'
152
75
153 where
76 where
77+ res x = do
78+ m <- gets (Map.lookup ref)
79+ case m of
154− res x = modify (Map.insert ref x) >> pure ref
80+ Nothing -> modify (Map.insert ref x) >> pure ref
81+ -- FIXME:
82+ Just e -> error $ "Already exists: " ++ show (ref, e, x)
155
83
156 ref = maybe k (<> k) p
84 ref = maybe k (<> k) p
157
85
86+merge :: Versions -> [Service Data] -> [Library]
87+merge v = map go . groupBy (on (==) _svcLibrary)
88+ where
89+ go [x] = mk x
90+ go (x:xs) = (mk x) { _libServices = x :| xs }
91+
92+ mk x = Library
93+ { _libName = _svcLibrary x
94+ , _libTitle = renameTitle (_svcTitle x)
95+ , _libVersions = v
96+ , _libServices = x :| []
97+ }
98+
158−render :: Service (Schema Ref) -> Either Error (Service Data)
99+render :: Service (Fix Schema) -> Either Error (Service Data)
159−render s = undefined -- do
100+render s = runAST (Memo mempty mempty ss) $ do
160− -- rs <- traverse schema (_svcSchemas s)
101+ r <- kvTraverseMaybe go ss
161− -- return $! s { _svcSchemas = rs }
102+ return $! s { _svcSchemas = r }
162− -- where
103+ where
163− -- schema :: Schema -> Either Error Data
104+ ss = flatten (_svcSchemas s)
105+
106+ go :: Ref -> Schema Ref -> AST (Maybe Data)
164− -- schema = \case
107+ go k = \case
165− -- Obj ->
108+ Arr {} -> pure Nothing
109+ Ref {} -> pure Nothing
110+ Any' {} -> pure Nothing
111+ Lit {} -> pure Nothing
112+ Enum {} -> Just <$> sum
113+ where
114+ sum = Sum "sum help"
115+ <$> pp Indent enumDecl
116+
117+ Obj _ rs -> Just <$> prod
118+ where
119+ prod = Prod
120+ <$> (objDecl k rs >>= pp Indent)
121+ <*> ctor
122+ <*> traverse (uncurry lens) (Map.toList rs)
123+
124+ ctor = Fun' "ctor help"
125+ <$> pp None ctorSig
126+ <*> pp Indent ctorDecl
127+
128+ lens n v = Fun' "lens help"
129+ <$> pp None lensSig
130+ <*> pp Print lensDecl
131+
132+ -- record declaration
166− -- constructor [doc, sig, decl]
133+ -- smart constructor
167− -- decl
134+ -- signature
168−
135+ -- declaration
169− -- Arr -> Nothing
136+ -- documentation
170−
137+ -- lenses per property
171−
138+ -- signature
139+ -- declaration
140+ -- documentation
141+
142+data PP
143+ = Indent
144+ | Print
145+ | None
146+ deriving (Eq)
172
147
148+pp :: Pretty a => PP -> a -> AST Rendered
149+pp i x
150+ | i == Indent = result (reformat johanTibell Nothing p)
151+ | otherwise = pure p
152+ where
153+ result = hoistEither . bimap e Build.toLazyText
154+
155+ e = flip mappend (", when formatting datatype: " <> p) . LText.pack
156+
157+ p = LText.dropWhile isSpace
158+ . LText.pack
159+ $ prettyPrintStyleMode s m x
160+
161+ s = style
162+ { mode = PageMode
163+ , lineLength = 80
164+ , ribbonsPerLine = 1.5
165+ }
166+
167+ m | i == Print = defaultMode
168+ | i == Indent = defaultMode
169+ | otherwise = defaultMode
170+ { layout = PPNoLayout
171+ , spacing = False
172+ }
gen/src/Gen/Solve.hsnew file+150
@@ -0,0 +1,150 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+{-# LANGUAGE KindSignatures #-}
7+{-# LANGUAGE LambdaCase #-}
8+{-# LANGUAGE OverloadedStrings #-}
9+{-# LANGUAGE RankNTypes #-}
10+{-# LANGUAGE RecordWildCards #-}
11+{-# LANGUAGE TemplateHaskell #-}
12+
13+-- Module : Gen.Solve
14+-- Copyright : (c) 2015 Brendan Hay
15+-- License : Mozilla Public License, v. 2.0.
16+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
17+-- Stability : provisional
18+-- Portability : non-portable (GHC extensions)
19+
20+module Gen.Solve where
21+
22+import Control.Applicative
23+import Control.Error
24+import Control.Lens
25+import Control.Monad.Except
26+import Control.Monad.Morph
27+import Control.Monad.State
28+import qualified Data.Attoparsec.Text as A
29+import Data.Char
30+import Data.Function (on)
31+import qualified Data.HashMap.Strict as Map
32+import Data.List (groupBy, intersect, nub, sort)
33+import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
34+import qualified Data.List.NonEmpty as NE
35+import Data.Ord
36+import Data.Semigroup hiding (Sum)
37+import Data.Text (Text)
38+import qualified Data.Text as Text
39+import qualified Data.Text.Lazy as LText
40+import qualified Data.Text.Lazy.Builder as Build
41+import Data.Text.Manipulate
42+import Debug.Trace
43+import qualified Filesystem.Path.CurrentOS as Path
44+import Formatting
45+import Gen.Formatting
46+import Gen.Text
47+import Gen.Types
48+import HIndent
49+import Language.Haskell.Exts.Pretty
50+import Prelude hiding (sum)
51+import Text.EDE (Template)
52+
53+-- Just use hashmaps to lookup refs etc, and hide all the mutation
54+-- behind a StateT interface.
55+
56+data TType
57+ = TType Ref
58+ | TLit Lit
59+ | TMaybe TType
60+ | TEither TType TType
61+ | TList TType
62+
63+data Derive
64+ = DEq
65+ | DOrd
66+ | DRead
67+ | DShow
68+ | DEnum
69+ | DNum
70+ | DIntegral
71+ | DReal
72+ | DMonoid
73+ | DIsString
74+ | DData
75+ | DTypeable
76+ | DGeneric
77+ deriving (Eq, Show)
78+
79+data Memo = Memo
80+ { _typed :: Map Ref TType
81+ , _derived :: Map Ref [Derive]
82+ , _schemas :: Map Ref (Schema Ref)
83+ }
84+
85+makeLenses ''Memo
86+
87+type AST = ExceptT Error (State Memo)
88+
89+type Solved = (Schema Ref, TType, [Derive])
90+
91+runAST :: Memo -> AST a -> Either Error a
92+runAST s m = evalState (runExceptT m) s
93+
94+schema :: Ref -> AST (Schema Ref)
95+schema k = do
96+ m <- gets (Map.lookup k . view schemas)
97+ case m of
98+ Nothing -> failure ("Missing Schema: " % fref) k
99+ Just v -> pure v
100+
101+memo :: Lens' Memo (Map Ref v) -> Ref -> (Schema Ref -> AST v) -> AST v
102+memo l k f = do
103+ m <- gets (Map.lookup k . view l)
104+ case m of
105+ Just x -> return x
106+ Nothing -> do
107+ x <- f =<< schema k
108+ l %= Map.insert k x
109+ return x
110+
111+solve :: Ref -> AST Solved
112+solve k = (,,) <$> schema k <*> typeOf k <*> derive k
113+
114+typeOf :: Ref -> AST TType
115+typeOf k = loc "typeOf" k $ memo typed k go
116+ where
117+ go = \case
118+ Obj {} -> pure (TType k)
119+ Arr _ r -> pure (TList (TType r))
120+ Enum {} -> pure (TType k)
121+ Ref r -> typeOf r
122+ Any' -> pure (TEither (TLit Text) (TLit Long))
123+ Lit _ l -> pure (TLit l)
124+
125+derive :: Ref -> AST [Derive]
126+derive k = loc "derive" k $ memo derived k go
127+ where
128+ go = \case
129+ Obj _ rs -> foldM props base (Map.elems rs)
130+ Arr _ r -> pure [] -- mappend monoid . intersect base <$> derive r
131+ Enum {} -> pure enum
132+ Ref r -> derive r
133+ Any' -> pure base
134+ Lit _ l -> pure $
135+ case l of
136+ Text -> base <> [DOrd, DIsString]
137+ Bool -> base <> enum
138+ Int -> base
139+ Long -> base <> [DNum, DIntegral, DReal] <> enum
140+ Nat -> base
141+ Time -> base
142+
143+ props ds x = intersect ds <$> derive x
144+
145+ monoid = [DMonoid]
146+ enum = [DOrd, DEnum]
147+ base = [DEq, DRead, DShow, DData, DTypeable, DGeneric]
148+
149+loc :: String -> Ref -> a -> a
150+loc n r = id -- trace (n ++ ": " ++ Text.unpack (refToText r))
gen/src/Gen/Syntax.hsnew file+107
@@ -0,0 +1,107 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE TupleSections #-}
4+
5+-- Module : Gen.Syntax
6+-- Copyright : (c) 2015 Brendan Hay
7+-- License : Mozilla Public License, v. 2.0.
8+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
9+-- Stability : provisional
10+-- Portability : non-portable (GHC extensions)
11+
12+module Gen.Syntax where
13+
14+import qualified Data.HashMap.Strict as Map
15+import Data.Semigroup
16+import Data.String
17+import Data.Text (Text)
18+import qualified Data.Text as Text
19+import Data.Text.Manipulate
20+import Gen.Solve
21+import Gen.Types
22+import qualified Language.Haskell.Exts as Exts
23+import Language.Haskell.Exts.Build
24+import Language.Haskell.Exts.SrcLoc
25+import Language.Haskell.Exts.Syntax hiding (Int)
26+
27+objDecl :: Ref -> Map Ref Ref -> AST Decl
28+objDecl r rs = do
29+ con <- conDecl n rs
30+ ds <- derivings r
31+ return $! DataDecl noLoc arity [] n [] [con] ds
32+ where
33+ n = dname r
34+
35+ arity | Map.size rs == 1 = NewType
36+ | otherwise = DataType
37+
38+conDecl :: Name -> Map Ref Ref -> AST QualConDecl
39+conDecl n rs = QualConDecl noLoc [] [] <$> body
40+ where
41+ body = case Map.toList rs of
42+ [] -> pure (ConDecl n [])
43+ [x] -> RecDecl n . (:[]) <$> field internal x
44+ xs -> RecDecl n <$> traverse (field (strict . internal)) xs
45+
46+ field f (k, v) = do
47+ t <- typeOf v
48+ return ([fname k], f t)
49+
50+derivings :: Ref -> AST [Deriving]
51+derivings = fmap (map ((,[]) . unqual . drop 1 . show)) . derive
52+
53+ctorSig :: Decl
54+ctorSig = emptyDecl
55+
56+ctorDecl :: Decl
57+ctorDecl = emptyDecl
58+
59+lensSig :: Decl
60+lensSig = emptyDecl
61+
62+lensDecl :: Decl
63+lensDecl = emptyDecl
64+
65+enumDecl :: Decl
66+enumDecl = emptyDecl
67+
68+emptyDecl :: Decl
69+emptyDecl = DataDecl noLoc DataType [] (name "Empty") [] [] []
70+
71+internal :: TType -> Type
72+internal = go
73+ where
74+ go = \case
75+ TType r -> tycon r
76+ TMaybe t -> TyApp (tycon "Maybe") (go t)
77+-- TEither a b ->
78+ TList t -> TyList (go t)
79+ TLit l -> lit l
80+
81+ lit = \case
82+ Text -> tycon "Text"
83+ Bool -> tycon "Bool"
84+ Int -> tycon "Int"
85+ Long -> tycon "Integer"
86+ Nat -> tycon "Natural"
87+ Time -> tycon "UTCTime"
88+
89+strict :: Type -> Type
90+strict = TyBang BangedTy . \case
91+ t@TyApp{} -> TyParen t
92+ t -> t
93+
94+dname :: Ref -> Name
95+dname = name . ref upperHead
96+
97+fname :: Ref -> Name
98+fname = name . ref (Text.cons '_')
99+
100+tycon :: Ref -> Type
101+tycon = TyCon . unqual . ref upperHead
102+
103+ref :: (Text -> Text) -> Ref -> String
104+ref f = Text.unpack . f . refToText
105+
106+unqual :: String -> QName
107+unqual = UnQual . name
gen/src/Gen/Types.hs+98−42
@@ -3,6 +3,7 @@
3{-# LANGUAGE DeriveFunctor #-}
3{-# LANGUAGE DeriveFunctor #-}
4{-# LANGUAGE DeriveGeneric #-}
4{-# LANGUAGE DeriveGeneric #-}
5{-# LANGUAGE DeriveTraversable #-}
5{-# LANGUAGE DeriveTraversable #-}
6+{-# LANGUAGE ExtendedDefaultRules #-}
6{-# LANGUAGE FlexibleContexts #-}
7{-# LANGUAGE FlexibleContexts #-}
7{-# LANGUAGE FlexibleInstances #-}
8{-# LANGUAGE FlexibleInstances #-}
8{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -12,6 +13,8 @@
12{-# LANGUAGE RecordWildCards #-}
13{-# LANGUAGE RecordWildCards #-}
13{-# LANGUAGE TemplateHaskell #-}
14{-# LANGUAGE TemplateHaskell #-}
14
15
16+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
17+
15-- Module : Gen.Types
18-- Module : Gen.Types
16-- Copyright : (c) 2015 Brendan Hay
19-- Copyright : (c) 2015 Brendan Hay
17-- License : Mozilla Public License, v. 2.0.
20-- License : Mozilla Public License, v. 2.0.
@@ -21,11 +24,12 @@
21
24
22module Gen.Types
25module Gen.Types
23 ( module Gen.Types
26 ( module Gen.Types
27+ , module Gen.Types.Map
24 , module Gen.Types.NS
28 , module Gen.Types.NS
25 ) where
29 ) where
26
30
27import Control.Applicative
31import Control.Applicative
28−import Data.Aeson hiding (String)
32+import Data.Aeson hiding (Bool, String)
29import Data.Aeson.TH
33import Data.Aeson.TH
30import qualified Data.Attoparsec.Text as A
34import qualified Data.Attoparsec.Text as A
31import Data.Bifunctor
35import Data.Bifunctor
@@ -37,23 +41,27 @@ import Data.List (groupBy, nub, sort)
37import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
41import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
38import qualified Data.List.NonEmpty as NE
42import qualified Data.List.NonEmpty as NE
39import Data.Ord
43import Data.Ord
40−import Data.Semigroup
44+import Data.Semigroup hiding (Sum)
45+import Data.String
41import Data.Text (Text)
46import Data.Text (Text)
42import qualified Data.Text as Text
47import qualified Data.Text as Text
43import qualified Data.Text.Lazy as LText
48import qualified Data.Text.Lazy as LText
44import qualified Data.Text.Lazy.Builder as Build
49import qualified Data.Text.Lazy.Builder as Build
45import Data.Text.Manipulate
50import Data.Text.Manipulate
51+import qualified Data.Text.Read as Read
46import qualified Filesystem.Path.CurrentOS as Path
52import qualified Filesystem.Path.CurrentOS as Path
47import Formatting
53import Formatting
48import Gen.Text
54import Gen.Text
55+import Gen.Types.Map
49import Gen.Types.NS
56import Gen.Types.NS
50import GHC.Generics
57import GHC.Generics
51import GHC.TypeLits
58import GHC.TypeLits
52import Text.EDE (Template)
59import Text.EDE (Template)
53
60
61+default (Text)
62+
54newtype Fix f = Fix (f (Fix f))
63newtype Fix f = Fix (f (Fix f))
55
64
56−type Map = Map.HashMap
57type Error = LText.Text
65type Error = LText.Text
58type Rendered = LText.Text
66type Rendered = LText.Text
59type Path = Path.FilePath
67type Path = Path.FilePath
@@ -75,8 +83,8 @@ newtype Version (v :: Symbol) = Version Text
75instance ToJSON (Version v) where
83instance ToJSON (Version v) where
76 toJSON (Version v) = toJSON v
84 toJSON (Version v) = toJSON v
77
85
78−semver :: Format a (Version v -> a)
86+fver :: Format a (Version v -> a)
79−semver = later (\(Version v) -> Build.fromText v)
87+fver = later (\(Version v) -> Build.fromText v)
80
88
81type LibraryVer = Version "library"
89type LibraryVer = Version "library"
82type ClientVer = Version "client"
90type ClientVer = Version "client"
@@ -138,17 +146,54 @@ deriveJSON (js "") ''Location
138data Info = Info
146data Info = Info
139 { _infoDescription :: Maybe Text
147 { _infoDescription :: Maybe Text
140 , _infoDefault :: Maybe Text
148 , _infoDefault :: Maybe Text
141− , _infoRequired :: Maybe Bool
149+ , _infoRequired :: !Bool
150+ , _infoLocation :: Maybe Location
142 } deriving (Eq, Show)
151 } deriving (Eq, Show)
143
152
153+instance FromJSON Info where
154+ parseJSON = withObject "info" $ \o -> Info
155+ <$> o .:? "description"
156+ <*> o .:? "default"
157+ <*> o .:? "required" .!= False
158+ <*> o .:? "location"
159+
144−deriveJSON (js "_info") ''Info
160+deriveToJSON (js "_info") ''Info
145
161
146data Lit
162data Lit
147− = String
163+ = Text
148− | Boolean
164+ | Bool
149− | Integer
165+ | Int
166+ | Long
167+ | Nat
168+ | Time
150 deriving (Eq, Show)
169 deriving (Eq, Show)
151
170
171+instance FromJSON Lit where
172+ parseJSON = withObject "literal" $ \o -> do
173+ n <- min =<< (o .:? "minimum" .!= "0")
174+ (o .: "format" <|> o .: "type") >>= \case
175+ -- Types
176+ "string" -> pure Text
177+ "boolean" -> pure Bool
178+ -- Formats
179+ "uint64" -> pure (nat n Long)
180+ "int32" -> pure (nat n Int)
181+ "date-time" -> pure Time
182+ e -> fail $
183+ "Unable to parse Lit from " ++ Text.unpack e
184+ where
185+ min = either fail (pure . fst) . Read.decimal
186+
187+ nat :: Int -> Lit -> Lit
188+ nat n | n > 0 = const Nat
189+ | otherwise = id
190+
191+-- "pattern": "[A-Z]{3}",
192+-- "pattern": "[0-9a-zA-Z,]+",
193+-- "pattern": "[a-zA-Z]+==[a-zA-Z0-9_+-]+",
194+-- "minimum": "1"
195+-- "format": "date-time", "uint64", "int32",
196+
152deriveToJSON (js "") ''Lit
197deriveToJSON (js "") ''Lit
153
198
154data Ref
199data Ref
@@ -165,6 +210,9 @@ instance Semigroup Ref where
165
210
166instance Hashable Ref
211instance Hashable Ref
167
212
213+instance IsString Ref where
214+ fromString = Direct . fromString
215+
168instance FromJSON Ref where parseJSON = withText "ref" (pure . Direct)
216instance FromJSON Ref where parseJSON = withText "ref" (pure . Direct)
169instance ToJSON Ref where toJSON = toJSON . refToText
217instance ToJSON Ref where toJSON = toJSON . refToText
170
218
@@ -176,11 +224,11 @@ instance ToJSON a => ToJSON (Map Ref a) where
176
224
177refToText :: Ref -> Text
225refToText :: Ref -> Text
178refToText = \case
226refToText = \case
179− Opaque xs -> Text.intercalate "." xs
227+ Opaque xs -> mconcat (map upperHead xs)
180 Direct n -> n
228 Direct n -> n
181
229
182−ref :: Format a (Ref -> a)
230+fref :: Format a (Ref -> a)
183−ref = later (Build.fromText . refToText)
231+fref = later (Build.fromText . refToText)
184
232
185data Schema a
233data Schema a
186 = Obj Info (Map Ref a)
234 = Obj Info (Map Ref a)
@@ -192,35 +240,56 @@ data Schema a
192 deriving (Eq, Show, Functor, Foldable, Traversable)
240 deriving (Eq, Show, Functor, Foldable, Traversable)
193
241
194instance FromJSON (Fix Schema) where
242instance FromJSON (Fix Schema) where
195− parseJSON = withObject "schema" $ \o -> Fix <$> (schema o <|> ref o)
243+ parseJSON = withObject "schema" $ \o -> Fix <$> (ref o <|> schema o)
196 where
244 where
197 schema o = do
245 schema o = do
198 i <- parseJSON (Object o)
246 i <- parseJSON (Object o)
199 o .: "type" >>= \case
247 o .: "type" >>= \case
200− "object" -> Obj i <$> o .: "properties"
248+ "object" -> Obj i <$> o .: "properties"
201− "array" -> Arr i <$> o .: "items"
249+ "array" -> Arr i <$> o .: "items"
202− "string" -> enum i o <|> pure (Lit i String)
203− "boolean" -> pure (Lit i Boolean)
204− "any" -> pure Any'
250+ "any" -> pure Any'
205− e -> fail $
251+ _ -> enum i o <|> Lit i <$> parseJSON (Object o)
206− "Unable to parse Schema from: '" ++ Text.unpack e ++ "'"
207
252
208 enum i o = Enum i <$> o .: "enum" <*> o .: "enumDescriptions"
253 enum i o = Enum i <$> o .: "enum" <*> o .: "enumDescriptions"
209 ref o = Ref <$> o .: "$ref"
254 ref o = Ref <$> o .: "$ref"
210
255
211deriveToJSON (js "") ''Schema
256deriveToJSON (js "") ''Schema
212
257
213−data Param a = Param Location a
258+data Param = Param Location -- (Fix Schema)
214− deriving (Eq, Show, Functor, Foldable, Traversable)
215
259
216−instance FromJSON a => FromJSON (Param a) where
260+instance FromJSON Param where
217 parseJSON = withObject "parameter" $ \o ->
261 parseJSON = withObject "parameter" $ \o ->
218− Param <$> o .: "location" <*> parseJSON (Object o)
262+ Param <$> o .: "location" -- <*> parseJSON (Object o)
219
263
220deriveToJSON (js "") ''Param
264deriveToJSON (js "") ''Param
221
265
222−newtype Data = Data Rendered
266+data Fun = Fun' Text Rendered Rendered
223− deriving (Eq, Show, ToJSON)
267+
268+instance ToJSON Fun where
269+ toJSON (Fun' h s d) = object
270+ [ "help" .= h
271+ , "sig" .= s
272+ , "decl" .= d
273+ ]
274+
275+data Data
276+ = Sum Text Rendered
277+ | Prod Rendered Fun [Fun]
278+
279+instance ToJSON Data where
280+ toJSON = \case
281+ Sum h d -> object
282+ [ "type" .= "sum"
283+ , "decl" .= d
284+ , "help" .= h
285+ ]
286+
287+ Prod d c ls -> object
288+ [ "type" .= "prod"
289+ , "decl" .= d
290+ , "ctor" .= c
291+ , "lenses" .= ls
292+ ]
224
293
225data Service a = Service
294data Service a = Service
226 { _svcLibrary :: Text
295 { _svcLibrary :: Text
@@ -240,8 +309,8 @@ data Service a = Service
240 , _svcServicePath :: Text
309 , _svcServicePath :: Text
241 , _svcBatchPath :: Text
310 , _svcBatchPath :: Text
242 , _svcAuth :: Maybe Object
311 , _svcAuth :: Maybe Object
243− , _svcParameters :: Map Text (Param a)
312+ , _svcParameters :: Map Ref Param
244− , _svcSchemas :: Map Text a
313+ , _svcSchemas :: Map Ref a
245 , _svcResources :: Object
314 , _svcResources :: Object
246 } deriving (Generic)
315 } deriving (Generic)
247
316
@@ -284,16 +353,3 @@ instance ToJSON Library where
284 , "clientVersion" .= _clientVersion _libVersions
353 , "clientVersion" .= _clientVersion _libVersions
285 , "exposedModules" .= concatMap exposedModules (NE.toList _libServices)
354 , "exposedModules" .= concatMap exposedModules (NE.toList _libServices)
286 ]
355 ]
287−
288−mergeLibraries :: Versions -> [Service Data] -> [Library]
289−mergeLibraries v = map go . groupBy (on (==) _svcLibrary)
290− where
291− go [x] = mk x
292− go (x:xs) = (mk x) { _libServices = x :| xs }
293−
294− mk x = Library
295− { _libName = _svcLibrary x
296− , _libTitle = renameTitle (_svcTitle x)
297− , _libVersions = v
298− , _libServices = x :| []
299− }
gen/src/Gen/Types/Map.hsnew file+31
@@ -0,0 +1,31 @@
1+-- Module : Gen.Types.Map
2+-- Copyright : (c) 2013-2015 Brendan Hay
3+-- License : This Source Code Form is subject to the terms of
4+-- the Mozilla Public License, v. 2.0.
5+-- A copy of the MPL can be found in the LICENSE file or
6+-- you can obtain it at http://mozilla.org/MPL/2.0/.
7+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
8+-- Stability : provisional
9+-- Portability : non-portable (GHC extensions)
10+
11+module Gen.Types.Map where
12+
13+import Control.Lens
14+import Data.Hashable
15+import qualified Data.HashMap.Strict as Map
16+import Data.Maybe
17+
18+type Map = Map.HashMap
19+
20+vMapMaybe :: (Eq k, Hashable k)
21+ => (a -> Maybe b)
22+ -> Map k a
23+ -> Map k b
24+vMapMaybe f = runIdentity . kvTraverseMaybe (const (pure . f))
25+
26+kvTraverseMaybe :: (Applicative f, Eq k, Hashable k)
27+ => (k -> a -> f (Maybe b))
28+ -> Map k a
29+ -> f (Map k b)
30+kvTraverseMaybe f = fmap (Map.map fromJust . Map.filter isJust)
31+ . Map.traverseWithKey f
gen/src/Main.hs+3−3
@@ -14,7 +14,6 @@
14
14
15module Main (main) where
15module Main (main) where
16
16
17−import Gen.AST
18import Control.Error
17import Control.Error
19import Control.Lens hiding ((<.>))
18import Control.Lens hiding ((<.>))
20import Control.Monad.State
19import Control.Monad.State
@@ -24,6 +23,7 @@ import Data.Text (Text)
24import qualified Data.Text as Text
23import qualified Data.Text as Text
25import qualified Filesystem as FS
24import qualified Filesystem as FS
26import Filesystem.Path.CurrentOS
25import Filesystem.Path.CurrentOS
26+import Gen.AST
27import Gen.Formatting
27import Gen.Formatting
28import Gen.IO
28import Gen.IO
29import qualified Gen.JSON as JS
29import qualified Gen.JSON as JS
@@ -159,7 +159,7 @@ main = do
159
159
160 return s
160 return s
161
161
162− libs = mergeLibraries _optVersions <$> renderSchemas svcs
162+ libs <- merge _optVersions <$> traverse (hoistEither . render) svcs
163
163
164 void . counter "library" libs $ \l -> do
164 void . counter "library" libs $ \l -> do
165 say ("Creating " % stext % " package.") (_libTitle l)
165 say ("Creating " % stext % " package.") (_libTitle l)
@@ -167,7 +167,7 @@ main = do
167 dir <- hoistEither (Tree.populate _optOutput tmpl l)
167 dir <- hoistEither (Tree.populate _optOutput tmpl l)
168 >>= Tree.fold createDir (\x -> maybe (touchFile x) (writeLTFile x))
168 >>= Tree.fold createDir (\x -> maybe (touchFile x) (writeLTFile x))
169
169
170− say ("Successfully rendered " % stext % "-" % semver % " package")
170+ say ("Successfully rendered " % stext % "-" % fver % " package")
171 (_libName l)
171 (_libName l)
172 (_libraryVersion _optVersions)
172 (_libraryVersion _optVersions)
173
173
gen/template/_include/type.edenew file+19
@@ -0,0 +1,19 @@
1+{% case type.type %}
2+{% when "prod" %}
3+{{ type.decl }}
4+
5+{{ type.ctor.help }}
6+{{ type.ctor.sig }}
7+{{ type.ctor.decl }}
8+ {% for lens in type.lenses %}
9+
10+{{ lens.value.help }}
11+{{ lens.value.sig }}
12+{{ lens.value.decl }}
13+ {% endfor %}
14+ {% when "sum" %}
15+{{ type.help }}
16+{{ type.decl }}
17+{% else %}
18+ Error: Unrecognised type '{{ type.type }}'
19+{% endcase %}
gen/template/types.ede+5
@@ -7,3 +7,8 @@ module {{ moduleName }}
7{% for import in moduleImports %}
7{% for import in moduleImports %}
8import {{ import.value }}
8import {{ import.value }}
9{% endfor %}
9{% endfor %}
10+
11+{% for schema in schemas %}
12+ {% include "_include/type.ede" with type = schema.value %}
13+
14+{% endfor %}