nitro-codegen
Version:
The code-generator for react-native-nitro-modules.
103 lines (91 loc) • 3.22 kB
text/typescript
import type { SourceFile } from '../SourceFile.js'
import { createFileMetadataString } from './../helpers.js'
import { indent, toLowerCamelCase } from '../../utils.js'
import type { EnumMember } from '../types/EnumType.js'
import { includeNitroHeader } from './includeNitroHeader.js'
import { NitroConfig } from '../../config/NitroConfig.js'
/**
* Creates a C++ enum that converts to a TypeScript union (aka just strings).
*/
export function createCppUnion(
typename: string,
enumMembers: EnumMember[]
): SourceFile {
const cppEnumMembers = enumMembers
.map(
(m, i) => `${m.name} SWIFT_NAME(${toLowerCamelCase(m.name)}) = ${i},`
)
.join('\n')
const cppFromJsiHashCases = enumMembers
.map((v) =>
`case hashString("${v.stringValue}"): return ${typename}::${v.name};`.trim()
)
.join('\n')
const cppToJsiCases = enumMembers
.map(
(v) =>
`case ${typename}::${v.name}: return JSIConverter<std::string>::toJSI(runtime, "${v.stringValue}");`
)
.join('\n')
const cppCanConvertCases = enumMembers
.map((m) => `case hashString("${m.stringValue}"):`)
.join('\n')
const cxxNamespace = NitroConfig.getCxxNamespace('c++')
const cppCode = `
${createFileMetadataString(`${typename}.hpp`)}
#pragma once
${includeNitroHeader('NitroHash.hpp')}
${includeNitroHeader('JSIConverter.hpp')}
${includeNitroHeader('NitroDefines.hpp')}
namespace ${cxxNamespace} {
/**
* An enum which can be represented as a JavaScript union (${typename}).
*/
enum class ${typename} {
${indent(cppEnumMembers, ' ')}
} CLOSED_ENUM;
} // namespace ${cxxNamespace}
namespace margelo::nitro {
using namespace ${cxxNamespace};
// C++ ${typename} <> JS ${typename} (union)
template <>
struct JSIConverter<${typename}> final {
static inline ${typename} fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
switch (hashString(unionValue.c_str(), unionValue.size())) {
${indent(cppFromJsiHashCases, ' ')}
default: [[unlikely]]
throw std::invalid_argument("Cannot convert \\"" + unionValue + "\\" to enum ${typename} - invalid value!");
}
}
static inline jsi::Value toJSI(jsi::Runtime& runtime, ${typename} arg) {
switch (arg) {
${indent(cppToJsiCases, ' ')}
default: [[unlikely]]
throw std::invalid_argument("Cannot convert ${typename} to JS - invalid value: "
+ std::to_string(static_cast<int>(arg)) + "!");
}
}
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
if (!value.isString()) {
return false;
}
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
switch (hashString(unionValue.c_str(), unionValue.size())) {
${indent(cppCanConvertCases, ' ')}
return true;
default:
return false;
}
}
};
} // namespace margelo::nitro
`
return {
content: cppCode,
name: `${typename}.hpp`,
subdirectory: [],
language: 'c++',
platform: 'shared',
}
}