forked from facebook/lexical
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
107 changes: 107 additions & 0 deletions
107
scripts/www/__tests__/unit/transformFlowFileContents.test.js
This file contains 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,107 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
*/ | ||
// @ts-check | ||
'use strict'; | ||
|
||
const transformFlowFileContents = require('../../transformFlowFileContents'); | ||
|
||
const HEADER_BEFORE = | ||
` | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow strict | ||
*/ | ||
`.trim() + '\n'; | ||
|
||
const HEADER_AFTER = | ||
` | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow strict | ||
* @generated | ||
* @oncall lexical_web_text_editor | ||
*/ | ||
`.trim() + '\n'; | ||
|
||
const IMPORTS_BEFORE = | ||
` | ||
import type {Doc, RelativePosition, UndoManager, XmlText} from 'yjs'; | ||
import type { | ||
DecoratorNode, | ||
EditorState, | ||
ElementNode, | ||
LexicalCommand, | ||
LexicalEditor, | ||
LexicalNode, | ||
LineBreakNode, | ||
NodeMap, | ||
NodeKey, | ||
TextNode, | ||
} from 'lexical'; | ||
`.trim() + '\n'; | ||
|
||
const IMPORTS_AFTER = | ||
` | ||
import type {Doc, RelativePosition, UndoManager, XmlText} from 'yjs'; | ||
import type { | ||
DecoratorNode, | ||
EditorState, | ||
ElementNode, | ||
LexicalCommand, | ||
LexicalEditor, | ||
LexicalNode, | ||
LineBreakNode, | ||
NodeMap, | ||
NodeKey, | ||
TextNode, | ||
} from 'Lexical'; | ||
`.trim() + '\n'; | ||
|
||
const EXTRA_BLOCK_COMMENT = | ||
` | ||
/** | ||
* LexicalDevToolsCore | ||
*/ | ||
`.trim() + '\n'; | ||
|
||
describe('transformFlowFileContents', () => { | ||
[ | ||
{ | ||
input: [HEADER_BEFORE, IMPORTS_BEFORE, EXTRA_BLOCK_COMMENT].join('\n'), | ||
output: [HEADER_AFTER, IMPORTS_AFTER, EXTRA_BLOCK_COMMENT].join('\n'), | ||
title: 'header-imports-comment', | ||
}, | ||
{ | ||
input: [HEADER_BEFORE, EXTRA_BLOCK_COMMENT].join('\n'), | ||
output: [HEADER_AFTER, EXTRA_BLOCK_COMMENT].join('\n'), | ||
title: 'header-comment', | ||
}, | ||
{ | ||
input: [HEADER_BEFORE, IMPORTS_BEFORE].join('\n'), | ||
output: [HEADER_AFTER, IMPORTS_AFTER].join('\n'), | ||
title: 'header-imports', | ||
}, | ||
{ | ||
input: [HEADER_BEFORE].join('\n'), | ||
output: [HEADER_AFTER].join('\n'), | ||
title: 'header', | ||
}, | ||
].forEach(({input, output, title}) => { | ||
it(`transforms ${title}`, async () => { | ||
expect(await transformFlowFileContents(input)).toBe(output); | ||
}); | ||
}); | ||
}); |
This file contains 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,90 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
*/ | ||
|
||
'use strict'; | ||
|
||
const {packagesManager} = require('../shared/packagesManager'); | ||
const npmToWwwName = require('./npmToWwwName'); | ||
const {t, transform} = require('hermes-transform'); | ||
const prettier = require('prettier'); | ||
|
||
const wwwMappings = Object.fromEntries( | ||
packagesManager | ||
.getPublicPackages() | ||
.flatMap((pkg) => | ||
pkg.getExportedNpmModuleNames().map((npm) => [npm, npmToWwwName(npm)]), | ||
), | ||
); | ||
|
||
const prettierConfig = prettier.resolveConfig('./').then((cfg) => cfg || {}); | ||
|
||
/** | ||
* Add a statement to the end of the code so the comments don't | ||
* disappear. This is a workaround for a hermes transform issue. | ||
* | ||
* @param {string} code | ||
*/ | ||
function wrapCode(code) { | ||
return [code, 'export {};\n'].join('\n'); | ||
} | ||
|
||
/** | ||
* The inverse transform of wrapCode, removes the added statement. | ||
* | ||
* @param {string} code | ||
*/ | ||
function unwrapCode(code) { | ||
return code.replace(/\n+export {};\n?$/, '\n'); | ||
} | ||
|
||
/** | ||
* It would be nice to use jscodeshift for this but the flow sources are using | ||
* ast features that are not supported in ast-types (as of 2024-04-11) so it's | ||
* not possible to traverse the tree and replace the imports & comments. | ||
* | ||
* It might be possible going straight to flow-parser, but it was a slew of | ||
* hardcoded regexps before and now it's at least automated based on the | ||
* exports. | ||
* | ||
* @param {string} source | ||
* @returns {Promise<string>} transformed source | ||
*/ | ||
module.exports = async function transformFlowFileContents(source) { | ||
return unwrapCode( | ||
await transform( | ||
wrapCode(source), | ||
(context) => ({ | ||
ImportDeclaration(node) { | ||
const value = wwwMappings[node.source.value]; | ||
if (value) { | ||
context.replaceNode(node.source, t.StringLiteral({value})); | ||
} | ||
}, | ||
Program(node) { | ||
if ( | ||
node.docblock && | ||
node.docblock.comment && | ||
node.docblock.comment.value.includes('@flow strict') | ||
) { | ||
// This is mutated in-place because I couldn't find a mutation that | ||
// did not fail for replacing the Program node. | ||
node.docblock.comment.value = node.docblock.comment.value.replace( | ||
/ \* @flow strict/g, | ||
' * @flow strict\n * @generated\n * @oncall lexical_web_text_editor', | ||
); | ||
// We need the mutations array to be non-empty, so remove something | ||
// that is not there. The AST traversals use object identity in a | ||
// Set so we don't have to worry about some other line changing. | ||
context.removeComments(t.LineComment({value: ''})); | ||
} | ||
}, | ||
}), | ||
await prettierConfig, | ||
), | ||
); | ||
}; |