Skip to content

Instantly share code, notes, and snippets.

@zthxxx
Last active October 9, 2021 04:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zthxxx/0328559c300874139e483240073b12e6 to your computer and use it in GitHub Desktop.
Save zthxxx/0328559c300874139e483240073b12e6 to your computer and use it in GitHub Desktop.
import path from 'path'
import SuperExpressive from 'super-expressive'
// https://gist.github.com/zthxxx/0328559c300874139e483240073b12e6
const genImportRegex = ({ pathExpr, pathFollowedAssert }: {
/**
* path match expressive to captured for replace
*
* pathExpr need to include `.namedCapture('importPath')`
*/
pathExpr: SuperExpressive;
/**
* use for path prefix match,
* that expressive as non-capture followed from captured path
*/
pathFollowedAssert?: SuperExpressive;
}): RegExp => SuperExpressive()
.lineByLine
.allowMultipleMatches
.assertBehind
.startOfInput
.anyOf
.string('import')
.string('export')
.end()
.oneOrMore.whitespaceChar
.optional.group
.zeroOrMore.anyOf
.word
.whitespaceChar
.char('*')
.char('{')
.char('}')
.char(',')
.end()
.oneOrMore.whitespaceChar
.string('from')
.oneOrMore.whitespaceChar
.end()
.char("'")
.end()
.subexpression(pathExpr ?? (
SuperExpressive()
.namedCapture('importPath')
.zeroOrMoreLazy.anyChar
.end()
))
.assertAhead
.subexpression(pathFollowedAssert ?? SuperExpressive())
.char("'")
.zeroOrMoreLazy.whitespaceChar
.anyOf
.char(';')
.endOfInput
.end()
.end()
.toRegex()
const genExactReplace = ([source, target]: [string, string]): [RegExp, string] => ([
genImportRegex({
pathExpr: SuperExpressive()
.namedCapture('importPath')
.string(source)
.end(),
}),
target,
])
const genPrefixReplace = ([source, target]: [string, string]): [RegExp, string] => ([
genImportRegex({
pathExpr: SuperExpressive()
.namedCapture('importPath')
// trim tail slash of source
.string(source.replace(/\/$/, ''))
.end(),
pathFollowedAssert: SuperExpressive()
.optional.group
.char('/')
.oneOrMore.anyOf
.word
.digit
.char('.')
.char('/')
.end()
.end()
}),
target,
])
const pathRelative = (from: string, to: string) => {
const relative = path.relative(from, to)
if (!relative) return '.'
if (!relative.startsWith('.')) {
return ['.', relative].join(path.sep)
}
return relative
}
const calcRelativeReplace = ({ source, target, baseDir, filePath }: {
/** node resolve path, relative to file path */
source: string;
/** node resolve path, relative to baseDir */
target: string;
/** absolute path of base dir */
baseDir?: string;
/** absolute path of file */
filePath: string;
}): [RegExp, string] => genPrefixReplace([
source,
pathRelative(
path.dirname(filePath),
path.join(baseDir ?? process.cwd(), target),
),
])
import SuperExpressive from 'super-expressive'
// use super-expressive
// https://github.com/francisrstokes/super-expressive
/**
* /^(?:import|export)\s+(?:(?:\w|\s|[\*\{\},])*\s+from\s+)?(?<quote>["'])(?<importPath>.*?)\k<quote>\s*?(?:$|[;])/gm
*
* /^(?:import|export)\s+ (?<quote>["']) \k<quote> /gm
* (?<importPath>.*?)
* (?: \s+from\s+)? \s*?(?:$|[;])
* (?:\w|\s|[\*\{\},])*
*/
const importRegex = SuperExpressive()
.lineByLine
.allowMultipleMatches
.group
.startOfInput
.anyOf
.string('import')
.string('export')
.end()
.oneOrMore.whitespaceChar
.optional.group
.zeroOrMore.anyOf
.word
.whitespaceChar
.char('*')
.char('{')
.char('}')
.char(',')
.end()
.oneOrMore.whitespaceChar
.string('from')
.oneOrMore.whitespaceChar
.end()
.namedCapture('quote')
.anyOf
.char('"')
.char("'")
.end()
.end()
.namedCapture('importPath')
.zeroOrMoreLazy.anyChar
.end()
.namedBackreference('quote')
.zeroOrMoreLazy.whitespaceChar
.anyOf
.char(';')
.endOfInput
.end()
.end()
.toRegex()
// output -> (online: https://sepg.netlify.app)
// /^(?:import|export)\s+(?:(?:\w|\s|[\*\{\},])*\s+from\s+)?(?<quote>["'])(?<importPath>.*?)\k<quote>\s*?(?:$|[;])/gm
// online test: https://regexr.com/6748k
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment