Skip to content

Commit

Permalink
Add cppStringType option to @rnw/codegen (#11833)
Browse files Browse the repository at this point in the history
* Add option: cppStringType

* Update Document.md

* ...

* Apply options

* Fix @rnw/cli

* Change files

* Update Cli.ts

* manually yarn format (this command seems not working)

* yarn format
  • Loading branch information
ZihanChen-MSFT authored Jul 5, 2023
1 parent a27dcce commit 5a3dcf7
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add cppStringType option to @rnw/codegen",
"packageName": "@react-native-windows/cli",
"email": "53799235+ZihanChen-MSFT@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add cppStringType option to @rnw/codegen",
"packageName": "@react-native-windows/codegen",
"email": "53799235+ZihanChen-MSFT@users.noreply.github.com",
"dependentChangeType": "patch"
}
8 changes: 6 additions & 2 deletions packages/@react-native-windows/cli/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import {
endTelemetrySession,
} from './runWindows/utils/telemetryHelpers';

import {runCodeGen} from '@react-native-windows/codegen';
import {
CodeGenOptions as RnwCodeGenOptions,
runCodeGen,
} from '@react-native-windows/codegen';
import {Ora} from 'ora';

export class CodeGenWindows {
Expand Down Expand Up @@ -108,12 +111,13 @@ export class CodeGenWindows {
];

const jsRootPathRelative = path.relative(process.cwd(), jsRootDir);
const options = {
const options: RnwCodeGenOptions = {
files: [
`${jsRootPathRelative}${
jsRootPathRelative ? '/' : ''
}**/*Native*.[jt]s`,
],
cppStringType: 'std::string',
libraryName: projectName,
methodOnly: false,
modulesCxx: generators.indexOf('modulesCxx') !== -1,
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-native-windows/codegen/Document.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ Here are a list of supported types in TurboModule.

| TypeScript | Flow | C++ |
| ---------- | ---- | --- |
| `string` | `*` | `std::string` |
| `string` | `*` | `std::string` or `std::wstring` according to options |
| `number` | `*` | `double` |
| `float (number)` | `*` | `double` |
| `double (number)` | `*` | `double` |
Expand Down
21 changes: 19 additions & 2 deletions packages/@react-native-windows/codegen/src/Cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import yargs from 'yargs';
import {runCodeGen} from './index';
import {CodeGenOptions, runCodeGen} from './index';

const argv = yargs.options({
file: {
Expand Down Expand Up @@ -58,14 +58,31 @@ const argv = yargs.options({
required: true,
describe: 'Used for part of the path generated within the codegen dir',
},
cppStringType: {
choices: ['std::string', 'std::wstring'],
describe:
'C++ string type in generated code, should be "std::string" or "std::wstring"',
default: 'std::string',
},
}).argv;

if ((argv.file && argv.files) || (!argv.file && !argv.files)) {
console.error('You must specify either --file or --files.');
process.exit(1);
}

const changesNecessary = runCodeGen(argv);
if (
argv.cppStringType !== 'std::string' &&
argv.cppStringType !== 'std::wstring'
) {
console.error('cppStringType should be "std::string" or "std::wstring".');
process.exit(1);
}

// type casting is necessary here because
// cppStringType does not become union of string literals
// until yargs.options get improved in the future
const changesNecessary = runCodeGen(<CodeGenOptions>argv);

if (argv.test && changesNecessary) {
console.error(
Expand Down
24 changes: 18 additions & 6 deletions packages/@react-native-windows/codegen/src/generators/AliasGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import type {
Nullable,
} from '@react-native/codegen/lib/CodegenSchema';
import {AliasMap, getAliasCppName} from './AliasManaging';
import {translateField} from './ObjectTypes';
import {CppCodegenOptions, translateField} from './ObjectTypes';

function translateObjectBody(
type: NativeModuleObjectTypeAnnotation,
aliases: AliasMap,
baseAliasName: string,
prefix: string,
options: CppCodegenOptions,
) {
return type.properties
.map((prop: NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>) => {
Expand All @@ -32,6 +33,7 @@ function translateObjectBody(
propType,
aliases,
`${baseAliasName}_${prop.name}`,
options,
)} ${prop.name};`;
return `${first}\n${second}`;
})
Expand All @@ -56,12 +58,13 @@ function generateSingleAlias(
aliases: AliasMap,
aliasName: string,
aliasCode: AliasCodeMap,
options: CppCodegenOptions,
): void {
const aliasType = <NativeModuleObjectTypeAnnotation>aliases.types[aliasName];
aliasCode[aliasName] = `
REACT_STRUCT(${getAliasCppName(aliasName)})
struct ${getAliasCppName(aliasName)} {
${translateObjectBody(aliasType, aliases, aliasName, ' ')}
${translateObjectBody(aliasType, aliases, aliasName, ' ', options)}
};
`;
}
Expand All @@ -70,6 +73,7 @@ function generateNestedAliasesInCorrectOrder(
aliases: AliasMap,
aliasCode: AliasCodeMap,
aliasOrder: string[],
options: CppCodegenOptions,
): void {
// retrieve and clean all ungenerated aliases
const jobs = aliases.jobs;
Expand All @@ -80,21 +84,29 @@ function generateNestedAliasesInCorrectOrder(
// generate a new struct and all fields will be examined
// new anonymous objects could be found
// they will be stored in aliases.jobs
generateSingleAlias(aliases, aliasName, aliasCode);
generateSingleAlias(aliases, aliasName, aliasCode, options);
// nested C++ structs must be put before the current C++ struct
// as they will be used in the current C++ struct
// the order will be perfectly and easily ensured by doing this recursively
generateNestedAliasesInCorrectOrder(aliases, aliasCode, aliasOrder);
generateNestedAliasesInCorrectOrder(
aliases,
aliasCode,
aliasOrder,
options,
);
// all referenced C++ structs are generated
// put the current one following them
aliasOrder.push(aliasName);
}
}

export function generateAliases(aliases: AliasMap): string {
export function generateAliases(
aliases: AliasMap,
options: CppCodegenOptions,
): string {
const aliasCode: AliasCodeMap = {};
const aliasOrder: string[] = [];
generateNestedAliasesInCorrectOrder(aliases, aliasCode, aliasOrder);
generateNestedAliasesInCorrectOrder(aliases, aliasCode, aliasOrder, options);

// aliasOrder now has the correct order of C++ struct code
let traversedAliasedStructs = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {AliasMap, setPreferredModuleName} from './AliasManaging';
import {createAliasMap, generateAliases} from './AliasGen';
import {generateValidateConstants} from './ValidateConstants';
import {generateValidateMethods} from './ValidateMethods';
import type {CppStringTypes} from './ObjectTypes';

export type {CppStringTypes} from './ObjectTypes';

type FilesOutput = Map<string, string>;

Expand Down Expand Up @@ -46,9 +49,11 @@ struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec {
export function createNM2Generator({
methodOnly,
namespace,
cppStringType,
}: {
methodOnly: boolean;
namespace: string;
cppStringType: CppStringTypes;
}) {
return (
_libraryName: string,
Expand All @@ -74,7 +79,9 @@ export function createNM2Generator({
const aliases: AliasMap = createAliasMap(nativeModule.aliasMap);

// prepare methods
const methods = generateValidateMethods(nativeModule, aliases);
const methods = generateValidateMethods(nativeModule, aliases, {
cppStringType,
});
let tuples = `
static constexpr auto methods = std::tuple{
${methods[0]}
Expand All @@ -98,7 +105,9 @@ ${errors}`;
}

// generate code for structs
const traversedAliasedStructs = generateAliases(aliases);
const traversedAliasedStructs = generateAliases(aliases, {
cppStringType,
});

files.set(
`Native${preferredModuleName}Spec.g.h`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@ import {
getAnonymousAliasCppName,
} from './AliasManaging';

export type CppStringTypes = 'std::string' | 'std::wstring';

export interface CppCodegenOptions {
cppStringType: CppStringTypes;
}

function translateUnionReturnType(
type: NativeModuleEnumDeclaration | NativeModuleUnionTypeAnnotation,
options: CppCodegenOptions,
): string {
const memberType = type.memberType;
switch (type.memberType) {
case 'StringTypeAnnotation':
return 'std::string';
return options.cppStringType;
case 'NumberTypeAnnotation':
return 'double';
case 'ObjectTypeAnnotation':
Expand All @@ -47,12 +54,13 @@ export function translateFieldOrReturnType(
aliases: AliasMap,
baseAliasName: string,
callerName: 'translateField' | 'translateReturnType',
options: CppCodegenOptions,
): string {
// avoid: Property 'type' does not exist on type 'never'
const returnType = type.type;
switch (type.type) {
case 'StringTypeAnnotation':
return 'std::string';
return options.cppStringType;
case 'NumberTypeAnnotation':
case 'FloatTypeAnnotation':
case 'DoubleTypeAnnotation':
Expand All @@ -68,6 +76,7 @@ export function translateFieldOrReturnType(
aliases,
`${baseAliasName}_element`,
callerName,
options,
)}>`;
} else {
return `::React::JSValueArray`;
Expand All @@ -93,10 +102,11 @@ export function translateFieldOrReturnType(
aliases,
baseAliasName,
callerName,
options,
)}>`;
case 'EnumDeclaration':
case 'UnionTypeAnnotation':
return translateUnionReturnType(type);
return translateUnionReturnType(type, options);
default:
throw new Error(`Unhandled type in ${callerName}: ${returnType}`);
}
Expand All @@ -106,11 +116,13 @@ export function translateField(
type: Nullable<NativeModuleBaseTypeAnnotation>,
aliases: AliasMap,
baseAliasName: string,
options: CppCodegenOptions,
): string {
return translateFieldOrReturnType(
type,
aliases,
baseAliasName,
'translateField',
options,
);
}
Loading

0 comments on commit 5a3dcf7

Please sign in to comment.