jostraca 0.26.0 → 0.28.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/README.md +276 -1
- package/dist/build/FileHandler.d.ts +2 -0
- package/dist/build/FileHandler.js +24 -7
- package/dist/build/FileHandler.js.map +1 -1
- package/dist/cmp/Copy.js +12 -13
- package/dist/cmp/Copy.js.map +1 -1
- package/dist/cmp/Fragment.js +6 -6
- package/dist/cmp/Fragment.js.map +1 -1
- package/dist/jostraca.d.ts +36 -36
- package/dist/jostraca.js +15 -15
- package/dist/jostraca.js.map +1 -1
- package/dist/op/CopyOp.js +13 -11
- package/dist/op/CopyOp.js.map +1 -1
- package/dist/util/basic.js +93 -51
- package/dist/util/basic.js.map +1 -1
- package/dist/util/point.d.ts +17 -17
- package/dist/util/point.js +6 -6
- package/dist/util/point.js.map +1 -1
- package/package.json +4 -4
- package/src/build/FileHandler.ts +27 -7
- package/src/cmp/Copy.ts +10 -11
- package/src/cmp/Fragment.ts +2 -2
- package/src/jostraca.ts +3 -3
- package/src/op/CopyOp.ts +12 -12
- package/src/util/basic.ts +111 -60
- package/src/util/point.ts +2 -2
package/src/util/basic.ts
CHANGED
|
@@ -115,6 +115,16 @@ function select(key: any, map: Record<string, Function>) {
|
|
|
115
115
|
*/
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
// Hoisted from getx() to avoid recompilation on every call.
|
|
119
|
+
// A B C D E
|
|
120
|
+
const GETX_TOKEN_RE = /\s*("(\\.|[^"\\])*"|[\w\d_]+|\s+|[^\w\d_]+)\s*/g
|
|
121
|
+
// A: prefixing space and/or comma
|
|
122
|
+
// B: quoted string
|
|
123
|
+
// C: atom
|
|
124
|
+
// D: space
|
|
125
|
+
// E: operator
|
|
126
|
+
|
|
127
|
+
|
|
118
128
|
function getx(root: any, path: string | string[]): any {
|
|
119
129
|
if (null == root || 'object' !== typeof root) {
|
|
120
130
|
return undefined
|
|
@@ -127,13 +137,8 @@ function getx(root: any, path: string | string[]): any {
|
|
|
127
137
|
}
|
|
128
138
|
else if ('string' === typeof path) {
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
let tre =
|
|
132
|
-
// A: prefixing space and/or comma
|
|
133
|
-
// B: quoted string
|
|
134
|
-
// C: atom
|
|
135
|
-
// D: space
|
|
136
|
-
// E: operator
|
|
140
|
+
GETX_TOKEN_RE.lastIndex = 0
|
|
141
|
+
let tre = GETX_TOKEN_RE
|
|
137
142
|
|
|
138
143
|
tokens = []
|
|
139
144
|
let t = null
|
|
@@ -341,6 +346,15 @@ function escre(s: string) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') }
|
|
|
341
346
|
function idenstr(s: string) { return s.replace(/[^\w\d]/g, '_') }
|
|
342
347
|
|
|
343
348
|
|
|
349
|
+
// Cache for compiled template RegExps to avoid recompilation on repeated calls.
|
|
350
|
+
// Stores regex and the mapping from original keys to normalized canon keys.
|
|
351
|
+
const templateRECache = new Map<string, { re: RegExp, canonKeys: [string, string][] }>()
|
|
352
|
+
const TEMPLATE_RE_CACHE_MAX = 100
|
|
353
|
+
|
|
354
|
+
// Cache for eject RegExps.
|
|
355
|
+
const ejectRECache = new Map<string, RegExp>()
|
|
356
|
+
|
|
357
|
+
|
|
344
358
|
// NOTE: $$foo.bar$$ format used as explicit start and end markers mean regex can be used
|
|
345
359
|
// unambiguously ($fooa would not match `foo`)
|
|
346
360
|
function template(
|
|
@@ -364,10 +378,10 @@ function template(
|
|
|
364
378
|
if (null != eject) {
|
|
365
379
|
const ejectStart: RegExp | null = null == eject[0] ? null :
|
|
366
380
|
eject[0] instanceof RegExp ? eject[0] :
|
|
367
|
-
|
|
381
|
+
getCachedEjectRE('' + eject[0])
|
|
368
382
|
const ejectEnd: RegExp | null = null == eject[1] ? null :
|
|
369
383
|
eject[1] instanceof RegExp ? eject[1] :
|
|
370
|
-
|
|
384
|
+
getCachedEjectRE('' + eject[1])
|
|
371
385
|
|
|
372
386
|
if (null != ejectStart && null != ejectEnd) {
|
|
373
387
|
let startIndex = 0
|
|
@@ -392,62 +406,89 @@ function template(
|
|
|
392
406
|
let ref = null == spec?.ref ? '[^$]+' : spec.ref
|
|
393
407
|
let specReplaceMap = spec?.replace || {}
|
|
394
408
|
let specReplaceCanon: any = {}
|
|
395
|
-
|
|
396
|
-
let insertRE
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
409
|
+
|
|
410
|
+
let insertRE: RegExp
|
|
411
|
+
if (null != spec?.insert) {
|
|
412
|
+
insertRE = spec.insert
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
const cacheKey = open + '\0' + close + '\0' + ref + '\0' +
|
|
416
|
+
Object.keys(specReplaceMap).sort().join('\0')
|
|
417
|
+
const cached = templateRECache.get(cacheKey)
|
|
418
|
+
if (cached) {
|
|
419
|
+
insertRE = cached.re
|
|
420
|
+
// Rebuild specReplaceCanon from current values using cached key mapping.
|
|
421
|
+
for (const [origKey, canonKey] of cached.canonKeys) {
|
|
422
|
+
specReplaceCanon[canonKey] = specReplaceMap[origKey]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
let ngI = 1
|
|
427
|
+
const canonKeys: [string, string][] = []
|
|
428
|
+
insertRE = new RegExp(
|
|
429
|
+
|
|
430
|
+
// Match alternate for `$$foo.bar$$` model replacements.
|
|
431
|
+
'(?<J_O>' + open + ')' +
|
|
432
|
+
'(?<J_R>' + ref + ')' +
|
|
433
|
+
'(?<J_C>' + close + ')' +
|
|
434
|
+
|
|
435
|
+
// Template replace entries.
|
|
436
|
+
((Object.keys(specReplaceMap))
|
|
437
|
+
.sort((a, b) => a.startsWith('#') ?
|
|
438
|
+
(a.includes('-') ? b.includes('-') ? b.length - a.length : -1 : b.length - a.length) :
|
|
439
|
+
b.length - a.length)
|
|
440
|
+
.map((k: string, _: any) => (
|
|
441
|
+
|
|
442
|
+
// Normalize key for use as group name as key could be a regexp ('/foo/' format).
|
|
443
|
+
_ = idenstr(k).replace(/_+/g, '_'),
|
|
444
|
+
specReplaceCanon[_] = specReplaceMap[k],
|
|
445
|
+
canonKeys.push([k, _]),
|
|
446
|
+
|
|
447
|
+
// match alternate per key.
|
|
448
|
+
`|(?<J_K${ngI++}_${_}>` +
|
|
449
|
+
|
|
450
|
+
// Custom regexp.
|
|
451
|
+
(k.match(/^\/.+\/$/) ? k.substring(1, k.length - 1)
|
|
452
|
+
|
|
453
|
+
// Prepend a counter to custom group names to ensure they are unique.
|
|
454
|
+
.replace(/\(\?<([\w\d_]+)>/g, (_, p1) => `(?<J_N${ngI++}_${p1}>`) :
|
|
455
|
+
|
|
456
|
+
// Tags: #Name matches <indent><comment><space>#Name<space><newline>
|
|
457
|
+
// #Name-Tag matches same, but inner: #<Identifer>-Tag, and
|
|
458
|
+
// provides {Tag:<identifer>}
|
|
459
|
+
// See template utility unit test!
|
|
460
|
+
(_ = k.match(/^#([A-Za-z0-9]+)(-[A-Z][a-z0-9]+)?$/)) ?
|
|
461
|
+
(`(?<J_N${ngI++}_indent>[ \t]*)` +
|
|
462
|
+
'\\/\\/' +
|
|
463
|
+
'[ \t]*#' +
|
|
464
|
+
(_[1] ?
|
|
465
|
+
`(?<J_T${ngI++}_${_[2]?.substring(1) || 'TAG'}>` +
|
|
466
|
+
(_[2] ? '[A-Za-z0-9]+' : _[1]) + ')' : '') +
|
|
467
|
+
(_[2] ? `-(?<J_N${ngI++}_TAG>${_[2].substring(1)})` : '') +
|
|
468
|
+
'[ \t]*\\n?') :
|
|
469
|
+
|
|
470
|
+
// Just a key string.
|
|
471
|
+
escre(k)) + ')'
|
|
472
|
+
))
|
|
473
|
+
.join('')))
|
|
474
|
+
|
|
475
|
+
if (templateRECache.size >= TEMPLATE_RE_CACHE_MAX) {
|
|
476
|
+
templateRECache.clear()
|
|
477
|
+
}
|
|
478
|
+
templateRECache.set(cacheKey, { re: insertRE, canonKeys })
|
|
479
|
+
}
|
|
480
|
+
}
|
|
443
481
|
|
|
444
482
|
let remain = src
|
|
445
483
|
let nextm = true
|
|
446
484
|
|
|
485
|
+
const hasCustomHandle = null != spec?.handle
|
|
447
486
|
let out = ''
|
|
487
|
+
let parts: string[] = hasCustomHandle ? [] : []
|
|
448
488
|
|
|
449
|
-
// By default,
|
|
450
|
-
let handle =
|
|
489
|
+
// By default, collect into array (O(n) join), but allow for custom handling.
|
|
490
|
+
let handle = hasCustomHandle ? spec!.handle! :
|
|
491
|
+
((s: string) => parts.push(null == s ? '' : s))
|
|
451
492
|
|
|
452
493
|
while (nextm) {
|
|
453
494
|
let m = remain.match(insertRE)
|
|
@@ -536,7 +577,17 @@ function template(
|
|
|
536
577
|
}
|
|
537
578
|
|
|
538
579
|
|
|
539
|
-
return out
|
|
580
|
+
return hasCustomHandle ? out : parts.join('')
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
function getCachedEjectRE(s: string): RegExp {
|
|
585
|
+
let re = ejectRECache.get(s)
|
|
586
|
+
if (!re) {
|
|
587
|
+
re = new RegExp('[ \t]*' + escre(s) + '[ \t]*\\n?')
|
|
588
|
+
ejectRECache.set(s, re)
|
|
589
|
+
}
|
|
590
|
+
return re
|
|
540
591
|
}
|
|
541
592
|
|
|
542
593
|
|
package/src/util/point.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import { Shape, Skip, Any } from 'shape'
|
|
3
3
|
|
|
4
4
|
import { getx } from './basic'
|
|
5
5
|
|
|
@@ -204,7 +204,7 @@ class PrintPoint extends Point {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
const PointDefShape =
|
|
207
|
+
const PointDefShape = Shape({
|
|
208
208
|
k: Skip(String),
|
|
209
209
|
n: Skip(String),
|
|
210
210
|
p: Skip([]),
|