UNPKG

warp-drive

Version:

WarpDrive is the data framework for ambitious web applications

244 lines (234 loc) 7.38 kB
import chalk from 'chalk'; import fs from 'fs'; import path from 'path'; import { a as getInfo, e as exec } from './warp-drive-pO7pDWOi.js'; function adjustForWords(str, max_length) { // The string iterator that is used here iterates over characters, // not mere code units let count = 0; let len = 0; let lastWhitespaceLen = 0; let isColorChar = false; let isMaybeStartingWhitespace = true; // color chars follow the pattern // \u001b[<number>m for (const char of str) { const charIndex = len; len++; if (isMaybeStartingWhitespace) { if (char === ' ' || char === '\t') { // increment len but not count lastWhitespaceLen = charIndex; continue; } else { isMaybeStartingWhitespace = false; } } if (isColorChar && char === 'm') { isColorChar = false; } else if (char === '\u001b') { isColorChar = true; } else if (!isColorChar) { count++; if (count > max_length) { return lastWhitespaceLen; } if (char === ' ' || char === '\t') { lastWhitespaceLen = charIndex; } } } return len; } function indent(str, depth = 1) { const indentStr = getPadding(depth); return str.split('\n').map(line => { return indentStr + line; }).join('\n'); } function getPadding(depth, filler = '\t') { return new Array(depth).fill(filler).join(''); } function isKeyOf(key, obj) { return key in obj; } /** * colorizes a string based on color<<>> syntax * where color is one of the following: * - gr (grey) * - bg (brightGreen) * - bm (brightMagenta) * - cy (cyan) * - ye (yellow) * * e.g. * * color`This is gr<<grey>> and this is bg<<bright green>> and this is bm<<bright magenta>> and this is cy<<cyan>> and this is ye<<yellow>>` */ function color(str) { const colors = { gr: 'grey', gb: 'greenBright', mb: 'magentaBright', cy: 'cyan', ye: 'yellow' }; const colorized = str.replace(/(\w+)<<(.+?)>>/g, (match, possibleColor, text) => { const c = isKeyOf(possibleColor, colors) ? colors[possibleColor] : null; if (!c) { throw new Error(`Unknown color ${possibleColor}`); } return chalk[c](text); }); return colorized; } // TODO if the last line of a context is too long we don't always // end up rebalancing correctly. We need to splice an additional // line in in this case. If we do this on a rolling basis its // probably easier. function rebalanceLines(str, max_length = 75) { const lines = str.split('\n'); let inContext = false; let contextIndent = ''; let contextHasBullet = false; let contextIndex = 0; let contextBulletIndent = ''; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line === '') { inContext = false; continue; } if (line.trim() === '---') { lines[i] = chalk.grey(getPadding(max_length, '-')); inContext = false; continue; } if (line.trim() === '===') { lines[i] = chalk.grey(getPadding(max_length, '=')); inContext = false; continue; } const indentMatch = line.match(/^\s+/); // eslint-disable-next-line no-useless-escape const hasBullet = line.match(/^\s*[-\*]\s+/) || line.match(/^\s*\d+\)?\.\s+/); const bulletIndent = hasBullet ? hasBullet[0] : ''; let strIndent = ''; if (indentMatch) { strIndent = indentMatch[0]; } // if we have our own bullet, this is a new context // so nothing can be rebalanced if (hasBullet || !inContext) { contextIndex = i; inContext = true; contextIndent = strIndent; contextHasBullet = Boolean(hasBullet); contextBulletIndent = bulletIndent; continue; } const isBulletContinuation = contextHasBullet && strIndent.startsWith(contextIndent) && strIndent.length === contextBulletIndent.length; const isNonBulletContinuation = !contextHasBullet && strIndent === contextIndent; // determine if we match if (isBulletContinuation || isNonBulletContinuation) { // we are in the same context // rebalance if needed const fullText = lines[contextIndex] + ' ' + line.slice(strIndent.length); const len = adjustForWords(fullText, max_length); const prevLine = fullText.slice(0, len).trimEnd(); const thisLine = strIndent + fullText.slice(len).trim(); lines[contextIndex] = prevLine; lines[i] = thisLine || null; if (thisLine) { // only update if we have content on the line contextIndex = i; } } else { // we are a new context contextIndex = i; inContext = true; contextIndent = strIndent || ''; contextHasBullet = false; contextBulletIndent = ''; continue; } } return lines.filter(l => l !== null).join('\n'); } function write(out) { // eslint-disable-next-line no-console console.log(out); } function getPkgJson() { const file = fs.readFileSync(path.join(process.cwd(), 'package.json'), { encoding: 'utf-8' }); const json = JSON.parse(file); return json; } function writePkgJson(json) { fs.writeFileSync(path.join(process.cwd(), 'package.json'), JSON.stringify(json, null, 2) + '\n'); } const pkgJsonCache = {}; function getLocalPkgJson(name, version) { if (pkgJsonCache[`${name}@${version}`]) { return pkgJsonCache[`${name}@${version}`]; } const file = fs.readFileSync(path.join(process.cwd(), 'node_modules', name, 'package.json'), { encoding: 'utf-8' }); const json = JSON.parse(file); pkgJsonCache[`${name}@${json.version}`] = json; if (json.version === version) { return json; } return null; } async function getRemotePkgJson(name, version) { if (pkgJsonCache[`${name}@${version}`]) { return pkgJsonCache[`${name}@${version}`]; } const dir = path.join(process.cwd(), 'tmp'); fs.mkdirSync(dir, { recursive: true }); // get the tarball path const info = await getInfo(`${name}@${version}`); const remoteTarball = info.dist.tarball; const tarballName = `${name}-${version}`.replace('/', '_'); // download the package if needed if (!fs.existsSync(path.join(dir, tarballName, 'package.json'))) { await exec(`curl -L ${remoteTarball} -o ${tarballName}.tgz`, { cwd: dir }); await exec(`tar -xzf ${tarballName}.tgz && mv package ${tarballName}`, { cwd: dir }); } const file = fs.readFileSync(path.join(dir, tarballName, 'package.json'), { encoding: 'utf-8' }); const json = JSON.parse(file); pkgJsonCache[`${name}@${json.version}`] = json; return json; } async function getPkgJsonFor(name, version) { try { const pkg = getLocalPkgJson(name, version); if (pkg) { return pkg; } } catch { // ignore } return getRemotePkgJson(name, version); } async function getTypePathFor(name, version) { const pkg = await getPkgJsonFor(name, version); const isAlpha = pkg.files?.includes('unstable-preview-types'); const isBeta = pkg.files?.includes('preview-types'); const base = pkg.exports?.['.']; const isStable = !isAlpha && !isBeta && typeof base === 'object' && base?.['types'] !== undefined; return isAlpha ? 'unstable-preview-types' : isBeta ? 'preview-types' : isStable ? 'types' : null; } export { writePkgJson as a, getTypePathFor as b, color as c, getPkgJson as g, indent as i, rebalanceLines as r, write as w };