Path: blob/main/tools/sass-variable-explainer/_attic/process-scss.ts
12921 views
import { getSassAst } from "./sass-analyze.ts";1import { walk } from "./sass-analyzer/ast-utils.ts";23let contents = Deno.readTextFileSync(Deno.args[0] || "/dev/stdin");4const ast = getSassAst(contents);56type Matcher = number | ((v: unknown) => unknown);78const isType = (type: string): Matcher => {9return (v: unknown) => {10if (!v || typeof v !== "object") return false;11if ((v as Record<string, unknown>).type === type) { return v; } else { return false };12};13}1415const getSingleValueOfType = (type: string): Matcher => {16return (v: unknown) => {17if (!v || typeof v !== "object") return false;18const value = (v as Record<string, unknown>).value;19if (!Array.isArray(value)) return false;20const valuesOfType = value.filter((v) => (v as Record<string, unknown>).type === type);21if (valuesOfType.length !== 1) return false;22return valuesOfType[0];23};24}2526const isDefault = (v: unknown): Matcher => {27return (v: unknown) => {28if (!v || typeof v !== "object") return false;29if ((v as Record<string, unknown>).type !== "value") return false;30const value = (v as Record<string, unknown>).value as any[];31if (value[value.length - 1].type !== "identifier" || value[value.length - 1].value !== "default") return false;32if (value[value.length - 2].type !== "operator" || value[value.length - 2].value !== "!") return false;33return v;34}35}3637const match = (param: unknown, matcher: Matcher[]): unknown => {38if (!param || typeof param !== "object") return undefined;39if (matcher.length === 0) return param;40const obj = param as Record<string, unknown>;41const [key, ...rest] = matcher;42if (typeof key === "function") {43const result = key(obj);44if (!result) return undefined;45return match(result, rest);46} else if (typeof key === "number") {47if (!(Array.isArray(obj.value))) {48return undefined;49}50return match(obj.value[key], rest);51}52}5354type Dependency = {55name: string;56references: string[];57};5859const getDependencies = (ast: any): Dependency[] => {60const dependencies: any[] = [];6162for (const entry of ast.value) {63const variableNameMatcher = [64isType("declaration"),650,66isType("property"),670,68isType("variable"),69];70const variableNameNode = match(entry, variableNameMatcher);71if (!variableNameNode) {72continue;73}74const variableValueMatcher = [75isType("declaration"),76getSingleValueOfType("value"),77];78const variableValueNode = match(entry, variableValueMatcher);79if (!variableValueNode) {80continue;81}8283// console.log((variableNameNode as any).type);84// console.log(variableValueNode); // (variableValueNode as any).type);85const variableName = (variableNameNode as { value: string }).value;8687const references: string[] = [];8889const walker = (node: any) => {90const ifStmt = [91isType("function"),920,93isType("identifier"),94(v: any) => v.value === "if" && v,95];96if (match(node, ifStmt)) {97// this thing really is not a parser, it's a glorified tokenizer9899const tokenStream = node.value[1].value.filter(100(x: any) => x.type !== "space" &&101x.type !== "comment_singleline" &&102x.type !== "comment_multiline");103// split on comma: { type: "punctuation", value: "," }104let currentArg: any[] = [];105let firstArg = true;106for (const token of tokenStream) {107if (token.type === "punctuation" && token.value === ",") {108if (firstArg) {109firstArg = false;110} else {111walk(currentArg, walker);112}113currentArg = [];114} else {115currentArg.push(token);116}117}118if (!firstArg) {119walk(currentArg, walker);120}121return false;122}123if (node.type === "variable") {124references.push(node.value);125}126return true;127};128129walk(variableValueNode, walker);130131if (references.length) {132dependencies.push({ name: variableName, references });133}134}135return dependencies;136}137138const dependencies = getDependencies(ast);139140const getTypeAnalysis = (ast: any) => {141// now we try to figure out variable types as best we can142const variableTypes: Record<string, string[]> = {};143for (const entry of ast.value) {144}145}146147148console.log(JSON.stringify({149dependencies150}, null, 2));151152