Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@

Generate Dart bindings from native code. It's based on [dart_native](https://pub.dev/packages/dart_native).

This is the cyan part(DartNative Codegen) in the picture below:
![](images/introduction.png)

You can use codegen to convert native SDK into Flutter SDK. Such as Login SDK:

![](images/login_sample.png)

Codegen is a part of DartNative. It's the cyan part(DartNative Codegen) in the picture below:

![](https://github.com/dart-native/dart_native/blob/master/images/dartnative.png?raw=true)

It's still under development.
Expand All @@ -22,12 +29,13 @@ $ npm install -g @dartnative/codegen
```
Usage: codegen [options] <input>

generate dart code from native api.
Generate dart code from native API.

Options:
-V, --version output the version number
-l, --language <language> Input Language
-l, --language <language> [objc(default), java]
-o, --output <output> Output directory
-p, --package <package> Generate a shareable Flutter project containing modular Dart code.
-h, --help display help for command
```

Expand Down
106 changes: 81 additions & 25 deletions bin/codegen.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#!/usr/bin/env node

const { program } = require('commander')
const { exec } = require('child_process')
const { execSync } = require('child_process')
var DNObjectiveConverter = require('../lib/objc/DNObjectiveConverter').DNObjectiveConverter
var fs = require("fs")
var path = require("path")
const fs = require("fs")
const path = require("path")
const yaml = require('js-yaml')
var outputDir
var outputPackage
var packageSet = new Set()

function mkdirs(dirname) {
if (fs.existsSync(dirname)) {
Expand All @@ -20,7 +23,10 @@ function mkdirs(dirname) {

function recFindByExt(base, ext, files, result) {
if (!fs.statSync(base).isDirectory()) {
return [base]
if (base.substr(-1 * (ext.length + 1)) == '.' + ext) {
return [base]
}
return []
}
files = files || fs.readdirSync(base)
result = result || []
Expand All @@ -42,52 +48,102 @@ function recFindByExt(base, ext, files, result) {

function writeOutputToFileByPath(result, srcPath){
var srcFile = srcPath.substr(srcPath.lastIndexOf('/') + 1)
var dartFile = srcFile.substring(0,srcFile.indexOf('.')) + '.dart'
var dartFile = srcFile.substring(0, srcFile.indexOf('.')).toLowerCase() + '.dart'
var outputFile = outputDir ? path.join(outputDir, dartFile) : dartFile
fs.writeFileSync(outputFile, result)
}

function callback(result, srcPath, error) {
if (result) {
writeOutputToFileByPath(result, srcPath)
if (!result) {
return
}

writeOutputToFileByPath(result.dartCode, srcPath)

if(outputPackage) {
result.packages.forEach(item => packageSet.add(item))
}
}

function formatDartFile(dartPath) {
var command = 'flutter format ' + path.dirname(dartPath)
exec(command, (err, stdout, stderr) => {
if (err) {
console.log(err)
execSync(command, { stdio: 'inherit' })
}

function createFlutterPackage(packageName) {
var command = 'flutter create --template=package ' + packageName
execSync(command, { stdio: 'inherit' })
}

function writeDependencyToPubSpec(filePath) {
var doc = yaml.safeLoad(fs.readFileSync(filePath, 'utf8'));
packageSet.forEach(item => {
if(typeof(item) == "undefined") {
return
}
console.log(stdout + stderr)
item = item.toLowerCase()
doc.dependencies[item] = { path : item}
})
fs.writeFileSync(filePath, yaml.safeDump(doc).replace(/null/g,''))
}

program.version('1.0.0')
program.version('1.0.2')

program
.arguments('<input>', 'Iutput directory')
.option('-l, --language <language>', 'Input Language')
.option('-l, --language <language>', '[objc, java, auto(default)]')
.option('-o, --output <output>', 'Output directory')
.description('generate dart code from native api.')
.option('-p, --package <package>', 'Generate a shareable Flutter project containing modular Dart code.')
.description('Generate dart code from native API.')
.action(function (input, options) {
var ext
if (options.language == 'objc') {
ext = 'h'
language = options.language
if (!language) {
language = 'auto'
}
const dirs = recFindByExt(input, ext)
console.log(dirs)

if (options.output) {
mkdirs(options.output)
outputDir = options.output
var extMap = {'objc': ['h'], 'java': ['java'], 'auto': ['h', 'java']}
var extArray = extMap[language]

outputDir = options.output
if (outputDir) {
mkdirs(outputDir)
}

outputPackage = options.package
if (outputPackage) {
outputDir = path.join(outputDir, outputPackage)
createFlutterPackage(outputDir)
outputDir = path.join(outputDir, 'lib')
}

dirs.forEach((dir) => {
new DNObjectiveConverter(dir, callback)
console.log(dir)
console.log('Output Dir: ' + outputDir)

var baseOutputDir = outputDir
extArray.forEach((ext) => {
var files = recFindByExt(input, ext)
if (files.length == 0) {
return
}
var extToLang = {'h': 'objc', 'java': 'java'}
outputDir = path.join(baseOutputDir, extToLang[ext])
mkdirs(outputDir)

files.forEach((file) => {
console.log('processing ' + file)
if (ext == 'h') {
new DNObjectiveConverter(file, callback)
} else if (ext == 'java') {
// TODO: handle java
}
})
})
outputDir = baseOutputDir
formatDartFile(outputDir)

if (outputPackage) {
var filePath = path.join(path.join(options.output, outputPackage), 'pubspec.yaml')
writeDependencyToPubSpec(filePath)
}
console.log('codegen finished')
})

Expand Down
Binary file added images/introduction.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/login_sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var DNObjectiveConverter = require('./lib/objc/DNObjectiveConverter').DNObjectiv
new DNObjectiveConverter("./test/objc/RuntimeStub.h", callback)

function callback(result, path, error) {
console.log('result:\n' + result + '\n\npath:\n' + path)
console.log('result:\n' + result.dartCode + '\n\npath:\n' + path)
if (error) {
console.log('\nerror:\n' + error)
}
Expand Down
10 changes: 8 additions & 2 deletions lib/objc/DNObjectiveCContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,8 @@ class DNRootContext extends DNContext {
}

parse() {
var result = '';
var result = ''
var packageSet = new Set()
if (!this.needExport) {
result += "import 'dart:ffi';\n\n"
result += "import 'package:dart_native/dart_native.dart';\n"
Expand All @@ -537,10 +538,15 @@ class DNRootContext extends DNContext {
var childResult = ctx.parse()
if (!(ctx instanceof DNImportContext)) {
childResult = '\n' + childResult
} else {
packageSet.add(ctx.package)
}
return childResult
}).join('\n')
return result
return {
dartCode : result,
packages : packageSet
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"homepage": "https://github.com/dart-native/codegen#readme",
"dependencies": {
"antlr4": "^4.8.0",
"commander": "^5.0.0"
"commander": "^5.0.0",
"js-yaml": "^3.14.0"
},
"devDependencies": {}
}