Fix website not loading on Safari
It's caused by lookahead regex used in dash comment regex for inlining PowerShell. This commit changes dash comment inlining. - Change regex to one without lookahead. - Add more test cases for inlining dash comment in tricky situations. - Refactor makeInlineComment to be it's own function to easily test other regex options. - Document all regex alternatives. - Remove redundant null check (`||`) with adding safe navigation operator (`?`) to allow variable before check to be null instead of throwing exception.
This commit is contained in:
@@ -6,7 +6,7 @@ export class InlinePowerShell implements IPipe {
|
|||||||
if (!code || !hasLines(code)) {
|
if (!code || !hasLines(code)) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
code = replaceComments(code);
|
code = inlineComments(code);
|
||||||
code = mergeLinesWithBacktick(code);
|
code = mergeLinesWithBacktick(code);
|
||||||
code = mergeHereStrings(code);
|
code = mergeHereStrings(code);
|
||||||
const lines = getLines(code)
|
const lines = getLines(code)
|
||||||
@@ -25,18 +25,71 @@ function hasLines(text: string) {
|
|||||||
Line comments using "#" are replaced with inline comment syntax <# comment.. #>
|
Line comments using "#" are replaced with inline comment syntax <# comment.. #>
|
||||||
Otherwise single # comments out rest of the code
|
Otherwise single # comments out rest of the code
|
||||||
*/
|
*/
|
||||||
function replaceComments(code: string) {
|
function inlineComments(code: string): string {
|
||||||
return code.replaceAll(/#(?<!<#)(?![<>])(.*)$/gm, (_$, match1 ) => {
|
const makeInlineComment = (comment: string) => {
|
||||||
const value = match1?.trim();
|
const value = comment?.trim();
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return '<##>';
|
return '<##>';
|
||||||
}
|
}
|
||||||
return `<# ${value} #>`;
|
return `<# ${value} #>`;
|
||||||
|
};
|
||||||
|
return code.replaceAll(/<#.*?#>|#(.*)/g, (match, captureComment) => {
|
||||||
|
if (captureComment === undefined) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return makeInlineComment(captureComment);
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
Other alternatives considered:
|
||||||
|
--------------------------
|
||||||
|
/#(?<!<#)(?![<>])(.*)$/gm
|
||||||
|
-------------------------
|
||||||
|
✅ Simple, yet matches and captures only what's necessary
|
||||||
|
❌ Fails to match some cases
|
||||||
|
❌ `Write-Host "hi" # Comment ending line inline comment but not one #>`
|
||||||
|
❌ `Write-Host "hi" <#Comment starting like inline comment start but not one`
|
||||||
|
❌ `Write-Host "hi" #>Comment starting like inline comment end but not one`
|
||||||
|
❌ Uses lookbehind
|
||||||
|
Safari does not yet support lookbehind and syntax, leading application to not
|
||||||
|
load and throw "Invalid regular expression: invalid group specifier name"
|
||||||
|
https://caniuse.com/js-regexp-lookbehind
|
||||||
|
⏩ Usage
|
||||||
|
return code.replaceAll(/#(?<!<#)(?![<>])(.*)$/gm, (match, captureComment) => {
|
||||||
|
return makeInlineComment(captureComment)
|
||||||
|
});
|
||||||
|
----------------
|
||||||
|
/<#.*?#>|#(.*)/g
|
||||||
|
----------------
|
||||||
|
✅ Simple yet affective
|
||||||
|
❌ Matches all comments, but only captures dash comments
|
||||||
|
❌ Fails to match some cases
|
||||||
|
❌ `Write-Host "hi" # Comment ending line inline comment but not one #>`
|
||||||
|
❌ `Write-Host "hi" <#Comment starting like inline comment start but not one`
|
||||||
|
⏩ Usage
|
||||||
|
return code.replaceAll(/<#.*?#>|#(.*)/g, (match, captureComment) => {
|
||||||
|
if (captureComment === undefined) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return makeInlineComment(captureComment);
|
||||||
|
});
|
||||||
|
------------------------------------
|
||||||
|
/(^(?:<#.*?#>|[^#])*)(?:(#)(.*))?/gm
|
||||||
|
------------------------------------
|
||||||
|
✅ Covers all cases
|
||||||
|
❌ Matches every line, three capture groups are used to build result
|
||||||
|
⏩ Usage
|
||||||
|
return code.replaceAll(/(^(?:<#.*?#>|[^#])*)(?:(#)(.*))?/gm,
|
||||||
|
(match, captureLeft, captureDash, captureComment) => {
|
||||||
|
if (!captureDash) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return captureLeft + makeInlineComment(captureComment);
|
||||||
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLines(code: string) {
|
function getLines(code: string): string [] {
|
||||||
return (code.split(/\r\n|\r|\n/) || []);
|
return (code?.split(/\r\n|\r|\n/) || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ function getCommentCases(): IPipeTestCase[] {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'can convert comment with inline comment parts',
|
name: 'can convert comment with inline comment parts inside',
|
||||||
input: getWindowsLines(
|
input: getWindowsLines(
|
||||||
'$text+= #Comment with < inside',
|
'$text+= #Comment with < inside',
|
||||||
'$text+= #Comment ending with >',
|
'$text+= #Comment ending with >',
|
||||||
@@ -295,14 +295,28 @@ function getCommentCases(): IPipeTestCase[] {
|
|||||||
'$text+= <# Comment with <# inline comment #> #>',
|
'$text+= <# Comment with <# inline comment #> #>',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'can convert comment with inline comment parts around', // Pretty uncommon
|
||||||
|
input: getWindowsLines(
|
||||||
|
'Write-Host "hi" # Comment ending line inline comment but not one #>',
|
||||||
|
'Write-Host "hi" #>Comment starting like inline comment end but not one',
|
||||||
|
// Following line does not compile as valid PowerShell referring to missing #> for inline comment
|
||||||
|
'Write-Host "hi" <#Comment starting like inline comment start but not one',
|
||||||
|
),
|
||||||
|
expectedOutput: getSingleLinedOutput(
|
||||||
|
'Write-Host "hi" <# Comment ending line inline comment but not one #> #>',
|
||||||
|
'Write-Host "hi" <# >Comment starting like inline comment end but not one #>',
|
||||||
|
'Write-Host "hi" <<# Comment starting like inline comment start but not one #>',
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'converts empty hash comment',
|
name: 'converts empty hash comment',
|
||||||
input: getWindowsLines(
|
input: getWindowsLines(
|
||||||
'Write-Host "Lorem ipsus" #',
|
'Write-Host "Comment without text" #',
|
||||||
'Write-Host "Non-empty line"',
|
'Write-Host "Non-empty line"',
|
||||||
),
|
),
|
||||||
expectedOutput: getSingleLinedOutput(
|
expectedOutput: getSingleLinedOutput(
|
||||||
'Write-Host "Lorem ipsus" <##>',
|
'Write-Host "Comment without text" <##>',
|
||||||
'Write-Host "Non-empty line"',
|
'Write-Host "Non-empty line"',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -318,7 +332,7 @@ function getCommentCases(): IPipeTestCase[] {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'trims whitespaces around from match',
|
name: 'trims whitespaces around comment',
|
||||||
input: getWindowsLines(
|
input: getWindowsLines(
|
||||||
'# Comment with whitespaces around ',
|
'# Comment with whitespaces around ',
|
||||||
'#\tComment with tabs around\t\t',
|
'#\tComment with tabs around\t\t',
|
||||||
|
|||||||
Reference in New Issue
Block a user