@emasoft/svg-matrix 1.1.0 → 1.2.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/bin/svg-matrix.js +7 -6
- package/bin/svgm.js +109 -40
- package/dist/svg-matrix.min.js +7 -7
- package/dist/svg-toolbox.min.js +148 -228
- package/dist/svgm.min.js +152 -232
- package/dist/version.json +5 -5
- package/package.json +1 -1
- package/scripts/postinstall.js +72 -41
- package/scripts/test-postinstall.js +18 -16
- package/scripts/version-sync.js +78 -60
- package/src/animation-optimization.js +190 -98
- package/src/animation-references.js +11 -3
- package/src/arc-length.js +23 -20
- package/src/bezier-analysis.js +9 -13
- package/src/bezier-intersections.js +18 -4
- package/src/browser-verify.js +35 -8
- package/src/clip-path-resolver.js +285 -114
- package/src/convert-path-data.js +20 -8
- package/src/css-specificity.js +33 -9
- package/src/douglas-peucker.js +272 -141
- package/src/geometry-to-path.js +79 -22
- package/src/gjk-collision.js +287 -126
- package/src/index.js +56 -21
- package/src/inkscape-support.js +122 -101
- package/src/logger.js +43 -27
- package/src/marker-resolver.js +201 -121
- package/src/mask-resolver.js +231 -98
- package/src/matrix.js +9 -5
- package/src/mesh-gradient.js +22 -14
- package/src/off-canvas-detection.js +53 -17
- package/src/path-optimization.js +356 -171
- package/src/path-simplification.js +671 -256
- package/src/pattern-resolver.js +1 -3
- package/src/polygon-clip.js +396 -78
- package/src/svg-boolean-ops.js +90 -23
- package/src/svg-collections.js +1546 -667
- package/src/svg-flatten.js +152 -38
- package/src/svg-matrix-lib.js +2 -2
- package/src/svg-parser.js +5 -1
- package/src/svg-rendering-context.js +3 -1
- package/src/svg-toolbox-lib.js +2 -2
- package/src/svg-toolbox.js +99 -457
- package/src/svg-validation-data.js +513 -345
- package/src/svg2-polyfills.js +156 -93
- package/src/svgm-lib.js +8 -4
- package/src/transform-optimization.js +168 -51
- package/src/transforms2d.js +73 -40
- package/src/transforms3d.js +34 -27
- package/src/use-symbol-resolver.js +175 -76
- package/src/vector.js +80 -44
- package/src/vendor/inkscape-hatch-polyfill.js +143 -108
- package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
- package/src/vendor/inkscape-mesh-polyfill.js +953 -766
- package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
- package/src/verification.js +3 -4
package/bin/svg-matrix.js
CHANGED
|
@@ -603,6 +603,7 @@ function parseFileList(listPath) {
|
|
|
603
603
|
if (isFile(resolved)) files.push(resolved);
|
|
604
604
|
else if (isDir(resolved))
|
|
605
605
|
files.push(...getSvgFiles(resolved, config.recursive));
|
|
606
|
+
// NOTE: Intentional batch mode behavior - warn but continue processing remaining files
|
|
606
607
|
else logWarn(`File not found: ${trimmed}`);
|
|
607
608
|
} catch (e) {
|
|
608
609
|
logWarn(`Invalid path in list: ${trimmed} - ${e.message}`);
|
|
@@ -893,7 +894,7 @@ ${boxLine("", W)}
|
|
|
893
894
|
${boxLine(` ${colors.dim}-o, --output <path>${colors.reset} Output file or directory`, W)}
|
|
894
895
|
${boxLine(` ${colors.dim}-l, --list <file>${colors.reset} Read input files from text file`, W)}
|
|
895
896
|
${boxLine(` ${colors.dim}-r, --recursive${colors.reset} Process directories recursively`, W)}
|
|
896
|
-
${boxLine(` ${colors.dim}-p, --precision <n>${colors.reset} Decimal precision (default: 6, max: 50)`, W)}
|
|
897
|
+
${boxLine(` ${colors.dim}-p, --precision <n>${colors.reset} Decimal precision (default: 6, min: 1, max: 50)`, W)}
|
|
897
898
|
${boxLine(` ${colors.dim}-f, --force${colors.reset} Overwrite existing output files`, W)}
|
|
898
899
|
${boxLine(` ${colors.dim}-n, --dry-run${colors.reset} Show what would be done`, W)}
|
|
899
900
|
${boxLine(` ${colors.dim}-q, --quiet${colors.reset} Suppress all output except errors`, W)}
|
|
@@ -2176,9 +2177,7 @@ function parseArgs(args) {
|
|
|
2176
2177
|
.filter((ns) => ns.length > 0);
|
|
2177
2178
|
// Why: Reject empty array after filtering whitespace-only entries
|
|
2178
2179
|
if (cfg.preserveNamespaces.length === 0) {
|
|
2179
|
-
logError(
|
|
2180
|
-
"--preserve-ns list is empty after filtering whitespace",
|
|
2181
|
-
);
|
|
2180
|
+
logError("--preserve-ns list is empty after filtering whitespace");
|
|
2182
2181
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
2183
2182
|
}
|
|
2184
2183
|
break;
|
|
@@ -2230,8 +2229,10 @@ function parseArgs(args) {
|
|
|
2230
2229
|
logError("--e2e-tolerance requires a value");
|
|
2231
2230
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
2232
2231
|
}
|
|
2233
|
-
if (!/^
|
|
2234
|
-
logError(
|
|
2232
|
+
if (!/^[\d.]+e[+-]?\d+$/i.test(value)) {
|
|
2233
|
+
logError(
|
|
2234
|
+
"e2e-tolerance must be in scientific notation (e.g., 1e-10, 0.5e-12, 2e-8)",
|
|
2235
|
+
);
|
|
2235
2236
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
2236
2237
|
}
|
|
2237
2238
|
cfg.e2eTolerance = value;
|
package/bin/svgm.js
CHANGED
|
@@ -137,12 +137,30 @@ function log(msg) {
|
|
|
137
137
|
function logError(msg) {
|
|
138
138
|
// Why: Validate parameter to prevent runtime errors with null/undefined
|
|
139
139
|
if (typeof msg !== "string") {
|
|
140
|
-
console.error(
|
|
140
|
+
console.error(
|
|
141
|
+
`${colors.red}error:${colors.reset} Invalid error message type: ${typeof msg}`,
|
|
142
|
+
);
|
|
141
143
|
return;
|
|
142
144
|
}
|
|
143
145
|
console.error(`${colors.red}error:${colors.reset} ${msg}`);
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Log warning message to console.
|
|
150
|
+
* @param {string} msg - Warning message
|
|
151
|
+
* @returns {void}
|
|
152
|
+
*/
|
|
153
|
+
function logWarn(msg) {
|
|
154
|
+
// Why: Validate parameter to prevent runtime errors with null/undefined
|
|
155
|
+
if (typeof msg !== "string") {
|
|
156
|
+
console.warn(
|
|
157
|
+
`${colors.yellow}warn:${colors.reset} Invalid warning message type: ${typeof msg}`,
|
|
158
|
+
);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
console.warn(`${colors.yellow}warn:${colors.reset} ${msg}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
146
164
|
// ============================================================================
|
|
147
165
|
// AVAILABLE OPTIMIZATIONS (matching SVGO plugins)
|
|
148
166
|
// ============================================================================
|
|
@@ -381,7 +399,9 @@ function getSvgFiles(dir, recursive = false, exclude = []) {
|
|
|
381
399
|
throw new Error(`getSvgFiles: directory does not exist: ${dir}`);
|
|
382
400
|
}
|
|
383
401
|
if (!Array.isArray(exclude)) {
|
|
384
|
-
throw new TypeError(
|
|
402
|
+
throw new TypeError(
|
|
403
|
+
`getSvgFiles: expected array exclude, got ${typeof exclude}`,
|
|
404
|
+
);
|
|
385
405
|
}
|
|
386
406
|
|
|
387
407
|
// Why: Validate and compile regex patterns once before scanning to fail fast
|
|
@@ -418,8 +438,8 @@ function getSvgFiles(dir, recursive = false, exclude = []) {
|
|
|
418
438
|
const fullPath = join(d, entry.name);
|
|
419
439
|
|
|
420
440
|
// Check exclusion patterns using pre-compiled regexes
|
|
421
|
-
const shouldExclude = excludeRegexes.some(
|
|
422
|
-
regex.test(fullPath) || regex.test(entry.name)
|
|
441
|
+
const shouldExclude = excludeRegexes.some(
|
|
442
|
+
(regex) => regex.test(fullPath) || regex.test(entry.name),
|
|
423
443
|
);
|
|
424
444
|
if (shouldExclude) continue;
|
|
425
445
|
|
|
@@ -451,13 +471,17 @@ function getSvgFiles(dir, recursive = false, exclude = []) {
|
|
|
451
471
|
async function optimizeSvg(content, options = {}) {
|
|
452
472
|
// Why: Validate parameters to prevent runtime errors
|
|
453
473
|
if (typeof content !== "string") {
|
|
454
|
-
throw new TypeError(
|
|
474
|
+
throw new TypeError(
|
|
475
|
+
`optimizeSvg: expected string content, got ${typeof content}`,
|
|
476
|
+
);
|
|
455
477
|
}
|
|
456
478
|
if (content.length === 0) {
|
|
457
479
|
throw new Error("optimizeSvg: content is empty");
|
|
458
480
|
}
|
|
459
481
|
if (options !== null && typeof options !== "object") {
|
|
460
|
-
throw new TypeError(
|
|
482
|
+
throw new TypeError(
|
|
483
|
+
`optimizeSvg: expected object options, got ${typeof options}`,
|
|
484
|
+
);
|
|
461
485
|
}
|
|
462
486
|
const doc = parseSVG(content);
|
|
463
487
|
const pipeline = DEFAULT_PIPELINE;
|
|
@@ -478,8 +502,10 @@ async function optimizeSvg(content, options = {}) {
|
|
|
478
502
|
precision: options.precision,
|
|
479
503
|
preserveNamespaces: options.preserveNamespaces,
|
|
480
504
|
});
|
|
481
|
-
} catch {
|
|
482
|
-
//
|
|
505
|
+
} catch (err) {
|
|
506
|
+
// Batch processing: log and continue so one plugin failure doesn't abort the pipeline.
|
|
507
|
+
// This is intentional - optimization plugins are non-critical and should not halt processing.
|
|
508
|
+
logWarn(`Plugin "${pluginName}" failed: ${err.message}`);
|
|
483
509
|
}
|
|
484
510
|
}
|
|
485
511
|
}
|
|
@@ -494,8 +520,10 @@ async function optimizeSvg(content, options = {}) {
|
|
|
494
520
|
precision: options.precision,
|
|
495
521
|
preserveNamespaces: options.preserveNamespaces,
|
|
496
522
|
});
|
|
497
|
-
} catch {
|
|
498
|
-
//
|
|
523
|
+
} catch (err) {
|
|
524
|
+
// Batch processing: log and continue so one plugin failure doesn't abort the pipeline.
|
|
525
|
+
// This is intentional - optimization plugins are non-critical and should not halt processing.
|
|
526
|
+
logWarn(`Plugin "${pluginName}" failed: ${err.message}`);
|
|
499
527
|
}
|
|
500
528
|
}
|
|
501
529
|
}
|
|
@@ -567,7 +595,9 @@ function prettifyXml(xml, indent = 2) {
|
|
|
567
595
|
throw new TypeError(`prettifyXml: expected string xml, got ${typeof xml}`);
|
|
568
596
|
}
|
|
569
597
|
if (typeof indent !== "number" || indent < 0 || indent > 16) {
|
|
570
|
-
throw new RangeError(
|
|
598
|
+
throw new RangeError(
|
|
599
|
+
`prettifyXml: indent must be number 0-16, got ${indent}`,
|
|
600
|
+
);
|
|
571
601
|
}
|
|
572
602
|
// Simple XML prettifier
|
|
573
603
|
const indentStr = " ".repeat(indent);
|
|
@@ -614,11 +644,15 @@ function prettifyXml(xml, indent = 2) {
|
|
|
614
644
|
function toDataUri(content, format) {
|
|
615
645
|
// Why: Validate parameters to prevent runtime errors
|
|
616
646
|
if (typeof content !== "string") {
|
|
617
|
-
throw new TypeError(
|
|
647
|
+
throw new TypeError(
|
|
648
|
+
`toDataUri: expected string content, got ${typeof content}`,
|
|
649
|
+
);
|
|
618
650
|
}
|
|
619
651
|
const validFormats = ["base64", "enc", "unenc"];
|
|
620
652
|
if (!validFormats.includes(format)) {
|
|
621
|
-
throw new Error(
|
|
653
|
+
throw new Error(
|
|
654
|
+
`toDataUri: format must be one of ${validFormats.join(", ")}, got ${format}`,
|
|
655
|
+
);
|
|
622
656
|
}
|
|
623
657
|
if (format === "base64") {
|
|
624
658
|
return (
|
|
@@ -644,13 +678,25 @@ function toDataUri(content, format) {
|
|
|
644
678
|
async function processFile(inputPath, outputPath, options) {
|
|
645
679
|
// Why: Validate parameters to prevent runtime errors
|
|
646
680
|
if (typeof inputPath !== "string") {
|
|
647
|
-
return {
|
|
681
|
+
return {
|
|
682
|
+
success: false,
|
|
683
|
+
error: `Invalid input path: ${typeof inputPath}`,
|
|
684
|
+
inputPath,
|
|
685
|
+
};
|
|
648
686
|
}
|
|
649
687
|
if (typeof outputPath !== "string") {
|
|
650
|
-
return {
|
|
688
|
+
return {
|
|
689
|
+
success: false,
|
|
690
|
+
error: `Invalid output path: ${typeof outputPath}`,
|
|
691
|
+
inputPath,
|
|
692
|
+
};
|
|
651
693
|
}
|
|
652
694
|
if (options !== null && typeof options !== "object") {
|
|
653
|
-
return {
|
|
695
|
+
return {
|
|
696
|
+
success: false,
|
|
697
|
+
error: `Invalid options: ${typeof options}`,
|
|
698
|
+
inputPath,
|
|
699
|
+
};
|
|
654
700
|
}
|
|
655
701
|
|
|
656
702
|
try {
|
|
@@ -662,7 +708,7 @@ async function processFile(inputPath, outputPath, options) {
|
|
|
662
708
|
return {
|
|
663
709
|
success: false,
|
|
664
710
|
error: `File too large: ${originalSize} bytes (max ${CONSTANTS.MAX_FILE_SIZE_BYTES} bytes)`,
|
|
665
|
-
inputPath
|
|
711
|
+
inputPath,
|
|
666
712
|
};
|
|
667
713
|
}
|
|
668
714
|
|
|
@@ -716,9 +762,8 @@ async function processFile(inputPath, outputPath, options) {
|
|
|
716
762
|
|
|
717
763
|
const savings = originalSize - optimizedSize;
|
|
718
764
|
// Why: Handle case where optimizedSize > originalSize (negative savings)
|
|
719
|
-
const percent =
|
|
720
|
-
? ((savings / originalSize) * 100).toFixed(1)
|
|
721
|
-
: "0.0";
|
|
765
|
+
const percent =
|
|
766
|
+
originalSize > 0 ? ((savings / originalSize) * 100).toFixed(1) : "0.0";
|
|
722
767
|
|
|
723
768
|
return {
|
|
724
769
|
success: true,
|
|
@@ -752,7 +797,7 @@ Arguments:
|
|
|
752
797
|
|
|
753
798
|
Options:
|
|
754
799
|
-v, --version Output the version number
|
|
755
|
-
-i, --input <INPUT...> Input files
|
|
800
|
+
-i, --input <INPUT...> Input files
|
|
756
801
|
-s, --string <STRING> Input SVG data string
|
|
757
802
|
-f, --folder <FOLDER> Input folder, optimize and rewrite all *.svg files
|
|
758
803
|
-o, --output <OUTPUT...> Output file or folder (by default same as input),
|
|
@@ -857,7 +902,9 @@ function loadConfigFile(configPath) {
|
|
|
857
902
|
|
|
858
903
|
// Why: Validate loaded config is an object to prevent runtime errors
|
|
859
904
|
if (loadedConfig === null || typeof loadedConfig !== "object") {
|
|
860
|
-
logError(
|
|
905
|
+
logError(
|
|
906
|
+
`Invalid config file: expected object, got ${typeof loadedConfig}`,
|
|
907
|
+
);
|
|
861
908
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
862
909
|
}
|
|
863
910
|
|
|
@@ -1045,7 +1092,9 @@ function parseArgs(args) {
|
|
|
1045
1092
|
const parsed = parseInt(precisionArg, 10);
|
|
1046
1093
|
// Why: Validate parseInt result to prevent NaN and negative values
|
|
1047
1094
|
if (isNaN(parsed) || parsed < 0) {
|
|
1048
|
-
logError(
|
|
1095
|
+
logError(
|
|
1096
|
+
`--precision requires a non-negative number, got: ${precisionArg}`,
|
|
1097
|
+
);
|
|
1049
1098
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1050
1099
|
}
|
|
1051
1100
|
cfg.precision = parsed;
|
|
@@ -1074,7 +1123,9 @@ function parseArgs(args) {
|
|
|
1074
1123
|
const parsed = parseInt(indentArg, 10);
|
|
1075
1124
|
// Why: Validate parseInt result to prevent NaN and negative values
|
|
1076
1125
|
if (isNaN(parsed) || parsed < 0) {
|
|
1077
|
-
logError(
|
|
1126
|
+
logError(
|
|
1127
|
+
`--indent requires a non-negative number, got: ${indentArg}`,
|
|
1128
|
+
);
|
|
1078
1129
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1079
1130
|
}
|
|
1080
1131
|
cfg.indent = parsed;
|
|
@@ -1236,7 +1287,9 @@ function parseArgs(args) {
|
|
|
1236
1287
|
const parsed = parseInt(depthArg, 10);
|
|
1237
1288
|
// Why: Validate parseInt result to prevent NaN and negative/zero values
|
|
1238
1289
|
if (isNaN(parsed) || parsed < 1) {
|
|
1239
|
-
logError(
|
|
1290
|
+
logError(
|
|
1291
|
+
`--embed-max-depth requires a positive number, got: ${depthArg}`,
|
|
1292
|
+
);
|
|
1240
1293
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1241
1294
|
}
|
|
1242
1295
|
cfg.embedMaxRecursionDepth = parsed;
|
|
@@ -1251,7 +1304,9 @@ function parseArgs(args) {
|
|
|
1251
1304
|
const parsed = parseInt(timeoutArg, 10);
|
|
1252
1305
|
// Why: Validate parseInt result to prevent NaN and negative/zero values
|
|
1253
1306
|
if (isNaN(parsed) || parsed < 1000) {
|
|
1254
|
-
logError(
|
|
1307
|
+
logError(
|
|
1308
|
+
`--embed-timeout requires a number >= 1000 (ms), got: ${timeoutArg}`,
|
|
1309
|
+
);
|
|
1255
1310
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1256
1311
|
}
|
|
1257
1312
|
cfg.embedTimeout = parsed;
|
|
@@ -1280,23 +1335,34 @@ function parseArgs(args) {
|
|
|
1280
1335
|
// Validate numeric arguments
|
|
1281
1336
|
// Why: Check type first before using isNaN to prevent incorrect validation
|
|
1282
1337
|
if (
|
|
1283
|
-
cfg.precision !== undefined &&
|
|
1284
|
-
|
|
1285
|
-
|
|
1338
|
+
cfg.precision !== undefined &&
|
|
1339
|
+
cfg.precision !== null &&
|
|
1340
|
+
(typeof cfg.precision !== "number" ||
|
|
1341
|
+
isNaN(cfg.precision) ||
|
|
1342
|
+
cfg.precision < CONSTANTS.MIN_PRECISION ||
|
|
1343
|
+
cfg.precision > CONSTANTS.MAX_PRECISION)
|
|
1286
1344
|
) {
|
|
1287
|
-
logError(
|
|
1345
|
+
logError(
|
|
1346
|
+
`--precision must be a number between ${CONSTANTS.MIN_PRECISION} and ${CONSTANTS.MAX_PRECISION}`,
|
|
1347
|
+
);
|
|
1288
1348
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1289
1349
|
}
|
|
1290
1350
|
if (
|
|
1291
|
-
cfg.indent !== undefined &&
|
|
1292
|
-
|
|
1351
|
+
cfg.indent !== undefined &&
|
|
1352
|
+
cfg.indent !== null &&
|
|
1353
|
+
(typeof cfg.indent !== "number" ||
|
|
1354
|
+
isNaN(cfg.indent) ||
|
|
1355
|
+
cfg.indent < 0 ||
|
|
1356
|
+
cfg.indent > 16)
|
|
1293
1357
|
) {
|
|
1294
1358
|
logError("--indent must be a number between 0 and 16");
|
|
1295
1359
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1296
1360
|
}
|
|
1297
1361
|
if (
|
|
1298
|
-
cfg.embedMaxRecursionDepth !== undefined &&
|
|
1299
|
-
|
|
1362
|
+
cfg.embedMaxRecursionDepth !== undefined &&
|
|
1363
|
+
cfg.embedMaxRecursionDepth !== null &&
|
|
1364
|
+
(typeof cfg.embedMaxRecursionDepth !== "number" ||
|
|
1365
|
+
isNaN(cfg.embedMaxRecursionDepth) ||
|
|
1300
1366
|
cfg.embedMaxRecursionDepth < 1 ||
|
|
1301
1367
|
cfg.embedMaxRecursionDepth > 100)
|
|
1302
1368
|
) {
|
|
@@ -1304,8 +1370,10 @@ function parseArgs(args) {
|
|
|
1304
1370
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1305
1371
|
}
|
|
1306
1372
|
if (
|
|
1307
|
-
cfg.embedTimeout !== undefined &&
|
|
1308
|
-
|
|
1373
|
+
cfg.embedTimeout !== undefined &&
|
|
1374
|
+
cfg.embedTimeout !== null &&
|
|
1375
|
+
(typeof cfg.embedTimeout !== "number" ||
|
|
1376
|
+
isNaN(cfg.embedTimeout) ||
|
|
1309
1377
|
cfg.embedTimeout < 1000 ||
|
|
1310
1378
|
cfg.embedTimeout > 300000)
|
|
1311
1379
|
) {
|
|
@@ -1327,7 +1395,6 @@ function parseArgs(args) {
|
|
|
1327
1395
|
const validSvgMode = ["extract", "full"];
|
|
1328
1396
|
if (
|
|
1329
1397
|
cfg.embedExternalSVGMode != null &&
|
|
1330
|
-
cfg.embedExternalSVGMode !== "extract" &&
|
|
1331
1398
|
!validSvgMode.includes(cfg.embedExternalSVGMode)
|
|
1332
1399
|
) {
|
|
1333
1400
|
logError(`--embed-svg-mode must be one of: ${validSvgMode.join(", ")}`);
|
|
@@ -1485,7 +1552,9 @@ async function main() {
|
|
|
1485
1552
|
if (config.output === "-") {
|
|
1486
1553
|
// Why: Validate stdout output only works with single file
|
|
1487
1554
|
if (files.length > 1) {
|
|
1488
|
-
logError(
|
|
1555
|
+
logError(
|
|
1556
|
+
"Cannot output multiple files to stdout (use -o <dir> instead)",
|
|
1557
|
+
);
|
|
1489
1558
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1490
1559
|
}
|
|
1491
1560
|
outputPath = "-";
|
|
@@ -1494,7 +1563,7 @@ async function main() {
|
|
|
1494
1563
|
if (config.output.length !== files.length) {
|
|
1495
1564
|
logError(
|
|
1496
1565
|
`Output count mismatch: ${files.length} input file(s) but ${config.output.length} output path(s). ` +
|
|
1497
|
-
|
|
1566
|
+
`Provide either one output directory or exactly ${files.length} output file(s).`,
|
|
1498
1567
|
);
|
|
1499
1568
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1500
1569
|
}
|
|
@@ -1506,7 +1575,7 @@ async function main() {
|
|
|
1506
1575
|
if (files.length > 1 && !isDir(outputDir)) {
|
|
1507
1576
|
logError(
|
|
1508
1577
|
`Processing ${files.length} files but output "${config.output}" is not a directory. ` +
|
|
1509
|
-
|
|
1578
|
+
`Create the directory first or provide ${files.length} output paths.`,
|
|
1510
1579
|
);
|
|
1511
1580
|
process.exit(CONSTANTS.EXIT_ERROR);
|
|
1512
1581
|
}
|