Biome reported 229 diagnostics after aligning the config with
bsi-ni.brain.riken.jp. Fix them all so `biome check` passes clean
without per-rule overrides.
- replace `any` in LokiJS queries with an `ItemFilter` interface and
a single `asLokiQuery()` cast, matching bsi-ni
- type the XOOPS redirect maps as
`Record<string, { key: string; isNumber: boolean }>`
- use `ItemSubTypes<string>` instead of `any` for sub item types
- join author lists with `.join(', ')` instead of index-keyed nodes
- give list elements stable keys derived from their own data
- return `React.ReactNode` from `ListBase.renderBody()`
- drop the temporary `noArrayIndexKey` override from biome.json
137 lines
3.9 KiB
TypeScript
137 lines
3.9 KiB
TypeScript
import Config, { type MultiLang } from './config';
|
|
|
|
const escapeUrl = (str: string) => {
|
|
return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {
|
|
return `%${c.charCodeAt(0).toString(16)}`;
|
|
});
|
|
};
|
|
|
|
const unescapeUrl = (str: string) => {
|
|
return decodeURIComponent(str);
|
|
};
|
|
|
|
const htmlspecialchars = (str: string) => {
|
|
return str.replace(/(<|>|&|'|")/g, (match) => {
|
|
switch (match) {
|
|
case '<':
|
|
return '<';
|
|
case '>':
|
|
return '>';
|
|
case '&':
|
|
return '&';
|
|
case "'":
|
|
return ''';
|
|
case '"':
|
|
return '"';
|
|
}
|
|
return '';
|
|
});
|
|
};
|
|
|
|
const camelCase = (str: string) => {
|
|
return str.replace(/[-_](.)/g, (...matches) => {
|
|
return matches[1].toUpperCase();
|
|
});
|
|
};
|
|
|
|
const snakeCase = (str: string) => {
|
|
var camel = camelCase(str);
|
|
return camel.replace(/[A-Z]/g, (...matches) => {
|
|
return `_${matches[0].charAt(0).toLowerCase()}`;
|
|
});
|
|
};
|
|
|
|
const pascalCase = (str: string) => {
|
|
var camel = camelCase(str);
|
|
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
};
|
|
|
|
const base64Encode = (str: string) => {
|
|
return btoa(unescape(encodeURIComponent(str)));
|
|
};
|
|
|
|
const base64Decode = (str: string) => {
|
|
return decodeURIComponent(escape(atob(str)));
|
|
};
|
|
|
|
const ordinal = (num: number) => {
|
|
const hundred = num % 100;
|
|
if (hundred >= 10 && hundred <= 20) {
|
|
return 'th';
|
|
}
|
|
const ten = num % 10;
|
|
const suffix = ['st', 'nd', 'rd'];
|
|
return ten > 0 && ten < 4 ? suffix[ten - 1] : 'th';
|
|
};
|
|
|
|
const mlang = (str: string, lang: MultiLang) => {
|
|
const mlLangs = ['en', 'ja'];
|
|
// escape brackets inside of <input type="text" value="...">
|
|
let text = str.replace(/(<input)([^>]*)(>)/gis, (whole, m1, m2, m3) => {
|
|
if (m2.match(/type=["']?(?:text|hidden)["']?/is)) {
|
|
return m1 + m2.replace(/\[/g, '__ml[ml__') + m3;
|
|
}
|
|
return whole;
|
|
});
|
|
// escape brackets inside of <textarea></textarea>
|
|
text = text.replace(/(<textarea[^>]*>)(.*)(<\/textarea>)/gis, (_whole, m1, m2, m3) => {
|
|
return m1 + m2.replace(/\[/g, '__ml[ml__') + m3;
|
|
});
|
|
// simple pattern to strip selected lang_tags
|
|
const re = new RegExp(`\\[/?(?:[^\\]]+\\|)?${lang}(?:\\|[^\\]]+)?\\](?:<br />)?`, 'g');
|
|
text = text.replace(re, '');
|
|
// eliminate description between the other language tags.
|
|
mlLangs.forEach((mlLang) => {
|
|
if (mlLang !== lang) {
|
|
const re = new RegExp(
|
|
'\\[(?:[^/][^\\]]+\\|)?' +
|
|
mlLang +
|
|
'(?:\\|[^\\]]+)?\\].*?\\[/(?:[^\\]]+\\|)?' +
|
|
mlLang +
|
|
'(?:\\|[^\\]]+)?\\](?:<br />)?',
|
|
'gis'
|
|
);
|
|
text = text.replace(re, (whole) => {
|
|
return whole.match(/<\/table>/) ? whole : '';
|
|
});
|
|
}
|
|
});
|
|
// unescape brackets inside of <textarea></textarea>
|
|
text = text.replace(/(<textarea[^>]*>)(.*)(<\/textarea>)/gis, (_whole, m1, m2, m3) => {
|
|
return m1 + m2.replace(/__ml\[ml__/g, '[') + m3;
|
|
});
|
|
// unescape brackets inside of <input type="text" value="...">
|
|
text = text.replace(/(<input)([^>]*)(>)/gis, (whole, m1, m2, m3) => {
|
|
if (m2.match(/type=["']?(?:text|hidden)["']?/is)) {
|
|
return m1 + m2.replace(/__ml\[ml__/g, '[') + m3;
|
|
}
|
|
return whole;
|
|
});
|
|
return text;
|
|
};
|
|
|
|
const siteTitle = (lang: MultiLang) => {
|
|
return mlang(Config.SITE_TITLE, lang);
|
|
};
|
|
|
|
const siteSlogan = (lang: MultiLang) => {
|
|
return mlang(Config.SITE_SLOGAN, lang);
|
|
};
|
|
|
|
const Functions = {
|
|
escape: escapeUrl,
|
|
unescape: unescapeUrl,
|
|
htmlspecialchars,
|
|
camelCase,
|
|
snakeCase,
|
|
pascalCase,
|
|
base64Encode,
|
|
base64Decode,
|
|
ordinal,
|
|
mlang,
|
|
siteTitle,
|
|
siteSlogan,
|
|
};
|
|
|
|
export default Functions;
|