Scriptablify - lets you require('modules') in Scriptable app!
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: gray; icon-glyph: magic; | |
// Defaults to the latest version and no automatic update; if the file exists, just use it | |
const moment = await require('moment'); | |
// Use any SemVer options to specify a version you want | |
// Refer to the calculator here: https://semver.npmjs.com/ | |
const lodash = await require('lodash@^3.9.1'); | |
// Pass the second parameter to auto-update or force-download to satisfy the version specified | |
const d3 = await require('d3@>5.3.0', true); | |
console.log(moment()); |
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: gray; icon-glyph: magic; | |
const fm = FileManager.iCloud(); | |
const dir = fm.documentsDirectory(); | |
const downloadIfNeeded = async (pkg, isAutoUpdateOn) => { | |
let name = getPackageName(pkg); | |
let filePath = fm.joinPath(dir, name + '.js'); | |
let isInstalled = await isFound(filePath); | |
// If the package exists and autoupdate is off, stop checking further | |
if (isInstalled && !isAutoUpdateOn) { | |
console.log(`'${name}' is already installed, and autoupdate is disabled! Proceeding to import from disk...`); | |
return; | |
} | |
// Get the package information which satisfies the given semver range | |
let versionInfo = await getStatus(pkg); | |
let versions = versionInfo.satisfied; | |
let version = versionInfo.highest; | |
// Download the newer version if necessary | |
if (isInstalled && isAutoUpdateOn) { | |
let installedVersion = await getInstalledVersion(name); | |
// Check if the installed version satisfies the semver range | |
if (versions.includes(installedVersion)) { | |
console.log(`'${name}@${installedVersion}' satisfies the requested version. Good to go!`); | |
return; | |
} else { | |
console.log(`'${name}@${installedVersion}' doesn't match the version requested. Reinstalling '${version}' now...`); | |
} | |
} else { | |
console.log(`'${name}' was never installed previously. Downloading now...`); | |
} | |
// Download the package source and save to disk | |
let source = await getPackageSource(pkg); | |
savePackageToDisk(name, version, source); | |
}; | |
const getInstalledVersion = async name => { | |
// Read the version from {package}.ver | |
let filePath = fm.joinPath(dir, name + '.ver'); | |
let version; | |
if (isFound(filePath)) { | |
let content = fm.readString(filePath); | |
if (/^\d+\.\d+\.\d+$/g.test(content)) { | |
version = content; | |
} | |
} | |
console.log(`The installed version of '${name}' is ${version}.`); | |
return version; | |
}; | |
const getPackageSource = async pkg => { | |
// Get the standalone package source from wzrd.in | |
let request = new Request(`https://wzrd.in/standalone/${encodeURIComponent(pkg)}`); | |
let response = await request.loadString(); | |
return response; | |
}; | |
const getPackageName = pkg => { | |
return pkg.split('@')[0]; | |
}; | |
const getStatus = async pkg => { | |
// Retrieve the information about the package | |
let request = new Request(`https://wzrd.in/status/${encodeURIComponent(pkg)}`); | |
let response = await request.loadJSON(); | |
// Fail if the response is not good | |
if (response.statusCode >= 400 || response.ok === false) { | |
throw response.message; | |
} | |
// Fail if the semver did not satisfy any versions available on npm | |
// Otherwise, sort the versions in descending order | |
let versions = response.builds && Object.keys(response.builds); | |
if (versions.length < 1) { | |
throw `'${pkg}' did not satisfy any versions available on npm!`; | |
} else { | |
versions.sort((a, b) => b.localeCompare(a, undefined, { numeric: true })); | |
} | |
// Get all the satisfied versions and the highest version | |
let result = { | |
highest: versions[0], | |
satisfied: versions, | |
}; | |
return result; | |
}; | |
const isFound = async filePath => { | |
// Check if the package is already downloaded | |
if (fm.fileExists(filePath)) { | |
return true; | |
} | |
// Sync with iCloud and check again | |
await syncFileWithiCloud(filePath); | |
if (fm.fileExists(filePath)) { | |
return true; | |
} | |
return false; | |
}; | |
const savePackageToDisk = (name, version, source) => { | |
// Write the package source and version info to disk | |
let filename = fm.joinPath(dir, name); | |
let jsFilePath = filename + '.js'; | |
let versionFilePath = filename + '.ver'; | |
let pkg = `${name}@${version}`; | |
tryWriteFile(jsFilePath, source, pkg); | |
tryWriteFile(versionFilePath, version, pkg); | |
console.log(`Successfully installed ${name}@${version}!`); | |
}; | |
const syncFileWithiCloud = async filePath => { | |
// Try to sync with iCloud in case the package exists only on iCloud | |
try { | |
console.log(`Attempting to sync with iCloud just in case...`); | |
await fm.downloadFileFromiCloud(filePath); | |
console.log(`Finished syncing ${filePath}`); | |
} catch (err) { | |
console.log(`${filePath} does not exist on iCloud.`); | |
} | |
}; | |
const tryWriteFile = (path, content, pkg) => { | |
// Sometimes wzrd.in is acting up and the file content is undefined. | |
// So, here is a little trick to let you know what's going on. | |
try { | |
console.log(`Saving ${pkg} to disk at ${path}...`); | |
fm.writeString(path, content); | |
} catch (err) { | |
throw `The package source from 'https://wzrd.in/standalone/${pkg}' is probably corrupted! Try with the different patch version.`; | |
} | |
}; | |
module.exports = async (pkg, isAutoUpdateOn = false) => { | |
let name = getPackageName(pkg); | |
await downloadIfNeeded(pkg, isAutoUpdateOn); | |
return importModule(`${name}`); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment