Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v1.4.2

- [x] fix bug when using remove prefix #120

## v1.4.0

### CSS Module support
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,45 @@ console.debug(render(result.ast.chi[0].chi[1].chi[1], {withParents: true}));

```

### CSS Modules

CSS modules features are fully supported. refer to the [CSS modules](https://tbela99.github.io/css-parser/docs/documents/Guide.CSS_modules.html) documentation for more information.

```javascript
import {transform} from '@tbela99/css-parser';

const css = `
.table {
border-collapse: collapse;
width: 100%;
}

.table td, .table th {
border: 1px solid #ddd;
padding: 8px;
}

.table tr:nth-child(even){background-color: #f2f2f2;}

.table tr:hover {background-color: #ddd;}

.table th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #4CAF50;
color: white;
}
`;

const result = await transform(css, {module: true});

// css code
console.log(result.code);
// css mapping
console.log(result.mapping);
```

### Convert colors

```javascript
Expand Down
26 changes: 17 additions & 9 deletions dist/index-umd-web.js
Original file line number Diff line number Diff line change
Expand Up @@ -23205,6 +23205,7 @@
const combinators = ['+', '>', '~', '||', '|'];
const definedPropertySettings = { configurable: true, enumerable: false, writable: true };
const notEndingWith = ['(', '['].concat(combinators);
const rules = [exports.EnumToken.AtRuleNodeType, exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleTokenType, exports.EnumToken.KeyFramesRuleNodeType];
// @ts-ignore
const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
/**
Expand Down Expand Up @@ -23256,6 +23257,9 @@
if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || (feature.accept != null && !feature.accept.has(parent.typ))) {
continue;
}
if (rules.includes(replacement.typ) && !Array.isArray(replacement.tokens)) {
Object.defineProperty(replacement, 'tokens', { ...definedPropertySettings, value: parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ == exports.EnumToken.KeyFramesRuleNodeType ? replacement.sel : replacement.val) });
}
const result = feature.run(replacement, options, parent.parent ?? ast, context, exports.FeatureWalkMode.Pre);
if (result != null) {
replacement = result;
Expand Down Expand Up @@ -24636,26 +24640,30 @@
})(exports.ResponseType || (exports.ResponseType = {}));

/**
* default file or url loader
* load file or url
* @param url
* @param currentFile
*
* @param currentDirectory
* @param responseType
* @private
* @throws Error file not found
*
* ```ts
* import {load, ResponseType} from '@tbela99/css-parser';
* const result = await load(file, '.', ResponseType.ArrayBuffer) as ArrayBuffer;
* ```
*/
async function load(url, currentFile = '.', responseType = false) {
async function load(url, currentDirectory = '.', responseType = false) {
if (typeof responseType == 'boolean') {
responseType = responseType ? exports.ResponseType.ReadableStream : exports.ResponseType.Text;
}
let t;
if (matchUrl.test(url)) {
t = new URL(url);
}
else if (currentFile != null && matchUrl.test(currentFile)) {
t = new URL(url, currentFile);
else if (currentDirectory != null && matchUrl.test(currentDirectory)) {
t = new URL(url, currentDirectory);
}
else {
const path = resolve(url, currentFile).absolute;
const path = resolve(url, currentDirectory).absolute;
t = new URL(path, self.origin);
}
return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(async (response) => {
Expand All @@ -24665,7 +24673,7 @@
if (responseType == exports.ResponseType.ArrayBuffer) {
return response.arrayBuffer();
}
return responseType == exports.ResponseType.ReadableStream ? response.body : await response.text();
return responseType == exports.ResponseType.ReadableStream ? response.body : response.text();
});
}
/**
Expand Down
31 changes: 19 additions & 12 deletions dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23391,6 +23391,7 @@ var allFeatures = /*#__PURE__*/Object.freeze({
const combinators = ['+', '>', '~', '||', '|'];
const definedPropertySettings = { configurable: true, enumerable: false, writable: true };
const notEndingWith = ['(', '['].concat(combinators);
const rules = [exports.EnumToken.AtRuleNodeType, exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleTokenType, exports.EnumToken.KeyFramesRuleNodeType];
// @ts-ignore
const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
/**
Expand Down Expand Up @@ -23442,6 +23443,9 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || (feature.accept != null && !feature.accept.has(parent.typ))) {
continue;
}
if (rules.includes(replacement.typ) && !Array.isArray(replacement.tokens)) {
Object.defineProperty(replacement, 'tokens', { ...definedPropertySettings, value: parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ == exports.EnumToken.KeyFramesRuleNodeType ? replacement.sel : replacement.val) });
}
const result = feature.run(replacement, options, parent.parent ?? ast, context, exports.FeatureWalkMode.Pre);
if (result != null) {
replacement = result;
Expand Down Expand Up @@ -24637,16 +24641,19 @@ function replaceCompoundLiteral(selector, replace) {
}

/**
* load file or url as stream
* load file or url
* @param url
* @param currentFile
* @param currentDirectory
* @param responseType
* @throws Error file not found
*
* @private
* ```ts
* import {load, ResponseType} from '@tbela99/css-parser';
* const result = await load(file, '.', ResponseType.ArrayBuffer) as ArrayBuffer;
* ```
*/
async function load(url, currentFile = '.', responseType = false) {
const resolved = resolve(url, currentFile);
async function load(url, currentDirectory = '.', responseType = false) {
const resolved = resolve(url, currentDirectory);
if (typeof responseType == 'boolean') {
responseType = responseType ? exports.ResponseType.ReadableStream : exports.ResponseType.Text;
}
Expand All @@ -24658,18 +24665,18 @@ async function load(url, currentFile = '.', responseType = false) {
if (responseType == exports.ResponseType.ArrayBuffer) {
return response.arrayBuffer();
}
return responseType == exports.ResponseType.ReadableStream ? response.body : await response.text();
return responseType == exports.ResponseType.ReadableStream ? response.body : response.text();
});
}
try {
if (responseType == exports.ResponseType.Text) {
return promises.readFile(resolved.absolute, 'utf-8');
}
if (responseType == exports.ResponseType.ArrayBuffer) {
return promises.readFile(resolved.absolute).then(buffer => buffer.buffer);
}
const stats = await promises.lstat(resolved.absolute);
if (stats.isFile()) {
if (responseType == exports.ResponseType.Text) {
return promises.readFile(resolved.absolute, 'utf-8');
}
if (responseType == exports.ResponseType.ArrayBuffer) {
return promises.readFile(resolved.absolute).then(buffer => buffer.buffer);
}
return node_stream.Readable.toWeb(node_fs.createReadStream(resolved.absolute, {
encoding: 'utf-8',
highWaterMark: 64 * 1024
Expand Down
21 changes: 12 additions & 9 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3521,11 +3521,11 @@ export declare interface ParserOptions extends MinifyOptions, MinifyFeatureOptio
/**
* url and file loader
* @param url
* @param currentUrl
* @param asStream
* @param currentDirectory
* @param responseType
*
*/
load?: (url: string, currentUrl?: string, asStream?: boolean) => LoadResult;
load?: (url: string, currentDirectory: string, responseType?: boolean | ResponseType) => Promise<string | ArrayBuffer | ReadableStream<Uint8Array<ArrayBufferLike>>>;
/**
* get directory name
* @param path
Expand Down Expand Up @@ -4027,7 +4027,7 @@ declare function resolve(url: string, currentDirectory: string, cwd?: string): {
/**
* response type
*/
declare enum ResponseType {
declare enum ResponseType$1 {
/**
* return text
*/
Expand All @@ -4043,15 +4043,18 @@ declare enum ResponseType {
}

/**
* load file or url as stream
* load file or url
* @param url
* @param currentFile
* @param currentDirectory
* @param responseType
* @throws Error file not found
*
* @private
* ```ts
* import {load, ResponseType} from '@tbela99/css-parser';
* const result = await load(file, '.', ResponseType.ArrayBuffer) as ArrayBuffer;
* ```
*/
declare function load(url: string, currentFile?: string, responseType?: boolean | ResponseType): Promise<string | ArrayBuffer | ReadableStream<Uint8Array<ArrayBufferLike>>>;
declare function load(url: string, currentDirectory?: string, responseType?: boolean | ResponseType$1): Promise<string | ArrayBuffer | ReadableStream<Uint8Array<ArrayBufferLike>>>;
/**
* render the ast tree
* @param data
Expand Down Expand Up @@ -4222,5 +4225,5 @@ declare function transformFile(file: string, options?: TransformOptions, asStrea
*/
declare function transform(css: string | ReadableStream<Uint8Array>, options?: TransformOptions): Promise<TransformResult>;

export { ColorType, EnumToken, FeatureWalkMode, ModuleCaseTransformEnum, ModuleScopeEnumOptions, ResponseType, SourceMap, ValidationLevel, WalkerEvent, WalkerOptionEnum, convertColor, dirname, expand, isOkLabClose, load, mathFuncs, minify, okLabDistance, parse, parseDeclarations, parseFile, parseString, parseTokens, render, renderToken, resolve, transform, transformFile, transformFunctions, walk, walkValues };
export { ColorType, EnumToken, FeatureWalkMode, ModuleCaseTransformEnum, ModuleScopeEnumOptions, ResponseType$1 as ResponseType, SourceMap, ValidationLevel, WalkerEvent, WalkerOptionEnum, convertColor, dirname, expand, isOkLabClose, load, mathFuncs, minify, okLabDistance, parse, parseDeclarations, parseFile, parseString, parseTokens, render, renderToken, resolve, transform, transformFile, transformFunctions, walk, walkValues };
export type { AddToken, AngleToken, AstAtRule, AstComment, AstDeclaration, AstInvalidAtRule, AstInvalidDeclaration, AstInvalidRule, AstKeyFrameRule, AstKeyframesAtRule, AstKeyframesRule, AstNode$1 as AstNode, AstRule, AstRuleList, AstStyleSheet, AtRuleToken, AtRuleVisitorHandler, AttrEndToken, AttrStartToken, AttrToken, Background, BackgroundAttachmentMapping, BackgroundPosition, BackgroundPositionClass, BackgroundPositionConstraints, BackgroundPositionMapping, BackgroundProperties, BackgroundRepeat, BackgroundRepeatMapping, BackgroundSize, BackgroundSizeMapping, BadCDOCommentToken, BadCommentToken, BadStringToken, BadUrlToken, BaseToken, BinaryExpressionNode, BinaryExpressionToken, BlockEndToken, BlockStartToken, Border, BorderColor, BorderColorClass, BorderProperties, BorderRadius, CDOCommentToken, ChildCombinatorToken, ClassSelectorToken, ColonToken, ColorToken, ColumnCombinatorToken, CommaToken, CommentToken, ComposesSelectorToken, ConstraintsMapping, ContainMatchToken, Context, CssVariableImportTokenType$1 as CssVariableImportTokenType, CssVariableMapTokenType, CssVariableToken$1 as CssVariableToken, DashMatchToken, DashedIdentToken, DeclarationVisitorHandler, DelimToken, DescendantCombinatorToken, DimensionToken, DivToken, EOFToken, EndMatchToken, EqualMatchToken, ErrorDescription, FlexToken, Font, FontFamily, FontProperties, FontWeight, FontWeightConstraints, FontWeightMapping, FractionToken, FrequencyToken, FunctionImageToken, FunctionToken, FunctionURLToken, GenericVisitorAstNodeHandlerMap, GenericVisitorHandler, GenericVisitorResult, GreaterThanOrEqualToken, GreaterThanToken, GridTemplateFuncToken, HashToken, IdentListToken, IdentToken, ImportantToken, IncludeMatchToken, InvalidAttrToken, InvalidClassSelectorToken, LengthToken, LessThanOrEqualToken, LessThanToken, LineHeight, ListToken, LiteralToken, LoadResult, Location, Map$1 as Map, MatchExpressionToken, MatchedSelector, MediaFeatureAndToken, MediaFeatureNotToken, MediaFeatureOnlyToken, MediaFeatureOrToken, MediaFeatureToken, MediaQueryConditionToken, MinifyFeature, MinifyFeatureOptions, MinifyOptions, ModuleOptions, MulToken, NameSpaceAttributeToken, NestingSelectorToken, NextSiblingCombinatorToken, NumberToken, OptimizedSelector, OptimizedSelectorToken, Outline, OutlineProperties, ParensEndToken, ParensStartToken, ParensToken, ParseInfo, ParseResult, ParseResultStats, ParseTokenOptions, ParserOptions, PercentageToken, Position, Prefix, PropertiesConfig, PropertiesConfigProperties, PropertyListOptions, PropertyMapType, PropertySetType, PropertyType, PseudoClassFunctionToken, PseudoClassToken, PseudoElementToken, PseudoPageToken, PurpleBackgroundAttachment, RawSelectorTokens, RenderOptions, RenderResult, ResolutionToken, ResolvedPath, RuleVisitorHandler, SemiColonToken, Separator, ShorthandDef, ShorthandMapType, ShorthandProperties, ShorthandPropertyType, ShorthandType, SourceMapObject, StartMatchToken, StringToken, SubToken, SubsequentCombinatorToken, TimeToken, TimelineFunctionToken, TimingFunctionToken, Token$1 as Token, TokenizeResult, TransformOptions, TransformResult, UnaryExpression, UnaryExpressionNode, UnclosedStringToken, UniversalSelectorToken, UrlToken, ValidationConfiguration, ValidationOptions, ValidationResult, ValidationSelectorOptions, ValidationSyntaxNode, ValidationSyntaxResult, Value, ValueVisitorHandler, VariableScopeInfo, VisitorNodeMap, WalkAttributesResult, WalkResult, WalkerFilter, WalkerOption, WalkerValueFilter, WhitespaceToken };
6 changes: 5 additions & 1 deletion dist/lib/ast/minify.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { replaceToken, parseString } from '../parser/parse.js';
import { parseString, replaceToken } from '../parser/parse.js';
import '../parser/tokenize.js';
import '../parser/utils/config.js';
import { EnumToken } from './types.js';
Expand All @@ -13,6 +13,7 @@ import { FeatureWalkMode } from './features/type.js';
const combinators = ['+', '>', '~', '||', '|'];
const definedPropertySettings = { configurable: true, enumerable: false, writable: true };
const notEndingWith = ['(', '['].concat(combinators);
const rules = [EnumToken.AtRuleNodeType, EnumToken.RuleNodeType, EnumToken.AtRuleTokenType, EnumToken.KeyFramesRuleNodeType];
// @ts-ignore
const features = Object.values(index).sort((a, b) => a.ordering - b.ordering);
/**
Expand Down Expand Up @@ -64,6 +65,9 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
if ((feature.processMode & FeatureWalkMode.Pre) === 0 || (feature.accept != null && !feature.accept.has(parent.typ))) {
continue;
}
if (rules.includes(replacement.typ) && !Array.isArray(replacement.tokens)) {
Object.defineProperty(replacement, 'tokens', { ...definedPropertySettings, value: parseString(replacement.typ == EnumToken.RuleNodeType || replacement.typ == EnumToken.KeyFramesRuleNodeType ? replacement.sel : replacement.val) });
}
const result = feature.run(replacement, options, parent.parent ?? ast, context, FeatureWalkMode.Pre);
if (result != null) {
replacement = result;
Expand Down
29 changes: 16 additions & 13 deletions dist/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,24 @@ import './lib/validation/syntax.js';
import { resolve, matchUrl, dirname } from './lib/fs/resolve.js';
import { Readable } from 'node:stream';
import { createReadStream } from 'node:fs';
import { readFile, lstat } from 'node:fs/promises';
import { lstat, readFile } from 'node:fs/promises';
import { ResponseType } from './types.js';
export { FeatureWalkMode } from './lib/ast/features/type.js';

/**
* load file or url as stream
* load file or url
* @param url
* @param currentFile
* @param currentDirectory
* @param responseType
* @throws Error file not found
*
* @private
* ```ts
* import {load, ResponseType} from '@tbela99/css-parser';
* const result = await load(file, '.', ResponseType.ArrayBuffer) as ArrayBuffer;
* ```
*/
async function load(url, currentFile = '.', responseType = false) {
const resolved = resolve(url, currentFile);
async function load(url, currentDirectory = '.', responseType = false) {
const resolved = resolve(url, currentDirectory);
if (typeof responseType == 'boolean') {
responseType = responseType ? ResponseType.ReadableStream : ResponseType.Text;
}
Expand All @@ -47,18 +50,18 @@ async function load(url, currentFile = '.', responseType = false) {
if (responseType == ResponseType.ArrayBuffer) {
return response.arrayBuffer();
}
return responseType == ResponseType.ReadableStream ? response.body : await response.text();
return responseType == ResponseType.ReadableStream ? response.body : response.text();
});
}
try {
if (responseType == ResponseType.Text) {
return readFile(resolved.absolute, 'utf-8');
}
if (responseType == ResponseType.ArrayBuffer) {
return readFile(resolved.absolute).then(buffer => buffer.buffer);
}
const stats = await lstat(resolved.absolute);
if (stats.isFile()) {
if (responseType == ResponseType.Text) {
return readFile(resolved.absolute, 'utf-8');
}
if (responseType == ResponseType.ArrayBuffer) {
return readFile(resolved.absolute).then(buffer => buffer.buffer);
}
return Readable.toWeb(createReadStream(resolved.absolute, {
encoding: 'utf-8',
highWaterMark: 64 * 1024
Expand Down
22 changes: 13 additions & 9 deletions dist/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,30 @@ import { ResponseType } from './types.js';
export { FeatureWalkMode } from './lib/ast/features/type.js';

/**
* default file or url loader
* load file or url
* @param url
* @param currentFile
*
* @param currentDirectory
* @param responseType
* @private
* @throws Error file not found
*
* ```ts
* import {load, ResponseType} from '@tbela99/css-parser';
* const result = await load(file, '.', ResponseType.ArrayBuffer) as ArrayBuffer;
* ```
*/
async function load(url, currentFile = '.', responseType = false) {
async function load(url, currentDirectory = '.', responseType = false) {
if (typeof responseType == 'boolean') {
responseType = responseType ? ResponseType.ReadableStream : ResponseType.Text;
}
let t;
if (matchUrl.test(url)) {
t = new URL(url);
}
else if (currentFile != null && matchUrl.test(currentFile)) {
t = new URL(url, currentFile);
else if (currentDirectory != null && matchUrl.test(currentDirectory)) {
t = new URL(url, currentDirectory);
}
else {
const path = resolve(url, currentFile).absolute;
const path = resolve(url, currentDirectory).absolute;
t = new URL(path, self.origin);
}
return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(async (response) => {
Expand All @@ -51,7 +55,7 @@ async function load(url, currentFile = '.', responseType = false) {
if (responseType == ResponseType.ArrayBuffer) {
return response.arrayBuffer();
}
return responseType == ResponseType.ReadableStream ? response.body : await response.text();
return responseType == ResponseType.ReadableStream ? response.body : response.text();
});
}
/**
Expand Down
Loading