create-react-native-library
Version:
CLI to scaffold React Native libraries
200 lines (196 loc) • 8.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.applyTemplates = applyTemplates;
exports.generateTemplateConfiguration = generateTemplateConfiguration;
var _path = _interopRequireDefault(require("path"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _ejs = _interopRequireDefault(require("ejs"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
// Please think at least 5 times before introducing a new config key
// You can just reuse the existing ones most of the time
const BINARIES = [/(gradlew|\.(jar|keystore|png|jpg|gif))$/, /\$\.yarn(?![a-z])/];
const COMMON_FILES = _path.default.resolve(__dirname, '../templates/common');
const COMMON_LOCAL_FILES = _path.default.resolve(__dirname, '../templates/common-local');
const EXAMPLE_COMMON_FILES = _path.default.resolve(__dirname, '../templates/example-common');
const EXAMPLE_MODULE_LEGACY_FILES = _path.default.resolve(__dirname, '../templates/example-module-legacy');
const EXAMPLE_MODULE_NEW_FILES = _path.default.resolve(__dirname, '../templates/example-module-new');
const EXAMPLE_VIEW_FILES = _path.default.resolve(__dirname, '../templates/example-view');
const JS_FILES = _path.default.resolve(__dirname, '../templates/js-library');
const EXPO_FILES = _path.default.resolve(__dirname, '../templates/expo-library');
const CPP_FILES = _path.default.resolve(__dirname, '../templates/cpp-library');
const NATIVE_COMMON_FILES = _path.default.resolve(__dirname, '../templates/native-common');
const NATIVE_COMMON_EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/native-common-example');
const NATIVE_FILES = {
module_legacy: _path.default.resolve(__dirname, '../templates/native-library-legacy'),
module_new: _path.default.resolve(__dirname, '../templates/native-library-new'),
view_legacy: _path.default.resolve(__dirname, '../templates/native-view-legacy'),
view_new: _path.default.resolve(__dirname, '../templates/native-view-new'),
module_nitro: _path.default.resolve(__dirname, '../templates/nitro-module')
};
const OBJC_FILES = {
module_common: _path.default.resolve(__dirname, '../templates/objc-library'),
view_legacy: _path.default.resolve(__dirname, '../templates/objc-view-legacy'),
view_new: _path.default.resolve(__dirname, '../templates/objc-view-new')
};
const KOTLIN_FILES = {
module_legacy: _path.default.resolve(__dirname, '../templates/kotlin-library-legacy'),
module_new: _path.default.resolve(__dirname, '../templates/kotlin-library-new'),
view_legacy: _path.default.resolve(__dirname, '../templates/kotlin-view-legacy'),
view_new: _path.default.resolve(__dirname, '../templates/kotlin-view-new')
};
const SWIFT_FILES = {
module_legacy: _path.default.resolve(__dirname, '../templates/swift-library-legacy'),
view_legacy: _path.default.resolve(__dirname, '../templates/swift-view-legacy')
};
function generateTemplateConfiguration({
versions,
basename,
answers
}) {
const {
slug,
languages,
type
} = answers;
const arch = type === 'legacy-module' || type === 'legacy-view' || type === 'library' ? 'legacy' : 'new';
const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
let namespace;
if (slug.startsWith('@') && slug.includes('/')) {
namespace = slug.split('/')[0]?.replace(/[^a-z0-9]/g, '').toLowerCase();
}
// Create a package identifier with specified namespace when possible
const pack = `${namespace ? `${namespace}.` : ''}${project.replace(/[^a-z0-9]/g, '').toLowerCase()}`;
return {
versions,
project: {
slug,
description: answers.description,
name: /^[A-Z]/.test(basename) && /^[a-z0-9]+$/i.test(basename) ?
// If the project name is already in PascalCase, use it as-is
basename :
// Otherwise, convert it to PascalCase and remove any non-alphanumeric characters
`${project.charAt(0).toUpperCase()}${project.replace(/[^a-z0-9](\w)/g, (_, $1) => $1.toUpperCase()).slice(1)}`,
package: pack,
package_dir: pack.replace(/\./g, '/'),
package_cpp: pack.replace(/\./g, '_'),
identifier: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''),
native: languages !== 'js',
arch,
cpp: languages === 'cpp',
swift: languages === 'kotlin-swift',
viewConfig: getViewConfig(type),
moduleConfig: getModuleConfig(type)
},
author: {
name: answers.authorName,
email: answers.authorEmail,
url: answers.authorUrl
},
repo: answers.repoUrl,
example: answers.example,
year: new Date().getFullYear()
};
}
function getModuleConfig(projectType) {
switch (projectType) {
case 'nitro-module':
return 'nitro-modules';
case 'turbo-module':
return 'turbo-modules';
case 'legacy-module':
return 'native-modules';
default:
return null;
}
}
function getViewConfig(projectType) {
switch (projectType) {
case 'legacy-view':
return 'paper-view';
case 'fabric-view':
return 'fabric-view';
default:
return null;
}
}
async function applyTemplates(answers, config, folder) {
const {
local
} = answers;
if (local) {
await applyTemplate(config, COMMON_LOCAL_FILES, folder);
} else {
await applyTemplate(config, COMMON_FILES, folder);
if (config.example !== 'none') {
await applyTemplate(config, EXAMPLE_COMMON_FILES, folder);
if (config.project.viewConfig !== null) {
await applyTemplate(config, EXAMPLE_VIEW_FILES, folder);
} else {
if (config.project.arch === 'legacy') {
await applyTemplate(config, EXAMPLE_MODULE_LEGACY_FILES, folder);
} else {
await applyTemplate(config, EXAMPLE_MODULE_NEW_FILES, folder);
}
}
}
}
if (answers.languages === 'js') {
await applyTemplate(config, JS_FILES, folder);
await applyTemplate(config, EXPO_FILES, folder);
} else {
await applyTemplate(config, NATIVE_COMMON_FILES, folder);
if (config.example !== 'none') {
await applyTemplate(config, NATIVE_COMMON_EXAMPLE_FILES, folder);
}
if (config.project.moduleConfig === 'nitro-modules') {
await applyTemplate(config, NATIVE_FILES['module_nitro'], folder);
return;
}
if (config.project.moduleConfig !== null) {
await applyTemplate(config, NATIVE_FILES[`module_${config.project.arch}`], folder);
} else {
await applyTemplate(config, NATIVE_FILES[`view_${config.project.arch}`], folder);
}
if (config.project.swift) {
await applyTemplate(config, SWIFT_FILES[`module_legacy`], folder);
} else {
if (config.project.moduleConfig !== null) {
await applyTemplate(config, OBJC_FILES[`module_common`], folder);
} else {
await applyTemplate(config, OBJC_FILES[`view_${config.project.arch}`], folder);
}
}
const templateType = `${config.project.moduleConfig !== null ? 'module' : 'view'}_${config.project.arch}`;
await applyTemplate(config, KOTLIN_FILES[templateType], folder);
if (config.project.cpp) {
await applyTemplate(config, CPP_FILES, folder);
await _fsExtra.default.remove(_path.default.join(folder, 'ios', `${config.project.name}.m`));
}
}
}
/**
* This copies the template files and renders them via ejs
*/
async function applyTemplate(config, source, destination) {
await _fsExtra.default.mkdirp(destination);
const files = await _fsExtra.default.readdir(source);
for (const f of files) {
const target = _path.default.join(destination, _ejs.default.render(f.replace(/^\$/, ''), config, {
openDelimiter: '{',
closeDelimiter: '}'
}));
const file = _path.default.join(source, f);
const stats = await _fsExtra.default.stat(file);
if (stats.isDirectory()) {
await applyTemplate(config, file, target);
} else if (!BINARIES.some(r => r.test(file))) {
const content = await _fsExtra.default.readFile(file, 'utf8');
await _fsExtra.default.writeFile(target, _ejs.default.render(content, config));
} else {
await _fsExtra.default.copyFile(file, target);
}
}
}
//# sourceMappingURL=template.js.map