Comparing version 3.5.0 to 4.0.0
@@ -29,5 +29,5 @@ #!/usr/bin/env node | ||
let input, output, directory, ext, config, currentErrorcode, arg | ||
let input, output, directory, ext, config | ||
let currentErrorcode = 0 | ||
const args = process.argv.slice(2) | ||
let shouldBreak = false | ||
@@ -37,11 +37,11 @@ process.on('exit', () => { process.reallyExit(currentErrorcode) }) | ||
function printWarning (...args) { | ||
console.warn(picocolors.yellow(...args)) | ||
args.forEach(a => console.warn(picocolors.yellow(a))) | ||
} | ||
function printInfo (...args) { | ||
console.info(picocolors.green(...args)) | ||
args.forEach(a => console.info(picocolors.green(a))) | ||
} | ||
function printError (...args) { | ||
console.error(picocolors.red(...args)) | ||
args.forEach(a => console.error(picocolors.red(a))) | ||
} | ||
@@ -56,191 +56,185 @@ | ||
while ((arg = args.shift())) { | ||
switch (arg) { | ||
case '-h': | ||
case '--help': | ||
printHelp() | ||
shouldBreak = true | ||
break | ||
case '-v': | ||
case '--version': | ||
printInfo(`rtlcss version: ${version}`) | ||
shouldBreak = true | ||
break | ||
case '-c': | ||
case '--config': | ||
arg = args.shift() | ||
try { | ||
config = configLoader.load(path.resolve(arg)) | ||
} catch (e) { | ||
printError('rtlcss: invalid config file. ', e) | ||
shouldBreak = true | ||
currentErrorcode = 1 | ||
} | ||
break | ||
case '-d': | ||
case '--directory': | ||
directory = true | ||
break | ||
case '-e': | ||
case '--ext': | ||
ext = args.shift() | ||
break | ||
case '-s': | ||
case '--silent': | ||
console.log = console.info = console.warn = () => {} | ||
break | ||
case '-': | ||
case '--stdin': | ||
input = '-' | ||
break | ||
default: | ||
if (arg[0] === '-') { | ||
printError(`rtlcss: unknown option. ${arg}`) | ||
shouldBreak = true | ||
} else if (!input) { | ||
input = path.resolve(arg) | ||
} else if (!output) { | ||
output = path.resolve(arg) | ||
} | ||
break | ||
function processCSSFile (error, data, outputName) { | ||
if (error) { | ||
printError(`rtlcss: ${error.message}`) | ||
return | ||
} | ||
} | ||
if (!shouldBreak) { | ||
if (!directory && !input) { | ||
printError('rtlcss: no input file') | ||
console.log('') | ||
printHelp() | ||
shouldBreak = true | ||
let result | ||
const opt = { map: false } | ||
if (input !== '-') { | ||
opt.from = input | ||
opt.to = output | ||
} | ||
if (!config && input !== '-') { | ||
try { | ||
let cwd = input | ||
if (directory !== true) { | ||
cwd = path.dirname(input) | ||
} | ||
config = configLoader.load(null, cwd) | ||
} catch (e) { | ||
printError('rtlcss: invalid config file. ', e) | ||
currentErrorcode = 1 | ||
shouldBreak = true | ||
if (!config) { | ||
printWarning('rtlcss: Warning! No config present, using defaults.') | ||
result = postcss([rtlcss]).process(data, opt) | ||
} else { | ||
if ('map' in config === true && input !== '-') { | ||
opt.map = config.map | ||
} | ||
} | ||
} | ||
if (!shouldBreak) { | ||
if (!output && input !== '-') { | ||
if (directory !== true) { | ||
const extension = path.extname(input) | ||
output = extension ? input.replace(extension, `.rtl${extension}`) : `${input}.rtl` | ||
} else { | ||
output = input | ||
} | ||
result = postcss([rtlcss.configure(config)]).process(data, opt) | ||
} | ||
const processCSSFile = (error, data, outputName) => { | ||
if (error) { | ||
printError(`rtlcss: ${error.message}`) | ||
return | ||
} | ||
if (output) { | ||
const savePath = directory !== true ? output : outputName | ||
printInfo('Saving:', savePath) | ||
let result | ||
const opt = { map: false } | ||
fs.writeFile(savePath, result.css, (err) => { | ||
if (err) printError(err) | ||
}) | ||
if (input !== '-') { | ||
opt.from = input | ||
opt.to = output | ||
if (result.map) { | ||
fs.writeFile(`${savePath}.map`, result.map, (err) => { | ||
if (err) printError(err) | ||
}) | ||
} | ||
} else { | ||
process.stdout.write(`${result.css}\n`) | ||
} | ||
} | ||
if (!config) { | ||
printWarning('rtlcss: Warning! No config present, using defaults.') | ||
result = postcss([rtlcss]).process(data, opt) | ||
} else { | ||
if ('map' in config === true && input !== '-') { | ||
opt.map = config.map | ||
} | ||
result = postcss([rtlcss.configure(config)]).process(data, opt) | ||
function walk (dir, done) { | ||
fs.readdir(dir, (error, list) => { | ||
if (error) { | ||
return done(error) | ||
} | ||
if (output) { | ||
let savePath = outputName | ||
if (directory !== true) { | ||
savePath = output | ||
let i = 0; | ||
(function next () { | ||
let file = list[i++] | ||
if (!file) { | ||
return done(null) | ||
} | ||
printInfo('Saving:', savePath) | ||
file = path.join(dir, file) | ||
fs.stat(file, (err, stat) => { | ||
if (err) { | ||
printError(err) | ||
} else if (stat && stat.isDirectory()) { | ||
walk(file, (err) => { | ||
if (err) { | ||
printError(err) | ||
} else { | ||
next() | ||
} | ||
}) | ||
} else { | ||
// process only *.css files | ||
if (path.extname(file) === '.css') { | ||
// TODO: this could probably be simplified | ||
// compute output directory | ||
const relativePath = path.relative(input, file).split(path.sep) | ||
relativePath.pop() | ||
relativePath.push(path.basename(file).replace('.css', ext || '.rtl.css')) | ||
fs.writeFile(savePath, result.css, (err) => { | ||
if (err) printError(err) | ||
}) | ||
// set rtl filename | ||
const rtlFile = path.join(output, relativePath.join(path.sep)) | ||
if (result.map) { | ||
fs.writeFile(`${savePath}.map`, result.map, (err) => { | ||
if (err) printError(err) | ||
}) | ||
} | ||
} else { | ||
process.stdout.write(`${result.css}\n`) | ||
} | ||
} | ||
// create output directory if it does not exist | ||
const dirName = path.dirname(rtlFile) | ||
if (!fs.existsSync(dirName)) { | ||
fs.mkdirSync(dirName, { recursive: true }) | ||
} | ||
const walk = (dir, done) => { | ||
fs.readdir(dir, (error, list) => { | ||
if (error) { | ||
return done(error) | ||
} | ||
// read and process the file. | ||
fs.readFile(file, 'utf8', (e, data) => { | ||
try { | ||
processCSSFile(e, data, rtlFile) | ||
} catch (e) { | ||
printError(`rtlcss: error processing file ${file}`) | ||
printError(e) | ||
} | ||
}) | ||
} | ||
let i = 0; | ||
(function next () { | ||
let file = list[i++] | ||
if (!file) { | ||
return done(null) | ||
next() | ||
} | ||
}) | ||
})() | ||
}) | ||
} | ||
file = dir + path.sep + file | ||
fs.stat(file, (err, stat) => { | ||
if (err) { | ||
printError(err) | ||
} else if (stat && stat.isDirectory()) { | ||
walk(file, (err) => { | ||
if (err) { | ||
printError(err) | ||
} else { | ||
next() | ||
} | ||
}) | ||
} else { | ||
// process only *.css files | ||
if (file.endsWith('.css')) { | ||
// compute output directory | ||
const relativePath = path.relative(input, file).split(path.sep) | ||
relativePath.pop() | ||
relativePath.push(path.basename(file).replace('.css', ext || '.rtl.css')) | ||
function main () { | ||
let arg | ||
while ((arg = args.shift())) { | ||
switch (arg) { | ||
case '-h': | ||
case '--help': | ||
printHelp() | ||
return | ||
case '-v': | ||
case '--version': | ||
printInfo(`rtlcss version: ${version}`) | ||
return | ||
case '-c': | ||
case '--config': | ||
arg = args.shift() | ||
try { | ||
config = configLoader.load(path.resolve(arg)) | ||
} catch (e) { | ||
printError(`rtlcss: invalid config file. ${e}`) | ||
currentErrorcode = 1 | ||
return | ||
} | ||
break | ||
case '-d': | ||
case '--directory': | ||
directory = true | ||
break | ||
case '-e': | ||
case '--ext': | ||
ext = args.shift() | ||
break | ||
case '-s': | ||
case '--silent': | ||
console.log = console.info = console.warn = () => {} | ||
break | ||
case '-': | ||
case '--stdin': | ||
input = '-' | ||
break | ||
default: | ||
if (arg[0] === '-') { | ||
printError(`rtlcss: unknown option. ${arg}`) | ||
currentErrorcode = 1 | ||
return | ||
} | ||
// set rtl filename | ||
const rtlFile = path.join(output, relativePath.join(path.sep)) | ||
if (!input) { | ||
input = path.resolve(arg) | ||
} else if (!output) { | ||
output = path.resolve(arg) | ||
} | ||
break | ||
} | ||
} | ||
// create output directory if it does not exist | ||
const dirName = path.dirname(rtlFile) | ||
if (!fs.existsSync(dirName)) { | ||
fs.mkdirSync(dirName, { recursive: true }) | ||
} | ||
if (!directory && !input) { | ||
printError('rtlcss: no input file\n') | ||
printHelp() | ||
currentErrorcode = 1 | ||
return | ||
} | ||
// read and process the file. | ||
fs.readFile(file, 'utf8', (e, data) => { | ||
try { | ||
processCSSFile(e, data, rtlFile) | ||
} catch (e) { | ||
printError('rtlcss: error processing file', file) | ||
printError(e) | ||
} | ||
}) | ||
} | ||
if (!config && input !== '-') { | ||
try { | ||
const cwd = directory !== true ? path.dirname(input) : input | ||
config = configLoader.load(null, cwd) | ||
} catch (error) { | ||
printError(`rtlcss: invalid config file. ${error}`) | ||
currentErrorcode = 1 | ||
} | ||
} | ||
next() | ||
} | ||
}) | ||
})() | ||
}) | ||
if (!output && input !== '-') { | ||
if (directory !== true) { | ||
const extension = path.extname(input) | ||
output = extension ? input.replace(extension, `.rtl${extension}`) : `${input}.rtl` | ||
} else { | ||
output = input | ||
} | ||
} | ||
@@ -256,8 +250,8 @@ | ||
} else { | ||
fs.readFile(input, 'utf8', (e, data) => { | ||
fs.readFile(input, 'utf8', (err, data) => { | ||
try { | ||
processCSSFile(e, data) | ||
} catch (e) { | ||
printError('rtlcss: error processing file', input) | ||
printError(e) | ||
processCSSFile(err, data) | ||
} catch (err) { | ||
printError(`rtlcss: error processing file ${input}`) | ||
printError(err) | ||
} | ||
@@ -291,1 +285,3 @@ }) | ||
} | ||
main() |
140
CHANGELOG.md
@@ -1,25 +0,39 @@ | ||
# 3.5.0 - 02 Nov. 2021 | ||
# RTLCSS Changelog | ||
## 4.0.0 - 09 Aug. 2022 | ||
* Update dependencies, Internal code refactoring, cleanup and optimizations. **Thanks @XhmikosR** | ||
* Support flipping `justify-content`, `justify-items` and `justify-self`. **Thanks @mbehzad** | ||
* Support flipping length position without using `calc` option. | ||
## 3.5.0 - 02 Nov. 2021 | ||
* Update dependencies. **Thanks @XhmikosR** | ||
* Internal code cleanup/formatting. **Thanks @XhmikosR** | ||
# 3.4.0 - 18 Oct. 2021 | ||
## 3.4.0 - 18 Oct. 2021 | ||
* Support flipping `object-position`. | ||
* Update dev. dependencies. | ||
# 3.3.0 - 08 Jul. 2021 | ||
* Update devDependencies. | ||
## 3.3.0 - 08 Jul. 2021 | ||
* Add `processEnv` option to support flipping agent-defined environment variables (`safe-area-inset-left`, `safe-area-inset-right`). | ||
# 3.2.1 - 22 Jun. 2021 | ||
## 3.2.1 - 22 Jun. 2021 | ||
* Bump [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2. | ||
# 3.2.0 - 23 May. 2021 | ||
## 3.2.0 - 23 May. 2021 | ||
* Add `aliases` option to support processing Custom Properties (CSS Variables). **Thanks @elchininet** | ||
# 3.1.2 - 04 Feb. 2021 | ||
## 3.1.2 - 04 Feb. 2021 | ||
* Update `README.md`. | ||
# 3.1.1 - 02 Feb. 2021 | ||
## 3.1.1 - 02 Feb. 2021 | ||
* Fixes `TypeError` when placing value directive before `!important`. [#218](https://github.com/MohammadYounes/rtlcss/issues/218) | ||
# 3.1.0 - 30 Jan. 2021 | ||
## 3.1.0 - 30 Jan. 2021 | ||
@@ -30,8 +44,8 @@ * Use `strict` mode across all files. **Thanks @XhmikosR** | ||
* Allow value directives to be placed any where inside the declaration value. | ||
* Handle value directives placed after `!important`. | ||
* Handle value directives placed after `!important`. | ||
* Fix reading config file sources ([#209](https://github.com/MohammadYounes/rtlcss/issues/209)). | ||
# 3.0.0 - 10 Dec. 2020 | ||
## 3.0.0 - 10 Dec. 2020 | ||
* Upgrade to [POSTCSS] 8. | ||
* Upgrade to [postcss] 8. | ||
* Dropped **Node.js 6.x, 8.x, 11.x, and 13.x** versions. | ||
@@ -79,3 +93,3 @@ | ||
* Support for pre/post hooks. | ||
* Upgrade to [POSTCSS] v6.x | ||
* Upgrade to [postcss] v6.x | ||
@@ -88,3 +102,3 @@ ## 2.1.2 - 31 Dec. 2016 | ||
* Fixes a bug in self closing ignore directive (Fixes [#88](https://github.com/MohammadYounes/rtlcss/issues/88)). | ||
* Fixes a bug in self-closing ignore directive (Fixes [#88](https://github.com/MohammadYounes/rtlcss/issues/88)). | ||
@@ -95,36 +109,36 @@ ## 2.1.0 - 30 Nov. 2016 | ||
### 2.0.7 - 16 Nov. 2016 | ||
## 2.0.7 - 16 Nov. 2016 | ||
* Fixes a bug in flipping backgrounds having url placed first (Fixes [#84](https://github.com/MohammadYounes/rtlcss/issues/84)). | ||
* Fixes a bug in flipping backgrounds having URL placed first (Fixes [#84](https://github.com/MohammadYounes/rtlcss/issues/84)). | ||
* Update `node.value` so changes will be picked up by other processors (Closes [#85](https://github.com/MohammadYounes/rtlcss/issues/85)). | ||
### 2.0.6 - 12 Jul. 2016 | ||
## 2.0.6 - 12 Jul. 2016 | ||
* README updates. | ||
### 2.0.5 - 17 May. 2016 | ||
## 2.0.5 - 17 May. 2016 | ||
* Fixes a bug in complementing calc values (Fixes [#71](https://github.com/MohammadYounes/rtlcss/issues/71)). | ||
### 2.0.4 - 25 Apr. 2016 | ||
* Fixes a bug in complementing `calc` values (Fixes [#71](https://github.com/MohammadYounes/rtlcss/issues/71)). | ||
## 2.0.4 - 25 Apr. 2016 | ||
* Fixes a bug in flipping cursor value (Fixes [#68](https://github.com/MohammadYounes/rtlcss/issues/68)). | ||
### 2.0.3 - 23 Mar. 2016 | ||
## 2.0.3 - 23 Mar. 2016 | ||
* Guard against flipping tokens, e.g: [shadows starting with a color function](https://github.com/MohammadYounes/rtlcss/blob/master/test/data/special.js#L2-L7). | ||
### 2.0.2 - 05 Mar. 2016 | ||
## 2.0.2 - 05 Mar. 2016 | ||
* Fixes a bug in flipping background with a hex color value (Fixes [#60](https://github.com/MohammadYounes/rtlcss/issues/60)). | ||
### 2.0.1 - 23 Feb. 2016 | ||
## 2.0.1 - 23 Feb. 2016 | ||
* Fixes a bug when having `decl` nodes inside `atrule`s and `autoRename` enabled. | ||
* Fixes a bug in flipping multi-valued transforms. | ||
# 2.0.0 - 18 Feb. 2016 | ||
## 2.0.0 - 18 Feb. 2016 | ||
* Support for control directive blocks, e.g. `/*rtl:begin:ignore*/ ... /*rtl:end:ignore*/`. | ||
* Support for strict auto renaming, Which ensures `autoRename` is applied only when a pair exists. | ||
* Support for strict auto renaming, which ensures `autoRename` is applied only when a pair exists. | ||
* New directives: | ||
@@ -137,3 +151,3 @@ * `config` | ||
#### Upgrading from version 1.0 | ||
### Upgrading from version 1.0 | ||
@@ -153,3 +167,3 @@ Options and config settings have changed. However, you need not to worry about your CSS files as all directives are backward-compatible. This is a summary of what's changed: | ||
* added `exclusive` attribute, which determines if a map execution should stop iterating over other maps. | ||
* dropped 'west-east' map from the default map collection. | ||
* dropped `'west-east'` map from the default map collection. | ||
@@ -165,19 +179,19 @@ * Removed Options: | ||
### v1.7.4 - 23 Feb. 2016 | ||
## v1.7.4 - 23 Feb. 2016 | ||
* Fixes a bug in flipping multiple transforms. | ||
### v1.7.3 - 30 Jan. 2016 | ||
## v1.7.3 - 30 Jan. 2016 | ||
* Fixes a bug in flipping N-Values containing comments. | ||
### 1.7.2 - 30 Jan. 2016 | ||
## 1.7.2 - 30 Jan. 2016 | ||
* Fixes a bug in flipping N-Values containing comments. | ||
### 1.7.2 - 04 Dec. 2015 | ||
## 1.7.2 - 04 Dec. 2015 | ||
* Fixes a compatibility issue with postcss-js (Fixes [#48](https://github.com/MohammadYounes/rtlcss/issues/48)). | ||
### 1.7.1 - 10 Nov. 2015 | ||
## 1.7.1 - 10 Nov. 2015 | ||
@@ -192,12 +206,12 @@ * Fixed a bug in flipping backgrounds having functions (Issue [#45](https://github.com/MohammadYounes/rtlcss/issues/45)). | ||
### 1.6.3 - 28 Aug. 2015 | ||
## 1.6.3 - 28 Aug. 2015 | ||
* CLI: fix source map option (issue #40). | ||
* Upgrade to [POSTCSS] v5.0.x | ||
* Upgrade to [postcss] v5.0.x | ||
### 1.6.2 - 21 Jul. 2015 | ||
## 1.6.2 - 21 Jul. 2015 | ||
* CLI: fix loading custom configuration file manually via the --config flag. **Thanks @KeyKaKiTO** | ||
### 1.6.1 - 17 Mar. 2015 | ||
## 1.6.1 - 17 Mar. 2015 | ||
@@ -210,7 +224,7 @@ * Fixed flipping units having more than 1 digit before the decimal point. | ||
### 1.5.2 - 28 Feb. 2015 | ||
## 1.5.2 - 28 Feb. 2015 | ||
* Fix flipping string maps containing regular expressions special characters (Fixes [#24](https://github.com/MohammadYounes/rtlcss/issues/24)). | ||
### 1.5.1 - 14 Feb. 2015 | ||
## 1.5.1 - 14 Feb. 2015 | ||
@@ -223,11 +237,11 @@ * Fix flipping multiple shadows when a hex color was used. **Thanks @ocean90** | ||
### 1.4.3 - 24 Jan. 2015 | ||
## 1.4.3 - 24 Jan. 2015 | ||
* Upgrade to [POSTCSS] v4.0.x **Thanks @necolas** | ||
* Upgrade to [postcss] v4.0.x **Thanks @necolas** | ||
### 1.4.2 - 24 Oct. 2014 | ||
## 1.4.2 - 24 Oct. 2014 | ||
* CLI: Switch to Unix line endings (Fixes [#14](https://github.com/MohammadYounes/rtlcss/issues/14)) | ||
### 1.4.1 - 24 Oct. 2014 | ||
## 1.4.1 - 24 Oct. 2014 | ||
@@ -238,5 +252,5 @@ * CLI: Print processing errors. | ||
* CLI: Support processing a directory. see [CLI documentation](https://github.com/MohammadYounes/rtlcss/blob/master/CLI.md#directory) | ||
* CLI: Support processing a directory. See [CLI documentation](https://github.com/MohammadYounes/rtlcss/blob/master/docs/CLI.md). | ||
### 1.3.1 - 29 Sep. 2014 | ||
## 1.3.1 - 29 Sep. 2014 | ||
@@ -256,9 +270,9 @@ * Update README.md (typos). | ||
* Upgrade to [POSTCSS] v2.2.5 | ||
* Upgrade to [postcss] v2.2.5 | ||
* Support flipping `border-color`, `border-style` and `background-position-x` | ||
# 1.0.0 - 24 Aug. 2014 | ||
## 1.0.0 - 24 Aug. 2014 | ||
* Upgrade to [POSTCSS] v2.2.1 | ||
* Support flipping urls in '@import' rule. | ||
* Upgrade to [postcss] v2.2.1 | ||
* Support flipping urls in `@import` rule. | ||
* Fix JSON parse error when configuration file is UTF-8 encoded. | ||
@@ -298,12 +312,12 @@ * Better minification. | ||
* Support flipping rotateZ. | ||
* Fix flipping rotate3d. | ||
* Fix flipping skew, skewX and skewY. | ||
* Fix flipping cursor value. | ||
* Fix flipping translate3d. | ||
* Update flipping background horizontal position to treat 0 as 0% | ||
* Support flipping `rotateZ`. | ||
* Fix flipping `rotate3d`. | ||
* Fix flipping `skew`, `skewX` and `skewY`. | ||
* Fix flipping `cursor` value. | ||
* Fix flipping `translate3d`. | ||
* Update flipping background horizontal position to treat `0` as `0%` | ||
### 0.2.1 - 20 Mar. 2014 | ||
## 0.2.1 - 20 Mar. 2014 | ||
* Upgrade to [POSTCSS] v0.3.4 | ||
* Upgrade to [postcss] v0.3.4 | ||
@@ -316,7 +330,7 @@ ## 0.2.0 - 20 Mar. 2014 | ||
### 0.1.3 - 7 Mar. 2014 | ||
## 0.1.3 - 7 Mar. 2014 | ||
* Fix missing include in rules.js | ||
### 0.1.2 - 5 Mar. 2014 | ||
## 0.1.2 - 5 Mar. 2014 | ||
@@ -326,6 +340,6 @@ * New option: minify output CSS. | ||
### 0.1.1 - 4 Mar. 2014 | ||
## 0.1.1 - 4 Mar. 2014 | ||
* Initial commit. | ||
[POSTCSS]: https://postcss.org/ | ||
[postcss]: https://postcss.org/ |
@@ -5,3 +5,3 @@ 'use strict' | ||
const path = require('path') | ||
const findUp = require('find-up') | ||
const escalade = require('escalade/sync') | ||
const stripJSONComments = require('strip-json-comments') | ||
@@ -17,6 +17,2 @@ | ||
const readConfig = (configFilePath) => { | ||
return JSON.parse(stripJSONComments(fs.readFileSync(configFilePath, 'utf-8').trim())) | ||
} | ||
module.exports.load = (configFilePath, cwd, overrides) => { | ||
@@ -50,21 +46,18 @@ if (configFilePath) { | ||
function readConfig (configFilePath) { | ||
try { | ||
const data = fs.readFileSync(path.normalize(configFilePath), 'utf-8') | ||
return JSON.parse(stripJSONComments(data.trim())) | ||
} catch (error) { | ||
throw new Error(`${error} ${configFilePath}`) | ||
} | ||
} | ||
function loadConfig (cwd) { | ||
for (const source of configSources) { | ||
let foundPath | ||
const foundPath = escalade(cwd, (dir, names) => names.includes(source) && source) | ||
try { | ||
foundPath = findUp.sync(source, { cwd }) | ||
} catch (e) { | ||
continue | ||
} | ||
if (foundPath) { | ||
const configFilePath = path.normalize(foundPath) | ||
config = readConfig(foundPath) | ||
try { | ||
config = readConfig(configFilePath) | ||
} catch (e) { | ||
throw new Error(`${e} ${configFilePath}`) | ||
} | ||
if (source === 'package.json') { | ||
@@ -71,0 +64,0 @@ config = config.rtlcssConfig |
'use strict' | ||
let options | ||
const config = {} | ||
const corePlugin = require('./plugin.js') | ||
const defaultOptions = { | ||
autoRename: false, | ||
autoRenameStrict: false, | ||
blacklist: {}, | ||
clean: true, | ||
greedy: false, | ||
processUrls: false, | ||
stringMap: [], | ||
useCalc: false, | ||
aliases: {}, | ||
processEnv: true | ||
} | ||
function sort (arr) { | ||
@@ -11,79 +22,57 @@ return arr.sort((a, b) => a.priority - b.priority) | ||
function optionOrDefault (option, def) { | ||
return option in options ? options[option] : def | ||
} | ||
function setupStringMap (stringMap) { | ||
if (!Array.isArray(stringMap)) { | ||
return | ||
} | ||
function addKey (key, def) { | ||
config[key] = optionOrDefault(key, def) | ||
} | ||
let hasLeftRight = false | ||
let hasLtrRtl = false | ||
function main (opts, plugins, hooks) { | ||
options = opts || {} | ||
hooks = hooks || {} | ||
addKey('autoRename', false) | ||
addKey('autoRenameStrict', false) | ||
addKey('blacklist', {}) | ||
addKey('clean', true) | ||
addKey('greedy', false) | ||
addKey('processUrls', false) | ||
addKey('stringMap', []) | ||
addKey('useCalc', false) | ||
addKey('aliases', {}) | ||
addKey('processEnv', true) | ||
// default strings map | ||
if (Array.isArray(config.stringMap)) { | ||
let hasLeftRight, hasLtrRtl | ||
for (const map of config.stringMap) { | ||
if (hasLeftRight && hasLtrRtl) { | ||
break | ||
} else if (map.name === 'left-right') { | ||
hasLeftRight = true | ||
} else if (map.name === 'ltr-rtl') { | ||
hasLtrRtl = true | ||
} | ||
for (const map of stringMap) { | ||
if (hasLeftRight && hasLtrRtl) { | ||
break | ||
} else if (map.name === 'left-right') { | ||
hasLeftRight = true | ||
} else if (map.name === 'ltr-rtl') { | ||
hasLtrRtl = true | ||
} | ||
} | ||
if (!hasLeftRight) { | ||
config.stringMap.push({ | ||
name: 'left-right', | ||
priority: 100, | ||
exclusive: false, | ||
search: ['left', 'Left', 'LEFT'], | ||
replace: ['right', 'Right', 'RIGHT'], | ||
options: { scope: '*', ignoreCase: false } | ||
}) | ||
} | ||
if (!hasLeftRight) { | ||
stringMap.push({ | ||
name: 'left-right', | ||
priority: 100, | ||
exclusive: false, | ||
search: ['left', 'Left', 'LEFT'], | ||
replace: ['right', 'Right', 'RIGHT'], | ||
options: { scope: '*', ignoreCase: false } | ||
}) | ||
} | ||
if (!hasLtrRtl) { | ||
config.stringMap.push({ | ||
name: 'ltr-rtl', | ||
priority: 100, | ||
exclusive: false, | ||
search: ['ltr', 'Ltr', 'LTR'], | ||
replace: ['rtl', 'Rtl', 'RTL'], | ||
options: { scope: '*', ignoreCase: false } | ||
}) | ||
} | ||
sort(config.stringMap) | ||
if (!hasLtrRtl) { | ||
stringMap.push({ | ||
name: 'ltr-rtl', | ||
priority: 100, | ||
exclusive: false, | ||
search: ['ltr', 'Ltr', 'LTR'], | ||
replace: ['rtl', 'Rtl', 'RTL'], | ||
options: { scope: '*', ignoreCase: false } | ||
}) | ||
} | ||
// plugins | ||
config.plugins = [] | ||
return sort(stringMap) | ||
} | ||
if (Array.isArray(plugins)) { | ||
if (!plugins.some((plugin) => plugin.name === 'rtlcss')) { | ||
config.plugins.push(corePlugin) | ||
} | ||
function setupPlugins (plugins) { | ||
const newPlugins = [] | ||
config.plugins = config.plugins.concat(plugins) | ||
} else if (!plugins || plugins.name !== 'rtlcss') { | ||
config.plugins.push(corePlugin) | ||
if (!plugins || !plugins.some((plugin) => plugin.name === 'rtlcss')) { | ||
newPlugins.push(corePlugin) | ||
} | ||
sort(config.plugins) | ||
return sort([...newPlugins, ...plugins]) | ||
} | ||
// hooks | ||
config.hooks = { | ||
function setupHooks (hooks) { | ||
const newHooks = { | ||
pre () {}, | ||
@@ -94,12 +83,23 @@ post () {} | ||
if (typeof hooks.pre === 'function') { | ||
config.hooks.pre = hooks.pre | ||
newHooks.pre = hooks.pre | ||
} | ||
if (typeof hooks.post === 'function') { | ||
config.hooks.post = hooks.post | ||
newHooks.post = hooks.post | ||
} | ||
return newHooks | ||
} | ||
module.exports.configure = (opts = {}, plugins = [], hooks = {}) => { | ||
const config = { ...defaultOptions, ...opts } | ||
// string map | ||
config.stringMap = setupStringMap(config.stringMap) | ||
// plugins | ||
config.plugins = setupPlugins(plugins) | ||
// hooks | ||
config.hooks = setupHooks(hooks) | ||
return config | ||
} | ||
module.exports.configure = main |
'use strict' | ||
module.exports = (comment) => { | ||
let pos = 0 | ||
let value = comment.text | ||
const match = value.match(/^\s*!?\s*rtl:/) | ||
let meta | ||
const match = comment.text.match(/^\s*!?\s*rtl:/) | ||
if (!match) return | ||
if (match) { | ||
meta = { | ||
source: comment, | ||
name: '', | ||
param: '', | ||
begin: true, | ||
end: true, | ||
blacklist: false, | ||
preserve: false | ||
} | ||
value = value.slice(match[0].length) | ||
pos = value.indexOf(':') | ||
let value = comment.text.slice(match[0].length) | ||
let pos = value.indexOf(':') | ||
const meta = { | ||
source: comment, | ||
name: '', | ||
param: '', | ||
begin: true, | ||
end: true, | ||
blacklist: false, | ||
preserve: false | ||
} | ||
if (pos > -1) { | ||
meta.name = value.slice(0, pos) | ||
// begin/end are always true, unless one of them actually exists. | ||
meta.begin = meta.name !== 'end' | ||
meta.end = meta.name !== 'begin' | ||
if (meta.name === 'begin' || meta.name === 'end') { | ||
value = value.slice(meta.name.length + 1) | ||
pos = value.indexOf(':') | ||
if (pos > -1) { | ||
meta.name = value.slice(0, pos) | ||
value = value.slice(pos) | ||
meta.param = value.slice(1) | ||
} else { | ||
meta.name = value | ||
} | ||
if (pos !== -1) { | ||
meta.name = value.slice(0, pos) | ||
// begin/end are always true, unless one of them actually exists. | ||
meta.begin = meta.name !== 'end' | ||
meta.end = meta.name !== 'begin' | ||
if (meta.name === 'begin' || meta.name === 'end') { | ||
value = value.slice(meta.name.length + 1) | ||
pos = value.indexOf(':') | ||
if (pos !== -1) { | ||
meta.name = value.slice(0, pos) | ||
meta.param = value.slice(pos + 1) | ||
} else { | ||
meta.param = value.slice(pos + 1) | ||
meta.name = value | ||
} | ||
} else { | ||
meta.name = value | ||
meta.param = value.slice(pos + 1) | ||
} | ||
} else { | ||
meta.name = value | ||
} | ||
@@ -44,0 +41,0 @@ |
@@ -15,4 +15,4 @@ 'use strict' | ||
begin (node, metadata, context) { | ||
// find the ending node in case of self closing directive | ||
if (!this.endNode && metadata.begin && metadata.end) { | ||
// find the ending node in case of self-closing directive | ||
if (this.endNode === null && metadata.begin && metadata.end) { | ||
let n = node | ||
@@ -26,8 +26,3 @@ while (n && n.nodes) { | ||
let prevent = true | ||
if (node.type === 'comment' && node.text.match(/^\s*!?\s*rtl:end:ignore/)) { | ||
prevent = false | ||
} | ||
return prevent | ||
return node.type !== 'comment' || !/^\s*!?\s*rtl:end:ignore/.test(node.text) | ||
}, | ||
@@ -37,3 +32,3 @@ end (node, metadata, context) { | ||
// 1. block directive and the node is comment | ||
// 2. self closing directive and node is endNode | ||
// 2. self-closing directive and node is endNode | ||
if ((metadata.begin !== metadata.end && node.type === 'comment') || (metadata.begin && metadata.end && node === this.endNode)) { | ||
@@ -183,3 +178,3 @@ // clear ending node | ||
const raw = `${decl.raws.between.substr(1).trim()}${hasRawValue ? decl.raws.value.raw : decl.value}${decl.important ? decl.raws.important.substr(9).trim() : ''}` | ||
const result = raw.replace(expr, (match, value) => hasRawValue ? value + match : value) | ||
const result = raw.replace(expr, (match, value) => value + match) | ||
decl.value = hasRawValue ? (decl.raws.value.raw = result) : result | ||
@@ -223,3 +218,3 @@ return true | ||
action (prop, value, context) { | ||
return { prop: prop.replace(this.expr, () => 'right'), value } | ||
return { prop: prop.replace(this.expr, 'right'), value } | ||
} | ||
@@ -231,3 +226,3 @@ }, | ||
action (prop, value, context) { | ||
return { prop: prop.replace(this.expr, () => 'left'), value } | ||
return { prop: prop.replace(this.expr, 'left'), value } | ||
} | ||
@@ -369,25 +364,21 @@ }, | ||
flipMatrix (value, context) { | ||
return this.flip(value, (i, num) => { | ||
if (i === 2 || i === 3 || i === 5) { | ||
return context.util.negate(num) | ||
} | ||
return num | ||
}, context) | ||
return this.flip( | ||
value, | ||
(i, num) => i === 2 || i === 3 || i === 5 ? context.util.negate(num) : num, | ||
context | ||
) | ||
}, | ||
flipMatrix3D (value, context) { | ||
return this.flip(value, (i, num) => { | ||
if (i === 2 || i === 4 || i === 5 || i === 13) { | ||
return context.util.negate(num) | ||
} | ||
return num | ||
}, context) | ||
return this.flip( | ||
value, | ||
(i, num) => i === 2 || i === 4 || i === 5 || i === 13 ? context.util.negate(num) : num, | ||
context | ||
) | ||
}, | ||
flipRotate3D (value, context) { | ||
return this.flip(value, (i, num) => { | ||
if (i === 1 || i === 4) { | ||
return context.util.negate(num) | ||
} | ||
return num | ||
}, context) | ||
return this.flip( | ||
value, | ||
(i, num) => i === 1 || i === 4 ? context.util.negate(num) : num, | ||
context | ||
) | ||
}, | ||
@@ -439,3 +430,3 @@ action (prop, value, context) { | ||
cache: null, | ||
flip (value, context) { | ||
flip (value, context, isPositionX) { | ||
const state = util.saveTokens(value, true) | ||
@@ -449,9 +440,18 @@ const parts = state.value.match(this.cache.match) | ||
} else { | ||
parts[0] = parts[0] === '0' | ||
? '100%' | ||
: (parts[0].match(this.cache.percent) | ||
? context.util.complement(parts[0]) | ||
: (parts[0].match(this.cache.length) | ||
? context.util.flipLength(parts[0]) | ||
: context.util.swapLeftRight(parts[0]))) | ||
if (parts[0] === '0') { | ||
parts[0] = '100%' | ||
} else if (parts[0].match(this.cache.percent)) { | ||
parts[0] = context.util.complement(parts[0]) | ||
} else if (parts[0].match(this.cache.length)) { | ||
if (isPositionX) { | ||
parts[0] = context.util.flipLength(parts[0]) | ||
} else if (parts.length === 1) { // X 50% ==> left X top 50% | ||
parts[0] = `right ${parts[0]} top 50%` | ||
} else if (!keywords && parts.length === 2) { // X Y ==> left X top Y | ||
parts[0] = `right ${parts[0]}` | ||
parts[1] = `top ${parts[1]}` | ||
} | ||
} else { | ||
parts[0] = context.util.swapLeftRight(parts[0]) | ||
} | ||
state.value = state.value.replace(this.cache.match, () => parts.shift()) | ||
@@ -493,3 +493,3 @@ } | ||
for (let x = 0; x < parts.length; x++) { | ||
parts[x] = this.flip(parts[x], context) | ||
parts[x] = this.flip(parts[x], context, lprop.endsWith('-x')) | ||
} | ||
@@ -508,3 +508,3 @@ } | ||
name: 'keyword', | ||
expr: /float|clear|text-align/i, | ||
expr: /float|clear|text-align|justify-(content|items|self)/i, | ||
action (prop, value, context) { | ||
@@ -519,6 +519,5 @@ return { prop, value: context.util.swapLeftRight(value) } | ||
update (context, value, name) { | ||
if ((context.config.processUrls === true || context.config.processUrls.decl === true) && name.match(this.cache.url)) { | ||
value = context.util.applyStringMap(value, true) | ||
} | ||
return value | ||
return (context.config.processUrls === true || context.config.processUrls.decl === true) && name.match(this.cache.url) | ||
? context.util.applyStringMap(value, true) | ||
: value | ||
}, | ||
@@ -525,0 +524,0 @@ flip (value) { |
@@ -57,8 +57,8 @@ /** | ||
postcssPlugin: 'rtlcss', | ||
Once (root, { result }) { | ||
Once (root) { | ||
context.config.hooks.pre(root, postcss) | ||
shouldProcess(root, result) | ||
shouldProcess(root) | ||
}, | ||
Rule (node, { result }) { | ||
if (shouldProcess(node, result)) { | ||
Rule (node) { | ||
if (shouldProcess(node)) { | ||
// new rule, reset flipped decl count to zero | ||
@@ -68,13 +68,12 @@ flipped = 0 | ||
}, | ||
AtRule (node, { result }) { | ||
if (shouldProcess(node, result) && | ||
AtRule (node) { | ||
if (shouldProcess(node) && | ||
// @rules requires url flipping only | ||
(context.config.processUrls === true || context.config.processUrls.atrule === true) | ||
) { | ||
const params = context.util.applyStringMap(node.params, true) | ||
node.params = params | ||
node.params = context.util.applyStringMap(node.params, true) | ||
} | ||
}, | ||
Comment (node, { result }) { | ||
if (shouldProcess(node, result)) { | ||
if (shouldProcess(node)) { | ||
state.parse(node, result, (current) => { | ||
@@ -131,3 +130,3 @@ let push = true | ||
Declaration (node, { result }) { | ||
if (shouldProcess(node, result)) { | ||
if (shouldProcess(node)) { | ||
// if broken by a matching value directive .. break | ||
@@ -138,3 +137,3 @@ if (!context.util.each(context.config.plugins, (plugin) => { | ||
const expr = context.util.regexDirective(directive.name) | ||
if (expr.test(`${node.raws.between}${hasRawValue ? node.raws.value.raw : ''}${node.important && node.raws.important ? node.raws.important : ''}`)) { | ||
if (expr.test(`${node.raws.between}${hasRawValue ? node.raws.value.raw : node.value}${node.important && node.raws.important ? node.raws.important : ''}`)) { | ||
expr.lastIndex = 0 | ||
@@ -148,5 +147,5 @@ if (directive.action(node, expr, context)) { | ||
if (hasRawValue) { | ||
node.value = node.raws.value.raw = context.util.trimDirective(node.raws.value.raw) | ||
} | ||
node.value = hasRawValue | ||
? (node.raws.value.raw = context.util.trimDirective(node.raws.value.raw)) | ||
: context.util.trimDirective(node.value) | ||
} | ||
@@ -237,5 +236,4 @@ | ||
*/ | ||
module.exports.configure = function (config) { | ||
config = config || {} | ||
module.exports.configure = function (config = {}) { | ||
return postcss([this(config.options, config.plugins, config.hooks)]) | ||
} |
@@ -34,3 +34,3 @@ 'use strict' | ||
if (current === undefined) { | ||
lazyResult.warn(`found end "${metadata.name}" without a matching begin.`, { node: node }) | ||
lazyResult.warn(`found end "${metadata.name}" without a matching begin.`, { node }) | ||
} else if (callback(current)) { | ||
@@ -37,0 +37,0 @@ this.stack.push(current) |
@@ -20,3 +20,3 @@ 'use strict' | ||
const REGEX_COMMENT = /\/\*[^]*?\*\//igm // non-greedy | ||
const REGEX_DIRECTIVE = /\/\*\s*(?:!)?\s*rtl:[^]*?\*\//img | ||
const REGEX_DIRECTIVE = /\/\*\s*!?\s*rtl:[^]*?\*\//img | ||
const REGEX_ESCAPE = /[.*+?^${}()|[\]\\]/g | ||
@@ -59,5 +59,4 @@ const REGEX_FUNCTION = /\([^()]+\)/i | ||
}, | ||
swap (value, a, b, options) { | ||
swap (value, a, b, options = DEFAULT_STRING_MAP_OPTIONS) { | ||
let expr = `${escapeRegExp(a)}|${escapeRegExp(b)}` | ||
options = options || DEFAULT_STRING_MAP_OPTIONS | ||
const greedy = Object.prototype.hasOwnProperty.call(options, 'greedy') ? options.greedy : config.greedy | ||
@@ -134,3 +133,3 @@ if (!greedy) expr = `\\b(${expr})\\b` | ||
state.value = state.value.replace(what, (c) => { | ||
if (exclude && c.match(exclude)) { | ||
if (exclude && exclude.test(c)) { | ||
return c | ||
@@ -146,5 +145,3 @@ } | ||
let index = 0 | ||
const result = state.value.replace(state.restorer, () => { | ||
return state.store[index++] | ||
}) | ||
const result = state.value.replace(state.restorer, () => state.store[index++]) | ||
state.store.length = 0 | ||
@@ -167,3 +164,3 @@ return result | ||
}, | ||
guard (what, who, indexed) { | ||
guard (what, who) { | ||
const state = { | ||
@@ -173,16 +170,9 @@ value: who, | ||
offset: tokenId++, | ||
token: CHAR_TOKEN_START + tokenId, | ||
indexed: indexed === true | ||
token: CHAR_TOKEN_START + tokenId | ||
} | ||
if (state.indexed === true) { | ||
while (what.test(state.value)) { | ||
state.value = state.value.replace(what, (m) => { | ||
state.store.push(m) | ||
return `${state.token}:${state.store.length}${CHAR_TOKEN_END}` | ||
}) | ||
} | ||
} else { | ||
while (what.test(state.value)) { | ||
state.value = state.value.replace(what, (m) => { | ||
state.store.push(m) | ||
return state.token + CHAR_TOKEN_END | ||
return `${state.token}:${state.store.length}${CHAR_TOKEN_END}` | ||
}) | ||
@@ -194,25 +184,16 @@ } | ||
unguard (state, callback) { | ||
if (state.indexed === true) { | ||
const detokenizer = new RegExp('(\\w*?)' + state.token + ':(\\d+)' + CHAR_TOKEN_END, 'i') | ||
while (detokenizer.test(state.value)) { | ||
state.value = state.value.replace(detokenizer, (match, name, index) => { | ||
const value = state.store[index - 1] | ||
return typeof callback === 'function' | ||
? name + callback(value, name) | ||
: name + value | ||
}) | ||
} | ||
return state.value | ||
const detokenizer = new RegExp('(\\w*?)' + state.token + ':(\\d+)' + CHAR_TOKEN_END, 'i') | ||
while (detokenizer.test(state.value)) { | ||
state.value = state.value.replace(detokenizer, (match, name, index) => { | ||
const value = state.store[index - 1] | ||
return typeof callback === 'function' | ||
? name + callback(value, name) | ||
: name + value | ||
}) | ||
} | ||
return state.value.replace(new RegExp('(\\w*?)' + state.token + CHAR_TOKEN_END, 'i'), (match, name) => { | ||
const value = state.store.shift() | ||
return typeof callback === 'function' | ||
? name + callback(value, name) | ||
: name + value | ||
}) | ||
return state.value | ||
}, | ||
guardHexColors (value) { | ||
return this.guard(REGEX_HEX_COLOR, value, true) | ||
return this.guard(REGEX_HEX_COLOR, value) | ||
}, | ||
@@ -223,3 +204,3 @@ unguardHexColors (state, callback) { | ||
guardFunctions (value) { | ||
return this.guard(REGEX_FUNCTION, value, true) | ||
return this.guard(REGEX_FUNCTION, value) | ||
}, | ||
@@ -239,3 +220,2 @@ unguardFunctions (state, callback) { | ||
regex (what, options) { | ||
what = what || [] | ||
let expression = '' | ||
@@ -281,13 +261,7 @@ | ||
/** | ||
* Simple breakable each: returning false in the callback will break the loop | ||
* returns false if the loop was broken, otherwise true | ||
* Simple breakable each returning false if the callback returns false | ||
* otherwise it returns true | ||
*/ | ||
each (array, callback) { | ||
for (const element of array) { | ||
if (callback(element) === false) { | ||
return false | ||
} | ||
} | ||
return true | ||
return !array.some((element) => callback(element) === false) | ||
} | ||
@@ -294,0 +268,0 @@ } |
{ | ||
"author": "Mohammad Younes", | ||
"name": "rtlcss", | ||
"version": "3.5.0", | ||
"version": "4.0.0", | ||
"description": "Framework for transforming cascading style sheets (CSS) from left-to-right (LTR) to right-to-left (RTL)", | ||
@@ -28,14 +28,23 @@ "homepage": "https://rtlcss.com/", | ||
"bin": { | ||
"rtlcss": "./bin/rtlcss.js" | ||
"rtlcss": "bin/rtlcss.js" | ||
}, | ||
"main": "./lib/rtlcss.js", | ||
"files": [ | ||
"bin/*.js", | ||
"lib/*.js" | ||
], | ||
"dependencies": { | ||
"find-up": "^5.0.0", | ||
"escalade": "^3.1.1", | ||
"picocolors": "^1.0.0", | ||
"postcss": "^8.3.11", | ||
"postcss": "^8.4.6", | ||
"strip-json-comments": "^3.1.1" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^9.1.3", | ||
"c8": "^7.11.0", | ||
"mocha": "^9.2.0", | ||
"standard": "^16.0.4" | ||
}, | ||
"engines": { | ||
"node": ">=12.0.0" | ||
}, | ||
"scripts": { | ||
@@ -45,11 +54,8 @@ "main": "node ./lib/rtlcss.js", | ||
"lint:fix": "npm run lint -- --fix", | ||
"mocha": "mocha -R spec", | ||
"mocha:special": "npm run mocha -- --fgrep \"# Special\"", | ||
"test": "npm run lint && npm run main && npm run mocha" | ||
}, | ||
"main": "./lib/rtlcss.js", | ||
"files": [ | ||
"bin/*.js", | ||
"lib/*.js" | ||
] | ||
"mocha": "mocha", | ||
"mocha:special": "mocha --fgrep \"# Special\"", | ||
"test": "npm run lint && npm run main && npm run mocha", | ||
"test:ci": "npm run main && npm run mocha", | ||
"coverage": "c8 npm run mocha" | ||
} | ||
} |
@@ -10,3 +10,2 @@ # RTLCSS | ||
[![Build Status](https://img.shields.io/github/workflow/status/MohammadYounes/rtlcss/CI/master?label=CI&logo=github)](https://github.com/MohammadYounes/rtlcss/actions?query=workflow%3ACI+branch%3Amaster) | ||
[![Dependencies](https://img.shields.io/david/MohammadYounes/rtlcss)](https://david-dm.org/MohammadYounes/rtlcss) | ||
@@ -13,0 +12,0 @@ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-blue)](https://standardjs.com/) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61839
3
1448
36
+ Addedescalade@^3.1.1
+ Addedescalade@3.2.0(transitive)
- Removedfind-up@^5.0.0
- Removedfind-up@5.0.0(transitive)
- Removedlocate-path@6.0.0(transitive)
- Removedp-limit@3.1.0(transitive)
- Removedp-locate@5.0.0(transitive)
- Removedpath-exists@4.0.0(transitive)
- Removedyocto-queue@0.1.0(transitive)
Updatedpostcss@^8.4.6