Skip to content
This repository was archived by the owner on Dec 3, 2021. It is now read-only.

Commit 8c13f07

Browse files
committed
chore: add migration scripts
1 parent ab966aa commit 8c13f07

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

build/css-classes-migration.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env node
2+
/* eslint-disable arrow-parens */
3+
'use strict'
4+
5+
/* global Set */
6+
7+
const fs = require('fs')
8+
const path = require('path')
9+
const extension = path.extname
10+
const { join } = require('path')
11+
const sh = require('shelljs')
12+
// sh.config.fatal = true
13+
const sed = sh.sed
14+
const replace = fs.readFileSync('css_prefix_migration.json')
15+
16+
// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
17+
RegExp.quote = (string) => string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
18+
RegExp.quoteReplacement = (string) => string.replace(/[$]/g, '$$')
19+
20+
const getFiles = (directory, allFiles = []) => {
21+
const files = fs.readdirSync(directory).map(file => join(directory, file))
22+
allFiles.push(...files)
23+
files.forEach((file) => {
24+
fs.statSync(file).isDirectory() && getFiles(file, allFiles)
25+
})
26+
return allFiles
27+
}
28+
29+
const findCSSClasses = (filepath, classes) => {
30+
const file = fs.readFileSync(filepath, 'utf8')
31+
let cssClasses
32+
let elementsToReplace = {}
33+
34+
if (path.extname(filepath) === '.pug') {
35+
const pugRegex = /(\.([a-zA-Z_-]{1}[\w-_]+))/g
36+
cssClasses = file.match(pugRegex)
37+
if (Array.isArray(cssClasses)) {
38+
cssClasses = cssClasses.map(cssClass => {
39+
let newValue = classes.find(el => el.old === `${cssClass}`)
40+
if (newValue) {
41+
newValue = newValue.new
42+
} else {
43+
newValue = cssClass
44+
}
45+
elementsToReplace = {
46+
original: cssClass,
47+
replacement: newValue
48+
}
49+
return elementsToReplace
50+
})
51+
cssClasses = cssClasses.filter(cssClass => cssClass.original !== cssClass.replacement)
52+
}
53+
} else {
54+
const htmlRegex = new RegExp(`(?:class)=['|"]([^'|"]*).`,'g')
55+
const classTags = file.match(htmlRegex)
56+
if (Array.isArray(classTags)) {
57+
cssClasses = classTags.map(classTag => {
58+
const newClassTag = classTag.replace(htmlRegex, '$1').split(' ').map(cssClass => {
59+
let newValue = classes.find(el => el.old === `.${cssClass}`)
60+
if (newValue) {
61+
newValue = newValue.new.replace('.','')
62+
} else {
63+
newValue = cssClass
64+
}
65+
return newValue
66+
})
67+
elementsToReplace = {
68+
original: classTag,
69+
replacement: classTag.replace(classTag.replace(htmlRegex, '$1'), newClassTag.join(' '))
70+
}
71+
return elementsToReplace
72+
})
73+
cssClasses = cssClasses.filter(cssClass => cssClass.original !== cssClass.replacement)
74+
}
75+
}
76+
77+
return Array.isArray(cssClasses) ? [...new Set(cssClasses.sort())] : cssClasses
78+
}
79+
80+
function getUnique(arr, comp) {
81+
82+
const unique = arr.map(e => e[comp]).map((e, i, final) => final.indexOf(e) === i && i).filter(e => arr[e]).map(e => arr[e])
83+
return unique;
84+
}
85+
86+
function findDataAttributes(filepath, allowedDataAttributes, classes) {
87+
const file = fs.readFileSync(filepath, 'utf8')
88+
let dataAttributes
89+
90+
const regex = new RegExp(`(?:${allowedDataAttributes.join('|')})=['|"]([^'|"]*)`,'g')
91+
92+
dataAttributes = file.match(regex)
93+
if (Array.isArray(dataAttributes)) {
94+
dataAttributes = dataAttributes.map(element => {
95+
const value = element.replace(regex, '$1')
96+
let newValue = classes.find(el => el.old === `.${value}`)
97+
let object = {}
98+
if (newValue) {
99+
newValue = newValue.new.replace('.','')
100+
object = {
101+
original: element,
102+
replacement: element.replace(value, newValue)
103+
}
104+
} else {
105+
object = {
106+
original: element,
107+
replacement: element
108+
}
109+
}
110+
return object
111+
})
112+
dataAttributes = getUnique(dataAttributes, 'original')
113+
}
114+
return Array.isArray(dataAttributes) ? [...new Set(dataAttributes.sort())] : dataAttributes
115+
}
116+
117+
function main(args) {
118+
const directory = args[0]
119+
const newClasses = JSON.parse(replace).replace
120+
// const EXCLUDED_DIRS = new Set([
121+
// '.git',
122+
// 'node_modules',
123+
// 'vendor'
124+
// ])
125+
const INCLUDED_EXTENSIONS = new Set([
126+
// This extension whitelist is how we avoid modifying binary files
127+
'.html',
128+
'.pug'
129+
])
130+
const DATA_ATTRIBUTES = [
131+
'data-toggle',
132+
'data-dismiss'
133+
]
134+
135+
const files = getFiles(directory)
136+
files.forEach((file) => {
137+
if (!fs.statSync(file).isDirectory()) {
138+
const classes = findCSSClasses(file, newClasses)
139+
console.log(classes)
140+
if (Array.isArray(classes)) {
141+
classes.forEach(cl => {
142+
const original = new RegExp(RegExp.quote(cl.original), 'g')
143+
const replacement = RegExp.quoteReplacement(cl.replacement)
144+
sed('-i', original, replacement, file)
145+
})
146+
}
147+
const dataAttributes = findDataAttributes(file, DATA_ATTRIBUTES, newClasses)
148+
if (Array.isArray(dataAttributes)) {
149+
console.log(dataAttributes)
150+
dataAttributes.forEach(dataAttribute => {
151+
const original = new RegExp(RegExp.quote(dataAttribute.original), 'g')
152+
const replacement = RegExp.quoteReplacement(dataAttribute.replacement)
153+
sed('-i', original, replacement, file)
154+
})
155+
}
156+
}
157+
})
158+
}
159+
160+
main(process.argv.slice(2))

0 commit comments

Comments
 (0)