export function escapeWhistespace ( input ) { return input . replace ( /[ ]{1,}/gmu , ( text ) => `@W${ text . length }}` ) . replace ( /\n{1,}/gmu , ( text ) => `@N${ text . length }}` ) ; } const jsxRegex = /\/\*\s?@jsx\s+([a-zA-Z\.]+)\s*\*\// ; const jsxFragmentRegex = /\/\*\s?@jsxFragment\s+([a-zA-Z\.]+)\s*\*\// ; export function detectPragma ( input ) { let jsx = undefined , jsxFragment = undefined ; const jsxMatch = jsxRegex . exec ( input ) ; if ( jsxMatch ) { jsx = jsxMatch [ 1 ] ; } const jsxFragmentMatch = jsxFragmentRegex . exec ( input ) ; if ( jsxFragmentMatch ) { jsxFragment = jsxFragmentMatch [ 1 ] ; } return { jsx , jsxFragment } ; } export function restoreEscaped ( input , literals ) { return input . replace ( /@(W|L|N)(\d+)\}/g , ( full , type , $2 ) => { if ( type === "L" ) { return literals . get ( full ) as string ; } if ( type === "W" ) { return " " . repeat ( Number ( $2 ) ) ; } if ( type === "N" ) { return "\n" . repeat ( Number ( $2 ) ) ; } throw new Error ( `Unknown type ${ type }` ) ; } ) ; } export function escapeLiteral ( input ) { const literals = new Map ( ) ; let cnt = 1 ; const escaped = input . replace ( /"[^"]*"|'[^']*'|`[^`]*`|\/!\*[^\/]*!\*\//gmu , ( text ) => { const key = `@L${ cnt ++ }}` ; literals . set ( key , text ) ; return key ; } ) ; return { escaped , literals } ; } export function preprocessLight ( input ) { const { escaped , literals } = escapeLiteral ( input ) ; const out = escaped . replace ( /\/\*(.*?)\*\//gmu , "" ) . replace ( /(.*?)(\/\/.*)/gu , "$1" ) . replace ( /(?<!for\s?\()([\n\r\t; ]*;[\n\r\t ;]*)(?!\))/gmu , ";" ) . replace ( /[ \t]+/gmu , " " ) . replace ( /([><%&\|}{\(\)\+\-\*\/\/\n\r,;><])[\n\r\t]+\s*/gmu , "$1" ) ; return restoreEscaped ( out , literals ) ; } export function preprocess ( input ) { const { escaped , literals } = escapeLiteral ( input ) ; const modified = escaped . replace ( /\/\*([.\n]*?)\*\//gmu , "" ) . replace ( /(.*)(\/\/.*)/gu , "$1" ) ; const escaped2 = escapeWhistespace ( modified ) ; return { out : escaped2 , data : literals } ; } export function postprocess ( out , literals ) { return restoreEscaped ( out , literals ) ; } import { is , run , test } from "@mizchi/test" ; const isMain = require . main === module ; if ( process . env . NODE_ENV === "test" ) { const now = Date . now ( ) ; test ( "escape literal" , ( ) => { is ( escapeLiteral ( `"x"` ) , { escaped : `@L1}` } ) ; is ( escapeLiteral ( `"x" "y"` ) , { escaped : `@L1} @L2}` } ) ; is ( escapeLiteral ( `"x" "y" 'zzz'` ) , { escaped : `@L1} @L2} @L3}` } ) ; const e = escapeLiteral ( `"x" "y" 'zzz'` ) ; is ( restoreEscaped ( e . escaped , e . literals ) , `"x" "y" 'zzz'` ) ; } ) ; test ( "tokenize whitespace" , ( ) => { is ( escapeWhistespace ( ` a` ) , `@W1}a` ) ; is ( escapeWhistespace ( `  a` ) , `@W2}a` ) ; is ( escapeWhistespace ( `  a ` ) , `@W2}a@W1}` ) ; is ( restoreEscaped ( escapeWhistespace ( `  a  ` ) , new Map ( ) ) , `  a  ` ) ; } ) ; test ( "preprocessLight" , ( ) => { is ( preprocessLight ( `  a  \n` ) , ` a \n` ) ; is ( preprocessLight ( `  a  \nb` ) , ` a \nb` ) ; is ( preprocessLight ( `class X{
	f() {
    1;
		// x
    // y

		const y = 1;
	}
}
` ) , `class X{f() {1;const y = 1;}}` ) ; is ( preprocessLight ( `` ) , `` ) ; } ) ; test ( "strip inline comment" , ( ) => { is ( preprocess ( "/**/" ) . out , "" ) ; is ( preprocess ( "/**/a/**/" ) . out , "a" ) ; is ( preprocess ( "/*\n*/ax/**/" ) . out , "ax" ) ; } ) ; test ( "line comment" , ( ) => { is ( preprocess ( "a" ) . out , "a" ) ; is ( preprocess ( "//a" ) . out , "" ) ; is ( preprocess ( " //a" ) . out , "@W1}" ) ; is ( preprocess ( "//a\n//b" ) . out , "@N1}" ) ; is ( preprocess ( "a//a\n//b" ) . out , "a@N1}" ) ; is ( preprocess ( "a//a\n//b" ) . out , "a@N1}" ) ; is ( preprocess ( "a\n//xxx\n" ) . out , "a@N2}" ) ; } ) ; run ( { stopOnFail : true , stub : true , isMain } ) . then ( ( ) => { console . log ( "[test:time]" , Date . now ( ) - now ) ; } ) ; }