Skip to content

Instantly share code, notes, and snippets.

@Grohden
Last active June 28, 2019 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Grohden/899b43e4da614f537266077bfbc5e5c6 to your computer and use it in GitHub Desktop.
Save Grohden/899b43e4da614f537266077bfbc5e5c6 to your computer and use it in GitHub Desktop.
Generate dart deserialization and model classes based on JSON input
{
"pageCount": 1,
"result": [
{
"page_number": 12,
"is_favorite": true,
"cover": {
"width": 40,
"height": 50,
"url": "www.test.com"
}
}
]
}
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)
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
@Grohden
Copy link
Author

Grohden commented Jun 27, 2019

Just wanted to say that this is of course SIMPLE, and does not deal with more complex cases (like non uniform lists)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment