Skip to content

Commit

Permalink
Merge pull request #48 from tbela99/fix_nesting_rules_expansion
Browse files Browse the repository at this point in the history
Fix nesting rules expansion
  • Loading branch information
tbela99 authored Sep 17, 2024
2 parents fbe89ba + 073751e commit 44e7e31
Show file tree
Hide file tree
Showing 19 changed files with 479 additions and 58 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/jsr.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# publish to jsr
name: Publish

on:
push:
branches:
Expand All @@ -9,9 +7,13 @@ on:
jobs:
publish:
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write # The OIDC ID token is used for authentication with JSR.
id-token: write

steps:
- uses: actions/checkout@v4
- run: npx jsr publish

- name: Publish package
run: npx jsr publish
36 changes: 20 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# Changelog

# v0.7.1

- [x] fix nesting rules expansion #45

#v0.7.0

- [x] fix merging rules
- [ ] experimental CSS prefix removal
- [x] declaration name
- [ ] declaration value
- [ ] exclude -webkit-* gradients
- [x] css selector validation
- [x] pseudo element
- [x] partial pseudo class validation. does not validate parameters
- [x] attribute selector
- [x] combinator
- [x] simple selector
- [x] nested selector
- [x] strict vs permissive validation: allow unknown items such as pseudo classes
- [x] allow unknown pseudo classes
- [x] allow unknown attribute selectors
- [x] css selector validation
- [x] pseudo element
- [x] partial pseudo class validation. does not validate parameters
- [x] attribute selector
- [x] combinator
- [x] simple selector
- [x] nested selector
- [x] strict vs permissive validation: allow unknown items such as pseudo classes
- [x] allow unknown pseudo classes
- [x] allow unknown attribute selectors
- [x] strip universal selector when possible

# v0.6.0
Expand All @@ -28,27 +32,27 @@

- [x] incorrectly expand css nesting rules

## V0.5.3
## v0.5.3

- [x] incorrectly expand css nesting rules

## V0.5.1
## v0.5.1

- [x] failed to flatten @import when using url() syntax

## V0.5.0
## v0.5.0

- [x] render node with parents
- [x] fix relative color from xyz
- [x] fix bug when inlineCss is true bug no css variable exists
- [x] compute more shorthands
- [x] (web) fetch imported css files from external domains using cors

## V0.4.1
## v0.4.1

no code change

## V0.4.0
## v0.4.0

Parsing

Expand All @@ -66,7 +70,7 @@ CSS color level 4 & 5
- [x] oklab()
- [x] oklch()

## V0.3.0
## v0.3.0

### shorthands

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
[![npm](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Ftbela99%2Fcss-parser%2Fmaster%2Fpackage.json&query=version&logo=npm&label=npm&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser) [![cov](https://tbela99.github.io/css-parser/badges/coverage.svg)](https://github.com/tbela99/css-parser/actions) [![NPM Downloads](https://img.shields.io/npm/dm/%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser)
[![npm](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Ftbela99%2Fcss-parser%2Fmaster%2Fpackage.json&query=version&logo=npm&label=npm&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser) [![npm](https://img.shields.io/jsr/v/%40tbela99/css-parser?link=https%3A%2F%2Fjsr.io%2F%40tbela99%2Fcss-parser
)](https://jsr.io/@tbela99/css-parser) [![cov](https://tbela99.github.io/css-parser/badges/coverage.svg)](https://github.com/tbela99/css-parser/actions) [![NPM Downloads](https://img.shields.io/npm/dm/%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser)

# css-parser

CSS parser and minifier for node and the browser

## Installation

From npm
```shell
$ npm install @tbela99/css-parser
```
from jsr
```shell
$ deno add @tbela99/css-parser
```


## Features

Expand Down
78 changes: 77 additions & 1 deletion dist/index-umd-web.js
Original file line number Diff line number Diff line change
Expand Up @@ -5760,6 +5760,13 @@
buffer = '';
}
break;
case '&':
if (buffer.length > 0) {
yield pushToken(buffer, parseInfo);
buffer = '';
}
yield pushToken(value, parseInfo);
break;
case '<':
if (buffer.length > 0) {
yield pushToken(buffer, parseInfo);
Expand Down Expand Up @@ -60872,7 +60879,67 @@
}
}
else {
rule.sel = replaceCompound(rule.sel, ast.sel);
let childSelectorCompund = [];
let withCompound = [];
let withoutCompound = [];
const rules = splitRule(ast.sel);
for (const sel of (rule.raw ?? splitRule(rule.sel))) {
const s = sel.join('');
if (s.includes('&')) {
if (s.indexOf('&', 1) == -1) {
if (s.at(0) == '&') {
if (s.at(1) == ' ') {
childSelectorCompund.push(s.slice(2));
}
else {
if (s == '&') {
withCompound.push(s);
}
else {
withoutCompound.push(s.slice(1));
}
}
}
}
else {
withCompound.push(s);
}
}
else {
withoutCompound.push(s);
}
}
const selectors = [];
const selector = rules.length > 1 ? ':is(' + rules.map(a => a.join('')).join(',') + ')' : rules[0].join('');
if (childSelectorCompund.length > 0) {
if (childSelectorCompund.length == 1) {
selectors.push(replaceCompound('& ' + childSelectorCompund[0].trim(), selector));
}
else {
selectors.push(replaceCompound('& :is(' + childSelectorCompund.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.trim(), '') + ')', selector));
}
}
if (withoutCompound.length > 0) {
if (withoutCompound.length == 1) {
const useIs = rules.length == 1 && selector.match(/^[a-zA-Z.:]/) != null && selector.includes(' ') && withoutCompound.length == 1 && withoutCompound[0].match(/^[a-zA-Z]+$/) != null;
const compound = useIs ? ':is(&)' : '&';
selectors.push(replaceCompound(rules.length == 1 ? (useIs ? withoutCompound[0] + ':is(&)' : (selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) ? withoutCompound[0] + compound : compound + withoutCompound[0])) : (withoutCompound[0].match(/^[a-zA-Z:]+$/) ? withoutCompound[0].trim() + compound : '&' + (withoutCompound[0].match(/^\S+$/) ? withoutCompound[0].trim() : ':is(' + withoutCompound[0].trim() + ')')), selector));
}
else {
selectors.push(replaceCompound('&:is(' + withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.trim(), '') + ')', selector));
}
}
if (withCompound.length > 0) {
if (withCompound.length == 1) {
selectors.push(replaceCompound(withCompound[0], selector));
}
else {
for (const w of withCompound) {
selectors.push(replaceCompound(w, selector));
}
}
}
rule.sel = selectors.reduce((acc, curr) => curr.length == 0 ? acc : acc + (acc.length > 0 ? ',' : '') + curr, '');
}
ast.chi.splice(i--, 1);
result.push(...expandRule(rule));
Expand Down Expand Up @@ -63355,6 +63422,9 @@
return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(parseResponse);
}

/**
* render ast node
*/
function render(data, options = {}) {
return doRender(data, Object.assign(options, {
load,
Expand All @@ -63363,6 +63433,9 @@
cwd: options.cwd ?? self.location.pathname.endsWith('/') ? self.location.pathname : dirname(self.location.pathname)
}));
}
/**
* parse css
*/
async function parse(iterator, opt = {}) {
return doParse(iterator, Object.assign(opt, {
load,
Expand All @@ -63371,6 +63444,9 @@
cwd: opt.cwd ?? self.location.pathname.endsWith('/') ? self.location.pathname : dirname(self.location.pathname)
}));
}
/**
* parse and render css
*/
async function transform(css, options = {}) {
options = { minify: true, removeEmpty: true, removeCharset: true, ...options };
const startTime = performance.now();
Expand Down
82 changes: 81 additions & 1 deletion dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5759,6 +5759,13 @@ function* tokenize(stream) {
buffer = '';
}
break;
case '&':
if (buffer.length > 0) {
yield pushToken(buffer, parseInfo);
buffer = '';
}
yield pushToken(value, parseInfo);
break;
case '<':
if (buffer.length > 0) {
yield pushToken(buffer, parseInfo);
Expand Down Expand Up @@ -60871,7 +60878,67 @@ function expandRule(node) {
}
}
else {
rule.sel = replaceCompound(rule.sel, ast.sel);
let childSelectorCompund = [];
let withCompound = [];
let withoutCompound = [];
const rules = splitRule(ast.sel);
for (const sel of (rule.raw ?? splitRule(rule.sel))) {
const s = sel.join('');
if (s.includes('&')) {
if (s.indexOf('&', 1) == -1) {
if (s.at(0) == '&') {
if (s.at(1) == ' ') {
childSelectorCompund.push(s.slice(2));
}
else {
if (s == '&') {
withCompound.push(s);
}
else {
withoutCompound.push(s.slice(1));
}
}
}
}
else {
withCompound.push(s);
}
}
else {
withoutCompound.push(s);
}
}
const selectors = [];
const selector = rules.length > 1 ? ':is(' + rules.map(a => a.join('')).join(',') + ')' : rules[0].join('');
if (childSelectorCompund.length > 0) {
if (childSelectorCompund.length == 1) {
selectors.push(replaceCompound('& ' + childSelectorCompund[0].trim(), selector));
}
else {
selectors.push(replaceCompound('& :is(' + childSelectorCompund.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.trim(), '') + ')', selector));
}
}
if (withoutCompound.length > 0) {
if (withoutCompound.length == 1) {
const useIs = rules.length == 1 && selector.match(/^[a-zA-Z.:]/) != null && selector.includes(' ') && withoutCompound.length == 1 && withoutCompound[0].match(/^[a-zA-Z]+$/) != null;
const compound = useIs ? ':is(&)' : '&';
selectors.push(replaceCompound(rules.length == 1 ? (useIs ? withoutCompound[0] + ':is(&)' : (selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) ? withoutCompound[0] + compound : compound + withoutCompound[0])) : (withoutCompound[0].match(/^[a-zA-Z:]+$/) ? withoutCompound[0].trim() + compound : '&' + (withoutCompound[0].match(/^\S+$/) ? withoutCompound[0].trim() : ':is(' + withoutCompound[0].trim() + ')')), selector));
}
else {
selectors.push(replaceCompound('&:is(' + withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.trim(), '') + ')', selector));
}
}
if (withCompound.length > 0) {
if (withCompound.length == 1) {
selectors.push(replaceCompound(withCompound[0], selector));
}
else {
for (const w of withCompound) {
selectors.push(replaceCompound(w, selector));
}
}
}
rule.sel = selectors.reduce((acc, curr) => curr.length == 0 ? acc : acc + (acc.length > 0 ? ',' : '') + curr, '');
}
ast.chi.splice(i--, 1);
result.push(...expandRule(rule));
Expand Down Expand Up @@ -63343,12 +63410,25 @@ async function load(url, currentFile) {
return matchUrl.test(resolved.absolute) ? fetch(resolved.absolute).then(parseResponse) : promises.readFile(resolved.absolute, { encoding: 'utf-8' });
}

/**
* entry point for node and other runtimes
* @module
*/
/**
* render ast node
*/
function render(data, options = {}) {
return doRender(data, Object.assign(options, { load, resolve, dirname, cwd: options.cwd ?? process.cwd() }));
}
/**
* parse css
*/
async function parse(iterator, opt = {}) {
return doParse(iterator, Object.assign(opt, { load, resolve, dirname, cwd: opt.cwd ?? process.cwd() }));
}
/**
* parse and render css
*/
async function transform(css, options = {}) {
options = { minify: true, removeEmpty: true, removeCharset: true, ...options };
const startTime = performance.now();
Expand Down
14 changes: 14 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1013,8 +1013,22 @@ declare function resolve(url: string, currentDirectory: string, cwd?: string): {

declare function load(url: string, currentFile: string): Promise<string>;

/**
* entry point for node and other runtimes
* @module
*/

/**
* render ast node
*/
declare function render(data: AstNode, options?: RenderOptions): RenderResult;
/**
* parse css
*/
declare function parse(iterator: string, opt?: ParserOptions): Promise<ParseResult>;
/**
* parse and render css
*/
declare function transform(css: string, options?: TransformOptions): Promise<TransformResult>;

export { EnumToken, dirname, expand, load, minify, parse, parseString, parseTokens, render, renderToken, resolve, transform, walk, walkValues };
Loading

0 comments on commit 44e7e31

Please sign in to comment.