create-react-native-library
Version:
CLI to scaffold React Native libraries
208 lines (204 loc) • 7.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.applyTemplate = applyTemplate;
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_NEW_FILES = _path.default.resolve(__dirname, '../templates/example-module-new');
const EXAMPLE_VIEW_FILES = _path.default.resolve(__dirname, '../templates/example-view');
const EXAMPLE_EXPO_FILES = _path.default.resolve(__dirname, '../templates/example-expo');
const JS_FILES = _path.default.resolve(__dirname, '../templates/js-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 NITRO_COMMON_FILES = _path.default.resolve(__dirname, '../templates/nitro-common');
const NATIVE_FILES = {
module_new: _path.default.resolve(__dirname, '../templates/native-library-new'),
view_new: _path.default.resolve(__dirname, '../templates/native-view-new'),
module_nitro: _path.default.resolve(__dirname, '../templates/nitro-module'),
view_nitro: _path.default.resolve(__dirname, '../templates/nitro-view')
};
const OBJC_FILES = {
module_common: _path.default.resolve(__dirname, '../templates/objc-library'),
view_new: _path.default.resolve(__dirname, '../templates/objc-view-new')
};
const KOTLIN_FILES = {
module_new: _path.default.resolve(__dirname, '../templates/kotlin-library-new'),
view_new: _path.default.resolve(__dirname, '../templates/kotlin-view-new')
};
function generateTemplateConfiguration({
versions,
basename,
answers
}) {
const {
slug,
languages,
type
} = answers;
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, _path.default.sep),
package_cpp: pack.replace(/\./g, '_'),
identifier: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''),
native: languages !== 'js',
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,
tools: answers.tools,
year: new Date().getFullYear()
};
}
function getModuleConfig(projectType) {
switch (projectType) {
case 'nitro-module':
return 'nitro-modules';
case 'turbo-module':
return 'turbo-modules';
case 'fabric-view':
case 'library':
case 'nitro-view':
return null;
}
}
function getViewConfig(projectType) {
switch (projectType) {
case 'fabric-view':
return 'fabric-view';
case 'nitro-view':
return 'nitro-view';
case 'nitro-module':
case 'turbo-module':
case 'library':
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 != null) {
await applyTemplate(config, EXAMPLE_COMMON_FILES, folder);
if (config.project.viewConfig !== null) {
await applyTemplate(config, EXAMPLE_VIEW_FILES, folder);
} else {
await applyTemplate(config, EXAMPLE_MODULE_NEW_FILES, folder);
}
}
}
if (answers.languages === 'js') {
await applyTemplate(config, JS_FILES, folder);
await applyTemplate(config, EXAMPLE_EXPO_FILES, folder);
} else {
await applyTemplate(config, NATIVE_COMMON_FILES, folder);
if (config.example != null) {
await applyTemplate(config, NATIVE_COMMON_EXAMPLE_FILES, folder);
}
if (config.example === 'expo') {
await applyTemplate(config, EXAMPLE_EXPO_FILES, folder);
}
if (config.project.moduleConfig === 'nitro-modules') {
await applyTemplate(config, NITRO_COMMON_FILES, folder);
await applyTemplate(config, NATIVE_FILES['module_nitro'], folder);
return;
}
if (config.project.viewConfig === 'nitro-view') {
await applyTemplate(config, NITRO_COMMON_FILES, folder);
await applyTemplate(config, NATIVE_FILES['view_nitro'], folder);
return;
}
if (config.project.moduleConfig !== null) {
await applyTemplate(config, NATIVE_FILES[`module_new`], folder);
} else {
await applyTemplate(config, NATIVE_FILES[`view_new`], folder);
}
if (config.project.moduleConfig !== null) {
await applyTemplate(config, OBJC_FILES[`module_common`], folder);
} else {
await applyTemplate(config, OBJC_FILES[`view_new`], folder);
}
const templateType = `${config.project.moduleConfig !== null ? 'module' : 'view'}_new`;
await applyTemplate(config, KOTLIN_FILES[templateType], folder);
}
}
/**
* 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) {
let name;
try {
name = _ejs.default.render(f.replace(/^\$/, ''), config, {
openDelimiter: '{',
closeDelimiter: '}'
});
} catch (e) {
throw new Error(`Failed to render template file name: ${f}`, {
cause: e
});
}
const target = _path.default.join(destination, name);
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');
let result;
try {
result = _ejs.default.render(content, config)
// Make sure that line endings are 'lf' (Unix style)
.replace(/\r\n/g, '\n');
} catch (e) {
throw new Error(`Failed to render template file content: ${f}`, {
cause: e
});
}
await _fsExtra.default.writeFile(target, result);
} else {
await _fsExtra.default.copyFile(file, target);
}
}
}
//# sourceMappingURL=template.js.map