-
Notifications
You must be signed in to change notification settings - Fork 28
poc: preserve comments in esbuild #1565
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { promises } from 'node:fs'; | ||
|
||
/** | ||
* @returns {import("esbuild").Plugin} | ||
*/ | ||
export function commentPlugin() { | ||
const PLUGIN_ID = 'comment-override'; | ||
|
||
/** @type {import("esbuild").Plugin} */ | ||
const plugin = { | ||
name: PLUGIN_ID, | ||
setup(build) { | ||
build.onLoad({ filter: /.*/ }, async (args) => { | ||
if (!args.path.includes('node_modules')) return undefined; | ||
const text = await promises.readFile(args.path, 'utf8'); | ||
return { | ||
contents: convertToLegalComments(text.toString()), | ||
loader: 'js', | ||
}; | ||
}); | ||
}, | ||
}; | ||
return plugin; | ||
} | ||
|
||
/** | ||
* Detect the start of a particular comment and change the | ||
* lines to have the prefix `//!` - this allows esbuild to keep it | ||
* | ||
* When a line is matched, continue to match further lines until a non-comment is seen. | ||
* | ||
* @param {string} source | ||
*/ | ||
export function convertToLegalComments(source) { | ||
// Process block comments - find all block comments | ||
const blockComments = source.match(/\/\*[\s\S]*?\*\//g) || []; | ||
|
||
// Selectively replace only block comments that contain "copyright" | ||
let modifiedSource = source; | ||
for (const comment of blockComments) { | ||
if (/copyright/i.test(comment)) { | ||
// Replace only the block comments with copyright | ||
modifiedSource = modifiedSource.replace(comment, comment.replace(/\/\*/, '/*!')); | ||
} | ||
} | ||
|
||
// Process line comments | ||
const lines = modifiedSource.split('\n'); | ||
const result = []; | ||
let inCommentBlock = false; | ||
|
||
for (let i = 0; i < lines.length; i++) { | ||
const line = lines[i]; | ||
|
||
// Check if the line contains a block comment - this breaks any line comment sequence | ||
if (line.includes('/*') || line.includes('*/')) { | ||
inCommentBlock = false; | ||
result.push(line); | ||
} | ||
// Check if this line starts a line comment block with "copyright" | ||
else if (!inCommentBlock && /^\s*\/\/(?=.*copyright.*$)/i.test(line)) { | ||
// Start of a copyright comment - mark it and convert | ||
inCommentBlock = true; | ||
result.push(line.replace(/^\s*\/\//, (match) => match.replace('//', '//!'))); | ||
} | ||
// Check if we're continuing a line comment block | ||
else if (inCommentBlock && /^\s*\/\//.test(line)) { | ||
// Continue the comment block - convert the prefix | ||
result.push(line.replace(/^\s*\/\//, (match) => match.replace('//', '//!'))); | ||
} | ||
// Check if we're exiting a comment block | ||
else { | ||
// Not a comment line or doesn't match our criteria, end the block | ||
inCommentBlock = false; | ||
result.push(line); | ||
} | ||
} | ||
|
||
return result.join('\n'); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import { convertToLegalComments } from '../scripts/utils/comment-plugin.js'; | ||
|
||
describe('convertToLegalComments', () => { | ||
it('should convert single line comments with copyright', () => { | ||
const input = `// This is a copyright notice | ||
const foo = 'bar';`; | ||
|
||
const expected = `//! This is a copyright notice | ||
const foo = 'bar';`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should convert multiple consecutive line comments following a copyright line', () => { | ||
const input = `// This is a copyright notice | ||
// This is a second line | ||
// This is a third line | ||
const foo = 'bar';`; | ||
|
||
const expected = `//! This is a copyright notice | ||
//! This is a second line | ||
//! This is a third line | ||
const foo = 'bar';`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should stop converting after a non-comment line is encountered', () => { | ||
const input = `// This is a copyright notice | ||
// This is a second line | ||
const foo = 'bar'; | ||
// This is a regular comment that should not be converted`; | ||
|
||
const expected = `//! This is a copyright notice | ||
//! This is a second line | ||
const foo = 'bar'; | ||
// This is a regular comment that should not be converted`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle multiple separate comment blocks', () => { | ||
const input = `// This is a regular comment | ||
const a = 1; | ||
|
||
// This has copyright info | ||
// And continues here | ||
const b = 2; | ||
|
||
// Another copyright notice | ||
// With more details | ||
// And even more info | ||
const c = 3;`; | ||
|
||
const expected = `// This is a regular comment | ||
const a = 1; | ||
|
||
//! This has copyright info | ||
//! And continues here | ||
const b = 2; | ||
|
||
//! Another copyright notice | ||
//! With more details | ||
//! And even more info | ||
const c = 3;`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle indented comments', () => { | ||
const input = `function test() { | ||
// This has copyright info | ||
// This is indented | ||
return true; | ||
}`; | ||
|
||
const expected = `function test() { | ||
//! This has copyright info | ||
//! This is indented | ||
return true; | ||
}`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle block comments with copyright', () => { | ||
const input = `/* This is a copyright block comment */ | ||
const foo = 'bar'; | ||
|
||
/* This is a regular | ||
multiline comment */`; | ||
|
||
const expected = `/*! This is a copyright block comment */ | ||
const foo = 'bar'; | ||
|
||
/* This is a regular | ||
multiline comment */`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle mixed comment types', () => { | ||
const input = `// This has copyright info | ||
// This continues | ||
/* This is a regular block comment */ | ||
const foo = 'bar'; | ||
|
||
/* This is a copyright block comment */ | ||
// This is a regular comment after a block`; | ||
|
||
const expected = `//! This has copyright info | ||
//! This continues | ||
/* This is a regular block comment */ | ||
const foo = 'bar'; | ||
|
||
/*! This is a copyright block comment */ | ||
// This is a regular comment after a block`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle block comments breaking line comment sequences', () => { | ||
const input = `// This has copyright info | ||
// This line should be converted | ||
/* This block comment breaks the sequence */ | ||
// This line should NOT be converted | ||
// Even though it follows another comment`; | ||
|
||
const expected = `//! This has copyright info | ||
//! This line should be converted | ||
/* This block comment breaks the sequence */ | ||
// This line should NOT be converted | ||
// Even though it follows another comment`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle case insensitivity for "copyright"', () => { | ||
const input = `// This has COPYRIGHT info | ||
// This continues | ||
const foo = 'bar'; | ||
|
||
// This has Copyright mixed case | ||
// More comments | ||
const baz = 'qux';`; | ||
|
||
const expected = `//! This has COPYRIGHT info | ||
//! This continues | ||
const foo = 'bar'; | ||
|
||
//! This has Copyright mixed case | ||
//! More comments | ||
const baz = 'qux';`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should not convert comments without copyright', () => { | ||
const input = `// This is a regular comment | ||
// Another regular comment | ||
const foo = 'bar';`; | ||
|
||
const expected = `// This is a regular comment | ||
// Another regular comment | ||
const foo = 'bar';`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should handle code with no comments', () => { | ||
const input = `const foo = 'bar'; | ||
function test() { | ||
return true; | ||
} | ||
const obj = { key: 'value' };`; | ||
|
||
const expected = input; // Should remain unchanged | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
|
||
it('should treat empty lines as non-comment lines that break the sequence', () => { | ||
const input = `// This has copyright info | ||
// This continues | ||
|
||
// These comments should NOT be converted | ||
// Because empty line breaks the sequence | ||
const foo = 'bar';`; | ||
|
||
const expected = `//! This has copyright info | ||
//! This continues | ||
|
||
// These comments should NOT be converted | ||
// Because empty line breaks the sequence | ||
const foo = 'bar';`; | ||
|
||
expect(convertToLegalComments(input)).toEqual(expected); | ||
}); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ const checks = { | |
tests: [ | ||
{ kind: 'maxFileSize', value: CSS_OUTPUT_SIZE }, | ||
{ kind: 'containsString', text: '$TRACKER_LOOKUP$', includes: true }, | ||
{ kind: 'containsString', text: 'Copyright (C) 2010 by Johannes Baagøe <[email protected]>', includes: true }, | ||
], | ||
}, | ||
firefox: { | ||
|
@@ -34,7 +35,7 @@ const checks = { | |
}, | ||
integration: { | ||
file: join(BUILD, 'integration/contentScope.js'), | ||
tests: [{ kind: 'containsString', text: 'trackerLookup: ', includes: true }], | ||
tests: [{ kind: 'containsString', text: 'init_define_import_meta_trackerLookup = ', includes: true }], | ||
}, | ||
windows: { | ||
file: join(BUILD, 'windows/contentScope.js'), | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.