function getFeatures()

in build/releaseMetadata.js [219:286]


function getFeatures() {
	const skipImports = [
		'vs/editor/browser/widget/codeEditorWidget',
		'vs/editor/browser/widget/diffEditorWidget',
		'vs/editor/browser/widget/diffNavigator',
		'vs/editor/common/standaloneStrings',
		'vs/editor/contrib/tokenization/tokenization',
		'vs/editor/editor.all',
		'vs/base/browser/ui/codicons/codiconStyles',
		'vs/editor/contrib/gotoSymbol/documentSymbols'
	];

	/** @type {string[]} */
	let features = [];
	const files =
		fs.readFileSync(path.join(REPO_ROOT, 'release/esm/vs/editor/edcore.main.js')).toString() +
		fs.readFileSync(path.join(REPO_ROOT, 'release/esm/vs/editor/editor.all.js')).toString();
	files.split(/\r\n|\n/).forEach((line) => {
		const m = line.match(/import '([^']+)'/);
		if (m) {
			const tmp = path.posix.join('vs/editor', m[1]).replace(/\.js$/, '');
			if (skipImports.indexOf(tmp) === -1) {
				features.push(tmp);
			}
		}
	});

	/** @type {{label:string;entry:any;}[]} */
	let result = features.map((feature) => {
		/** @type {string} */ let label;
		if (customFeatureLabels[feature]) {
			label = customFeatureLabels[feature];
		} else {
			const m1 = feature.match(/^vs\/editor\/contrib\/([^\/]+)/);
			if (m1) {
				// for editor/contrib features, use the first segment
				label = m1[1];
			} else {
				// for everything else, use the last segment folder
				label = path.basename(path.dirname(feature));
			}
		}
		return {
			label: label,
			entry: feature
		};
	});

	result.sort((a, b) => {
		const labelCmp = strcmp(a.label, b.label);
		if (labelCmp === 0) {
			return strcmp(a.entry, b.entry);
		}
		return labelCmp;
	});

	for (let i = 0; i < result.length; i++) {
		if (i + 1 < result.length && result[i].label === result[i + 1].label) {
			if (typeof result[i].entry === 'string') {
				result[i].entry = [result[i].entry];
			}
			result[i].entry.push(result[i + 1].entry);
			result.splice(i + 1, 1);
		}
	}

	return result;
}