55/** @typedef {import("./index.js").MinimizedResult } MinimizedResult */
66/** @typedef {import("./index.js").CustomOptions } CustomOptions */
77/** @typedef {import("./index.js").RawSourceMap } RawSourceMap */
8+ /** @typedef {import("./index.js").EXPECTED_OBJECT } EXPECTED_OBJECT */
89
910/**
1011 * @template T
@@ -77,10 +78,9 @@ async function terserMinify(
7778 minimizerOptions ,
7879 extractComments ,
7980) {
80- // eslint-disable-next-line jsdoc/no-restricted-syntax
8181 /**
8282 * @param {unknown } value value
83- * @returns {value is object } true when value is object or function
83+ * @returns {value is EXPECTED_OBJECT } true when value is object or function
8484 */
8585 const isObject = ( value ) => {
8686 const type = typeof value ;
@@ -333,10 +333,9 @@ async function uglifyJsMinify(
333333 minimizerOptions ,
334334 extractComments ,
335335) {
336- // eslint-disable-next-line jsdoc/no-restricted-syntax
337336 /**
338337 * @param {unknown } value value
339- * @returns {value is object } true when value is object or function
338+ * @returns {boolean } true when value is object or function
340339 */
341340 const isObject = ( value ) => {
342341 const type = typeof value ;
@@ -555,12 +554,112 @@ uglifyJsMinify.supportsWorkerThreads = () => true;
555554 * @param {Input } input input
556555 * @param {RawSourceMap= } sourceMap source map
557556 * @param {CustomOptions= } minimizerOptions options
557+ * @param {ExtractCommentsOptions= } extractComments extract comments option
558558 * @returns {Promise<MinimizedResult> } minimized result
559559 */
560- async function swcMinify ( input , sourceMap , minimizerOptions ) {
560+ async function swcMinify ( input , sourceMap , minimizerOptions , extractComments ) {
561+ /**
562+ * @param {unknown } value value
563+ * @returns {boolean } true when value is object or function
564+ */
565+ const isObject = ( value ) => {
566+ const type = typeof value ;
567+
568+ // eslint-disable-next-line no-eq-null, eqeqeq
569+ return value != null && ( type === "object" || type === "function" ) ;
570+ } ;
571+
572+ /**
573+ * @param {unknown } extractCommentsOptions extract comments option
574+ * @returns {Error } error for unsupported extract comments option
575+ */
576+ const createExtractCommentsError = ( extractCommentsOptions ) =>
577+ new Error (
578+ `The 'extractComments' option for 'swcMinify' only supports booleans, "some", "all", string patterns, RegExp values without flags, or object conditions that resolve to those forms. Received: ${ extractCommentsOptions instanceof RegExp ? extractCommentsOptions . toString ( ) : typeof extractCommentsOptions } .` ,
579+ ) ;
580+
581+ /**
582+ * @param {unknown } extractCommentsOptions extract comments option
583+ * @returns {{ extractComments: false | true | "some" | "all" | { regex: string }, useDefaultPreserveComments: boolean } } normalized swc extract comments options
584+ */
585+ const normalizeExtractComments = ( extractCommentsOptions ) => {
586+ if ( typeof extractCommentsOptions === "boolean" ) {
587+ return {
588+ extractComments : extractCommentsOptions ,
589+ useDefaultPreserveComments : ! extractCommentsOptions ,
590+ } ;
591+ }
592+
593+ if ( typeof extractCommentsOptions === "string" ) {
594+ return {
595+ extractComments :
596+ extractCommentsOptions === "some" || extractCommentsOptions === "all"
597+ ? extractCommentsOptions
598+ : { regex : extractCommentsOptions } ,
599+ useDefaultPreserveComments : false ,
600+ } ;
601+ }
602+
603+ if ( extractCommentsOptions instanceof RegExp ) {
604+ if ( extractCommentsOptions . flags ) {
605+ throw createExtractCommentsError ( extractCommentsOptions ) ;
606+ }
607+
608+ return {
609+ extractComments : { regex : extractCommentsOptions . source } ,
610+ useDefaultPreserveComments : false ,
611+ } ;
612+ }
613+
614+ if ( typeof extractCommentsOptions === "function" ) {
615+ throw createExtractCommentsError ( extractCommentsOptions ) ;
616+ }
617+
618+ if ( extractCommentsOptions && isObject ( extractCommentsOptions ) ) {
619+ const { condition = "some" } =
620+ /** @type {{ condition?: unknown } } */
621+ ( extractCommentsOptions ) ;
622+
623+ if ( typeof condition === "boolean" ) {
624+ return {
625+ extractComments : condition ? "some" : false ,
626+ useDefaultPreserveComments : false ,
627+ } ;
628+ }
629+
630+ if ( typeof condition === "string" ) {
631+ return {
632+ extractComments :
633+ condition === "some" || condition === "all"
634+ ? condition
635+ : { regex : condition } ,
636+ useDefaultPreserveComments : false ,
637+ } ;
638+ }
639+
640+ if ( condition instanceof RegExp ) {
641+ if ( condition . flags ) {
642+ throw createExtractCommentsError ( condition ) ;
643+ }
644+
645+ return {
646+ extractComments : { regex : condition . source } ,
647+ useDefaultPreserveComments : false ,
648+ } ;
649+ }
650+
651+ throw createExtractCommentsError ( condition ) ;
652+ }
653+
654+ return {
655+ extractComments : false ,
656+ useDefaultPreserveComments : false ,
657+ } ;
658+ } ;
659+
561660 /**
562661 * @param {PredefinedOptions<import("@swc/core").JsMinifyOptions> & import("@swc/core").JsMinifyOptions= } swcOptions swc options
563- * @returns {import("@swc/core").JsMinifyOptions & { sourceMap: undefined | boolean } & { compress: import("@swc/core").TerserCompressOptions } } built swc options
662+ * @returns {import("@swc/core").JsMinifyOptions & { extractComments?: false | true | "some" | "all" | { regex: string } } & { sourceMap: undefined | boolean } & { compress: import("@swc/core").TerserCompressOptions } } built swc options
564663 */
565664 const buildSwcOptions = ( swcOptions = { } ) =>
566665 // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
@@ -579,6 +678,7 @@ async function swcMinify(input, sourceMap, minimizerOptions) {
579678 : typeof swcOptions . mangle === "boolean"
580679 ? swcOptions . mangle
581680 : { ...swcOptions . mangle } ,
681+ format : { ...swcOptions . format } ,
582682 // ecma: swcOptions.ecma,
583683 // keep_classnames: swcOptions.keep_classnames,
584684 // keep_fnames: swcOptions.keep_fnames,
@@ -599,12 +699,29 @@ async function swcMinify(input, sourceMap, minimizerOptions) {
599699
600700 // Copy `swc` options
601701 const swcOptions = buildSwcOptions ( minimizerOptions ) ;
702+ const normalizedExtractComments = normalizeExtractComments ( extractComments ) ;
703+
704+ if ( ! swcOptions . format ) {
705+ swcOptions . format = { } ;
706+ }
602707
603708 // Let `swc` generate a SourceMap
604709 if ( sourceMap ) {
605710 swcOptions . sourceMap = true ;
606711 }
607712
713+ if (
714+ normalizedExtractComments . useDefaultPreserveComments &&
715+ typeof swcOptions . format . comments === "undefined"
716+ ) {
717+ swcOptions . format . comments = "some" ;
718+ }
719+
720+ if ( normalizedExtractComments . extractComments !== false ) {
721+ /** @type {import("@swc/core").JsMinifyOptions & { extractComments?: false | true | "some" | "all" | { regex: string } } } */
722+ ( swcOptions ) . extractComments = normalizedExtractComments . extractComments ;
723+ }
724+
608725 if ( swcOptions . compress ) {
609726 // More optimizations
610727 if ( typeof swcOptions . compress . ecma === "undefined" ) {
@@ -621,7 +738,9 @@ async function swcMinify(input, sourceMap, minimizerOptions) {
621738 }
622739
623740 const [ [ filename , code ] ] = Object . entries ( input ) ;
624- const result = await swc . minify ( code , swcOptions ) ;
741+ const result =
742+ /** @type {import("@swc/core").Output & { extractedComments?: string[] } } */
743+ ( await swc . minify ( code , swcOptions ) ) ;
625744
626745 let map ;
627746
@@ -637,6 +756,7 @@ async function swcMinify(input, sourceMap, minimizerOptions) {
637756 return {
638757 code : result . code ,
639758 map,
759+ extractedComments : result . extractedComments || [ ] ,
640760 } ;
641761}
642762
0 commit comments