Files
OpenScript/src/utils/parser.js
2026-09-12 22:14:22 -07:00

54 lines
1.7 KiB
JavaScript

// Parse OpenScript's deliberately small metadata format.
const SINGLE_KEYS = new Set(['name', 'version', 'description', 'run-at']);
const MULTI_KEYS = new Set(['match', 'require']);
const RUN_AT_OPTIONS = new Set(['document_start', 'document_end', 'document_idle']);
export const getMetaRunAt = code => {
const block = code.match(/\/\/ ==UserScript==([\s\S]*?)\/\/ ==\/UserScript==/)?.[1] || '';
const val = block.match(/\/\/\s*@run-at\s+([\w-]+)/i)?.[1]?.toLowerCase().replace('-', '_');
return RUN_AT_OPTIONS.has(val) ? val : null;
};
export const parseMeta = code => {
const block = code.match(/\/\/ ==UserScript==([\s\S]*?)\/\/ ==\/UserScript==/)?.[1] || '';
const meta = { match: [], require: [] };
for (const line of block.split('\n')) {
const m = line.match(/\/\/\s*@([\w-]+)\s+(.*)/);
if (!m) continue;
const [, rawK, rawV] = m;
const k = rawK.trim().toLowerCase();
const v = rawV.trim();
if (MULTI_KEYS.has(k)) meta[k].push(v);
else if (SINGLE_KEYS.has(k)) meta[k] = v;
}
return {
name: meta.name || 'Untitled Script',
version: meta.version || '',
description: meta.description || '',
matches: meta.match.length ? meta.match : ['*://*/*'],
runAt: (meta['run-at'] || 'document_idle').replace('-', '_'),
requires: meta.require,
};
};
export const normalizeMatch = pattern => {
let p = pattern.trim();
if (!p) return '*://*/*';
if (/^https?:\/\/[^/]+$/.test(p)) p += '/*';
if (!/^[a-z*]+:\/\//i.test(p)) p = `*://${p}`;
return p;
};
export const getBoilerplate = (name = 'New Userscript') =>
`// ==UserScript==
// @name ${name}
// @match *://*/*
// ==/UserScript==
console.log('Running on', location.hostname);
`;