nativescript
Version:
Command-line interface for building NativeScript projects
282 lines (272 loc) • 11.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NativeAddSwiftCommand = exports.NativeAddObjectiveCCommand = exports.NativeAddKotlinCommand = exports.NativeAddJavaCommand = exports.NativeAddAndroidCommand = exports.NativeAddSingleCommand = exports.NativeAddCommand = void 0;
const fs = require("fs");
const path = require("path");
const yok_1 = require("../common/yok");
const utils_1 = require("../common/utils");
const os_1 = require("os");
class NativeAddCommand {
constructor($projectData, $logger, $errors) {
this.$projectData = $projectData;
this.$logger = $logger;
this.$errors = $errors;
this.allowedParameters = [];
this.$projectData.initializeProjectData();
}
async execute(args) {
this.failWithUsage();
return Promise.resolve();
}
failWithUsage() {
this.$errors.failWithHelp("Usage: ns native add [swift|objective-c|java|kotlin] [class name]");
}
async canExecute(args) {
this.failWithUsage();
return false;
}
getIosSourcePathBase() {
const resources = this.$projectData.getAppResourcesDirectoryPath();
return path.join(resources, "iOS", "src");
}
getAndroidSourcePathBase() {
const resources = this.$projectData.getAppResourcesDirectoryPath();
return path.join(resources, "Android", "src", "main", "java");
}
}
exports.NativeAddCommand = NativeAddCommand;
class NativeAddSingleCommand extends NativeAddCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
async canExecute(args) {
if (!args || args.length !== 1) {
this.failWithUsage();
}
return true;
}
}
exports.NativeAddSingleCommand = NativeAddSingleCommand;
class NativeAddAndroidCommand extends NativeAddSingleCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
getPackageName(className) {
const lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex !== -1) {
return className.substring(0, lastDotIndex);
}
return "";
}
getClassSimpleName(className) {
const lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex !== -1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
generateJavaClassContent(packageName, classSimpleName) {
return ((packageName.length > 0 ? `package ${packageName};` : "") +
`
import android.util.Log;
public class ${classSimpleName} {
public void logMessage() {
Log.d("JS", "Hello from ${classSimpleName}!");
}
}
`);
}
generateKotlinClassContent(packageName, classSimpleName) {
return ((packageName.length > 0 ? `package ${packageName};` : "") +
`
import android.util.Log
class ${classSimpleName} {
fun logMessage() {
Log.d("JS", "Hello from ${classSimpleName}!")
}
}
`);
}
doJavaKotlin(className, extension) {
const fileExt = extension == "java" ? extension : "kt";
const packageName = this.getPackageName(className);
const classSimpleName = this.getClassSimpleName(className);
const packagePath = path.join(this.getAndroidSourcePathBase(), ...packageName.split("."));
const filePath = path.join(packagePath, `${classSimpleName}.${fileExt}`);
if (fs.existsSync(filePath)) {
this.$errors.failWithHelp(`${extension} file '${filePath}' already exists.`);
return;
}
if (extension == "kotlin" && !this.checkAndUpdateGradleProperties()) {
return;
}
const fileContent = extension == "java"
? this.generateJavaClassContent(packageName, classSimpleName)
: this.generateKotlinClassContent(packageName, classSimpleName);
fs.mkdirSync(packagePath, { recursive: true });
fs.writeFileSync(filePath, fileContent);
this.$logger.info(`${(0, utils_1.capitalizeFirstLetter)(extension)} file '${filePath}' generated successfully.`);
}
checkAndUpdateGradleProperties() {
const resources = this.$projectData.getAppResourcesDirectoryPath();
const filePath = path.join(resources, "Android", "gradle.properties");
if (fs.existsSync(filePath)) {
const fileContent = fs.readFileSync(filePath, "utf8");
const propertyRegex = /^useKotlin\s*=\s*(true|false)$/m;
const match = propertyRegex.exec(fileContent);
if (match) {
const useKotlin = match[1];
if (useKotlin === "false") {
this.$errors.failWithHelp("The useKotlin property is set to false. Stopping processing. Kotlin must be enabled in gradle.properties to use.");
return false;
}
if (useKotlin === "true") {
return true;
}
}
else {
fs.appendFileSync(filePath, `${os_1.EOL}useKotlin=true${os_1.EOL}`);
this.$logger.info('Added "useKotlin=true" property to gradle.properties.');
}
}
else {
fs.writeFileSync(filePath, `useKotlin=true${os_1.EOL}`);
this.$logger.info('Created gradle.properties with "useKotlin=true" property.');
}
return true;
}
}
exports.NativeAddAndroidCommand = NativeAddAndroidCommand;
class NativeAddJavaCommand extends NativeAddAndroidCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
async execute(args) {
this.doJavaKotlin(args[0], "java");
return Promise.resolve();
}
}
exports.NativeAddJavaCommand = NativeAddJavaCommand;
class NativeAddKotlinCommand extends NativeAddAndroidCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
async execute(args) {
this.doJavaKotlin(args[0], "kotlin");
return Promise.resolve();
}
}
exports.NativeAddKotlinCommand = NativeAddKotlinCommand;
class NativeAddObjectiveCCommand extends NativeAddSingleCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
async execute(args) {
this.doObjectiveC(args[0]);
return Promise.resolve();
}
doObjectiveC(className) {
const iosSourceBase = this.getIosSourcePathBase();
const classFilePath = path.join(iosSourceBase, `${className}.m`);
const headerFilePath = path.join(iosSourceBase, `${className}.h`);
if (this.generateObjectiveCFiles(className, classFilePath, headerFilePath)) {
// Modify/Generate moduleMap
this.generateOrUpdateModuleMap(`${className}.h`, path.join(iosSourceBase, "module.modulemap"));
}
}
generateOrUpdateModuleMap(headerFileName, moduleMapPath) {
const moduleName = "LocalModule";
const headerPath = headerFileName;
let moduleMapContent = "";
if (fs.existsSync(moduleMapPath)) {
moduleMapContent = fs.readFileSync(moduleMapPath, "utf8");
}
const headerDeclaration = `header "${headerPath}"`;
if (moduleMapContent.includes(`module ${moduleName}`)) {
// Module declaration already exists in the module map
if (moduleMapContent.includes(headerDeclaration)) {
// Header is already present in the module map
this.$logger.warn(`Header '${headerFileName}' is already added to the module map.`);
return;
}
const updatedModuleMapContent = moduleMapContent.replace(new RegExp(`module ${moduleName} {\\s*([^}]*)\\s*}`, "s"), `module ${moduleName} {${os_1.EOL} $1${os_1.EOL} ${headerDeclaration}${os_1.EOL}}`);
fs.writeFileSync(moduleMapPath, updatedModuleMapContent);
}
else {
// Module declaration does not exist in the module map
const moduleDeclaration = `module ${moduleName} {${os_1.EOL} ${headerDeclaration}${os_1.EOL} export *${os_1.EOL}}`;
moduleMapContent += `${os_1.EOL}${os_1.EOL}${moduleDeclaration}`;
fs.writeFileSync(moduleMapPath, moduleMapContent);
}
this.$logger.info(`Module map '${moduleMapPath}' has been updated with the header '${headerFileName}'.`);
}
generateObjectiveCFiles(className, classFilePath, interfaceFilePath) {
if (fs.existsSync(classFilePath)) {
this.$errors.failWithHelp(`Error: File '${classFilePath}' already exists.`);
return false;
}
if (fs.existsSync(interfaceFilePath)) {
this.$errors.failWithHelp(`Error: File '${interfaceFilePath}' already exists.`);
return false;
}
const interfaceContent = `#import <Foundation/Foundation.h>
@interface ${className} : NSObject
- (void)logMessage;
@end
`;
const classContent = `#import "${className}.h"
@implementation ${className}
- (void)logMessage {
NSLog(@"Hello from ${className} class!");
}
@end
`;
fs.writeFileSync(classFilePath, classContent);
this.$logger.trace(`Objective-C class file '${classFilePath}' generated successfully.`);
fs.writeFileSync(interfaceFilePath, interfaceContent);
this.$logger.trace(`Objective-C interface file '${interfaceFilePath}' generated successfully.`);
return true;
}
}
exports.NativeAddObjectiveCCommand = NativeAddObjectiveCCommand;
class NativeAddSwiftCommand extends NativeAddSingleCommand {
constructor($projectData, $logger, $errors) {
super($projectData, $logger, $errors);
}
async execute(args) {
this.doSwift(args[0]);
return Promise.resolve();
}
doSwift(className) {
const iosSourceBase = this.getIosSourcePathBase();
const swiftFilePath = path.join(iosSourceBase, `${className}.swift`);
this.generateSwiftFile(className, swiftFilePath);
}
generateSwiftFile(className, filePath) {
const directory = path.dirname(filePath);
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true });
this.$logger.trace(`Created directory: '${directory}'.`);
}
if (fs.existsSync(filePath)) {
this.$errors.failWithHelp(`Error: File '${filePath}' already exists.`);
return;
}
const content = `import Foundation;
import os;
@objc class ${className}: NSObject {
@objc func logMessage() {
os_log("Hello from ${className} class!")
}
}`;
fs.writeFileSync(filePath, content);
this.$logger.info(`Swift file '${filePath}' generated successfully.`);
}
}
exports.NativeAddSwiftCommand = NativeAddSwiftCommand;
yok_1.injector.registerCommand(["native|add"], NativeAddCommand);
yok_1.injector.registerCommand(["native|add|java"], NativeAddJavaCommand);
yok_1.injector.registerCommand(["native|add|kotlin"], NativeAddKotlinCommand);
yok_1.injector.registerCommand(["native|add|swift"], NativeAddSwiftCommand);
yok_1.injector.registerCommand(["native|add|objective-c"], NativeAddObjectiveCCommand);
//# sourceMappingURL=native-add.js.map