@zentered/issue-forms-body-parser 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53254,15 +53254,32 @@ function time_parseTime(text) {
53254
53254
 
53255
53255
 
53256
53256
  function parseDuration(text) {
53257
+ let matched = false
53257
53258
  const duration = {
53258
53259
  hours: 0,
53259
53260
  minutes: 0
53260
53261
  }
53261
53262
 
53262
- const pieces = text.replace('m', '').split('h')
53263
- duration.hours = parseInt(pieces[0]) ? parseInt(pieces[0]) : 0
53264
- duration.minutes = parseInt(pieces[1]) ? parseInt(pieces[1]) : 0
53265
- return duration
53263
+ const hoursAndMinutes = new RegExp(/([0-9]+)h([0-9]+)m/)
53264
+ const hours = new RegExp(/([0-9]+)h/)
53265
+
53266
+ if (text.match(hoursAndMinutes)) {
53267
+ matched = true
53268
+ const [, h, m] = text.match(hoursAndMinutes)
53269
+ duration.hours = parseInt(h)
53270
+ duration.minutes = parseInt(m)
53271
+ } else if (text.match(hours)) {
53272
+ matched = true
53273
+ const [, h] = text.match(hours)
53274
+ duration.hours = parseInt(h)
53275
+ duration.minutes = 0
53276
+ }
53277
+
53278
+ if (matched) {
53279
+ return duration
53280
+ } else {
53281
+ return null
53282
+ }
53266
53283
  }
53267
53284
 
53268
53285
  ;// CONCATENATED MODULE: ./src/parsers/list.js
@@ -53322,59 +53339,82 @@ const parsers_parseList = parseList
53322
53339
 
53323
53340
 
53324
53341
 
53342
+
53325
53343
  async function parseMD(body) {
53326
53344
  const tokens = await unified().use(remark_parse).use(remarkGfm).parse(body)
53327
53345
  if (!tokens) {
53328
53346
  return []
53329
53347
  }
53330
53348
 
53331
- const r = {}
53332
- let counter = 0
53333
- for (let idx = 0; idx < tokens.children.length; idx = idx + 2) {
53334
- const current = tokens.children[idx]
53335
- const hasNext = idx + 1 < tokens.children.length
53336
-
53337
- if (current.type === 'heading') {
53338
- const key = slugify(current.children[0].value)
53339
-
53340
- // issue-form answers start with a h3 heading, ignore everything else for now
53341
- const obj = {
53342
- title: current.children[0].value,
53343
- order: counter++
53349
+ const structuredResponse = {}
53350
+ let currentHeading = null
53351
+ for (const token of tokens.children) {
53352
+ const text = await unified()
53353
+ .use(remarkGfm)
53354
+ .use(remark_stringify)
53355
+ .stringify(token)
53356
+ const cleanText = stripFinalNewline(text)
53357
+
53358
+ // issue forms uses h3 as a heading
53359
+ if (token.type === 'heading' && token.depth === 3) {
53360
+ currentHeading = slugify(token.children[0].value)
53361
+ structuredResponse[currentHeading] = {
53362
+ title: token.children[0].value,
53363
+ content: []
53344
53364
  }
53365
+ } else if (token.type === 'paragraph' && currentHeading) {
53366
+ const obj = structuredResponse[currentHeading]
53345
53367
 
53346
- if (hasNext) {
53347
- const next = tokens.children[idx + 1]
53348
- if (next.type === 'list') {
53349
- obj.list = parsers_parseList(next).flat()
53350
- }
53351
- const text = await unified()
53352
- .use(remarkGfm)
53353
- .use(remark_stringify)
53354
- .stringify(next)
53355
- obj.text = stripFinalNewline(text)
53368
+ const date = parsers_parseDate(cleanText)
53369
+ const time = parsers_parseTime(cleanText)
53370
+ const duration = parsers_parseDuration(cleanText)
53356
53371
 
53357
- const date = parsers_parseDate(obj.text)
53358
- const time = parsers_parseTime(obj.text)
53372
+ if (date) {
53373
+ obj.date = date
53374
+ }
53359
53375
 
53360
- if (date) {
53361
- obj.date = date
53362
- }
53376
+ if (time) {
53377
+ obj.time = time
53378
+ }
53363
53379
 
53364
- if (time) {
53365
- obj.time = time
53366
- }
53380
+ if (duration) {
53381
+ obj.duration = duration
53382
+ }
53367
53383
 
53368
- if (key === 'duration') {
53369
- obj.duration = parsers_parseDuration(obj.text)
53370
- }
53384
+ obj.content.push(cleanText)
53385
+ } else if (token.type === 'list') {
53386
+ const obj = structuredResponse[currentHeading]
53387
+ obj.text = cleanText
53388
+ obj.list = parsers_parseList(token).flat()
53389
+ } else if (token.type === 'html') {
53390
+ const obj = structuredResponse[currentHeading]
53391
+ obj.content.push(token.html)
53392
+ } else if (token.type === 'code') {
53393
+ const obj = structuredResponse[currentHeading]
53394
+ obj.lang = token.lang
53395
+ obj.text = cleanText
53396
+ } else if (token.type === 'heading' && token.depth > 3) {
53397
+ const obj = structuredResponse[currentHeading]
53398
+ obj.content.push(token.children[0].value)
53399
+ } else {
53400
+ console.log('unhandled token type')
53401
+ console.log(token)
53402
+ }
53403
+ }
53371
53404
 
53372
- r[key] = obj
53405
+ for (const key in structuredResponse) {
53406
+ const token = structuredResponse[key]
53407
+ const content = token.content.filter(Boolean)
53408
+ if (content && content.length > 0) {
53409
+ if (content.length === 1) {
53410
+ token.text = content[0]
53373
53411
  }
53412
+ token.text = content.join('\n\n')
53374
53413
  }
53414
+ token.content = content
53375
53415
  }
53376
53416
 
53377
- return r
53417
+ return structuredResponse
53378
53418
  }
53379
53419
 
53380
53420
  ;// CONCATENATED MODULE: ./src/index.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zentered/issue-forms-body-parser",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "private": false,
5
5
  "description": "Parser for GitHub Issue Form body, also available as GitHub Action",
6
6
  "keywords": [
package/src/parse.js CHANGED
@@ -6,6 +6,7 @@ import remarkGfm from 'remark-gfm'
6
6
  import slugify from '@sindresorhus/slugify'
7
7
  import remarkStringify from 'remark-stringify'
8
8
  import stripFinalNewline from 'strip-final-newline'
9
+
9
10
  import {
10
11
  parseDate,
11
12
  parseTime,
@@ -19,51 +20,73 @@ export default async function parseMD(body) {
19
20
  return []
20
21
  }
21
22
 
22
- const r = {}
23
- let counter = 0
24
- for (let idx = 0; idx < tokens.children.length; idx = idx + 2) {
25
- const current = tokens.children[idx]
26
- const hasNext = idx + 1 < tokens.children.length
27
-
28
- if (current.type === 'heading') {
29
- const key = slugify(current.children[0].value)
23
+ const structuredResponse = {}
24
+ let currentHeading = null
25
+ for (const token of tokens.children) {
26
+ const text = await unified()
27
+ .use(remarkGfm)
28
+ .use(remarkStringify)
29
+ .stringify(token)
30
+ const cleanText = stripFinalNewline(text)
30
31
 
31
- // issue-form answers start with a h3 heading, ignore everything else for now
32
- const obj = {
33
- title: current.children[0].value,
34
- order: counter++
32
+ // issue forms uses h3 as a heading
33
+ if (token.type === 'heading' && token.depth === 3) {
34
+ currentHeading = slugify(token.children[0].value)
35
+ structuredResponse[currentHeading] = {
36
+ title: token.children[0].value,
37
+ content: []
35
38
  }
39
+ } else if (token.type === 'paragraph' && currentHeading) {
40
+ const obj = structuredResponse[currentHeading]
36
41
 
37
- if (hasNext) {
38
- const next = tokens.children[idx + 1]
39
- if (next.type === 'list') {
40
- obj.list = parseList(next).flat()
41
- }
42
- const text = await unified()
43
- .use(remarkGfm)
44
- .use(remarkStringify)
45
- .stringify(next)
46
- obj.text = stripFinalNewline(text)
42
+ const date = parseDate(cleanText)
43
+ const time = parseTime(cleanText)
44
+ const duration = parseDuration(cleanText)
47
45
 
48
- const date = parseDate(obj.text)
49
- const time = parseTime(obj.text)
46
+ if (date) {
47
+ obj.date = date
48
+ }
50
49
 
51
- if (date) {
52
- obj.date = date
53
- }
50
+ if (time) {
51
+ obj.time = time
52
+ }
54
53
 
55
- if (time) {
56
- obj.time = time
57
- }
54
+ if (duration) {
55
+ obj.duration = duration
56
+ }
58
57
 
59
- if (key === 'duration') {
60
- obj.duration = parseDuration(obj.text)
61
- }
58
+ obj.content.push(cleanText)
59
+ } else if (token.type === 'list') {
60
+ const obj = structuredResponse[currentHeading]
61
+ obj.text = cleanText
62
+ obj.list = parseList(token).flat()
63
+ } else if (token.type === 'html') {
64
+ const obj = structuredResponse[currentHeading]
65
+ obj.content.push(token.html)
66
+ } else if (token.type === 'code') {
67
+ const obj = structuredResponse[currentHeading]
68
+ obj.lang = token.lang
69
+ obj.text = cleanText
70
+ } else if (token.type === 'heading' && token.depth > 3) {
71
+ const obj = structuredResponse[currentHeading]
72
+ obj.content.push(token.children[0].value)
73
+ } else {
74
+ console.log('unhandled token type')
75
+ console.log(token)
76
+ }
77
+ }
62
78
 
63
- r[key] = obj
79
+ for (const key in structuredResponse) {
80
+ const token = structuredResponse[key]
81
+ const content = token.content.filter(Boolean)
82
+ if (content && content.length > 0) {
83
+ if (content.length === 1) {
84
+ token.text = content[0]
64
85
  }
86
+ token.text = content.join('\n\n')
65
87
  }
88
+ token.content = content
66
89
  }
67
90
 
68
- return r
91
+ return structuredResponse
69
92
  }
@@ -1,13 +1,30 @@
1
1
  'use strict'
2
2
 
3
3
  export default function parseDuration(text) {
4
+ let matched = false
4
5
  const duration = {
5
6
  hours: 0,
6
7
  minutes: 0
7
8
  }
8
9
 
9
- const pieces = text.replace('m', '').split('h')
10
- duration.hours = parseInt(pieces[0]) ? parseInt(pieces[0]) : 0
11
- duration.minutes = parseInt(pieces[1]) ? parseInt(pieces[1]) : 0
12
- return duration
10
+ const hoursAndMinutes = new RegExp(/([0-9]+)h([0-9]+)m/)
11
+ const hours = new RegExp(/([0-9]+)h/)
12
+
13
+ if (text.match(hoursAndMinutes)) {
14
+ matched = true
15
+ const [, h, m] = text.match(hoursAndMinutes)
16
+ duration.hours = parseInt(h)
17
+ duration.minutes = parseInt(m)
18
+ } else if (text.match(hours)) {
19
+ matched = true
20
+ const [, h] = text.match(hours)
21
+ duration.hours = parseInt(h)
22
+ duration.minutes = 0
23
+ }
24
+
25
+ if (matched) {
26
+ return duration
27
+ } else {
28
+ return null
29
+ }
13
30
  }
@@ -10,81 +10,75 @@ const test = t.test
10
10
  test('parse(md) should parse GitHub Issue Form data into useful, structured data', async (t) => {
11
11
  const expected = {
12
12
  'event-description': {
13
- order: 0,
14
13
  title: 'Event Description',
15
- text: "Let's meet for coffee and chat about tech, coding, Cyprus and the newly formed\nCDC (Cyprus Developer Community)."
14
+ content: [
15
+ 'Welcome to the CDC - Cyprus Developer Community! Join us for our monthly Larnaka\nmeet & greet event. Meet likeminded people, discuss topics we would like to hear\nabout in upcoming talks, welcome potential speakers, discuss all things tech and\nhave fun!',
16
+ 'Notice with regards to COVID:',
17
+ 'All attendees must follow measures in accordance with Ministry of Health\ndirectives. <https://www.pio.gov.cy/coronavirus/eng>'
18
+ ],
19
+ text: 'Welcome to the CDC - Cyprus Developer Community! Join us for our monthly Larnaka\nmeet & greet event. Meet likeminded people, discuss topics we would like to hear\nabout in upcoming talks, welcome potential speakers, discuss all things tech and\nhave fun!\n\nNotice with regards to COVID:\n\nAll attendees must follow measures in accordance with Ministry of Health\ndirectives. <https://www.pio.gov.cy/coronavirus/eng>'
16
20
  },
17
21
  location: {
18
- order: 1,
19
22
  title: 'Location',
23
+ content: [
24
+ '[Cafe Nero Finikoudes, Larnaka](https://goo.gl/maps/Bzjxdeat3BSdsUSVA)'
25
+ ],
20
26
  text: '[Cafe Nero Finikoudes, Larnaka](https://goo.gl/maps/Bzjxdeat3BSdsUSVA)'
21
27
  },
22
28
  date: {
23
- order: 2,
24
29
  title: 'Date',
25
- text: '11.03.2022',
26
- date: '2022-03-11'
30
+ content: ['11.03.2022'],
31
+ date: '2022-03-11',
32
+ text: '11.03.2022'
27
33
  },
28
- time: { order: 3, title: 'Time', text: '16:00', time: '16:00' },
34
+ time: { title: 'Time', content: ['16:00'], time: '16:00', text: '16:00' },
29
35
  duration: {
30
- order: 4,
31
36
  title: 'Duration',
32
- text: '2h',
33
- duration: { hours: 2, minutes: 0 }
37
+ content: ['2h'],
38
+ duration: { hours: 2, minutes: 0 },
39
+ text: '2h'
34
40
  },
35
41
  'list-item-checked': {
36
- order: 5,
37
42
  title: 'List Item Checked',
43
+ content: [],
44
+ text: "* [x] I agree to follow this project's\n [Code of Conduct](https://berlincodeofconduct.org)",
38
45
  list: [
39
46
  {
40
47
  checked: true,
41
48
  text: "I agree to follow this project's\nCode of Conduct"
42
49
  }
43
- ],
44
- text: "* [x] I agree to follow this project's\n [Code of Conduct](https://berlincodeofconduct.org)"
50
+ ]
45
51
  },
46
52
  'list-item-unchecked': {
47
- order: 6,
48
53
  title: 'List Item Unchecked',
54
+ content: [],
55
+ text: "* [ ] I agree to follow this project's\n [Code of Conduct](https://berlincodeofconduct.org)",
49
56
  list: [
50
57
  {
51
58
  checked: false,
52
59
  text: "I agree to follow this project's\nCode of Conduct"
53
60
  }
54
- ],
55
- text: "* [ ] I agree to follow this project's\n [Code of Conduct](https://berlincodeofconduct.org)"
61
+ ]
56
62
  },
57
63
  'mixed-task-list': {
58
- order: 7,
59
64
  title: 'Mixed Task List',
65
+ content: [],
66
+ text: '* [x] checked\n* [ ] unchecked\n* [x] checked 2\n* [x] checked 3\n* [ ] unchecked 2',
60
67
  list: [
61
68
  { checked: true, text: 'checked' },
62
69
  { checked: false, text: 'unchecked' },
63
70
  { checked: true, text: 'checked 2' },
64
71
  { checked: true, text: 'checked 3' },
65
72
  { checked: false, text: 'unchecked 2' }
66
- ],
67
- text: '* [x] checked\n* [ ] unchecked\n* [x] checked 2\n* [x] checked 3\n* [ ] unchecked 2'
68
- },
69
- 'complex-list': {
70
- order: 8,
71
- title: 'Complex List',
72
- list: [
73
- { checked: null, text: 'one' },
74
- { checked: null, text: 'two' }
75
- ],
76
- text: '* one\n* two\n * three\n * four\n 1. five\n 2. six'
73
+ ]
77
74
  },
78
75
  repositories: {
79
- order: 9,
80
76
  title: 'Repositories',
77
+ content: [],
78
+ lang: 'csv',
81
79
  text: '```csv\nhttps://example.com/repository-1\nhttps://example.com/repository-2\n```'
82
80
  },
83
- visibility: {
84
- order: 10,
85
- title: 'Visibility',
86
- text: 'Internal'
87
- }
81
+ visibility: { title: 'Visibility', content: ['Internal'], text: 'Internal' }
88
82
  }
89
83
 
90
84
  const md = await readFile(
@@ -93,7 +87,8 @@ test('parse(md) should parse GitHub Issue Form data into useful, structured data
93
87
  )
94
88
  const actual = await fn(md)
95
89
  // console.log(JSON.stringify(actual, null, 0))
96
- t.deepEqual(actual, expected)
90
+
91
+ t.same(actual, expected)
97
92
  })
98
93
 
99
94
  test('parse(md) return nothing', async (t) => {
@@ -105,5 +100,5 @@ test('parse(md) return nothing', async (t) => {
105
100
  )
106
101
  const actual = await fn(md)
107
102
  // console.log(JSON.stringify(actual, null, 0))
108
- t.deepEqual(actual, expected)
103
+ t.same(actual, expected)
109
104
  })
@@ -1,7 +1,16 @@
1
1
  ### Event Description
2
2
 
3
- Let's meet for coffee and chat about tech, coding, Cyprus and the newly formed
4
- CDC (Cyprus Developer Community).
3
+ <img width="1107" alt="The Brewery Larnaka" src="https://user-images.githubusercontent.com/3581331/162574191-3c023b32-34d9-4035-90bf-7297cdccaf06.png">
4
+
5
+ Welcome to the CDC - Cyprus Developer Community! Join us for our monthly Larnaka
6
+ meet & greet event. Meet likeminded people, discuss topics we would like to hear
7
+ about in upcoming talks, welcome potential speakers, discuss all things tech and
8
+ have fun!
9
+
10
+ #### Notice with regards to COVID:
11
+
12
+ All attendees must follow measures in accordance with Ministry of Health
13
+ directives. https://www.pio.gov.cy/coronavirus/eng
5
14
 
6
15
  ### Location
7
16
 
@@ -37,15 +46,6 @@ CDC (Cyprus Developer Community).
37
46
  - [x] checked 3
38
47
  - [ ] unchecked 2
39
48
 
40
- ### Complex List
41
-
42
- - one
43
- - two
44
- - three
45
- - four
46
- 1. five
47
- 2. six
48
-
49
49
  ### Repositories
50
50
 
51
51
  ```csv