Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tools/sass-variable-explainer/_attic/process-scss.ts
12925 views
1
import { getSassAst } from "./sass-analyze.ts";
2
import { walk } from "./sass-analyzer/ast-utils.ts";
3
4
let contents = Deno.readTextFileSync(Deno.args[0] || "/dev/stdin");
5
const ast = getSassAst(contents);
6
7
type Matcher = number | ((v: unknown) => unknown);
8
9
const isType = (type: string): Matcher => {
10
return (v: unknown) => {
11
if (!v || typeof v !== "object") return false;
12
if ((v as Record<string, unknown>).type === type) { return v; } else { return false };
13
};
14
}
15
16
const getSingleValueOfType = (type: string): Matcher => {
17
return (v: unknown) => {
18
if (!v || typeof v !== "object") return false;
19
const value = (v as Record<string, unknown>).value;
20
if (!Array.isArray(value)) return false;
21
const valuesOfType = value.filter((v) => (v as Record<string, unknown>).type === type);
22
if (valuesOfType.length !== 1) return false;
23
return valuesOfType[0];
24
};
25
}
26
27
const isDefault = (v: unknown): Matcher => {
28
return (v: unknown) => {
29
if (!v || typeof v !== "object") return false;
30
if ((v as Record<string, unknown>).type !== "value") return false;
31
const value = (v as Record<string, unknown>).value as any[];
32
if (value[value.length - 1].type !== "identifier" || value[value.length - 1].value !== "default") return false;
33
if (value[value.length - 2].type !== "operator" || value[value.length - 2].value !== "!") return false;
34
return v;
35
}
36
}
37
38
const match = (param: unknown, matcher: Matcher[]): unknown => {
39
if (!param || typeof param !== "object") return undefined;
40
if (matcher.length === 0) return param;
41
const obj = param as Record<string, unknown>;
42
const [key, ...rest] = matcher;
43
if (typeof key === "function") {
44
const result = key(obj);
45
if (!result) return undefined;
46
return match(result, rest);
47
} else if (typeof key === "number") {
48
if (!(Array.isArray(obj.value))) {
49
return undefined;
50
}
51
return match(obj.value[key], rest);
52
}
53
}
54
55
type Dependency = {
56
name: string;
57
references: string[];
58
};
59
60
const getDependencies = (ast: any): Dependency[] => {
61
const dependencies: any[] = [];
62
63
for (const entry of ast.value) {
64
const variableNameMatcher = [
65
isType("declaration"),
66
0,
67
isType("property"),
68
0,
69
isType("variable"),
70
];
71
const variableNameNode = match(entry, variableNameMatcher);
72
if (!variableNameNode) {
73
continue;
74
}
75
const variableValueMatcher = [
76
isType("declaration"),
77
getSingleValueOfType("value"),
78
];
79
const variableValueNode = match(entry, variableValueMatcher);
80
if (!variableValueNode) {
81
continue;
82
}
83
84
// console.log((variableNameNode as any).type);
85
// console.log(variableValueNode); // (variableValueNode as any).type);
86
const variableName = (variableNameNode as { value: string }).value;
87
88
const references: string[] = [];
89
90
const walker = (node: any) => {
91
const ifStmt = [
92
isType("function"),
93
0,
94
isType("identifier"),
95
(v: any) => v.value === "if" && v,
96
];
97
if (match(node, ifStmt)) {
98
// this thing really is not a parser, it's a glorified tokenizer
99
100
const tokenStream = node.value[1].value.filter(
101
(x: any) => x.type !== "space" &&
102
x.type !== "comment_singleline" &&
103
x.type !== "comment_multiline");
104
// split on comma: { type: "punctuation", value: "," }
105
let currentArg: any[] = [];
106
let firstArg = true;
107
for (const token of tokenStream) {
108
if (token.type === "punctuation" && token.value === ",") {
109
if (firstArg) {
110
firstArg = false;
111
} else {
112
walk(currentArg, walker);
113
}
114
currentArg = [];
115
} else {
116
currentArg.push(token);
117
}
118
}
119
if (!firstArg) {
120
walk(currentArg, walker);
121
}
122
return false;
123
}
124
if (node.type === "variable") {
125
references.push(node.value);
126
}
127
return true;
128
};
129
130
walk(variableValueNode, walker);
131
132
if (references.length) {
133
dependencies.push({ name: variableName, references });
134
}
135
}
136
return dependencies;
137
}
138
139
const dependencies = getDependencies(ast);
140
141
const getTypeAnalysis = (ast: any) => {
142
// now we try to figure out variable types as best we can
143
const variableTypes: Record<string, string[]> = {};
144
for (const entry of ast.value) {
145
}
146
}
147
148
149
console.log(JSON.stringify({
150
dependencies
151
}, null, 2));
152