UNPKG

@comuns-rpgmaker/plugin-metadata

Version:

Automated tool for plugin metadata schema validation and generation

238 lines (187 loc) 6.47 kB
const path = require('path'); const fs = require('fs'); const validate = require('./validate'); function localized(str, language) { return str[language] || str.default || str; } function isPrimitive(value) { return typeof value === 'string' || value instanceof String || typeof value === 'number' || value instanceof Number; } function serialize(value) { if (isPrimitive(value)) { return value; } if (value instanceof Array) { return `[${value.map(serialize).join(',')}]`; } return JSON.stringify(value); } function transformNumber(param) { const result = []; if (param.min !== undefined) result.push(`@min ${param.min}`); if (param.max !== undefined) result.push(`@max ${param.max}`); if (param.decimals !== undefined) result.push(`@decimals ${param.decimals}`); return result; } function transformFile(param) { const result = []; if (param.dir !== undefined) result.push(`@dir ${param.dir}`); return result.concat(transformRequire(param)); } function transformRequire(param) { if (param.require) return [`@require 1`]; else return []; } function transformBoolean(param, language) { const result = []; if (param.on) result.push(`@on ${localized(param.on, language)}`); if (param.off) result.push(`@off ${localized(param.off, language)}`); return result; } function transformSelect(param, language) { return param.options.reduce((result, option) => { if (typeof option === 'object' && 'text' in option) { result.push(`@option ${localized(option.text, language)}`); if (option.value) result.push(`@value ${serialize(option.value)}`); } else { result.push(`@option ${localized(option, language)}`); } return result; }, []); } function additionalOptions(param, language) { switch (param.type) { case 'number': return transformNumber(param); case 'file': return transformFile(param); case 'animation': return transformRequire(param); case 'boolean': return transformBoolean(param, language); case 'select': return transformSelect(param, language); case 'combo': return transformSelect(param, language); default: return []; } } function unitType(type, struct) { if (struct) return `struct<${type}>`; else return type; } function resolveType(param) { if (param.type === 'array') { const items = param.struct || param.items; return `${unitType(items, param.struct)}[]`; } else { return unitType(param.struct || param.type, param.struct); } } function transformParam(param, { command, parent, language }) { let result = [`@${command ? 'arg' : 'param'} ${param.name}`]; if (parent) result.push(`@parent ${parent}`); const type = resolveType(param); if (type) result.push(`@type ${type}`); result.push( `@text ${localized(param.text, language)}`, `@desc ${localized(param.description, language)}` ); result = result.concat(additionalOptions(param, language)); if (param.default !== undefined) result.push(`@default ${serialize(param.default)}`); if (param.children) { param.children.forEach(child => { result.push(''); result.push(...transformParam(child, { language, parent: param.name })) }); } return result; } function transformCommand(command, language) { const result = [ `@command ${command.name}`, `@text ${localized(command.text, language)}`, `@desc ${localized(command.description, language)}` ]; if (command.args) { command.args.forEach(arg => { result.push(...transformParam(arg, { command: true, language })); }); } return result; } function transformStructs(structs, language) { if (!structs) return null; return structs.map((struct) => { const tags = []; struct.params.forEach(param => { tags.push(''); tags.push(...transformParam(param, { language })); }); return { name: struct.name, tags }; }); } function transform(metadata, language) { let result = [ `@target ${metadata.target}`, `@author ${metadata.author}` ]; if (metadata.url) result.push(`@url ${metadata.url}`); result.push( `@plugindesc ${localized(metadata.description, language)}`, `@help ${localized(metadata.help, language)}` ); if (metadata.base) { metadata.base.forEach(plugin => result.push(`@base ${plugin}`)); } if (metadata.before) { metadata.before.forEach(plugin => result.push(`@before ${plugin}`)); } if (metadata.after) { metadata.after.forEach(plugin => result.push(`@after ${plugin}`)); } if (metadata.params) { metadata.params.forEach(param => { result.push(''); result.push(...transformParam(param, { language })); }); } if (metadata.commands) { metadata.commands.forEach(param => { result.push(''); result.push(...transformCommand(param, language)); }); } return { main: result, structs: transformStructs(metadata.structs, language) }; } function formatMain(tags, language) { const lines = tags.join('\n').trimRight().split('\n'); return `/*:${language}\n * ${lines.join('\n * ')}\n */\n` } function formatStructs(tags, language) { if (!tags) return ''; return tags.reduce((acc, { name, tags: structTags }) => { const lines = structTags.join('\n').trimRight().split('\n'); return acc + `/*~struct~${name}:${language}\n * ${lines.join('\n * ')}\n */\n`; }, ''); } module.exports = async function generate(file, output) { const metadata = await validate(file); let result = ''; const languages = ['', ...(metadata.languages || [])] ; languages.forEach(language => { const tags = transform(metadata, language); result += formatMain(tags.main, language) + formatStructs(tags.structs, language); }); result = result.replace(/(?<=[^\r])\n/g, '\r\n'); if (output) { fs.mkdirSync(path.dirname(output), { recursive: true }); fs.writeFileSync(output, result); return 'OK'; } else { return result; } };