Skip to content

Commit 83c22bf

Browse files
committedJun 21, 2020
feat: helper logic
1 parent 841afeb commit 83c22bf

19 files changed

+630
-295
lines changed
 

Diff for: ‎.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
/docs
88
/__tests__/fixtures
99
.eslintrc.js
10+
/helper/ui

Diff for: ‎.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
/*.log
88
/.eslintcache
99
/docs
10-
/scripts/ui
10+
/helper/ui

Diff for: ‎.prettierignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
/docs
88
/__tests__/fixtures/dist
99
/pnpm-lock.yaml
10-
/CHANGELOG.md
10+
/CHANGELOG.md
11+
/helper/ui

Diff for: ‎CONTRIBUTING.md

-25
This file was deleted.

Diff for: ‎README.md

+10
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,13 @@
33
Very WIP
44

55
Use before `rollup-plugin-vue`
6+
7+
## Helper
8+
9+
Located inside `helper` folder
10+
11+
Compile using `tsc` from inside `helper` folder and run, or using `ts-node`:
12+
13+
```sh
14+
ts-node --files --project helper/tsconfig.json helper/index.ts
15+
```

Diff for: ‎__tests__/helpers/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import path from "path";
33
import fs from "fs-extra";
44
import { rollup, InputOptions, OutputOptions } from "rollup";
55
import dotenv from "dotenv";
6-
import { Options } from "../..";
76

87
import vue3ui from "../../src";
8+
import { Options } from "../../src/types";
9+
910
import replace from "@rollup/plugin-replace";
1011
import commonjs from "@rollup/plugin-commonjs";
1112
import json from "@rollup/plugin-json";

Diff for: ‎helper/.eslintrc.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const path = require("path");
2+
module.exports = {
3+
root: true,
4+
extends: [path.resolve(__dirname, "..", "src", ".eslintrc.js")],
5+
};

Diff for: ‎helper/data.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// TODO: Figure out the allowed values for classes
2+
export const context = {
3+
position: "TODO-position",
4+
size: "TODO-size",
5+
type: "TODO-type",
6+
newType: "TODO-newType",
7+
closeType: "TODO-closeType",
8+
passiveType: "TODO-passiveType",
9+
navClasses: "TODO-navClasses",
10+
spanClasses: "TODO-spanClasses",
11+
};
12+
13+
export const truthy = {
14+
tabs: { activeTab: true },
15+
t: { disabled: true },
16+
closeIcon: true,
17+
ellipsis: true,
18+
disabled: true,
19+
rounded: true,
20+
loading: true,
21+
outlined: true,
22+
expanded: true,
23+
inverted: true,
24+
focused: true,
25+
active: true,
26+
hovered: true,
27+
selected: true,
28+
square: true,
29+
newAnimated: true,
30+
always: true,
31+
multilined: true,
32+
dashed: true,
33+
};
34+
35+
export const falsy = {
36+
// eslint-disable-next-line unicorn/no-reduce
37+
...Object.keys(truthy).reduce((acc, k) => ({ ...acc, [k]: false }), {}),
38+
tabs: { activeTab: false },
39+
t: { disabled: false },
40+
};

Diff for: ‎helper/index.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import path from "path";
2+
import fs from "fs-extra";
3+
import fg from "fast-glob";
4+
import download from "download-git-repo";
5+
6+
import { rollup, OutputAsset } from "rollup";
7+
import commonjs from "@rollup/plugin-commonjs";
8+
import json from "@rollup/plugin-json";
9+
import resolve from "@rollup/plugin-node-resolve";
10+
import vue from "rollup-plugin-vue";
11+
import styles from "rollup-plugin-styles";
12+
13+
// TODO: Directly parse Vue SFC files, without Rollup
14+
import gatherer from "./plugin";
15+
16+
const repoDir = path.join(__dirname, "ui");
17+
const srcDir = path.join(repoDir, "src");
18+
19+
const downloadAsync = async (url: string, dir: string) =>
20+
new Promise(resolve => void download(url, dir, {}, resolve));
21+
22+
async function gatherMappings(): Promise<void> {
23+
const mappings: Record<string, string[]> = {};
24+
25+
fs.removeSync(repoDir);
26+
await downloadAsync("pathscale/vue3-ui", repoDir);
27+
28+
// Avoid conflicting configs
29+
for (const file of fs.readdirSync(repoDir))
30+
if (file !== "src") fs.removeSync(path.join(repoDir, file));
31+
32+
const pattern = path.join(srcDir, "**", "*.vue").replace(/\\/g, "/");
33+
const vueFiles = await fg(pattern);
34+
35+
for await (const file of vueFiles) {
36+
const bundle = await rollup({
37+
input: file,
38+
plugins: [json(), resolve({ preferBuiltins: true }), commonjs(), gatherer(), vue(), styles()],
39+
});
40+
41+
const { output } = await bundle.generate({});
42+
const whitelistAsset = output.find(o => o.fileName === "gathered") as OutputAsset | undefined;
43+
if (!whitelistAsset) continue;
44+
45+
const whitelist = new Set(JSON.parse(whitelistAsset.source as string) as string[]);
46+
if (whitelist.size === 0) continue;
47+
48+
mappings[path.parse(file).name] = [...whitelist];
49+
}
50+
51+
fs.writeFileSync(path.join(__dirname, "mappings.json"), JSON.stringify(mappings, null, " "));
52+
}
53+
54+
void gatherMappings();

Diff for: ‎helper/mappings.json

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
{
2+
"App": [
3+
"hero",
4+
"is-fullheight",
5+
"hero-body",
6+
"navbar-item",
7+
"button",
8+
"is-primary",
9+
"is-light",
10+
"container",
11+
"columns",
12+
"is-centered",
13+
"column",
14+
"navbar",
15+
"navbar-brand",
16+
"navbar-menu",
17+
"navbar-start",
18+
"navbar-end",
19+
"buttons",
20+
"is-5-tablet",
21+
"is-4-desktop",
22+
"is-3-widescreen",
23+
"TODO-size",
24+
"TODO-type",
25+
"is-rounded",
26+
"is-loading",
27+
"is-outlined",
28+
"is-fullwidth",
29+
"is-inverted",
30+
"is-focused",
31+
"is-active",
32+
"is-hovered",
33+
"is-selected",
34+
"box",
35+
"b-checkbox",
36+
"checkbox",
37+
"is-disabled",
38+
"check",
39+
"control-label",
40+
"control",
41+
"is-expanded",
42+
"select",
43+
"TODO-spanClasses",
44+
"input",
45+
"progress-wrapper",
46+
"progress",
47+
"TODO-newType",
48+
"progress-value",
49+
"tabs",
50+
"TODO-navClasses",
51+
"switch",
52+
"TODO-passiveType-passive",
53+
"field",
54+
"label",
55+
"TODO-position",
56+
"b-tooltip",
57+
"is-square",
58+
"is-animated",
59+
"is-always",
60+
"is-multiline",
61+
"is-dashed",
62+
"tags",
63+
"has-addons",
64+
"tag",
65+
"has-ellipsis",
66+
"TODO-closeType",
67+
"has-delete-icon",
68+
"is-delete",
69+
"delete",
70+
"is-small",
71+
"modal",
72+
"modal-content",
73+
"modal-header",
74+
"close",
75+
"modal-title",
76+
"modal-body",
77+
"modal-footer"
78+
],
79+
"Modal": [
80+
"modal",
81+
"modal-content",
82+
"modal-header",
83+
"close",
84+
"modal-title",
85+
"modal-body",
86+
"modal-footer"
87+
],
88+
"Tab": ["tabs", "TODO-navClasses", "is-active", "is-disabled"],
89+
"Tabs": ["tabs", "TODO-navClasses", "is-active", "is-disabled"],
90+
"Tag": [
91+
"tags",
92+
"has-addons",
93+
"tag",
94+
"TODO-type",
95+
"TODO-size",
96+
"is-rounded",
97+
"has-ellipsis",
98+
"TODO-closeType",
99+
"has-delete-icon",
100+
"is-delete",
101+
"delete",
102+
"is-small"
103+
],
104+
"Tooltip": [
105+
"TODO-newType",
106+
"TODO-position",
107+
"TODO-size",
108+
"b-tooltip",
109+
"is-square",
110+
"is-animated",
111+
"is-always",
112+
"is-multiline",
113+
"is-dashed"
114+
],
115+
"Columns": ["container", "columns", "is-centered", "column"],
116+
"Login": [
117+
"container",
118+
"columns",
119+
"is-centered",
120+
"column",
121+
"is-5-tablet",
122+
"is-4-desktop",
123+
"is-3-widescreen",
124+
"box",
125+
"control",
126+
"input",
127+
"button",
128+
"TODO-size",
129+
"TODO-type",
130+
"is-rounded",
131+
"is-loading",
132+
"is-outlined",
133+
"is-fullwidth",
134+
"is-inverted",
135+
"is-focused",
136+
"is-active",
137+
"is-hovered",
138+
"is-selected",
139+
"field",
140+
"label",
141+
"switch",
142+
"is-disabled",
143+
"check",
144+
"TODO-passiveType-passive",
145+
"control-label"
146+
],
147+
"Nav": [
148+
"navbar",
149+
"navbar-brand",
150+
"navbar-item",
151+
"navbar-menu",
152+
"navbar-start",
153+
"navbar-end",
154+
"buttons"
155+
],
156+
"LoginForm": [
157+
"box",
158+
"control",
159+
"input",
160+
"button",
161+
"TODO-size",
162+
"TODO-type",
163+
"is-rounded",
164+
"is-loading",
165+
"is-outlined",
166+
"is-fullwidth",
167+
"is-inverted",
168+
"is-focused",
169+
"is-active",
170+
"is-hovered",
171+
"is-selected",
172+
"field",
173+
"label",
174+
"switch",
175+
"is-disabled",
176+
"check",
177+
"TODO-passiveType-passive",
178+
"control-label"
179+
],
180+
"Button": [
181+
"button",
182+
"TODO-size",
183+
"TODO-type",
184+
"is-rounded",
185+
"is-loading",
186+
"is-outlined",
187+
"is-fullwidth",
188+
"is-inverted",
189+
"is-focused",
190+
"is-active",
191+
"is-hovered",
192+
"is-selected"
193+
],
194+
"Checkbox": [
195+
"b-checkbox",
196+
"checkbox",
197+
"TODO-size",
198+
"is-disabled",
199+
"check",
200+
"TODO-type",
201+
"control-label"
202+
],
203+
"Container": ["container", "TODO-type"],
204+
"Field": ["field", "label"],
205+
"Input": ["control", "input"],
206+
"Progress": ["progress-wrapper", "progress", "TODO-newType", "progress-value"],
207+
"Select": ["control", "is-expanded", "select", "TODO-spanClasses"],
208+
"Switch": [
209+
"switch",
210+
"TODO-size",
211+
"is-disabled",
212+
"is-rounded",
213+
"is-outlined",
214+
"check",
215+
"TODO-passiveType-passive",
216+
"TODO-type",
217+
"control-label"
218+
]
219+
}

Diff for: ‎helper/node_modules/.pnpm-debug.log

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎helper/plugin.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import vm from "vm";
2+
import { createFilter } from "@rollup/pluginutils";
3+
import { Plugin } from "rollup";
4+
import { parseQuery } from "../src/utils";
5+
import * as htmlparser2 from "htmlparser2";
6+
import { context, falsy, truthy } from "./data";
7+
8+
// TODO: Seems like a very inefficient way to do this, hopefully redo using proper Vue AST in the future
9+
export default function (): Plugin {
10+
const whitelist: string[] = [];
11+
const filter = createFilter(null, ["**/node_modules/**"]);
12+
13+
const parser = new htmlparser2.Parser(
14+
{
15+
onattribute(name, data) {
16+
if (name === "class") whitelist.push(...data.split(" "));
17+
else if (name === ":class") {
18+
data = `[${data}]`;
19+
console.log(data);
20+
21+
const classes: string[] = [];
22+
23+
const res = [
24+
...(vm.runInNewContext(data, { ...context, ...truthy }) as []),
25+
...(vm.runInNewContext(data, { ...context, ...falsy }) as []),
26+
] as (string | Record<string, string> | (string | Record<string, string>)[])[];
27+
28+
for (const item of res) {
29+
const i = Array.isArray(item) ? item : [item];
30+
console.log(i);
31+
for (const v of i) {
32+
if (typeof v === "string") classes.push(...v.split(" "));
33+
else if (typeof v === "object") {
34+
for (const [v1, v2] of Object.entries(v)) {
35+
if (typeof v1 === "string") classes.push(...v1.split(" "));
36+
if (typeof v2 === "string") classes.push(...v2.split(" "));
37+
}
38+
}
39+
}
40+
}
41+
42+
console.log(classes);
43+
44+
whitelist.push(...classes);
45+
}
46+
},
47+
},
48+
{ decodeEntities: true },
49+
);
50+
51+
const plugin: Plugin = {
52+
name: "gatherer",
53+
54+
transform(code, id) {
55+
const query = parseQuery(id);
56+
if (!query.vue) return null;
57+
if (!query.src && !filter(query.filename)) return null;
58+
59+
// Gather user's classlist
60+
if (query.type === "template") parser.parseComplete(code);
61+
62+
return null;
63+
},
64+
65+
generateBundle() {
66+
this.emitFile({ type: "asset", fileName: "gathered", source: JSON.stringify(whitelist) });
67+
},
68+
};
69+
70+
return plugin;
71+
}

Diff for: ‎helper/shims.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "download-git-repo" {
2+
export default function (url: string, dir: string, options: unknown, cb: () => void): void;
3+
}

Diff for: ‎helper/tsconfig.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
/* Basic Options */
4+
"target": "es6",
5+
"module": "commonjs",
6+
/* Compile Options */
7+
"moduleResolution": "node",
8+
"resolveJsonModule": true,
9+
"esModuleInterop": true,
10+
"skipLibCheck": true,
11+
/* Compile Checks */
12+
"noEmitOnError": true,
13+
/* Strict Type-Checking Options */
14+
"strict": true,
15+
/* Additional Checks */
16+
"forceConsistentCasingInFileNames": true,
17+
"noUnusedLocals": true,
18+
"noUnusedParameters": true,
19+
"noImplicitReturns": true,
20+
"noFallthroughCasesInSwitch": true,
21+
/* Paths */
22+
"baseUrl": "."
23+
},
24+
"include": ["**/*.ts"]
25+
}

Diff for: ‎package.json

+6-7
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@
5858
"@babel/core": "^7.10.3",
5959
"@babel/plugin-proposal-class-properties": "^7.10.1",
6060
"@babel/preset-env": "^7.10.3",
61-
"@commitlint/cli": "^8.3.5",
62-
"@commitlint/config-angular": "^8.3.4",
63-
"@commitlint/prompt-cli": "^8.3.5",
61+
"@commitlint/cli": "^9.0.1",
62+
"@commitlint/config-angular": "^9.0.1",
63+
"@commitlint/prompt-cli": "^9.0.1",
6464
"@pathscale/bulma-css-var-only": "^0.9.0",
65-
"@pathscale/vue3-ui": "^0.8.4",
65+
"@pathscale/vue3-ui": "^0.8.8",
6666
"@rollup/plugin-babel": "^5.0.3",
6767
"@rollup/plugin-commonjs": "^13.0.0",
6868
"@rollup/plugin-json": "^4.1.0",
@@ -79,17 +79,16 @@
7979
"@typescript-eslint/eslint-plugin": "^3.3.0",
8080
"@typescript-eslint/parser": "^3.3.0",
8181
"@vue/compiler-sfc": "^3.0.0-beta.15",
82-
"@vue/composition-api": "^0.6.5",
82+
"@vue/composition-api": "^0.6.6",
8383
"@vue/runtime-dom": "^3.0.0-beta.15",
8484
"builtin-modules": "^3.1.0",
85-
"code-red": "^0.1.2",
8685
"dotenv": "^8.2.0",
8786
"download-git-repo": "^3.0.2",
8887
"eslint": "^7.3.0",
8988
"eslint-config-prettier": "^6.11.0",
9089
"eslint-import-resolver-node": "^0.3.4",
9190
"eslint-plugin-import": "^2.21.2",
92-
"eslint-plugin-jest": "^23.15.0",
91+
"eslint-plugin-jest": "^23.16.0",
9392
"eslint-plugin-node": "^11.1.0",
9493
"eslint-plugin-unicorn": "^20.1.0",
9594
"fast-glob": "^3.2.4",

Diff for: ‎pnpm-lock.yaml

+158-167
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎scripts/gather.js

-61
This file was deleted.

Diff for: ‎src/index.ts

+11-31
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,33 @@ import { createFilter } from "@rollup/pluginutils";
33
import { Plugin } from "rollup";
44
import postcss from "postcss";
55
import purgecss from "@fullhuman/postcss-purgecss";
6-
// import * as htmlparser2 from "htmlparser2";
76
import { simple as walk } from "acorn-walk";
87
import { inspect } from "util";
98
import { parseQuery } from "./utils";
109
import { Options } from "./types";
1110

11+
// eslint-disable-next-line @typescript-eslint/no-var-requires
12+
const whitelistMap = require("../helpers/mappings.json") as Record<string, string[]>;
1213
const debug = (...data: unknown[]) => void console.log(inspect(data, false, null));
1314

1415
export default (options: Options = {}): Plugin => {
15-
const whitelist: string[] = ["name", "fob"];
16-
1716
const isIncluded = createFilter(
1817
options.include ?? /\.vue$/,
1918
options.exclude ?? ["**/node_modules/**"],
2019
);
2120

22-
// const parser = new htmlparser2.Parser(
23-
// {
24-
// onattribute(name, data) {
25-
// if (name === "class") whitelist.push(data);
26-
// if (name === "id") whitelist.push(data);
27-
// },
28-
// },
29-
// { decodeEntities: true },
30-
// );
21+
console.log(whitelistMap);
3122

3223
const plugin: Plugin = {
3324
name: "vue3-ui-css-purge",
3425

35-
buildStart() {
36-
// // TODO: Very hacky because resolve does not work for some reason
37-
// const vue3uiFile = path.join(
38-
// process.cwd(),
39-
// "node_modules",
40-
// "@pathscale/vue3-ui",
41-
// "dist/bundle.js",
42-
// );
43-
// const vue3ui = fs.readFileSync(vue3uiFile, "utf-8");
44-
// console.log(vue3ui);
45-
},
46-
4726
async transform(code, id) {
4827
const query = parseQuery(id);
4928
if (!query.vue) return null;
5029
if (!query.src && !isIncluded(query.filename)) return null;
5130

52-
if (query.type === "style") {
53-
const purger = postcss(purgecss({ content: [], whitelist }));
54-
const { css } = await purger.process(code, { from: id });
55-
debug("purged", code.replace(/\s/g, ""), css.replace(/\s/g, ""));
56-
return { code: css };
57-
}
58-
5931
if (query.type === "script") {
32+
// TODO: Find all imports and map them to whitelist
6033
const ast = this.parse(code, {});
6134
walk(ast, {
6235
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -66,6 +39,13 @@ export default (options: Options = {}): Plugin => {
6639
});
6740
}
6841

42+
if (query.type === "style") {
43+
const purger = postcss(purgecss({ content: [], whitelist: [] }));
44+
const { css } = await purger.process(code, { from: id });
45+
debug("purged", code.replace(/\s/g, ""), css.replace(/\s/g, ""));
46+
return { code: css };
47+
}
48+
6949
return null;
7050
},
7151
};

Diff for: ‎tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
/* Paths */
2222
"baseUrl": "."
2323
},
24-
"include": ["src/**/*.ts", "__tests__/*.ts", "__tests__/helpers/*.ts"]
24+
"include": ["src/**/*.ts", "helper/**/*.ts", "__tests__/**/*.ts"]
2525
}

0 commit comments

Comments
 (0)
Please sign in to comment.