/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
const require_index = require('../../css-tokens/dist/index.cjs');
const require_print = require('../../cli/dist/lib/print.cjs');
const require_spinner = require('../../cli/dist/lib/spinner.cjs');
const require_entryPoints = require('../../utils/entryPoints.cjs');
const require_tsMorph = require('../../utils/tsMorph.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
node_path = require_runtime.__toESM(node_path);
let fast_glob = require("fast-glob");
fast_glob = require_runtime.__toESM(fast_glob);
let ts_morph = require("ts-morph");

//#region src/purger/legacy/purgeCSS.ts
const scaleModeToClass = {
	large: require_index.LARGE_SCALE_MODE_CLASSNAME,
	medium: require_index.MEDIUM_SCALE_MODE_CLASSNAME,
	small: require_index.SMALL_SCALE_MODE_CLASSNAME,
	xLarge: require_index.XLARGE_SCALE_MODE_CLASSNAME,
	xSmall: require_index.XSMALL_SCALE_MODE_CLASSNAME,
	xxLarge: require_index.XXLARGE_SCALE_MODE_CLASSNAME,
	xxxLarge: require_index.XXXLARGE_SCALE_MODE_CLASSNAME
};
const colorModeToClass = {
	dark: require_index.DARK_COLOR_MODE_CLASSNAME,
	light: require_index.LIGHT_COLOR_MODE_CLASSNAME
};
const getFiles = async (entry) => {
	try {
		const workspaceDir = process.env.PWD || process.cwd();
		if (!workspaceDir) throw new Error("Workspace directory not found.");
		const files = await Promise.all(require_entryPoints.resolveEntryPaths(entry, workspaceDir, require_entryPoints.DEFAULT_ENTRY).map((entryPath) => {
			if (entryPath.kind === "file") return [entryPath.absolutePath];
			return (0, fast_glob.default)(["**/*.jsx", "**/*.tsx"], {
				cwd: entryPath.absolutePath,
				absolute: true,
				ignore: ["**/node_modules/**"]
			});
		}));
		return [...new Set(files.flat())];
	} catch (error) {
		throw error instanceof Error ? error : /* @__PURE__ */ new Error(`Couldn't find the entry directory: ${entry}. Please make sure it exists.`);
	}
};
/**
* Find all JSX references for a named import.
*
* @example
* const references = findNamedImportReferences(project, '@yahoo/uds', 'HStack')
*/
function findNamedImportReferences(project, moduleSpecifierValue, namedImportName) {
	const references = [];
	for (const sourceFile of project.getSourceFiles()) for (const importDeclaration of sourceFile.getImportDeclarations()) if (importDeclaration.getModuleSpecifierValue() === moduleSpecifierValue) {
		for (const namedImport of importDeclaration.getNamedImports()) if (namedImport.getName() === namedImportName) {
			const identifier = namedImport.getFirstDescendantByKindOrThrow(ts_morph.ts.SyntaxKind.Identifier);
			references.push(...require_tsMorph.findReferencesAsJsxElements(identifier));
		}
	}
	return references;
}
/**
* Given a file it returns the list of imports from @yahoo/uds
*/
const parseFiles = (project, files) => {
	const importsSet = /* @__PURE__ */ new Set();
	files.map((file) => {
		return project.getSourceFile(file)?.getImportDeclarations().filter((declaration) => {
			return declaration.getModuleSpecifier().getText().includes("@yahoo/uds") || declaration.getModuleSpecifier().getText().includes("@yahoo/uds/experimental");
		}).map((declaration) => {
			return declaration.getNamedImports().map((namedImport) => namedImport.getName());
		}).flat() ?? [];
	}).flat().forEach((item) => {
		if (!importsSet.has(item)) importsSet.add(item);
	});
	return Array.from(importsSet);
};
const getTailwindSafelist = (project, componentList, variants, generatedPurgeCssData, packageJson) => {
	const { variantsList, componentToVariants, componentToTwClasses } = generatedPurgeCssData;
	const safeList = [];
	const validVariants = new Set(variantsList);
	const usedProps = /* @__PURE__ */ new Map();
	componentList.forEach((component) => {
		if (isUDSComponent(component, generatedPurgeCssData)) {
			componentToVariants[component].forEach(([propName, usedValues]) => {
				if (validVariants.has(propName)) {
					const options = usedProps.get(propName) ?? /* @__PURE__ */ new Set();
					usedValues.forEach((val) => options.add(val));
					usedProps.set(propName, options);
				}
			});
			getUsedProps(project, component, variants, packageJson).forEach(([propName, usedValues]) => {
				if (validVariants.has(propName)) {
					if (usedValues.length === 0) usedValues = Object.keys(variants[propName] ?? {});
					const options = usedProps.get(propName) ?? /* @__PURE__ */ new Set();
					usedValues.forEach((val) => options.add(val));
					usedProps.set(propName, options);
				}
			});
			safeList.push(...componentToTwClasses[component].replaceAll("\\", "").split(" "));
		}
	});
	for (const [propName, usedValues] of usedProps) {
		const variantGroup = variants[propName];
		if (variantGroup) usedValues.forEach((option) => {
			const variantClass = variantGroup[option];
			if (variantClass) safeList.push(variantClass.replaceAll("\\", ""));
		});
	}
	for (const [variant, variantOptions] of scanGetStylesReferences(project, variants, packageJson)) {
		const variantGroup = variants[variant];
		if (variantGroup) variantOptions.forEach((option) => {
			const variantClass = variantGroup[option];
			if (variantClass) safeList.push(variantClass.replaceAll("\\", ""));
		});
	}
	return Array.from(new Set(safeList)).filter(Boolean);
};
/**
* Get the used props for a given component.
*
* @example
* const usedProps = getUsedProps(project, 'HStack');
*/
const getUsedProps = (project, component, variants, packageJson) => {
	const references = [];
	references.push(...findNamedImportReferences(project, packageJson.name, component));
	references.push(...findNamedImportReferences(project, `${packageJson.name}/experimental`, component));
	return references.map((reference) => require_tsMorph.getUsedPropsInReference(reference, variants)).flat();
};
const isUDSComponent = (component, { componentToVariants }) => {
	return !!componentToVariants[component];
};
const saveToFile = (safeList, outputPath) => {
	const fileContent = `
    //! This file is generated by \`uds purge\` from @yahoo/uds
    //! Do not edit directly
    //! If there is issue with this file please report to #ask-uds
    export const safelist = ${JSON.stringify(safeList)};
    `;
	(0, node_fs.mkdirSync)(node_path.default.dirname(outputPath), { recursive: true });
	(0, node_fs.writeFileSync)(outputPath, fileContent);
};
const getComponentsToConvertToTW = (udsImport, generatedPurgeCssData) => {
	const { componentToVariants, componentsDependencies } = generatedPurgeCssData;
	const components = udsImport.filter((importedItem) => !!componentToVariants[importedItem]);
	const set = /* @__PURE__ */ new Set();
	components.forEach((component) => {
		if (!set.has(component)) set.add(component);
		if (componentsDependencies[component]) componentsDependencies[component].forEach((dependent) => {
			if (!set.has(dependent)) set.add(dependent);
		});
	});
	return Array.from(set);
};
/**
* Get the classes that corresponds to the used modes
*/
const getClassesForEnabledThemesAndScales = () => {
	const classes = [];
	if (process.env.ENABLED_SCALE_AND_COLOR_MODES) process.env.ENABLED_SCALE_AND_COLOR_MODES.split(",").map((mode) => {
		mode = mode.trim();
		if (colorModeToClass[mode]) classes.push(colorModeToClass[mode]);
		else if (scaleModeToClass[mode]) classes.push(scaleModeToClass[mode]);
	});
	else {
		classes.push(colorModeToClass.dark);
		classes.push(colorModeToClass.light);
		classes.push(scaleModeToClass.large);
	}
	return classes;
};
/**
* Scan the source code for all `getStyles` references
*
* Note: This currently only works if we are passing a literal object to getStyles.
*
* Explanation: They we are able to enfer what css to include is by looking at the properties of the object passed.
* If something other than an object is passed, we can fallback on the Type, but that would require handling
* a lot of edge cases (function return type, spread operator, ternary, ...) and each one of these cases will
* most likely have a sub case. Falling back to the Type will complicate the code a lot is error prone as there
* is only so much info we can get out of the types as the Users are free to use `any` on their project which will
* provide no value for us. Hence why having a literal object passed is the best and probably the only sane way
* to go about this.
*/
const scanGetStylesReferences = (project, variants, packageJson) => {
	const references = [];
	for (const sourceFile of project.getSourceFiles()) for (const importDeclaration of sourceFile.getImportDeclarations()) if (importDeclaration.getModuleSpecifierValue() === packageJson.name) {
		for (const namedImport of importDeclaration.getNamedImports()) if (namedImport.getName() === "getStyles") {
			const identifier = namedImport.getFirstDescendantByKindOrThrow(ts_morph.ts.SyntaxKind.Identifier);
			for (const reference of identifier.findReferencesAsNodes()) {
				const node = reference.getFirstAncestor((node) => {
					return ts_morph.Node.isCallExpression(node);
				});
				if (node) references.push(node);
			}
		}
	}
	const usedProps = /* @__PURE__ */ new Map();
	for (const reference of references) {
		const objectLiteralExpression = reference.getFirstChildByKindOrThrow(ts_morph.SyntaxKind.ObjectLiteralExpression);
		const propertyAssignments = objectLiteralExpression.getDescendantsOfKind(ts_morph.SyntaxKind.PropertyAssignment);
		const shorthandPropertyAssignments = objectLiteralExpression.getDescendantsOfKind(ts_morph.SyntaxKind.ShorthandPropertyAssignment);
		propertyAssignments.forEach((propertyAssigment) => {
			const identifier = propertyAssigment.getFirstChildByKind(ts_morph.SyntaxKind.Identifier)?.getText();
			const stringLiteral = propertyAssigment.getFirstChildByKind(ts_morph.SyntaxKind.StringLiteral)?.getLiteralText();
			if (identifier && !stringLiteral) {
				const fallback = !!variants[identifier] ? Object.keys(variants[identifier]) : [];
				usedProps.set(identifier, new Set(fallback));
			}
			if (identifier && stringLiteral) {
				let options;
				if (usedProps.has(identifier)) options = usedProps.get(identifier);
				else options = /* @__PURE__ */ new Set();
				options.add(stringLiteral);
				usedProps.set(identifier, options);
			}
		});
		shorthandPropertyAssignments.forEach((propertyAssigment) => {
			const identifier = propertyAssigment.getFirstChildByKind(ts_morph.SyntaxKind.Identifier)?.getText();
			if (identifier) usedProps.set(identifier, /* @__PURE__ */ new Set());
		});
	}
	return usedProps;
};
const applyPurgeDefaults = (options = {}) => ({
	config: options.config ?? process.env.UDS_OUT_FILE ?? "./uds.config.ts",
	output: options.output ?? "dist/safelist.ts",
	entry: options.entry ?? require_entryPoints.DEFAULT_ENTRY
});
async function purge(variants, packageJson, generatedPurgeCssData, options = {}) {
	const { config: configPath, output, entry } = applyPurgeDefaults(options);
	const workspaceDir = process.env.PWD || process.cwd();
	if (!workspaceDir) throw new Error("Workspace directory not found.");
	const project = new ts_morph.Project({ tsConfigFilePath: node_path.default.join(workspaceDir, "/tsconfig.json") });
	const outputFilePath = node_path.default.join(workspaceDir, output);
	const configAbsolutePath = node_path.default.join(workspaceDir, configPath);
	try {
		await import(configAbsolutePath);
	} catch {
		throw new Error("Couldn't load the UDS config. Make sure you have uds.config.ts in the root of your project.");
	}
	require_spinner.spinStart("Getting used UDS components...");
	require_print.print("Loading the project...");
	const files = await getFiles(entry);
	require_print.print("Going through the imports...");
	const udsImports = parseFiles(project, files);
	require_print.print("Finding all the components imported from UDS...");
	const udsComponents = getComponentsToConvertToTW(udsImports, generatedPurgeCssData);
	require_print.print("🧑‍🍳 Cooking...");
	const safeList = getTailwindSafelist(project, udsComponents, variants, generatedPurgeCssData, packageJson);
	const themesAndScalesClasses = getClassesForEnabledThemesAndScales();
	saveToFile(safeList.concat(themesAndScalesClasses), outputFilePath);
	require_spinner.spinStop("Generated your safelist!");
}

//#endregion
exports.getComponentsToConvertToTW = getComponentsToConvertToTW;
exports.getTailwindSafelist = getTailwindSafelist;
exports.parseFiles = parseFiles;
exports.purge = purge;