-
Notifications
You must be signed in to change notification settings - Fork 0
/
tw-reorder.js
72 lines (64 loc) · 2.75 KB
/
tw-reorder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
"use strict";
import * as prettier from "prettier";
import * as fs from 'fs';
const prettier_config = {
// https://www.npmjs.com/package/prettier-plugin-tailwindcss
// tailwindConfig: './tailwind.config.js',
plugins: ["prettier-plugin-tailwindcss"],
parser: "babel",
semi: true,
};
const rx_class_nowsp = /(?<=\bclass[a-z_0-9]*=)('[^\'\"]+\s[^\'\"]+'|"[^\"]+\s[^\"]+"|`[^\`\"]+\s[^\`\"]+`)/gi;
const rx_class = /(?<=\b(?:[a-z][a-z_0-9]*class|class[a-z_0-9]*)\s*=\s*)('[^\'\"]+\s[^\'\"]+'|"[^\"]+\s[^\"]+"|`[^\`\"]+\s[^\`\"]+`)/gi;
const rx_apply = /(?<=@apply\b)(\s+[^;`"']+\s[^;`"']+;)/g;
/// Reorder all tailwind class attributes in the input file, detected via regular expressions.
async function process_file (filename, { inplace, ignorespace })
{
const itext = String (fs.readFileSync (filename));
const regex = ignorespace ? rx_class : rx_class_nowsp;
let otext = await async_replace (itext, regex, tw_reorder);
otext = await async_replace (otext, rx_apply, tw_reorder);
if (!inplace)
process.stdout.write (otext);
else if (otext !== itext)
fs.writeFileSync (filename, otext);
}
/// Reorder tailwind class names in a `class="tw..."` attribute.
async function tw_reorder (classattr)
{
const separators = "'\"`:;\t \n\v\f";
const strip_separators = separators.search (classattr[0]) >= 0 && separators.search (classattr[classattr.length -1]) >= 0;
const twstring = !strip_separators ? classattr : classattr.substr (1, classattr.length -2);
// pad `class='tw'` to a valid html statement that prettier can digest
const istmt = '<br class="' + twstring + '" />';
const ostmt = await prettier.format (istmt, prettier_config);
if (0)
console.error ("INPUT :", istmt, "\nOUTPUT:", ostmt);
// strip html statemnt
const barestmt = ostmt.replace (/^\s*;?\s*<br\s+class="|"\s*\/>\s*;?\s*$/g, '');
const result = !strip_separators ? barestmt : classattr[0] + barestmt + classattr[classattr.length -1];
return result;
}
/// Implements `string.replace (pattern, func)` for `async func`.
async function async_replace (string, regex, asyncfunc)
{
const replacements = await Promise.all (Array.from (string.matchAll (regex),
match => asyncfunc (...match)));
let i = 0;
return string.replace (regex, () => replacements[i++]);
}
// Parse arguments, usage: tw-reorder.js [--inplace] {FILE...}
const args = process.argv.slice (2); // skip [0]='node' [1]='script.js'
let files = [], inplace = false, ignorespace = false;
for (let arg of args) {
if ('--inplace' === arg)
inplace = true;
else if ('-b' === arg)
ignorespace = true;
else
files.push (arg);
}
// Reformat all given files
for (let file of files)
await process_file (file, { inplace, ignorespace });