All files / lib download.js

82.41% Statements 75/91
76.92% Branches 10/13
66.66% Functions 2/3
82.41% Lines 75/91

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 1031x   1x 1x 1x 1x 1x 1x 1x                                   1x 1x 1x 1x 1x 1x 1x 1x 1x 2x   2x 1x 1x 1x   2x 2x 2x 2x 2x 9x 9x 9x   2x 2x 2x 2x   2x   2x 1x 1x 1x   1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x  
import YAML from 'yaml';
 
/**
 *
 * @param {BlobPart | string} content
 * @param {string} filename
 * @param {string} [contentType] defaults to 'text/plain' for strings and 'application/octet-stream' for blobs
 */
export function downloadAsFile(content, filename, contentType) {
	const blob =
		content instanceof Blob
			? content
			: new Blob([content], {
					type:
						contentType ??
						(typeof content === 'string' ? 'text/plain' : 'application/octet-stream')
				});
 
	const url = URL.createObjectURL(blob);
	const a = document.createElement('a');
	a.href = url;
	a.download = filename;
	a.click();
	URL.revokeObjectURL(url);
}
 
/**
 *
 * @template {string} Keys
 * @param { { [K in Keys]?: unknown } } object the object to serialize
 * @param {readonly Keys[]} ordering an array of keys in target order, for the top-level object
 * @param {'json' | 'yaml'} format
 * @param {string} schema the json schema URL
 */
export function stringifyWithToplevelOrdering(format, schema, object, ordering) {
	let keysOrder = [...ordering];
 
	if (format === 'json') {
		// @ts-expect-error
		keysOrder = ['$schema', ...keysOrder];
	}
 
	/**
	 * @param {*} _
	 * @param {*} value
	 */
	const reviver = (_, value) => {
		if (value === null) return value;
		if (Array.isArray(value)) return value;
		if (typeof value !== 'object') return value;
 
		// @ts-expect-error
		if (Object.keys(value).every((key) => keysOrder.includes(key))) {
			return Object.fromEntries(keysOrder.map((key) => [key, value[key]]));
		}
		return value;
	};
 
	if (format === 'yaml') {
		const yamled = YAML.stringify(object, reviver, 2);
		return `# yaml-language-server: $schema=${schema}\n\n${yamled}`;
	}
 
	return JSON.stringify({ $schema: schema, ...object }, reviver, 2);
}
 
if (import.meta.vitest) {
	const { test, expect } = import.meta.vitest;
	test('stringifyWithToplevelOrdering', () => {
		expect(
			stringifyWithToplevelOrdering(
				'json',
				'http://example.com/schema.json',
				{ a: 1, b: 2, c: 3 },
				['a', 'c', 'a', 'b']
			)
		).toMatchInlineSnapshot(`
			"{
			  "$schema": "http://example.com/schema.json",
			  "a": 1,
			  "c": 3,
			  "b": 2
			}"
		`);
 
		expect(
			stringifyWithToplevelOrdering(
				'yaml',
				'http://example.com/schema.json',
				{ a: 1, b: 2, c: 3 },
				['a', 'c', 'a', 'b']
			)
		).toMatchInlineSnapshot(`
			"# yaml-language-server: $schema=http://example.com/schema.json
 
			a: 1
			c: 3
			b: 2
			"
		`);
	});
}