mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 12:55:55 +00:00
* Added: Setting to hide the mass gift sub banner at the top of chat. * Changed: Messages for redeeming Channel Points now have custom rendering with less padding and background colors to properly highlight them. * Fixed: Moderation profiles not always applying when navigating between channels. * Fixed: Settings to disable auto-play not working. * Fixed: Remove debug logging when importing a profile.
153 lines
3.3 KiB
JavaScript
153 lines
3.3 KiB
JavaScript
const transformSync = require('@babel/core').transformSync;
|
|
const type = require('@babel/types');
|
|
const traverse = require('@babel/traverse').default;
|
|
|
|
const fs = require('fs');
|
|
const glob = require('glob');
|
|
|
|
function matchesPattern(member, match, allowPartial = false) {
|
|
if ( ! type.isMemberExpression(member) )
|
|
return false;
|
|
|
|
const parts = Array.isArray(match) ? match : match.split('.');
|
|
const nodes = [];
|
|
|
|
let node;
|
|
for(node = member; type.isMemberExpression(node); node = node.object)
|
|
nodes.push(node.property);
|
|
|
|
nodes.push(node);
|
|
|
|
if ( nodes.length < parts.length )
|
|
return false;
|
|
if ( ! allowPartial && nodes.length > parts.length )
|
|
return false;
|
|
|
|
for(let i = 0, j = nodes.length - 1; i < parts.length; i++, j--) {
|
|
const node = nodes[j];
|
|
let value;
|
|
if ( type.isIdentifier(node) )
|
|
value = node.name;
|
|
else if ( type.isStringLiteral(node) )
|
|
value = node.value;
|
|
else if ( type.isThisExpression(node) )
|
|
value = 'this';
|
|
else
|
|
return false;
|
|
|
|
if ( parts[i] !== value )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const babelOptions = {
|
|
ast: true,
|
|
parserOpts: JSON.parse(fs.readFileSync('.babelrc', 'utf8'))
|
|
};
|
|
|
|
babelOptions.parserOpts.plugins = [
|
|
'jsx',
|
|
'dynamicImport',
|
|
'optionalChaining',
|
|
'objectRestSpread'
|
|
]
|
|
|
|
function getString(node) {
|
|
if ( type.isStringLiteral(node) )
|
|
return node.value;
|
|
|
|
if ( type.isTemplateLiteral(node) && (! node.expressions || ! node.expressions.length) && node.quasis && node.quasis.length === 1 )
|
|
return node.quasis[0].value.cooked;
|
|
|
|
return null;
|
|
}
|
|
|
|
function extractFromCode(code) {
|
|
const { ast } = transformSync(code, babelOptions);
|
|
const matches = [];
|
|
|
|
traverse(ast, {
|
|
CallExpression(path) {
|
|
const callee = path.get('callee');
|
|
if ( ! callee )
|
|
return;
|
|
|
|
if ( !( matchesPattern(callee.node, 'this.i18n.t') ||
|
|
matchesPattern(callee.node, 'i18n.t') ||
|
|
matchesPattern(callee.node, 't.i18n.t') ||
|
|
matchesPattern(callee.node, 'this.i18n.tList') ||
|
|
matchesPattern(callee.node, 'i18n.tList') ||
|
|
matchesPattern(callee.node, 't.i18n.tList') ||
|
|
matchesPattern(callee.node, 'this.t') ||
|
|
matchesPattern(callee.node, 'this.tList') ))
|
|
return;
|
|
|
|
const key = getString(path.get('arguments.0').node);
|
|
if ( ! key )
|
|
return;
|
|
|
|
matches.push({
|
|
key,
|
|
loc: path.node.loc.start,
|
|
phrase: getString(path.get('arguments.1').node)
|
|
});
|
|
}
|
|
})
|
|
|
|
return matches;
|
|
}
|
|
|
|
function extractFromFiles(files) {
|
|
const results = [];
|
|
|
|
if ( ! Array.isArray(files) )
|
|
files = [files];
|
|
|
|
const scannable = new Set;
|
|
for(const thing of files) {
|
|
for(const file of glob.sync(thing, {}))
|
|
scannable.add(file);
|
|
}
|
|
|
|
for(const file of scannable) {
|
|
const code = fs.readFileSync(file, 'utf8');
|
|
const matches = extractFromCode(code);
|
|
for(const match of matches) {
|
|
match.source = `${file}:${match.loc.line}:${match.loc.column}`;
|
|
delete match.loc;
|
|
results.push(match);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
const bits = extractFromFiles([
|
|
'src/**/*.js',
|
|
'src/**/*.jsx'
|
|
]);
|
|
|
|
const seen = new Set;
|
|
const out = [];
|
|
|
|
for(const entry of bits) {
|
|
if ( seen.has(entry.key) )
|
|
continue;
|
|
|
|
seen.add(entry.key);
|
|
if ( entry.key && entry.phrase )
|
|
out.push({
|
|
key: entry.key,
|
|
phrase: entry.phrase,
|
|
calls: [
|
|
`/${entry.source}`
|
|
]
|
|
});
|
|
}
|
|
|
|
fs.writeFileSync('extracted.json', JSON.stringify(out, null, '\t'));
|
|
|
|
console.log(`Extracted ${out.length} strings.`);
|