refactor(compiler): replace Comment nodes with leadingComments property (#38811)

Common AST formats such as TS and Babel do not use a separate
node for comments, but instead attach comments to other AST nodes.
Previously this was worked around in TS by creating a `NotEmittedStatement`
AST node to attach the comment to. But Babel does not have this facility,
so it will not be a viable approach for the linker.

This commit refactors the output AST, to remove the `CommentStmt` and
`JSDocCommentStmt` nodes. Instead statements have a collection of
`leadingComments` that are rendered/attached to the final AST nodes
when being translated or printed.

PR Close #38811
This commit is contained in:
Pete Bacon Darwin
2020-09-11 16:43:23 +01:00
committed by Misko Hevery
parent 7fb388f929
commit d795a00137
24 changed files with 427 additions and 363 deletions

View File

@ -189,8 +189,49 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some
].join('\n'));
});
it('should support comments', () => {
expect(emitStmt(new o.CommentStmt('a\nb'))).toEqual(['// a', '// b'].join('\n'));
describe('comments', () => {
it('should support a preamble', () => {
expect(emitStmt(o.variable('a').toStmt(), '/* SomePreamble */')).toBe([
'/* SomePreamble */', 'a;'
].join('\n'));
});
it('should support singleline comments', () => {
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [o.leadingComment('a\nb')])))
.toBe('// a\n// b\nreturn 1;');
});
it('should support multiline comments', () => {
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment('Multiline comment', true)
]))).toBe('/* Multiline comment */\nreturn 1;');
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment(`Multiline\ncomment`, true)
]))).toBe(`/* Multiline\ncomment */\nreturn 1;`);
});
it('should support inline multiline comments', () => {
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment('inline comment', true, false)
]))).toBe('/* inline comment */return 1;');
});
it('should support JSDoc comments', () => {
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.jsDocComment([{text: 'Intro comment'}])
]))).toBe(`/**\n * Intro comment\n */\nreturn 1;`);
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.jsDocComment([{tagName: o.JSDocTagName.Desc, text: 'description'}])
]))).toBe(`/**\n * @desc description\n */\nreturn 1;`);
expect(emitStmt(new o.ReturnStatement(
o.literal(1), null, [o.jsDocComment([
{text: 'Intro comment'},
{tagName: o.JSDocTagName.Desc, text: 'description'},
{tagName: o.JSDocTagName.Id, text: '{number} identifier 123'},
])])))
.toBe(
`/**\n * Intro comment\n * @desc description\n * @id {number} identifier 123\n */\nreturn 1;`);
});
});
it('should support if stmt', () => {

View File

@ -21,22 +21,5 @@ import * as o from '../../src/output/output_ast';
expect(o.collectExternalReferences([stmt])).toEqual([ref1, ref2]);
});
});
describe('comments', () => {
it('different JSDocCommentStmt should not be equivalent', () => {
const comment1 = new o.JSDocCommentStmt([{text: 'text'}]);
const comment2 = new o.JSDocCommentStmt([{text: 'text2'}]);
const comment3 = new o.JSDocCommentStmt([{tagName: o.JSDocTagName.Desc, text: 'text2'}]);
const comment4 = new o.JSDocCommentStmt([{text: 'text2'}, {text: 'text3'}]);
expect(comment1.isEquivalent(comment2)).toBeFalsy();
expect(comment1.isEquivalent(comment3)).toBeFalsy();
expect(comment1.isEquivalent(comment4)).toBeFalsy();
expect(comment2.isEquivalent(comment3)).toBeFalsy();
expect(comment2.isEquivalent(comment4)).toBeFalsy();
expect(comment3.isEquivalent(comment4)).toBeFalsy();
expect(comment1.isEquivalent(comment1)).toBeTruthy();
});
});
});
}

View File

@ -239,7 +239,8 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some
});
it('should support comments', () => {
expect(emitStmt(new o.CommentStmt('a\nb'))).toEqual(['// a', '// b'].join('\n'));
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [o.leadingComment('a\nb')])))
.toEqual('// a\n// b\nreturn 1;');
});
it('should support if stmt', () => {
@ -441,29 +442,40 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some
});
it('should support singleline comments', () => {
expect(emitStmt(new o.CommentStmt('Simple comment'))).toBe('// Simple comment');
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [o.leadingComment('a\nb')])))
.toBe('// a\n// b\nreturn 1;');
});
it('should support multiline comments', () => {
expect(emitStmt(new o.CommentStmt('Multiline comment', true)))
.toBe('/* Multiline comment */');
expect(emitStmt(new o.CommentStmt(`Multiline\ncomment`, true)))
.toBe(`/* Multiline\ncomment */`);
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment('Multiline comment', true)
]))).toBe('/* Multiline comment */\nreturn 1;');
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment(`Multiline\ncomment`, true)
]))).toBe(`/* Multiline\ncomment */\nreturn 1;`);
});
it('should support inline multiline comments', () => {
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.leadingComment('inline comment', true, false)
]))).toBe('/* inline comment */return 1;');
});
it('should support JSDoc comments', () => {
expect(emitStmt(new o.JSDocCommentStmt([{text: 'Intro comment'}])))
.toBe(`/**\n * Intro comment\n */`);
expect(emitStmt(new o.JSDocCommentStmt([
{tagName: o.JSDocTagName.Desc, text: 'description'}
]))).toBe(`/**\n * @desc description\n */`);
expect(emitStmt(new o.JSDocCommentStmt([
{text: 'Intro comment'},
{tagName: o.JSDocTagName.Desc, text: 'description'},
{tagName: o.JSDocTagName.Id, text: '{number} identifier 123'},
])))
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.jsDocComment([{text: 'Intro comment'}])
]))).toBe(`/**\n * Intro comment\n */\nreturn 1;`);
expect(emitStmt(new o.ReturnStatement(o.literal(1), null, [
o.jsDocComment([{tagName: o.JSDocTagName.Desc, text: 'description'}])
]))).toBe(`/**\n * @desc description\n */\nreturn 1;`);
expect(emitStmt(new o.ReturnStatement(
o.literal(1), null, [o.jsDocComment([
{text: 'Intro comment'},
{tagName: o.JSDocTagName.Desc, text: 'description'},
{tagName: o.JSDocTagName.Id, text: '{number} identifier 123'},
])])))
.toBe(
`/**\n * Intro comment\n * @desc description\n * @id {number} identifier 123\n */`);
`/**\n * Intro comment\n * @desc description\n * @id {number} identifier 123\n */\nreturn 1;`);
});
});