Last active
June 28, 2019 15:29
-
-
Save Grohden/899b43e4da614f537266077bfbc5e5c6 to your computer and use it in GitHub Desktop.
Generate dart deserialization and model classes based on JSON input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"pageCount": 1, | |
"result": [ | |
{ | |
"page_number": 12, | |
"is_favorite": true, | |
"cover": { | |
"width": 40, | |
"height": 50, | |
"url": "www.test.com" | |
} | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
const path = require('path') | |
const generateModels = require('./model-generator') | |
const jsonModel = require('./example-json-model.json') | |
const BASE_PATH = path.join( | |
__dirname, | |
'./generated-models/' | |
) | |
const toSnakeCase = (str) => str.split(/(?=[A-Z])/).join('_').toLowerCase() | |
const generateTypes = () => { | |
console.info('> generating classes definitions') | |
const generatedClasses = generateModels('JsonResult', jsonModel) | |
for (const { content, className } of generatedClasses) { | |
const filePath = path.join(BASE_PATH, `${toSnakeCase(className)}.dart`) | |
console.info(`> writing ${filePath}`) | |
fs.writeFile(filePath, content, 'utf-8', function (err) { | |
if (err) { | |
console.error(err) | |
} | |
}) | |
} | |
console.info('> generation finished') | |
} | |
setTimeout(generateTypes, 500) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getDartType(value) { | |
const valueType = typeof value | |
switch (valueType) { | |
case 'string': | |
return 'String' | |
case 'boolean': | |
return 'boolean' | |
case 'number': | |
return 'int' | |
case 'object': | |
if (Array.isArray(value)) { | |
return 'list' | |
} else { | |
return 'object' | |
} | |
default: | |
return 'dynamic' | |
} | |
} | |
const camelize = str => | |
str.replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase()) | |
const capitalizeFirst = ([first, ...rest]) => | |
first.toUpperCase() + (rest || []).join('') | |
function createClassesFromJson(className, jsonModel) { | |
let generatedClasses = [] | |
const entries = Object.entries(jsonModel) | |
const constructorFields = entries.map(([key]) => { | |
const camelKey = camelize(key) | |
return `@required this.${camelKey}` | |
}) | |
const classFields = entries.map(([key, value]) => { | |
const type = getDartType(value) | |
const camelKey = camelize(key) | |
const generatedClassName = capitalizeFirst(camelKey) | |
if (type === 'object') { | |
return `${generatedClassName} ${camelKey};` | |
} else if (type === 'list') { | |
return `List<${generatedClassName}> ${camelKey};` | |
} else { | |
return `${type} ${camelKey};` | |
} | |
}) | |
const fromJsonContent = entries.map(([key, value]) => { | |
const type = getDartType(value) | |
const camelKey = camelize(key) | |
const generatedClassName = capitalizeFirst(camelKey) | |
if (type === 'object') { | |
generatedClasses = generatedClasses.concat( | |
createClassesFromJson(generatedClassName, value) | |
) | |
return `${camelKey}: ${generatedClassName}.fromJson(json['${key}'] as Map<String, dynamic>)` | |
} else if (type === 'list') { | |
generatedClasses = generatedClasses.concat( | |
// FIXME: we should merge the whole array to | |
// for the non uniform case | |
createClassesFromJson(generatedClassName, value[0]) | |
) | |
return [ | |
`${camelKey}: (json['${key}'] as List)`, | |
`?.map((e) => ${generatedClassName}.fromJson(e as Map<String, dynamic>))`, | |
`?.toList()` | |
].join('\n ') | |
} else { | |
return `${camelKey}: json['${key}'] as ${type}` | |
} | |
}) | |
const generated = `import 'package:meta/meta.dart'; | |
class ${className} { | |
${className}({ | |
${constructorFields.join(',\n ')} | |
}); | |
factory ${className}.fromJson(Map<String, dynamic> json) { | |
return ${className}( | |
${fromJsonContent.join(',\n ')} | |
); | |
} | |
${classFields.join('\n ')} | |
}` | |
return [{ content: generated, className }].concat(generatedClasses) | |
} | |
module.exports = createClassesFromJson |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just wanted to say that this is of course SIMPLE, and does not deal with more complex cases (like non uniform lists)