feat(yaml): use !match tag to process content

This commit is contained in:
Haoyu Xu
2023-01-21 17:20:17 -05:00
parent 899f424d5d
commit f363c0b908
4 changed files with 56 additions and 81 deletions

View File

@@ -1,4 +1,4 @@
description: "${func:split('title' ,' - ')[0]} Live 2D\n${func:split('title' ,' - ')[1]} Live 2D\nThe model is extracted from game with Spine support.\n模型来自游戏内提取支持Spine\nPlease set your FPS target in Wallpaper Engine > Settings > Performance > FPS\n请在 Wallpaper Engine > 设置 > 性能 > FPS 下设置FPS\n\nLive preview on: https://arknights.halyul.dev/${var:link}\nGithub: https://github.com/Halyul/aklive2d" description: !match "${replaceFunc:split('config', 'title' ,' - ')[0]} Live 2D\n${replaceFunc:split('config', 'title' ,' - ')[1]} Live 2D\nThe model is extracted from game with Spine support.\n模型来自游戏内提取支持Spine\nPlease set your FPS target in Wallpaper Engine > Settings > Performance > FPS\n请在 Wallpaper Engine > 设置 > 性能 > FPS 下设置FPS\n\nLive preview on: https://arknights.halyul.dev/${var:link}\nGithub: https://github.com/Halyul/aklive2d"
localization: localization:
en-us: en-us:
ui_custom_background: Custom Background ui_custom_background: Custom Background
@@ -67,11 +67,11 @@ properties:
value: value:
text: ui_default_background text: ui_default_background
type: combo type: combo
value: this.#assets.backgrounds[0] value: !match ${directFunc:getVar('assets', "backgrounds")[0]}
fraction: false fraction: false
max: 100 max: 100
min: 0 min: 0
options: options: !match ${directFunc:getVar('assets', "backgroundOptions")}
- key: background - key: background
value: value:
text: ui_custom_background text: ui_custom_background
@@ -86,7 +86,7 @@ properties:
value: value:
text: ui_position_padding_left text: ui_position_padding_left
type: slider type: slider
value: value: !match ${directFunc:getVar('config', "viewport_left")}
condition: position.value == true condition: position.value == true
fraction: false fraction: false
max: 100 max: 100
@@ -95,7 +95,7 @@ properties:
value: value:
text: ui_position_padding_right text: ui_position_padding_right
type: slider type: slider
value: value: !match ${directFunc:getVar('config', "viewport_right")}
condition: position.value == true condition: position.value == true
fraction: false fraction: false
max: 100 max: 100
@@ -104,7 +104,7 @@ properties:
value: value:
text: ui_position_padding_top text: ui_position_padding_top
type: slider type: slider
value: value: !match ${directFunc:getVar('config', "viewport_top")}
condition: position.value == true condition: position.value == true
fraction: false fraction: false
max: 100 max: 100
@@ -113,7 +113,7 @@ properties:
value: value:
text: ui_position_padding_bottom text: ui_position_padding_bottom
type: slider type: slider
value: value: !match ${directFunc:getVar('config', "viewport_bottom")}
condition: position.value == true condition: position.value == true
fraction: false fraction: false
max: 100 max: 100

View File

@@ -1,24 +1,20 @@
export default class Matcher { export default class Matcher {
#start #start
#end #end
#content
#reExp #reExp
#config #config
#assets
constructor(content, start, end, config) { constructor(start, end, config, assets) {
this.#start = start this.#start = start
this.#end = end this.#end = end
this.#content = content
this.#reExp = new RegExp(`\\${start}.+?${end}`, 'g') this.#reExp = new RegExp(`\\${start}.+?${end}`, 'g')
this.#config = config this.#config = config
this.#assets = assets
} }
match() { get result() {
return this.#content.match(this.#reExp) const matches = this.content.match(this.#reExp)
}
process() {
const matches = this.match()
if (matches !== null) { if (matches !== null) {
matches.forEach((match) => { matches.forEach((match) => {
const matchTypeName = match.replace(this.#start, '').replace(this.#end, '') const matchTypeName = match.replace(this.#start, '').replace(this.#end, '')
@@ -33,40 +29,55 @@ export default class Matcher {
} catch (e) { } catch (e) {
throw new Error(`Cannot find variable ${name}.`) throw new Error(`Cannot find variable ${name}.`)
} }
this.#content = this.#content.replace(match, replaceValue) this.content = this.content.replace(match, replaceValue)
}) })
break break
case 'func': case 'replaceFunc':
try { try {
this.#content = this.#content.replace(match, (new Function('Evalable', 'config', `return new Evalable(config).${name}`))(Evalable, this.#config)) this.content = this.content.replace(match, (new Function('Evalable', 'config', 'assets', `return new Evalable(config, assets).${name}`))(Evalable, this.#config, this.#assets))
} catch (e) { } catch (e) {
throw new Error(e) throw new Error(e)
} }
break break
case 'directFunc':
this.content = (new Function('Evalable', 'config', 'assets', `return new Evalable(config, assets).${name}`))(Evalable, this.#config, this.#assets)
break
default: default:
throw new Error(`Cannot find type ${type}.`) throw new Error(`Cannot find type ${type}.`)
} }
}) })
} }
return this.#content return this.content
} }
} }
class Evalable { class Evalable {
#config #config
#assets
constructor(config) { constructor(config, assets) {
this.#config = config this.#config = config
this.#assets = assets
} }
split(varName, separator) { split(location, varName, separator) {
return this.#step(location, varName).split(separator)
}
getVar(location, varName) {
return this.#step(location, varName)
}
#step(location, varName) {
let content = this.#config
varName.split("->").forEach((item) => { varName.split("->").forEach((item) => {
try { try {
this.#config = this.#config[item] if (location === 'assets') content = this.#assets
content = content[item]
} catch (e) { } catch (e) {
throw new Error(`Cannot split ${varName} with separator ${separator}.`) throw new Error(`Cannot step ${varName}.`)
} }
}) })
return this.#config.split(separator) return content
} }
} }

View File

@@ -16,12 +16,29 @@ export default class ProjectJson {
this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator) this.#operatorSourceFolder = path.join(__dirname, __config.folder.operator)
this.#operatorShareFolder = operatorShareFolder this.#operatorShareFolder = operatorShareFolder
this.#assets = assets this.#assets = assets
this.#template = this.#processYAML(readYAML(path.join(__dirname, 'config', '_project_json.yaml')))
} }
async load() { async load() {
// load json from file // load json from file
this.#json = JSON.parse(await readFile(this.#getPath())) this.#json = JSON.parse(await readFile(this.#getPath()))
const matcher = new Matcher('${', '}', __config.operators[this.#operatorName], {
...this.#assets,
backgroundOptions: this.#assets.backgrounds.map((b) => {
return {
"label": b,
"value": b
}
})
})
const match = {
identify: value => value.startsWith('!match'),
tag: '!match',
resolve(str) {
matcher.content = str
return matcher.result
}
}
this.#template = readYAML(path.join(__dirname, 'config', '_project_json.yaml'), [match])
this.#process() this.#process()
return this.#json return this.#json
} }
@@ -52,59 +69,6 @@ export default class ProjectJson {
} }
} }
#processYAML(template) {
const matcher = new Matcher(template.description, '${', '}', __config.operators[this.#operatorName])
if (matcher.match() !== null) {
template.description = matcher.process()
}
const replacePropertyPairs = [
{
key: "defaultbackground",
value: {
value: this.#assets.backgrounds[0],
options: this.#assets.backgrounds.map((b) => {
return {
"label": b,
"value": b
}
})
}
},
{
key: "paddingleft",
value: {
value: __config.operators[this.#operatorName].viewport_left
},
},
{
key: "paddingright",
value: {
value: __config.operators[this.#operatorName].viewport_right
},
},
{
key: "paddingtop",
value: {
value: __config.operators[this.#operatorName].viewport_top
},
},
{
key: "paddingbottom",
value: {
value: __config.operators[this.#operatorName].viewport_bottom
},
},
]
replacePropertyPairs.forEach((pair) => {
const property = template.properties.find((p) => p.key === pair.key)
property.value = {
...property.value,
...pair.value
}
})
return template
}
get #properties() { get #properties() {
const properties = this.#template.properties const properties = this.#template.properties
const output = {} const output = {}

View File

@@ -2,7 +2,7 @@ import path from 'path'
import { parse } from 'yaml' import { parse } from 'yaml'
import fs from 'fs' import fs from 'fs'
export function read(file_dir) { export function read(file_dir, customTags = []) {
const include = { const include = {
identify: value => value.startsWith('!include'), identify: value => value.startsWith('!include'),
tag: '!include', tag: '!include',
@@ -14,6 +14,6 @@ export function read(file_dir) {
} }
const file = fs.readFileSync(file_dir, 'utf8') const file = fs.readFileSync(file_dir, 'utf8')
return parse(file, { return parse(file, {
customTags: [include], customTags: [include, ...customTags],
}) })
} }