@scriptables/manifest
Version:
Utilities to generate, parse, and update manifest headers in Scriptable scripts.
108 lines (101 loc) • 3.88 kB
text/typescript
import {generateScriptableBanner} from './generateScriptableBanner';
import {normalizeManifest} from './normalizeManifest';
import {parseScriptableManifest} from './parseScriptableManifest';
import {SCRIPT_HEADER_NOTICES} from './scriptHeaderNotices';
import {ScriptableManifest} from './types';
interface ScriptableBannerResult {
/** The merged banner content */
banner: string;
/** The remaining script content without the banner */
content: string;
}
/**
* Merges Scriptable script banners according to priority rules. This function:
* 1. Merges manifest values from different sources (manifest object, old script, new script)
* 2. Preserves static banner lines
* 3. Creates new banner if none exists
*
* @param script - The script content to process
* @param manifestOrOldScript - Either a manifest object or old script content to extract manifest from
* @returns ScriptableBannerResult containing the merged banner and remaining content
*
* @example
* // Case 1: Merge manifest object with existing banner
* const script = `// Variables used by Scriptable.
* // These must be at the very top of the file. Do not edit.
* // icon-color: blue; icon-glyph: circle;
* console.log('Hello world');`;
*
* const manifest = {
* iconColor: 'red',
* iconGlyph: 'square'
* };
*
* const {banner, content} = mergeScriptableBanner(script, manifest);
* // banner will be:
* // // Variables used by Scriptable.
* // // These must be at the very top of the file. Do not edit.
* // // icon-color: red; icon-glyph: square;
*
* @example
* // Case 2: Merge banners from old and new scripts
* const oldScript = `// Variables used by Scriptable.
* // These must be at the very top of the file. Do not edit.
* // icon-color: blue; icon-glyph: circle;
* console.log('Old script');`;
*
* const newScript = `// Variables used by Scriptable.
* // These must be at the very top of the file. Do not edit.
* // icon-color: red; icon-glyph: square;
* console.log('New script');`;
*
* const {banner, content} = mergeScriptableBanner(newScript, oldScript);
* // banner will be:
* // // Variables used by Scriptable.
* // // These must be at the very top of the file. Do not edit.
* // // icon-color: blue; icon-glyph: circle;
*
* @remarks
* Merge Priority (highest to lowest):
* 1. Manifest object values (if provided)
* 2. Old script banner values (if oldScript provided)
* 3. New script banner values
* 4. Default values
*
* Supported manifest properties:
* - iconColor: The color of the script icon
* - iconGlyph: The glyph/symbol used for the script icon
* - alwaysRunInApp: Whether the script should always run in the app (true/false)
* - shareSheetInputs: Array of allowed input types for share sheet
*
* Banner Structure:
* 1. Static notice lines (preserved as-is)
* 2. Manifest properties (merged according to priority)
*/
export function mergeScriptableBanner(
script: string,
manifestOrOldScript?: Partial<ScriptableManifest> | string,
): ScriptableBannerResult {
if (!script || !script.includes(SCRIPT_HEADER_NOTICES[0])) {
return {
banner: generateScriptableBanner(manifestOrOldScript as Partial<ScriptableManifest>),
content: script || '',
};
}
const {manifest: currentManifest, content: scriptContent} = parseScriptableManifest(script);
let finalManifest: Partial<ScriptableManifest> = currentManifest ?? {};
if (manifestOrOldScript) {
if (typeof manifestOrOldScript === 'string') {
const {manifest} = parseScriptableManifest(manifestOrOldScript);
if (manifest && Object.keys(manifest).length) {
finalManifest = {...finalManifest, ...manifest};
}
} else {
finalManifest = {...finalManifest, ...normalizeManifest(manifestOrOldScript)};
}
}
return {
banner: generateScriptableBanner(finalManifest),
content: scriptContent,
};
}