pkgprn-internal 0.5.2

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.mjs ADDED
@@ -0,0 +1,1413 @@
1
+ import { readFile, writeFile, rm, readdir, mkdir, rename, stat, access } from 'node:fs/promises';
2
+ import path, { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { cli } from 'cleye';
5
+ import { decode, encode } from '@jridgewell/sourcemap-codec';
6
+
7
+ let globalAppender;
8
+ const appender = (appender) => {
9
+ if (appender !== undefined) {
10
+ globalAppender = appender;
11
+ }
12
+ return globalAppender;
13
+ };
14
+
15
+ let globalInputId = 0;
16
+ const getOptions = (options) => {
17
+ let parentId, tag;
18
+ if (options.length === 1) {
19
+ if (typeof options[0] === 'string') {
20
+ tag = options[0];
21
+ }
22
+ else {
23
+ parentId = options[0]?.id;
24
+ }
25
+ }
26
+ else if (options.length === 2) {
27
+ tag = options[0];
28
+ parentId = options[1]?.id;
29
+ }
30
+ return { parentId, tag };
31
+ };
32
+ const createLogger = (...args) => {
33
+ let initialLogLevel = 1 ;
34
+ let myAppender = (message) => { globalAppender && globalAppender(message); };
35
+ const inputId = globalInputId++;
36
+ const { tag, parentId } = getOptions(args);
37
+ const append = (message, action, loglevel, context) => {
38
+ myAppender && myAppender({
39
+ action,
40
+ inputId,
41
+ message,
42
+ loglevel,
43
+ tag,
44
+ parentId,
45
+ ref,
46
+ context
47
+ });
48
+ };
49
+ const loggerInstance = Object.assign((message, loglevel = 1 , context) => {
50
+ append(message, 3 , loglevel, context);
51
+ }, {
52
+
53
+ start(message, loglevel, context) {
54
+ if (loglevel !== undefined) {
55
+ initialLogLevel = loglevel;
56
+ }
57
+ append(message, 0 , initialLogLevel, context);
58
+ },
59
+
60
+ update(message, loglevel, context) {
61
+ append(message, 1 , loglevel ?? initialLogLevel, context);
62
+ },
63
+
64
+ finish(message, loglevel, context) {
65
+ append(message, 2 , loglevel ?? initialLogLevel, context);
66
+ },
67
+ appender(appender) {
68
+ if (appender !== undefined) {
69
+ myAppender = appender;
70
+ }
71
+ return myAppender;
72
+ }
73
+ });
74
+ Object.defineProperty(loggerInstance, 'id', {
75
+ value: inputId,
76
+ writable: false
77
+ });
78
+ const ref = new WeakRef(loggerInstance);
79
+ return loggerInstance;
80
+ };
81
+
82
+ if (!appender()) {
83
+ const [{ asciiPrefixes, colors, unicodePrefixes, tagFactory }, { createConsoleAppender }, { createFormatter, terminalSupportsUnicode }, { filterMessages }] = await Promise.all([
84
+ import('./default-formatting.Dpf5rT0f.mjs'),
85
+ import('./console-appender.D0FERGUF.mjs'),
86
+ import('./format-utils.CGsPFFMS.mjs'),
87
+ import('./appender-utils.B51llXhb.mjs')
88
+ ]);
89
+ const formatter = createFormatter(colors, terminalSupportsUnicode() ? unicodePrefixes : asciiPrefixes, tagFactory);
90
+ let minLogLevel = 1 ;
91
+ appender(filterMessages((message) => message.loglevel >= minLogLevel, createConsoleAppender(formatter),
92
+ { setMinLevel(logLevel) { minLogLevel = logLevel; } }
93
+ ));
94
+ }
95
+
96
+ function extractReferences(pkg) {
97
+
98
+ const result = [];
99
+
100
+ if (pkg.bin !== undefined && pkg.bin !== null) {
101
+ result.push(pkg.bin);
102
+ }
103
+
104
+ if (typeof pkg.bin === 'object' && pkg.bin !== null && !Array.isArray(pkg.bin)) {
105
+ for (const value of Object.values(pkg.bin)) {
106
+ result.push(value);
107
+ }
108
+ }
109
+
110
+ const topLevelFields = ['main', 'module', 'unpkg', 'umd', 'types', 'typings'];
111
+ for (const field of topLevelFields) {
112
+ if (pkg[field] !== undefined && pkg[field] !== null) {
113
+ result.push(pkg[field]);
114
+ }
115
+ }
116
+
117
+ if (typeof pkg.exports === 'object' && pkg.exports !== null && !Array.isArray(pkg.exports)) {
118
+ for (const level1 of Object.values(pkg.exports)) {
119
+ if (typeof level1 === 'object' && level1 !== null && !Array.isArray(level1)) {
120
+ for (const level2 of Object.values( (level1))) {
121
+ if (Array.isArray(level2)) {
122
+ for (const item of level2) {
123
+ result.push(item);
124
+ }
125
+ } else {
126
+ result.push(level2);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ if (typeof pkg.typesVersions === 'object' && pkg.typesVersions !== null && !Array.isArray(pkg.typesVersions)) {
134
+ for (const level1 of Object.values(pkg.typesVersions)) {
135
+ if (typeof level1 === 'object' && level1 !== null && !Array.isArray(level1)) {
136
+ for (const level2 of Object.values( (level1))) {
137
+ if (Array.isArray(level2)) {
138
+ for (const item of level2) {
139
+ result.push(item);
140
+ }
141
+ } else {
142
+ result.push(level2);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ if (typeof pkg.directories === 'object' && pkg.directories !== null) {
150
+ const dirs = (pkg.directories);
151
+ if (dirs.bin !== undefined && dirs.bin !== null) {
152
+ result.push(dirs.bin);
153
+ }
154
+ }
155
+
156
+ return result;
157
+ }
158
+
159
+ const jsExtensions = ['.js', '.mjs', '.cjs'];
160
+
161
+ function isStrippableFile(file) {
162
+ return jsExtensions.some(ext => file.endsWith(ext));
163
+ }
164
+
165
+ const regexPrecedingKeywords = new Set([
166
+ 'return',
167
+ 'throw',
168
+ 'typeof',
169
+ 'void',
170
+ 'delete',
171
+ 'new',
172
+ 'in',
173
+ 'instanceof',
174
+ 'case',
175
+ 'yield',
176
+ 'await',
177
+ 'of',
178
+ 'export',
179
+ 'import',
180
+ 'default',
181
+ 'extends',
182
+ 'else',
183
+ ]);
184
+
185
+ function classifyBlockComment(source, start, end) {
186
+
187
+ if (source[start + 2] === '!') {
188
+ return 'license';
189
+ }
190
+
191
+ const body = source.slice(start + 2, end - 2);
192
+ if (body.includes('@license') || body.includes('@preserve')) {
193
+ return 'license';
194
+ }
195
+
196
+ if (source[start + 2] === '*' && end - start > 4) {
197
+ return 'jsdoc';
198
+ }
199
+
200
+ return 'regular';
201
+ }
202
+
203
+ function scanComments(source) {
204
+
205
+ const comments = [];
206
+ const len = source.length;
207
+ let i = 0;
208
+
209
+ const templateStack = [];
210
+
211
+ let exprEnd = false;
212
+
213
+ if (len >= 2 && source[0] === '#' && source[1] === '!') {
214
+
215
+ while (i < len && source[i] !== '\n') i++;
216
+
217
+ }
218
+
219
+ while (i < len) {
220
+ const ch = source.charCodeAt(i);
221
+
222
+ if (ch <= 0x20 || ch === 0xfeff || ch === 0xa0) {
223
+ i++;
224
+ continue;
225
+ }
226
+
227
+ if (ch === 0x2f && i + 1 < len && source.charCodeAt(i + 1) === 0x2f ) {
228
+ const start = i;
229
+ i += 2;
230
+ while (i < len && source.charCodeAt(i) !== 0x0a ) i++;
231
+ comments.push({ start, end: i, type: 'regular' });
232
+
233
+ continue;
234
+ }
235
+
236
+ if (ch === 0x2f && i + 1 < len && source.charCodeAt(i + 1) === 0x2a ) {
237
+ const start = i;
238
+ i += 2;
239
+ while (i < len && !((source.charCodeAt(i) === 0x2a && i + 1 < len && source.charCodeAt(i + 1) === 0x2f) )) {
240
+ i++;
241
+ }
242
+ if (i < len) i += 2;
243
+ comments.push({ start, end: i, type: classifyBlockComment(source, start, i) });
244
+
245
+ continue;
246
+ }
247
+
248
+ if (ch === 0x2f && !exprEnd) {
249
+ i = skipRegex(source, i, len);
250
+ exprEnd = true;
251
+ continue;
252
+ }
253
+
254
+ if (ch === 0x27 ) {
255
+ i = skipSingleString(source, i, len);
256
+ exprEnd = true;
257
+ continue;
258
+ }
259
+
260
+ if (ch === 0x22 ) {
261
+ i = skipDoubleString(source, i, len);
262
+ exprEnd = true;
263
+ continue;
264
+ }
265
+
266
+ if (ch === 0x60 ) {
267
+ i = scanTemplateTail(source, i + 1, len, templateStack);
268
+ exprEnd = true;
269
+ continue;
270
+ }
271
+
272
+ if (ch === 0x7d ) {
273
+ if (templateStack.length > 0) {
274
+ const depth = templateStack[templateStack.length - 1];
275
+ if (depth === 0) {
276
+
277
+ templateStack.pop();
278
+ i = scanTemplateTail(source, i + 1, len, templateStack);
279
+ exprEnd = true;
280
+ continue;
281
+ }
282
+ templateStack[templateStack.length - 1] = depth - 1;
283
+ }
284
+ i++;
285
+
286
+ exprEnd = false;
287
+ continue;
288
+ }
289
+
290
+ if (ch === 0x7b ) {
291
+ if (templateStack.length > 0) {
292
+ templateStack[templateStack.length - 1]++;
293
+ }
294
+ i++;
295
+ exprEnd = false;
296
+ continue;
297
+ }
298
+
299
+ if (isIdentStart(ch) || isDigit(ch)) {
300
+ const wordStart = i;
301
+ i++;
302
+ while (i < len && isIdentPart(source.charCodeAt(i))) i++;
303
+ const word = source.slice(wordStart, i);
304
+ exprEnd = !regexPrecedingKeywords.has(word);
305
+ continue;
306
+ }
307
+
308
+ if ((ch === 0x2b || ch === 0x2d) && i + 1 < len && source.charCodeAt(i + 1) === ch) {
309
+ i += 2;
310
+ exprEnd = true;
311
+ continue;
312
+ }
313
+
314
+ if (ch === 0x29 || ch === 0x5d ) {
315
+ i++;
316
+ exprEnd = true;
317
+ continue;
318
+ }
319
+
320
+ i++;
321
+ exprEnd = false;
322
+ }
323
+
324
+ return comments;
325
+ }
326
+
327
+ function isDigit(ch) {
328
+ return ch >= 0x30 && ch <= 0x39;
329
+ }
330
+
331
+ function isIdentStart(ch) {
332
+ return (
333
+ (ch >= 0x41 && ch <= 0x5a) ||
334
+ (ch >= 0x61 && ch <= 0x7a) ||
335
+ ch === 0x5f ||
336
+ ch === 0x24 ||
337
+ ch === 0x5c ||
338
+ ch > 0x7f
339
+ );
340
+ }
341
+
342
+ function isIdentPart(ch) {
343
+ return isIdentStart(ch) || isDigit(ch);
344
+ }
345
+
346
+ function skipSingleString(s, i, len) {
347
+ i++;
348
+ while (i < len) {
349
+ const ch = s.charCodeAt(i);
350
+ if (ch === 0x27 ) {
351
+ i++;
352
+ break;
353
+ }
354
+ if (ch === 0x5c ) {
355
+ i += 2;
356
+ continue;
357
+ }
358
+ if (ch === 0x0a || ch === 0x0d ) break;
359
+ i++;
360
+ }
361
+ return i;
362
+ }
363
+
364
+ function skipDoubleString(s, i, len) {
365
+ i++;
366
+ while (i < len) {
367
+ const ch = s.charCodeAt(i);
368
+ if (ch === 0x22 ) {
369
+ i++;
370
+ break;
371
+ }
372
+ if (ch === 0x5c ) {
373
+ i += 2;
374
+ continue;
375
+ }
376
+ if (ch === 0x0a || ch === 0x0d) break;
377
+ i++;
378
+ }
379
+ return i;
380
+ }
381
+
382
+ function skipRegex(s, i, len) {
383
+ i++;
384
+ while (i < len) {
385
+ const ch = s.charCodeAt(i);
386
+ if (ch === 0x5c ) {
387
+ i += 2;
388
+ continue;
389
+ }
390
+ if (ch === 0x5b ) {
391
+
392
+ i++;
393
+ while (i < len) {
394
+ const cc = s.charCodeAt(i);
395
+ if (cc === 0x5c ) {
396
+ i += 2;
397
+ continue;
398
+ }
399
+ if (cc === 0x5d ) {
400
+ i++;
401
+ break;
402
+ }
403
+ if (cc === 0x0a || cc === 0x0d) break;
404
+ i++;
405
+ }
406
+ continue;
407
+ }
408
+ if (ch === 0x2f ) {
409
+ i++;
410
+
411
+ while (i < len && isRegexFlag(s.charCodeAt(i))) i++;
412
+ break;
413
+ }
414
+ if (ch === 0x0a || ch === 0x0d) break;
415
+ i++;
416
+ }
417
+ return i;
418
+ }
419
+
420
+ function isRegexFlag(ch) {
421
+ return ch >= 0x61 && ch <= 0x7a;
422
+ }
423
+
424
+ function scanTemplateTail(s, i, len, templateStack, comments) {
425
+ while (i < len) {
426
+ const ch = s.charCodeAt(i);
427
+ if (ch === 0x5c ) {
428
+ i += 2;
429
+ continue;
430
+ }
431
+ if (ch === 0x60 ) {
432
+ i++;
433
+ return i;
434
+ }
435
+ if (ch === 0x24 && i + 1 < len && s.charCodeAt(i + 1) === 0x7b ) {
436
+ i += 2;
437
+ templateStack.push(0);
438
+ return i;
439
+ }
440
+ i++;
441
+ }
442
+ return i;
443
+ }
444
+
445
+ function parseCommentTypes(value) {
446
+ if (value === true || value === 'all') {
447
+ return new Set( (['jsdoc', 'license', 'regular']));
448
+ }
449
+
450
+ const valid = (['jsdoc', 'license', 'regular']);
451
+ const parts = String(value)
452
+ .split(',')
453
+ .map(s => s.trim())
454
+ .filter(Boolean);
455
+
456
+ const result = new Set();
457
+
458
+ for (const part of parts) {
459
+ if (part === 'all') {
460
+ return new Set(valid);
461
+ }
462
+ if (!valid.includes( (part))) {
463
+ throw new Error(`unknown comment type "${part}" (expected: ${valid.join(', ')}, all)`);
464
+ }
465
+ result.add( (part));
466
+ }
467
+
468
+ if (result.size === 0) {
469
+ return new Set(valid);
470
+ }
471
+
472
+ return result;
473
+ }
474
+
475
+ function stripCommentsWithLineMap(source, typesToStrip) {
476
+ const comments = scanComments(source);
477
+
478
+ if (comments.length === 0) return { result: source, lineMap: null };
479
+
480
+ const toRemove = comments.filter(c => typesToStrip.has(c.type));
481
+
482
+ if (toRemove.length === 0) return { result: source, lineMap: null };
483
+
484
+ const parts = [];
485
+ let pos = 0;
486
+
487
+ for (const { start, end } of toRemove) {
488
+ if (start > pos) {
489
+ parts.push(source.slice(pos, start));
490
+ }
491
+ pos = end;
492
+ }
493
+
494
+ if (pos < source.length) {
495
+ parts.push(source.slice(pos));
496
+ }
497
+
498
+ let intermediate = parts.join('');
499
+
500
+ const origLines = source.split('\n');
501
+ const origLineCount = origLines.length;
502
+
503
+ function translateOffset(offset) {
504
+ let removed = 0;
505
+ for (const { start, end } of toRemove) {
506
+ if (offset < start) break;
507
+ if (offset < end) return -1;
508
+ removed += end - start;
509
+ }
510
+ return offset - removed;
511
+ }
512
+
513
+ const intermediateText = intermediate;
514
+ const intermediateLineStarts = buildLineStarts(intermediateText);
515
+
516
+ const origToIntermediate = new Int32Array(origLineCount).fill(-1);
517
+ let origOffset = 0;
518
+ for (let oi = 0; oi < origLineCount; oi++) {
519
+ const lineLen = origLines[oi].length;
520
+
521
+ let survived = false;
522
+ for (let ci = 0; ci < lineLen; ci++) {
523
+ const ch = source.charCodeAt(origOffset + ci);
524
+
525
+ if (ch === 0x20 || ch === 0x09 || ch === 0x0d) continue;
526
+ const mapped = translateOffset(origOffset + ci);
527
+ if (mapped !== -1) {
528
+ survived = true;
529
+
530
+ origToIntermediate[oi] = offsetToLine(intermediateLineStarts, mapped);
531
+ break;
532
+ }
533
+ }
534
+ if (!survived) {
535
+ origToIntermediate[oi] = -1;
536
+ }
537
+ origOffset += lineLen + 1;
538
+ }
539
+
540
+ intermediate = intermediate.replace(/[ \t]+$/gm, '');
541
+
542
+ intermediate = intermediate.replace(/\n{3,}/g, '\n\n');
543
+
544
+ if (intermediate.startsWith('#!')) {
545
+ const hashbangEnd = intermediate.indexOf('\n');
546
+ if (hashbangEnd !== -1) {
547
+ const before = intermediate.slice(0, hashbangEnd + 1);
548
+ const after = intermediate.slice(hashbangEnd + 1).replace(/^\n+/, '');
549
+ intermediate = before + after;
550
+ }
551
+ } else {
552
+ intermediate = intermediate.replace(/^\n+/, '');
553
+ }
554
+
555
+ if (source.endsWith('\n') && intermediate.length > 0) {
556
+ intermediate = intermediate.replace(/\n*$/, '\n');
557
+ }
558
+
559
+ const result = intermediate;
560
+
561
+ const finalLines = result.split('\n');
562
+ const intLines = intermediateText.split('\n');
563
+
564
+ const intLinesTrimmed = intLines.map(l => l.replace(/[ \t]+$/, ''));
565
+
566
+ const intermediateToFinal = new Int32Array(intLines.length).fill(-1);
567
+ let fi = 0;
568
+ for (let ii = 0; ii < intLinesTrimmed.length && fi < finalLines.length; ii++) {
569
+ if (intLinesTrimmed[ii] === finalLines[fi]) {
570
+ intermediateToFinal[ii] = fi;
571
+ fi++;
572
+ }
573
+
574
+ }
575
+
576
+ const lineMap = new Int32Array(origLineCount).fill(-1);
577
+ for (let oi = 0; oi < origLineCount; oi++) {
578
+ const il = origToIntermediate[oi];
579
+ if (il >= 0 && il < intermediateToFinal.length) {
580
+ lineMap[oi] = intermediateToFinal[il];
581
+ }
582
+ }
583
+
584
+ return { result, lineMap };
585
+ }
586
+
587
+ function buildLineStarts(text) {
588
+
589
+ const starts = [0];
590
+ for (let i = 0; i < text.length; i++) {
591
+ if (text.charCodeAt(i) === 0x0a) {
592
+ starts.push(i + 1);
593
+ }
594
+ }
595
+ return starts;
596
+ }
597
+
598
+ function offsetToLine(lineStarts, offset) {
599
+
600
+ let lo = 0;
601
+ let hi = lineStarts.length - 1;
602
+ while (lo < hi) {
603
+ const mid = (lo + hi + 1) >>> 1;
604
+ if (lineStarts[mid] <= offset) {
605
+ lo = mid;
606
+ } else {
607
+ hi = mid - 1;
608
+ }
609
+ }
610
+ return lo;
611
+ }
612
+
613
+ function adjustSourcemapLineMappings(map, sourceIndex, lineMap) {
614
+ if (map.version !== 3 || typeof map.mappings !== 'string') return;
615
+
616
+ const decoded = decode(map.mappings);
617
+
618
+ for (const line of decoded) {
619
+
620
+ for (let si = line.length - 1; si >= 0; si--) {
621
+ const seg = line[si];
622
+
623
+ if (seg.length < 4) continue;
624
+ const seg4 = (seg);
625
+
626
+ if (seg4[1] !== sourceIndex) continue;
627
+
628
+ const origLine = seg4[2];
629
+ if (origLine < 0 || origLine >= lineMap.length) {
630
+
631
+ line.splice(si, 1);
632
+ continue;
633
+ }
634
+
635
+ const newLine = lineMap[origLine];
636
+ if (newLine === -1) {
637
+
638
+ line.splice(si, 1);
639
+ continue;
640
+ }
641
+
642
+ seg4[2] = newLine;
643
+ }
644
+ }
645
+
646
+ map.mappings = encode(decoded);
647
+ }
648
+
649
+ const alwaysIncludedExact = ['package.json'];
650
+ const alwaysIncludedBasenames = ['README', 'LICENSE', 'LICENCE'];
651
+
652
+ const alwaysIgnored = ['.DS_Store', '.hg', '.lock-wscript', '.svn', 'CVS', 'config.gypi', 'npm-debug.log'];
653
+
654
+ const alwaysIgnoredPatterns = [
655
+
656
+ { test: ( basename) => basename.endsWith('.orig') },
657
+
658
+ { test: ( basename) => basename.startsWith('.') && basename.endsWith('.swp') },
659
+
660
+ { test: ( basename) => basename.startsWith('._') },
661
+
662
+ { test: ( basename) => /^\.wafpickle-\d+$/.test(basename) },
663
+ ];
664
+
665
+ const hardIgnored = new Set(['.git', '.npmrc', 'node_modules', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lockb']);
666
+
667
+ async function prunePkg(pkg, options, logger) {
668
+ const scriptsToKeep = getScriptsData();
669
+
670
+ const keys = scriptsToKeep[ (options.profile)];
671
+
672
+ if (!keys) {
673
+ throw new Error(`unknown profile ${options.profile}`);
674
+ }
675
+
676
+ pkg.devDependencies = undefined;
677
+ pkg.packageManager = undefined;
678
+
679
+ if (pkg.scripts) {
680
+ for (const key of Object.keys(pkg.scripts)) {
681
+ if (!keys.has(key)) {
682
+ delete pkg.scripts[key];
683
+ }
684
+ }
685
+
686
+ if (Object.keys(pkg.scripts).length === 0) {
687
+ pkg.scripts = undefined;
688
+ }
689
+ }
690
+
691
+ if (options.cleanupFiles) {
692
+ await removeJunkFiles('.');
693
+ } else if (options.flatten) {
694
+ logger('cleanup is disabled, junk files may cause flatten to fail', 2);
695
+ }
696
+
697
+ if (options.flatten) {
698
+ await flatten(pkg, options.flatten, logger);
699
+ }
700
+
701
+ if (options.removeSourcemaps) {
702
+ const sourceMaps = await walkDir('.', ['node_modules']).then(files => files.filter(file => file.endsWith('.map')));
703
+ for (const sourceMap of sourceMaps) {
704
+
705
+ const sourceFile = sourceMap.slice(0, -4);
706
+
707
+ const sourceFileContent = await readFile(sourceFile, 'utf8');
708
+
709
+ const sourceMappingUrl = `\n//# sourceMappingURL=${path.basename(sourceMap)}`;
710
+
711
+ const newContent = sourceFileContent.replace(sourceMappingUrl, '');
712
+
713
+ await writeFile(sourceFile, newContent, 'utf8');
714
+
715
+ await rm(sourceMap);
716
+ }
717
+ }
718
+
719
+ if (options.stripComments) {
720
+ const typesToStrip = parseCommentTypes( (options.stripComments));
721
+ logger.update('stripping comments...');
722
+ const allFiles = await walkDir('.', ['node_modules']);
723
+ const jsFiles = allFiles.filter(isStrippableFile);
724
+ const dtsMapFiles = allFiles.filter(f => f.endsWith('.d.ts.map'));
725
+
726
+ const lineMaps = new Map();
727
+ for (const file of jsFiles) {
728
+ const content = await readFile(file, 'utf8');
729
+ const { result: stripped, lineMap } = stripCommentsWithLineMap(content, typesToStrip);
730
+ if (lineMap) {
731
+ await writeFile(file, stripped, 'utf8');
732
+ lineMaps.set(path.normalize(file), lineMap);
733
+ }
734
+ }
735
+
736
+ if (lineMaps.size > 0 && dtsMapFiles.length > 0) {
737
+ for (const mapFile of dtsMapFiles) {
738
+ const mapContent = await readFile(mapFile, 'utf8');
739
+ let map;
740
+ try {
741
+ map = JSON.parse(mapContent);
742
+ } catch {
743
+ continue;
744
+ }
745
+ if (map.version !== 3 || !Array.isArray(map.sources)) continue;
746
+
747
+ const mapDir = path.dirname(mapFile) || '.';
748
+ let adjusted = false;
749
+ for (let si = 0; si < map.sources.length; si++) {
750
+ const resolved = path.normalize(path.join(mapDir, map.sourceRoot || '', map.sources[si]));
751
+ const lineMap = lineMaps.get(resolved);
752
+ if (lineMap) {
753
+ adjustSourcemapLineMappings(map, si, lineMap);
754
+ adjusted = true;
755
+ }
756
+ }
757
+ if (adjusted) {
758
+ await writeFile(mapFile, `${JSON.stringify(map, null, '\t')}\n`, 'utf8');
759
+ }
760
+ }
761
+ }
762
+ }
763
+
764
+ if (pkg.files && Array.isArray(pkg.files) && options.optimizeFiles) {
765
+ const filterFiles = getAlwaysIncludedFiles(pkg);
766
+
767
+ const depthToFiles = new Map();
768
+
769
+ for (const file of pkg.files.concat(filterFiles)) {
770
+ const dirname = path.dirname(file);
771
+ const depth = dirname.split('/').length;
772
+ if (!depthToFiles.has(depth)) {
773
+ depthToFiles.set(depth, [file]);
774
+ } else {
775
+ depthToFiles.get(depth)?.push(file);
776
+ }
777
+ }
778
+
779
+ const maxDepth = Math.max(...depthToFiles.keys());
780
+ for (let depth = maxDepth; depth > 0; --depth) {
781
+ const files = depthToFiles.get(depth);
782
+ const mapDirToFiles = new Map();
783
+ for (const file of files) {
784
+ const dirname = path.dirname(file);
785
+ const basename = normalizePath(path.basename(file));
786
+ if (!mapDirToFiles.has(dirname)) {
787
+ mapDirToFiles.set(dirname, [basename]);
788
+ } else {
789
+ mapDirToFiles.get(dirname)?.push(basename);
790
+ }
791
+ }
792
+ for (const [dirname, filesInDir] of mapDirToFiles) {
793
+
794
+ const realFiles = await readdir(dirname);
795
+
796
+ const allFilesInDir = realFiles.every(file => filesInDir.includes(file)) || realFiles.length === 0;
797
+ if (allFilesInDir && dirname !== '.') {
798
+ if (!depthToFiles.has(depth - 1)) {
799
+ depthToFiles.set(depth - 1, [dirname]);
800
+ } else {
801
+ depthToFiles.get(depth - 1).push(dirname);
802
+ }
803
+ const thisDepth = depthToFiles.get(depth);
804
+ depthToFiles.set(
805
+ depth,
806
+ thisDepth.filter(( file) =>
807
+ filesInDir.every(( fileInDir) => path.join(dirname, fileInDir) !== file)
808
+ )
809
+ );
810
+ }
811
+ }
812
+ }
813
+
814
+ pkg.files = [...new Set(Array.from(depthToFiles.values()).flat())];
815
+
816
+ pkg.files = pkg.files.filter(( file) => {
817
+ const fileNormalized = normalizePath(file);
818
+ const dirname = path.dirname(fileNormalized);
819
+ const basenameWithoutExtension = path.basename(fileNormalized, path.extname(fileNormalized)).toUpperCase();
820
+ return (
821
+ !filterFiles.includes(fileNormalized) &&
822
+ ((dirname !== '' && dirname !== '.') || !alwaysIncludedBasenames.includes(basenameWithoutExtension))
823
+ );
824
+ });
825
+
826
+ const ignoreDirs = [];
827
+
828
+ for (const fileOrDir of pkg.files) {
829
+ if (await isDirectory(fileOrDir)) {
830
+ const allFiles = await walkDir(fileOrDir);
831
+ if (
832
+ allFiles.every(( file) => {
833
+ const fileNormalized = normalizePath(file);
834
+ return filterFiles.includes(fileNormalized);
835
+ })
836
+ ) {
837
+ ignoreDirs.push(fileOrDir);
838
+ }
839
+ }
840
+ }
841
+
842
+ pkg.files = pkg.files.filter(dir => !ignoreDirs.includes(dir));
843
+
844
+ if (pkg.files.length === 0) {
845
+ pkg.files = undefined;
846
+ }
847
+ }
848
+
849
+ if (pkg.files && Array.isArray(pkg.files) && options.cleanupFiles) {
850
+ await cleanupDir(pkg, logger);
851
+ }
852
+ }
853
+
854
+ async function flatten(pkg, flatten, logger) {
855
+
856
+ const allReferences = extractReferences(pkg);
857
+
858
+ let distDirs;
859
+
860
+ if (flatten === true) {
861
+ let commonSegments;
862
+
863
+ for (const entry of allReferences) {
864
+ if (typeof entry !== 'string') {
865
+ continue;
866
+ }
867
+
868
+ const dirname = path.dirname(entry);
869
+
870
+ const cleanedSegments = dirname.split('/').filter(path => path && path !== '.');
871
+ if (!commonSegments) {
872
+ commonSegments = cleanedSegments;
873
+ } else {
874
+ for (let i = 0; i < commonSegments.length; ++i) {
875
+ if (commonSegments[i] !== cleanedSegments[i]) {
876
+ commonSegments.length = i;
877
+ break;
878
+ }
879
+ }
880
+ }
881
+ }
882
+ const distDir = commonSegments?.join('/');
883
+ if (!distDir) {
884
+ throw new Error('could not find dist folder');
885
+ }
886
+ distDirs = [distDir];
887
+ } else {
888
+
889
+ distDirs = flatten
890
+ .split(',')
891
+ .map(d => normalizePath(d.trim()))
892
+ .filter(Boolean);
893
+ }
894
+
895
+ logger.update(`flattening ${distDirs.join(', ')}...`);
896
+
897
+ const distDirInfo = new Map();
898
+
899
+ for (const distDir of distDirs) {
900
+ const relativeDistDir = `./${distDir}`;
901
+ const files = await walkDir(relativeDistDir);
902
+ distDirInfo.set(distDir, { distDir, relativeDistDir, files });
903
+ }
904
+
905
+ const destinationToSource = new Map();
906
+ const existsPromises = [];
907
+
908
+ for (const [distDir, info] of distDirInfo) {
909
+ for (const file of info.files) {
910
+ const relativePath = path.relative(info.relativeDistDir, file);
911
+
912
+ if (destinationToSource.has(relativePath)) {
913
+ const otherDir = destinationToSource.get(relativePath);
914
+ throw new Error(`cannot flatten because '${relativePath}' exists in both '${otherDir}' and '${distDir}'`);
915
+ }
916
+ destinationToSource.set(relativePath, distDir);
917
+ existsPromises.push(isExists(relativePath));
918
+ }
919
+ }
920
+
921
+ const exists = await Promise.all(existsPromises);
922
+
923
+ const filesAlreadyExist = exists.filter(Boolean);
924
+
925
+ if (filesAlreadyExist.length) {
926
+ throw new Error(`dist folder cannot be flattened because files already exist: ${filesAlreadyExist.join(', ')}`);
927
+ }
928
+
929
+ for (const distDir of distDirs) {
930
+ if (
931
+ 'directories' in pkg &&
932
+ pkg.directories != null &&
933
+ typeof pkg.directories === 'object' &&
934
+ 'bin' in pkg.directories &&
935
+ typeof pkg.directories.bin === 'string' &&
936
+ normalizePath(pkg.directories.bin) === distDir
937
+ ) {
938
+ delete pkg.directories.bin;
939
+ if (Object.keys(pkg.directories).length === 0) {
940
+ pkg.directories = undefined;
941
+ }
942
+ const files = await readdir(distDir);
943
+ if (files.length === 1) {
944
+ pkg.bin = files[0];
945
+ } else {
946
+ pkg.bin = {};
947
+ for (const file of files) {
948
+ pkg.bin[path.basename(file, path.extname(file))] = file;
949
+ }
950
+ }
951
+ }
952
+ }
953
+
954
+ const mkdirPromises = [];
955
+ for (const [, info] of distDirInfo) {
956
+ for (const file of info.files) {
957
+ const relativePath = path.relative(info.relativeDistDir, file);
958
+ mkdirPromises.push(mkdir(path.dirname(relativePath), { recursive: true }));
959
+ }
960
+ }
961
+
962
+ await Promise.all(mkdirPromises);
963
+
964
+ const renamePromises = [];
965
+ const newFiles = [];
966
+
967
+ const movedFiles = new Map();
968
+
969
+ for (const [, info] of distDirInfo) {
970
+ for (const file of info.files) {
971
+ const relativePath = path.relative(info.relativeDistDir, file);
972
+ newFiles.push(relativePath);
973
+ movedFiles.set(relativePath, file);
974
+ renamePromises.push(rename(file, relativePath));
975
+ }
976
+ }
977
+
978
+ await Promise.all(renamePromises);
979
+
980
+ if (typeof flatten === 'string') {
981
+
982
+ const oldToNew = new Map();
983
+ for (const [newPath, oldPath] of movedFiles) {
984
+ oldToNew.set(path.normalize(oldPath), newPath);
985
+ }
986
+
987
+ const sourcemapFiles = newFiles.filter(f => f.endsWith('.map'));
988
+ for (const newMapPath of sourcemapFiles) {
989
+ const oldMapPath = movedFiles.get(newMapPath);
990
+ if (oldMapPath) {
991
+ await adjustSourcemapPaths(newMapPath, oldMapPath, oldToNew);
992
+ }
993
+ }
994
+ }
995
+
996
+ const cleanedDirs = [];
997
+ for (const [, info] of distDirInfo) {
998
+ let cleanedDir = info.relativeDistDir;
999
+ while (await isEmptyDir(cleanedDir)) {
1000
+ await rm(cleanedDir, { recursive: true, force: true });
1001
+ const parentDir = path.dirname(cleanedDir);
1002
+ if (parentDir === '.') {
1003
+ break;
1004
+ }
1005
+ cleanedDir = parentDir;
1006
+ }
1007
+ cleanedDirs.push(normalizePath(cleanedDir));
1008
+ }
1009
+
1010
+ const allReferencesSet = new Set(allReferences);
1011
+
1012
+ const stringsToReplace = distDirs.map(d => `${d}/`);
1013
+ const pkgClone = cloneAndUpdate(pkg, value => {
1014
+ if (!allReferencesSet.has(value)) {
1015
+ return value;
1016
+ }
1017
+ for (const stringToReplace of stringsToReplace) {
1018
+ if (value.includes(stringToReplace)) {
1019
+ return value.replace(stringToReplace, '');
1020
+ }
1021
+ }
1022
+ return value;
1023
+ });
1024
+ Object.assign(pkg, pkgClone);
1025
+
1026
+ let files = pkg.files;
1027
+ if (files) {
1028
+ files = files.filter(file => {
1029
+ const fileNormalized = normalizePath(file);
1030
+ return !cleanedDirs.some(cleanedDir => isSubDirectory(cleanedDir, fileNormalized) || fileNormalized === cleanedDir);
1031
+ });
1032
+ files.push(...newFiles);
1033
+ pkg.files = [...files];
1034
+ }
1035
+
1036
+ const exports$1 = pkg.exports ? Object.keys(pkg.exports) : [];
1037
+ for (const key of exports$1) {
1038
+ if (key === '.') {
1039
+ continue;
1040
+ }
1041
+ const isDir = await isDirectory(key);
1042
+ if (isDir) {
1043
+ const pkgPath = path.join(key, 'package.json');
1044
+ const pkgExists = await isExists(pkgPath);
1045
+
1046
+ const files = await readdir(key);
1047
+ if (files.length === 1 && pkgExists) {
1048
+ await rm(key, { recursive: true, force: true });
1049
+ }
1050
+ }
1051
+ }
1052
+ }
1053
+
1054
+ function normalizePath(file) {
1055
+ let fileNormalized = path.normalize(file);
1056
+ if (fileNormalized.endsWith('/') || fileNormalized.endsWith('\\')) {
1057
+
1058
+ fileNormalized = fileNormalized.slice(0, -1);
1059
+ }
1060
+ return fileNormalized;
1061
+ }
1062
+
1063
+ function cloneAndUpdate(pkg, updater) {
1064
+ if (typeof pkg === 'string') {
1065
+ return updater(pkg);
1066
+ }
1067
+ if (Array.isArray(pkg)) {
1068
+ return pkg.map(value => cloneAndUpdate(value, updater));
1069
+ }
1070
+ if (typeof pkg === 'object' && pkg !== null) {
1071
+
1072
+ const clone = {};
1073
+ for (const key of Object.keys(pkg)) {
1074
+ clone[key] = cloneAndUpdate( (pkg)[key], updater);
1075
+ }
1076
+ return clone;
1077
+ }
1078
+ return pkg;
1079
+ }
1080
+
1081
+ async function adjustSourcemapPaths(newMapPath, oldMapPath, oldToNew) {
1082
+ const content = await readFile(newMapPath, 'utf8');
1083
+
1084
+ let map;
1085
+ try {
1086
+ map = JSON.parse(content);
1087
+ } catch {
1088
+ return;
1089
+ }
1090
+
1091
+ if (map.version !== 3 || !Array.isArray(map.sources)) {
1092
+ return;
1093
+ }
1094
+
1095
+ const oldDir = path.dirname(oldMapPath) || '.';
1096
+ const newDir = path.dirname(newMapPath) || '.';
1097
+ const sourceRoot = map.sourceRoot || '';
1098
+
1099
+ map.sources = map.sources.map(( source) => {
1100
+
1101
+ const resolved = path.normalize(path.join(oldDir, sourceRoot, source));
1102
+
1103
+ const effective = oldToNew.get(resolved) ?? resolved;
1104
+
1105
+ const newRelative = path.relative(newDir, effective);
1106
+
1107
+ return newRelative.split(path.sep).join('/');
1108
+ });
1109
+
1110
+ if (map.sourceRoot !== undefined) {
1111
+ delete map.sourceRoot;
1112
+ }
1113
+
1114
+ await writeFile(newMapPath, `${JSON.stringify(map, null, 2)}\n`, 'utf8');
1115
+ }
1116
+
1117
+ function isSubDirectory(parent, child) {
1118
+ const rel = path.relative(parent, child);
1119
+ return rel !== '' && !rel.startsWith('..');
1120
+ }
1121
+
1122
+ async function isEmptyDir(dir) {
1123
+ const entries = await readdir(dir, { withFileTypes: true });
1124
+ return entries.filter(entry => !entry.isDirectory()).length === 0;
1125
+ }
1126
+
1127
+ async function isDirectory(file) {
1128
+ const fileStat = await stat(file);
1129
+ return fileStat.isDirectory();
1130
+ }
1131
+
1132
+ async function walkDir(dir, ignoreDirs = []) {
1133
+ const entries = await readdir(dir, { withFileTypes: true });
1134
+
1135
+ const files = [];
1136
+
1137
+ for (const entry of entries) {
1138
+ if (!entry.isDirectory()) {
1139
+ const childPath = path.join(entry.parentPath, entry.name);
1140
+ files.push(childPath);
1141
+ }
1142
+ }
1143
+
1144
+ for (const entry of entries) {
1145
+ if (entry.isDirectory()) {
1146
+ const childPath = path.join(entry.parentPath, entry.name);
1147
+ const relativePath = path.relative(dir, childPath);
1148
+ const topLevelDir = relativePath.split(path.sep)[0];
1149
+
1150
+ if (!ignoreDirs.includes(topLevelDir)) {
1151
+ const childFiles = await walkDir(childPath);
1152
+ files.push(...childFiles);
1153
+ }
1154
+ }
1155
+ }
1156
+
1157
+ return files;
1158
+ }
1159
+
1160
+ async function isExists(file) {
1161
+ try {
1162
+ await access(file);
1163
+ } catch (e) {
1164
+ if (typeof e === 'object' && e != null && 'code' in e && e.code === 'ENOENT') {
1165
+ return false;
1166
+ }
1167
+ throw e;
1168
+ }
1169
+ return file;
1170
+ }
1171
+
1172
+ function getAlwaysIncludedFiles(pkg) {
1173
+ const files = [...alwaysIncludedExact];
1174
+ if (pkg.main && typeof pkg.main === 'string') {
1175
+ files.push(normalizePath(pkg.main));
1176
+ }
1177
+ if (pkg.bin) {
1178
+ if (typeof pkg.bin === 'string') {
1179
+ files.push(normalizePath(pkg.bin));
1180
+ }
1181
+ if (typeof pkg.bin === 'object' && pkg.bin !== null) {
1182
+ files.push(...Object.values(pkg.bin).map(normalizePath));
1183
+ }
1184
+ }
1185
+ return files;
1186
+ }
1187
+
1188
+ function isAlwaysIgnored(basename) {
1189
+ if (alwaysIgnored.includes(basename)) {
1190
+ return true;
1191
+ }
1192
+ return alwaysIgnoredPatterns.some(pattern => pattern.test(basename));
1193
+ }
1194
+
1195
+ async function removeJunkFiles(dir) {
1196
+ const entries = await readdir(dir, { withFileTypes: true });
1197
+ for (const entry of entries) {
1198
+ if (hardIgnored.has(entry.name)) {
1199
+ continue;
1200
+ }
1201
+ const fullPath = path.join(dir, entry.name);
1202
+ if (isAlwaysIgnored(entry.name)) {
1203
+ await rm(fullPath, { recursive: true, force: true });
1204
+ } else if (entry.isDirectory()) {
1205
+ await removeJunkFiles(fullPath);
1206
+ }
1207
+ }
1208
+ }
1209
+
1210
+ function isAlwaysIncludedByBasename(file) {
1211
+ const dir = path.dirname(file);
1212
+ if (dir !== '' && dir !== '.') {
1213
+ return false;
1214
+ }
1215
+ const basenameWithoutExtension = path.basename(file, path.extname(file)).toUpperCase();
1216
+ return alwaysIncludedBasenames.includes(basenameWithoutExtension);
1217
+ }
1218
+
1219
+ async function cleanupDir(pkg, logger) {
1220
+ logger.update('cleaning up files...');
1221
+
1222
+ const alwaysIncludedFiles = getAlwaysIncludedFiles(pkg);
1223
+ const filesEntries = (pkg.files).map(normalizePath);
1224
+
1225
+ const entries = await readdir('.');
1226
+
1227
+ for (const entry of entries) {
1228
+ if (hardIgnored.has(entry)) {
1229
+ continue;
1230
+ }
1231
+
1232
+ const normalized = normalizePath(entry);
1233
+
1234
+ if (filesEntries.some(f => normalized === f || normalized.startsWith(`${f}/`))) {
1235
+ continue;
1236
+ }
1237
+
1238
+ if (filesEntries.some(f => f.startsWith(`${normalized}/`))) {
1239
+
1240
+ await cleanupSubDir(normalized, filesEntries, alwaysIncludedFiles);
1241
+ continue;
1242
+ }
1243
+
1244
+ if (alwaysIncludedFiles.includes(normalized)) {
1245
+ continue;
1246
+ }
1247
+
1248
+ if (isAlwaysIncludedByBasename(normalized)) {
1249
+ continue;
1250
+ }
1251
+
1252
+ await rm(entry, { recursive: true, force: true });
1253
+ }
1254
+
1255
+ pkg.files = undefined;
1256
+ }
1257
+
1258
+ async function cleanupSubDir(dir, filesEntries, alwaysIncludedFiles) {
1259
+ const entries = await readdir(dir);
1260
+
1261
+ for (const entry of entries) {
1262
+ if (hardIgnored.has(entry)) {
1263
+ continue;
1264
+ }
1265
+
1266
+ const fullPath = path.join(dir, entry);
1267
+
1268
+ const normalized = normalizePath(fullPath);
1269
+
1270
+ if (filesEntries.some(f => normalized === f || normalized.startsWith(`${f}/`))) {
1271
+ continue;
1272
+ }
1273
+
1274
+ if (filesEntries.some(f => f.startsWith(`${normalized}/`))) {
1275
+ await cleanupSubDir(normalized, filesEntries, alwaysIncludedFiles);
1276
+ continue;
1277
+ }
1278
+
1279
+ if (alwaysIncludedFiles.includes(normalized)) {
1280
+ continue;
1281
+ }
1282
+
1283
+ await rm(fullPath, { recursive: true, force: true });
1284
+ }
1285
+
1286
+ const remaining = await readdir(dir);
1287
+ if (remaining.length === 0) {
1288
+ await rm(dir, { recursive: true, force: true });
1289
+ }
1290
+ }
1291
+
1292
+ function getScriptsData() {
1293
+ const libraryScripts = new Set(['preinstall', 'install', 'postinstall', 'prepublish', 'preprepare', 'prepare', 'postprepare']);
1294
+
1295
+ const appScripts = new Set([
1296
+ ...libraryScripts,
1297
+ 'prestart',
1298
+ 'start',
1299
+ 'poststart',
1300
+ 'prerestart',
1301
+ 'restart',
1302
+ 'postrestart',
1303
+ 'prestop',
1304
+ 'stop',
1305
+ 'poststop',
1306
+ 'pretest',
1307
+ 'test',
1308
+ 'posttest',
1309
+ ]);
1310
+
1311
+ return {
1312
+ library: libraryScripts,
1313
+ app: appScripts,
1314
+ };
1315
+ }
1316
+
1317
+ const __dirname$1 = dirname(fileURLToPath(import.meta.url));
1318
+
1319
+ const logger = createLogger();
1320
+ logger.update('preparing..');
1321
+
1322
+ try {
1323
+ const version = await getMyVersion();
1324
+
1325
+ logger.update('');
1326
+ process.stdout.moveCursor?.(0, -1);
1327
+
1328
+ const cliOptions = cli({
1329
+ name: 'pkgprn',
1330
+ version: version ?? '<unknown>',
1331
+ help: {
1332
+ description: 'prune devDependencies and redundant scripts from package.json',
1333
+ },
1334
+ flags: {
1335
+ profile: {
1336
+ type: String,
1337
+ description: 'profile to use',
1338
+ default: 'library',
1339
+ },
1340
+ flatten: {
1341
+ type: FlattenParam,
1342
+ description: 'flatten package files (comma-separated for multiple directories)',
1343
+ default: false,
1344
+ },
1345
+ removeSourcemaps: {
1346
+ type: Boolean,
1347
+ description: 'remove sourcemaps',
1348
+ default: false,
1349
+ },
1350
+ stripComments: {
1351
+ type: StripCommentsParam,
1352
+ description: 'strip comments: all (default), jsdoc, license, regular (comma-separated)',
1353
+ default: false,
1354
+ },
1355
+ optimizeFiles: {
1356
+ type: Boolean,
1357
+ description: 'optimize files array',
1358
+ default: true,
1359
+ },
1360
+ cleanupFiles: {
1361
+ type: Boolean,
1362
+ description: 'cleanup files not included in files array',
1363
+ default: true,
1364
+ },
1365
+ },
1366
+ });
1367
+
1368
+ const pkg = await readPackage('.');
1369
+ if (!pkg) {
1370
+ throw new Error('Could not read package.json');
1371
+ }
1372
+ await prunePkg(pkg, cliOptions.flags, logger);
1373
+
1374
+ await writePackage(pkg);
1375
+ } catch (error) {
1376
+ const errorMessage = error instanceof Error ? error.message : String(error);
1377
+ logger.finish(`Error: ${errorMessage}`, 3);
1378
+ process.exit(255);
1379
+ }
1380
+
1381
+ async function getMyVersion() {
1382
+ const pkg = await readPackage(resolve(__dirname$1));
1383
+
1384
+ return pkg && 'version' in pkg && typeof pkg.version === 'string' ? pkg.version : '<unknown>';
1385
+ }
1386
+
1387
+ async function readPackage(dir) {
1388
+ const packageFileName = resolve(dir, 'package.json');
1389
+ try {
1390
+ const pkgFile = await readFile(packageFileName);
1391
+ return JSON.parse(pkgFile.toString());
1392
+ } catch {
1393
+
1394
+ }
1395
+ }
1396
+
1397
+ async function writePackage(pkg) {
1398
+ await writeFile('./package.json', `${JSON.stringify(pkg, null, 2)}\n`);
1399
+ }
1400
+
1401
+ function StripCommentsParam(value) {
1402
+ if (value === '') {
1403
+ return 'all';
1404
+ }
1405
+ return value;
1406
+ }
1407
+
1408
+ function FlattenParam(value) {
1409
+ if (value === '') {
1410
+ return true;
1411
+ }
1412
+ return value;
1413
+ }