mockaton 12.6.1 → 12.7.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "12.6.1",
5
+ "version": "12.7.0",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
@@ -252,26 +252,24 @@ function togglePreference(param, nextVal) {
252
252
  * @param {string[]} paths - sorted
253
253
  */
254
254
  export function dittoSplitPaths(paths) {
255
- const result = [['', paths[0]]]
256
- const pathsInParts = paths.map(p => p.split('/').filter(Boolean))
257
-
258
- for (let i = 1; i < paths.length; i++) {
259
- const prev = pathsInParts[i - 1]
260
- const curr = pathsInParts[i]
255
+ const pParts = paths.map(p => p.split('/').filter(Boolean))
256
+ return paths.map((p, i) => {
257
+ if (i === 0)
258
+ return ['', p]
261
259
 
260
+ const prev = pParts[i - 1]
261
+ const curr = pParts[i]
262
262
  const min = Math.min(curr.length, prev.length)
263
263
  let j = 0
264
264
  while (j < min && curr[j] === prev[j])
265
265
  j++
266
266
 
267
267
  if (!j) // no common dirs
268
- result.push(['', paths[i]])
269
- else {
270
- const ditto = '/' + curr.slice(0, j).join('/') + '/'
271
- result.push([ditto, paths[i].slice(ditto.length)])
272
- }
273
- }
274
- return result
268
+ return ['', p]
269
+
270
+ const ditto = '/' + curr.slice(0, j).join('/') + '/'
271
+ return [ditto, p.slice(ditto.length)]
272
+ })
275
273
  }
276
274
 
277
275
 
package/src/client/app.js CHANGED
@@ -481,13 +481,38 @@ function DelayToggler({ checked, commit, optClassName }) {
481
481
  function ClickDragToggler({ checked, commit, className, title, body }) {
482
482
  function onPointerEnter(event) {
483
483
  if (event.buttons === 1)
484
- onPointerDown.call(this)
484
+ onPointerDown.call(this, event)
485
485
  }
486
- function onPointerDown() {
486
+
487
+ function onPointerDown(event) {
488
+ if (event.altKey) {
489
+ onExclusiveClick.call(this)
490
+ return
491
+ }
487
492
  this.checked = !this.checked
488
493
  this.focus()
489
494
  commit(this.checked)
490
495
  }
496
+
497
+ function onExclusiveClick() {
498
+ const selector = selectorForColumnOf(this)
499
+ if (!selector)
500
+ return
501
+
502
+ // Uncheck all other in the column.
503
+ for (const elem of leftSideRef.elem.querySelectorAll(selector))
504
+ if (elem !== this && elem.checked && !elem.disabled) {
505
+ elem.checked = false
506
+ elem.dispatchEvent(new Event('change'))
507
+ }
508
+
509
+ if (!this.checked) {
510
+ this.checked = true
511
+ this.dispatchEvent(new Event('change'))
512
+ }
513
+ this.focus()
514
+ }
515
+
491
516
  function onClick(event) {
492
517
  if (event.pointerType === 'mouse')
493
518
  event.preventDefault()
@@ -667,18 +692,24 @@ function initRealTimeUpdates() {
667
692
  }
668
693
  }
669
694
 
695
+ function selectorForColumnOf(elem) {
696
+ return columnSelectors().find(s => elem?.matches(s))
697
+ }
670
698
 
671
- function initKeyboardNavigation() {
672
- const columnSelectors = [
699
+ function columnSelectors() {
700
+ return [
673
701
  `.${CSS.TableRow} .${CSS.ProxyToggler} input`,
674
702
  `.${CSS.TableRow} .${CSS.DelayToggler} input`,
675
703
  `.${CSS.TableRow} .${CSS.StatusCodeToggler} input`,
676
704
  `.${CSS.TableRow} .${CSS.PreviewLink}`,
677
705
  // No .MockSelector because down/up arrows have native behavior on them
678
706
  ]
707
+ }
679
708
 
709
+
710
+ function initKeyboardNavigation() {
680
711
  const rowSelectors = [
681
- ...columnSelectors,
712
+ ...columnSelectors(),
682
713
  `.${CSS.TableRow} .${CSS.MockSelector}:enabled`,
683
714
  ]
684
715
 
@@ -687,7 +718,7 @@ function initKeyboardNavigation() {
687
718
  case 'ArrowDown':
688
719
  case 'ArrowUp': {
689
720
  const pivot = document.activeElement
690
- const sel = columnSelectors.find(s => pivot?.matches(s))
721
+ const sel = selectorForColumnOf(pivot)
691
722
  if (sel) {
692
723
  const offset = key === 'ArrowDown' ? +1 : -1
693
724
  const siblings = leftSideRef.elem.querySelectorAll(sel)
@@ -5,34 +5,35 @@ import { describe, test } from 'node:test'
5
5
 
6
6
  import pkgJSON from '../../package.json' with { type: 'json' }
7
7
 
8
- const CLI_PATH = join(import.meta.dirname, 'cli.js')
9
- const cli = args => spawnSync(CLI_PATH, args, { encoding: 'utf8' })
8
+ const cli = (...args) => spawnSync(join(import.meta.dirname, 'cli.js'), args, {
9
+ encoding: 'utf8'
10
+ })
10
11
 
11
12
  describe('CLI', () => {
12
13
  test('--invalid-flag', () => {
13
- const { stderr, status } = cli(['--invalid-flag'])
14
+ const { stderr, status } = cli('--invalid-flag')
14
15
  equal(stderr.trim(), `Unknown option '--invalid-flag'`)
15
16
  equal(status, 1)
16
17
  })
17
18
 
18
19
  test('invalid config file', () => {
19
- const { stderr, status } = cli(['--config', 'non-existing-file.js'])
20
+ const { stderr, status } = cli('--config', 'non-existing-file.js')
20
21
  equal(stderr.trim(), `Invalid config file: non-existing-file.js`)
21
22
  equal(status, 1)
22
23
  })
23
24
 
24
25
  test('-v outputs version from package.json', () => {
25
- const { stdout, status } = cli(['-v'])
26
+ const { stdout, status } = cli('-v')
26
27
  equal(stdout.trim(), pkgJSON.version)
27
28
  equal(status, 0)
28
29
  })
29
30
 
30
31
  test('-h outputs usage message', () => {
31
- const { stdout, status } = cli(['-h'])
32
+ const { stdout, status } = cli('-h')
32
33
  equal(stdout.split('\n')[0], 'Usage: mockaton [options]')
33
34
  equal(status, 0)
34
35
  })
35
-
36
+
36
37
  // Mockaton.test.js tests the remaining cli branch
37
38
  })
38
39
 
@@ -1,3 +1,4 @@
1
+ import { MIMEType } from 'node:util'
1
2
  import { config } from '../config.js'
2
3
  import { EXT_UNKNOWN_MIME, EXT_EMPTY } from '../../client/ApiConstants.js'
3
4
 
@@ -146,12 +147,8 @@ export function extFor(mime) {
146
147
  : EXT_EMPTY
147
148
  }
148
149
  function findExt(rawMime) {
149
- const m = parseMime(rawMime)
150
+ const m = new MIMEType(rawMime).essence
150
151
  const extraMimeToExt = mapMimeToExt(config.extraMimes)
151
152
  return extraMimeToExt[m] || mimeToExt[m] || EXT_UNKNOWN_MIME
152
153
  }
153
154
 
154
- export function parseMime(mime) {
155
- return mime.split(';')[0].toLowerCase()
156
- // RFC 9110 §8.3.1
157
- }
@@ -1,15 +1,8 @@
1
1
  import { test } from 'node:test'
2
2
  import { equal } from 'node:assert/strict'
3
- import { parseMime, extFor, mimeFor } from './mime.js'
3
+ import { extFor, mimeFor } from './mime.js'
4
4
 
5
5
 
6
- test('parseMime', () => [
7
- 'text/html',
8
- 'TEXT/html',
9
- 'text/html; charset=utf-8'
10
- ].map(input =>
11
- equal(parseMime(input), 'text/html')))
12
-
13
6
  test('extFor', () => [
14
7
  'text/html',
15
8
  'Text/html',