@tbela99/css-parser 0.0.1-rc1 → 0.0.1-rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -91,10 +91,7 @@ function isHash(name) {
91
91
  if (name.charAt(0) != '#') {
92
92
  return false;
93
93
  }
94
- if (isIdent(name.charAt(1))) {
95
- return true;
96
- }
97
- return true;
94
+ return isIdent(name.charAt(1));
98
95
  }
99
96
  function isNumber(name) {
100
97
  if (name.length == 0) {
@@ -1070,6 +1067,21 @@ var config$1 = {
1070
1067
 
1071
1068
  const getConfig = () => config$1;
1072
1069
 
1070
+ const funcList = ['clamp', 'calc'];
1071
+ function matchType(val, properties) {
1072
+ if (val.typ == 'Iden' && properties.keywords.includes(val.val) ||
1073
+ (properties.types.includes(val.typ))) {
1074
+ return true;
1075
+ }
1076
+ if (val.typ == 'Number' && val.val == '0') {
1077
+ return properties.types.some(type => type == 'Length' || type == 'Angle');
1078
+ }
1079
+ if (val.typ == 'Func' && funcList.includes(val.val)) {
1080
+ return val.chi.every((t => ['Literal', 'Comma', 'Whitespace', 'Start-parens', 'End-parens'].includes(t.typ) || matchType(t, properties)));
1081
+ }
1082
+ return false;
1083
+ }
1084
+
1073
1085
  // name to color
1074
1086
  const COLORS_NAMES = Object.seal({
1075
1087
  'aliceblue': '#f0f8ff',
@@ -1564,6 +1576,7 @@ function hsl2rgb(h, s, l, a = null) {
1564
1576
  }
1565
1577
 
1566
1578
  function render(data, opt = {}) {
1579
+ const startTime = performance.now();
1567
1580
  const options = Object.assign(opt.minify ?? true ? {
1568
1581
  indent: '',
1569
1582
  newLine: '',
@@ -1582,7 +1595,9 @@ function render(data, opt = {}) {
1582
1595
  }
1583
1596
  return acc + renderToken(curr, options);
1584
1597
  }
1585
- return { code: doRender(data, options, reducer, 0) };
1598
+ return { code: doRender(data, options, reducer, 0), stats: {
1599
+ total: `${(performance.now() - startTime).toFixed(2)}ms`
1600
+ } };
1586
1601
  }
1587
1602
  // @ts-ignore
1588
1603
  function doRender(data, options, reducer, level = 0, indents = []) {
@@ -1595,6 +1610,8 @@ function doRender(data, options, reducer, level = 0, indents = []) {
1595
1610
  const indent = indents[level];
1596
1611
  const indentSub = indents[level + 1];
1597
1612
  switch (data.typ) {
1613
+ case 'Declaration':
1614
+ return `${data.nam}:${options.indent}${data.val.reduce((acc, curr) => acc + renderToken(curr), '')}`;
1598
1615
  case 'Comment':
1599
1616
  return options.removeComments ? '' : data.val;
1600
1617
  case 'StyleSheet':
@@ -1611,7 +1628,7 @@ function doRender(data, options, reducer, level = 0, indents = []) {
1611
1628
  case 'AtRule':
1612
1629
  case 'Rule':
1613
1630
  if (data.typ == 'AtRule' && !('chi' in data)) {
1614
- return `${indent}@${data.nam} ${data.val};`;
1631
+ return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
1615
1632
  }
1616
1633
  // @ts-ignore
1617
1634
  let children = data.chi.reduce((css, node) => {
@@ -1620,10 +1637,14 @@ function doRender(data, options, reducer, level = 0, indents = []) {
1620
1637
  str = options.removeComments ? '' : node.val;
1621
1638
  }
1622
1639
  else if (node.typ == 'Declaration') {
1640
+ if (node.val.length == 0) {
1641
+ console.error(`invalid declaration`, node);
1642
+ return '';
1643
+ }
1623
1644
  str = `${node.nam}:${options.indent}${node.val.reduce(reducer, '').trimEnd()};`;
1624
1645
  }
1625
1646
  else if (node.typ == 'AtRule' && !('chi' in node)) {
1626
- str = `@${node.nam} ${node.val};`;
1647
+ str = `${data.val === '' ? '' : options.indent || ' '}${data.val};`;
1627
1648
  }
1628
1649
  else {
1629
1650
  str = doRender(node, options, reducer, level + 1, indents);
@@ -1640,7 +1661,7 @@ function doRender(data, options, reducer, level = 0, indents = []) {
1640
1661
  children = children.slice(0, -1);
1641
1662
  }
1642
1663
  if (data.typ == 'AtRule') {
1643
- return `@${data.nam}${data.val ? ' ' + data.val + options.indent : ''}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
1664
+ return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
1644
1665
  }
1645
1666
  return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
1646
1667
  }
@@ -1790,7 +1811,9 @@ function renderToken(token, options = {}) {
1790
1811
  case 'Delim':
1791
1812
  return /* options.minify && 'Pseudo-class' == token.typ && '::' == token.val.slice(0, 2) ? token.val.slice(1) : */ token.val;
1792
1813
  }
1793
- throw new Error(`unexpected token ${JSON.stringify(token, null, 1)}`);
1814
+ console.error(`unexpected token ${JSON.stringify(token, null, 1)}`);
1815
+ // throw new Error(`unexpected token ${JSON.stringify(token, null, 1)}`);
1816
+ return '';
1794
1817
  }
1795
1818
 
1796
1819
  function eq(a, b) {
@@ -1996,17 +2019,6 @@ class PropertySet {
1996
2019
  }
1997
2020
  }
1998
2021
 
1999
- function matchType(val, properties) {
2000
- if (val.typ == 'Iden' && properties.keywords.includes(val.val) ||
2001
- (properties.types.includes(val.typ))) {
2002
- return true;
2003
- }
2004
- if (val.typ == 'Number' && val.val == '0') {
2005
- return properties.types.some(type => type == 'Length' || type == 'Angle');
2006
- }
2007
- return false;
2008
- }
2009
-
2010
2022
  const propertiesConfig = getConfig();
2011
2023
  class PropertyMap {
2012
2024
  config;
@@ -2021,6 +2033,9 @@ class PropertyMap {
2021
2033
  this.pattern = config.pattern.split(/\s/);
2022
2034
  }
2023
2035
  add(declaration) {
2036
+ for (const val of declaration.val) {
2037
+ Object.defineProperty(val, 'propertyName', { enumerable: false, writable: true, value: declaration.nam });
2038
+ }
2024
2039
  if (declaration.nam == this.config.shorthand) {
2025
2040
  this.declarations = new Map;
2026
2041
  this.declarations.set(declaration.nam, declaration);
@@ -2054,7 +2069,7 @@ class PropertyMap {
2054
2069
  i--;
2055
2070
  continue;
2056
2071
  }
2057
- if (matchType(acc[i], props)) {
2072
+ if (('propertyName' in acc[i] && acc[i].propertyName == property) || matchType(acc[i], props)) {
2058
2073
  if ('prefix' in props && props.previous != null && !(props.previous in tokens)) {
2059
2074
  return acc;
2060
2075
  }
@@ -2188,10 +2203,12 @@ class PropertyMap {
2188
2203
  }
2189
2204
  else {
2190
2205
  let count = 0;
2206
+ let match;
2191
2207
  const separator = this.config.separator;
2192
2208
  const tokens = {};
2193
2209
  // @ts-ignore
2194
- /* const valid: string[] =*/ Object.entries(this.config.properties).reduce((acc, curr) => {
2210
+ /* const valid: string[] =*/
2211
+ Object.entries(this.config.properties).reduce((acc, curr) => {
2195
2212
  if (!this.declarations.has(curr[0])) {
2196
2213
  if (curr[1].required) {
2197
2214
  acc.push(curr[0]);
@@ -2200,33 +2217,39 @@ class PropertyMap {
2200
2217
  }
2201
2218
  let current = 0;
2202
2219
  const props = this.config.properties[curr[0]];
2203
- const declaration = this.declarations.get(curr[0]);
2204
- // @ts-ignore
2205
- for (const val of (declaration instanceof PropertySet ? [...declaration][0] : declaration).val) {
2206
- if (separator != null && separator.typ == val.typ && eq(separator, val)) {
2207
- current++;
2208
- if (tokens[curr[0]].length == current) {
2209
- tokens[curr[0]].push([]);
2220
+ const properties = this.declarations.get(curr[0]);
2221
+ for (const declaration of [(properties instanceof PropertySet ? [...properties][0] : properties)]) {
2222
+ // @ts-ignore
2223
+ for (const val of declaration.val) {
2224
+ if (separator != null && separator.typ == val.typ && eq(separator, val)) {
2225
+ current++;
2226
+ if (tokens[curr[0]].length == current) {
2227
+ tokens[curr[0]].push([]);
2228
+ }
2229
+ continue;
2210
2230
  }
2211
- continue;
2212
- }
2213
- if (val.typ == 'Whitespace' || val.typ == 'Comment') {
2214
- continue;
2215
- }
2216
- if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(props.separator, val)) {
2217
- continue;
2218
- }
2219
- if (matchType(val, curr[1])) {
2220
- if (!(curr[0] in tokens)) {
2221
- tokens[curr[0]] = [[]];
2231
+ if (val.typ == 'Whitespace' || val.typ == 'Comment') {
2232
+ continue;
2233
+ }
2234
+ if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(props.separator, val)) {
2235
+ continue;
2236
+ }
2237
+ match = matchType(val, curr[1]);
2238
+ if (isShorthand) {
2239
+ isShorthand = match;
2240
+ }
2241
+ if (('propertyName' in val && val.propertyName == property) || match) {
2242
+ if (!(curr[0] in tokens)) {
2243
+ tokens[curr[0]] = [[]];
2244
+ }
2245
+ // is default value
2246
+ tokens[curr[0]][current].push(val);
2247
+ // continue;
2248
+ }
2249
+ else {
2250
+ acc.push(curr[0]);
2251
+ break;
2222
2252
  }
2223
- // is default value
2224
- tokens[curr[0]][current].push(val);
2225
- // continue;
2226
- }
2227
- else {
2228
- acc.push(curr[0]);
2229
- break;
2230
2253
  }
2231
2254
  }
2232
2255
  if (count == 0) {
@@ -2235,7 +2258,10 @@ class PropertyMap {
2235
2258
  return acc;
2236
2259
  }, []);
2237
2260
  count++;
2238
- if (!Object.values(tokens).every(v => v.length == count)) {
2261
+ if (!isShorthand || Object.entries(this.config.properties).some(entry => {
2262
+ // missing required property
2263
+ return entry[1].required && !(entry[0] in tokens);
2264
+ }) || !Object.values(tokens).every(v => v.length == count)) {
2239
2265
  // @ts-ignore
2240
2266
  iterable = this.declarations.values();
2241
2267
  }
@@ -2579,7 +2605,7 @@ function minify(ast, options = {}, recursive = false) {
2579
2605
  // @ts-ignore
2580
2606
  return null;
2581
2607
  }
2582
- return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node2 : node2 };
2608
+ return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 };
2583
2609
  }
2584
2610
  function matchSelectors(selector1, selector2, parentType) {
2585
2611
  let match = [[]];
@@ -2767,11 +2793,27 @@ function minify(ast, options = {}, recursive = false) {
2767
2793
  if (node.typ == 'AtRule' && node.nam == 'font-face') {
2768
2794
  continue;
2769
2795
  }
2770
- if (node.typ == 'AtRule' && node.val == 'all') {
2796
+ if (node.typ == 'AtRule') {
2797
+ if (node.nam == 'media' && node.val == 'all') {
2798
+ // @ts-ignore
2799
+ ast.chi?.splice(i, 1, ...node.chi);
2800
+ i--;
2801
+ continue;
2802
+ }
2803
+ // console.debug({previous, node});
2771
2804
  // @ts-ignore
2772
- ast.chi?.splice(i, 1, ...node.chi);
2773
- i--;
2774
- continue;
2805
+ if (previous?.typ == 'AtRule' &&
2806
+ previous.nam == node.nam &&
2807
+ previous.val == node.val) {
2808
+ if ('chi' in node) {
2809
+ // @ts-ignore
2810
+ previous.chi.push(...node.chi);
2811
+ }
2812
+ // else {
2813
+ ast?.chi?.splice(i--, 1);
2814
+ continue;
2815
+ // }
2816
+ }
2775
2817
  }
2776
2818
  // @ts-ignore
2777
2819
  if (node.typ == 'Rule') {
@@ -3286,10 +3328,11 @@ function* tokenize(iterator) {
3286
3328
  }
3287
3329
  buffer += quoteStr;
3288
3330
  while (value = peek()) {
3289
- if (ind >= iterator.length) {
3290
- yield pushToken(buffer, hasNewLine ? 'Bad-string' : 'Unclosed-string');
3291
- break;
3292
- }
3331
+ // if (ind >= iterator.length) {
3332
+ //
3333
+ // yield pushToken(buffer, hasNewLine ? 'Bad-string' : 'Unclosed-string');
3334
+ // break;
3335
+ // }
3293
3336
  if (value == '\\') {
3294
3337
  const sequence = peek(6);
3295
3338
  let escapeSequence = '';
@@ -3312,7 +3355,7 @@ function* tokenize(iterator) {
3312
3355
  // not hex or new line
3313
3356
  // @ts-ignore
3314
3357
  if (i == 1 && !isNewLine(codepoint)) {
3315
- buffer += sequence[i];
3358
+ buffer += value + sequence[i];
3316
3359
  next(2);
3317
3360
  continue;
3318
3361
  }
@@ -3332,11 +3375,12 @@ function* tokenize(iterator) {
3332
3375
  continue;
3333
3376
  }
3334
3377
  // buffer += value;
3335
- if (ind >= iterator.length) {
3336
- // drop '\\' at the end
3337
- yield pushToken(buffer);
3338
- break;
3339
- }
3378
+ // if (ind >= iterator.length) {
3379
+ //
3380
+ // // drop '\\' at the end
3381
+ // yield pushToken(buffer);
3382
+ // break;
3383
+ // }
3340
3384
  buffer += next(2);
3341
3385
  continue;
3342
3386
  }
@@ -3505,7 +3549,7 @@ function* tokenize(iterator) {
3505
3549
  buffer = '';
3506
3550
  break;
3507
3551
  }
3508
- buffer += value;
3552
+ buffer += prev() + value;
3509
3553
  break;
3510
3554
  case '"':
3511
3555
  case "'":
@@ -3707,6 +3751,7 @@ const funcLike = ['Start-parens', 'Func', 'UrlFunc', 'Pseudo-class-func'];
3707
3751
  * @param opt
3708
3752
  */
3709
3753
  async function parse$1(iterator, opt = {}) {
3754
+ const startTime = performance.now();
3710
3755
  const errors = [];
3711
3756
  const options = {
3712
3757
  src: '',
@@ -3845,7 +3890,7 @@ async function parse$1(iterator, opt = {}) {
3845
3890
  src: options.resolve(url, options.src).absolute
3846
3891
  }));
3847
3892
  });
3848
- bytesIn += root.bytesIn;
3893
+ bytesIn += root.stats.bytesIn;
3849
3894
  if (root.ast.chi.length > 0) {
3850
3895
  context.chi.push(...root.ast.chi);
3851
3896
  }
@@ -3891,13 +3936,6 @@ async function parse$1(iterator, opt = {}) {
3891
3936
  // rule
3892
3937
  if (delim.typ == 'Block-start') {
3893
3938
  const position = map.get(tokens[0]);
3894
- // if (context.typ == 'Rule') {
3895
- //
3896
- // if (tokens[0]?.typ == 'Iden') {
3897
- // errors.push({action: 'drop', message: 'invalid nesting rule', location: {src, ...position}});
3898
- // return null;
3899
- // }
3900
- // }
3901
3939
  const uniq = new Map;
3902
3940
  parseTokens(tokens, { minify: options.minify }).reduce((acc, curr, index, array) => {
3903
3941
  if (curr.typ == 'Whitespace') {
@@ -4073,21 +4111,30 @@ async function parse$1(iterator, opt = {}) {
4073
4111
  if (tokens.length > 0) {
4074
4112
  await parseNode(tokens);
4075
4113
  }
4114
+ const endParseTime = performance.now();
4076
4115
  if (options.minify) {
4077
4116
  if (ast.chi.length > 0) {
4078
4117
  minify(ast, options, true);
4079
4118
  }
4080
4119
  }
4081
- return { ast, errors, bytesIn };
4120
+ const endTime = performance.now();
4121
+ return {
4122
+ ast, errors, stats: {
4123
+ bytesIn,
4124
+ parse: `${(endParseTime - startTime).toFixed(2)}ms`,
4125
+ minify: `${(endTime - endParseTime).toFixed(2)}ms`,
4126
+ total: `${(endTime - startTime).toFixed(2)}ms`
4127
+ }
4128
+ };
4082
4129
  }
4083
4130
  function parseString(src, options = { location: false }) {
4084
- return [...tokenize(src)].map(t => {
4131
+ return parseTokens([...tokenize(src)].map(t => {
4085
4132
  const token = getTokenType(t.token, t.hint);
4086
4133
  if (options.location) {
4087
4134
  Object.assign(token, { loc: t.position });
4088
4135
  }
4089
4136
  return token;
4090
- });
4137
+ }));
4091
4138
  }
4092
4139
  function getTokenType(val, hint) {
4093
4140
  if (val === '' && hint == null) {
@@ -4429,19 +4476,17 @@ function parseTokens(tokens, options = {}) {
4429
4476
  async function transform$1(css, options = {}) {
4430
4477
  options = { minify: true, removeEmpty: true, ...options };
4431
4478
  const startTime = performance.now();
4432
- const parseResult = await parse$1(css, options);
4433
- const renderTime = performance.now();
4434
- const rendered = render(parseResult.ast, options);
4435
- const endTime = performance.now();
4436
- return {
4437
- ...parseResult, ...rendered, stats: {
4438
- bytesIn: parseResult.bytesIn,
4439
- bytesOut: rendered.code.length,
4440
- parse: `${(renderTime - startTime).toFixed(2)}ms`,
4441
- render: `${(endTime - renderTime).toFixed(2)}ms`,
4442
- total: `${(endTime - startTime).toFixed(2)}ms`
4443
- }
4444
- };
4479
+ return parse$1(css, options).then((parseResult) => {
4480
+ const rendered = render(parseResult.ast, options);
4481
+ return {
4482
+ ...parseResult, ...rendered, stats: {
4483
+ bytesOut: rendered.code.length,
4484
+ ...parseResult.stats,
4485
+ render: rendered.stats.total,
4486
+ total: `${(performance.now() - startTime).toFixed(2)}ms`
4487
+ }
4488
+ };
4489
+ });
4445
4490
  }
4446
4491
 
4447
4492
  const matchUrl = /^(https?:)?\/\//;
@@ -4586,6 +4631,7 @@ exports.isResolution = isResolution;
4586
4631
  exports.isTime = isTime;
4587
4632
  exports.isWhiteSpace = isWhiteSpace;
4588
4633
  exports.load = load;
4634
+ exports.matchType = matchType;
4589
4635
  exports.matchUrl = matchUrl;
4590
4636
  exports.minify = minify;
4591
4637
  exports.minifyRule = minifyRule;
package/dist/index.d.ts CHANGED
@@ -173,6 +173,30 @@ interface AttrToken {
173
173
  }
174
174
  declare type Token = LiteralToken | IdentToken | CommaToken | ColonToken | SemiColonToken | NumberToken | AtRuleToken | PercentageToken | FunctionURLToken | FunctionToken | DimensionToken | LengthToken | AngleToken | StringToken | TimeToken | FrequencyToken | ResolutionToken | UnclosedStringToken | HashToken | BadStringToken | BlockStartToken | BlockEndToken | AttrStartToken | AttrEndToken | ParensStartToken | ParensEndToken | CDOCommentToken | BadCDOCommentToken | CommentToken | BadCommentToken | WhitespaceToken | IncludesToken | DashMatchToken | LessThanToken | GreaterThanToken | PseudoClassToken | PseudoClassFunctionToken | DelimToken | BadUrlToken | UrlToken | ImportantToken | ColorToken | AttrToken | EOFToken;
175
175
 
176
+ interface PropertyMapType {
177
+ default: string[];
178
+ types: string[];
179
+ keywords: string[];
180
+ required?: boolean;
181
+ multiple?: boolean;
182
+ prefix?: {
183
+ typ: 'Literal';
184
+ val: string;
185
+ };
186
+ previous?: string;
187
+ separator?: {
188
+ typ: 'Comma';
189
+ };
190
+ constraints?: {
191
+ [key: string]: {
192
+ [key: string]: any;
193
+ };
194
+ };
195
+ mapping?: {
196
+ [key: string]: any;
197
+ };
198
+ }
199
+
176
200
  interface PropertiesConfig {
177
201
  properties: PropertiesConfigProperties;
178
202
  map: Map;
@@ -487,11 +511,19 @@ interface TransformOptions extends ParserOptions, RenderOptions {
487
511
  interface ParseResult {
488
512
  ast: AstRuleStyleSheet;
489
513
  errors: ErrorDescription[];
490
- bytesIn: number;
514
+ stats: {
515
+ bytesIn: number;
516
+ parse: string;
517
+ minify: string;
518
+ total: string;
519
+ }
491
520
  }
492
521
 
493
522
  interface RenderResult {
494
523
  code: string ;
524
+ stats: {
525
+ total: string;
526
+ }
495
527
  }
496
528
 
497
529
  interface TransformResult extends ParseResult, RenderResult {
@@ -500,6 +532,7 @@ interface TransformResult extends ParseResult, RenderResult {
500
532
  bytesIn: number;
501
533
  bytesOut: number;
502
534
  parse: string;
535
+ minify: string;
503
536
  render: string;
504
537
  total: string;
505
538
  }
@@ -620,6 +653,8 @@ declare function isWhiteSpace(codepoint: number): boolean;
620
653
 
621
654
  declare const getConfig: () => PropertiesConfig;
622
655
 
656
+ declare function matchType(val: Token, properties: PropertyMapType): boolean;
657
+
623
658
  declare function render(data: AstNode, opt?: RenderOptions): RenderResult;
624
659
  declare function renderToken(token: Token, options?: RenderOptions): string;
625
660
 
@@ -652,4 +687,4 @@ declare function resolve(url: string, currentDirectory: string, cwd?: string): {
652
687
  declare function parse(iterator: string, opt?: ParserOptions): Promise<ParseResult>;
653
688
  declare function transform(css: string, options?: TransformOptions): Promise<TransformResult>;
654
689
 
655
- export { combinators, dirname, getConfig, hasDeclaration, isAngle, isAtKeyword, isDigit, isDimension, isFrequency, isFunction, isHash, isHexColor, isHexDigit, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNumber, isPercentage, isPseudo, isResolution, isTime, isWhiteSpace, load, matchUrl, minify, minifyRule, parse, parseDimension, parseString, reduceSelector, render, renderToken, resolve, tokenize, transform, urlTokenMatcher, walk };
690
+ export { combinators, dirname, getConfig, hasDeclaration, isAngle, isAtKeyword, isDigit, isDimension, isFrequency, isFunction, isHash, isHexColor, isHexDigit, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNumber, isPercentage, isPseudo, isResolution, isTime, isWhiteSpace, load, matchType, matchUrl, minify, minifyRule, parse, parseDimension, parseString, reduceSelector, render, renderToken, resolve, tokenize, transform, urlTokenMatcher, walk };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export { parseString, urlTokenMatcher } from './lib/parser/parse.js';
3
3
  export { tokenize } from './lib/parser/tokenize.js';
4
4
  export { isAngle, isAtKeyword, isDigit, isDimension, isFrequency, isFunction, isHash, isHexColor, isHexDigit, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNumber, isPercentage, isPseudo, isResolution, isTime, isWhiteSpace, parseDimension } from './lib/parser/utils/syntax.js';
5
5
  export { getConfig } from './lib/parser/utils/config.js';
6
+ export { matchType } from './lib/parser/utils/type.js';
6
7
  export { render, renderToken } from './lib/renderer/render.js';
7
8
  export { combinators, hasDeclaration, minify, minifyRule, reduceSelector } from './lib/ast/minify.js';
8
9
  export { walk } from './lib/ast/walk.js';
@@ -135,7 +135,7 @@ function minify(ast, options = {}, recursive = false) {
135
135
  // @ts-ignore
136
136
  return null;
137
137
  }
138
- return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node2 : node2 };
138
+ return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 };
139
139
  }
140
140
  function matchSelectors(selector1, selector2, parentType) {
141
141
  let match = [[]];
@@ -323,11 +323,27 @@ function minify(ast, options = {}, recursive = false) {
323
323
  if (node.typ == 'AtRule' && node.nam == 'font-face') {
324
324
  continue;
325
325
  }
326
- if (node.typ == 'AtRule' && node.val == 'all') {
326
+ if (node.typ == 'AtRule') {
327
+ if (node.nam == 'media' && node.val == 'all') {
328
+ // @ts-ignore
329
+ ast.chi?.splice(i, 1, ...node.chi);
330
+ i--;
331
+ continue;
332
+ }
333
+ // console.debug({previous, node});
327
334
  // @ts-ignore
328
- ast.chi?.splice(i, 1, ...node.chi);
329
- i--;
330
- continue;
335
+ if (previous?.typ == 'AtRule' &&
336
+ previous.nam == node.nam &&
337
+ previous.val == node.val) {
338
+ if ('chi' in node) {
339
+ // @ts-ignore
340
+ previous.chi.push(...node.chi);
341
+ }
342
+ // else {
343
+ ast?.chi?.splice(i--, 1);
344
+ continue;
345
+ // }
346
+ }
331
347
  }
332
348
  // @ts-ignore
333
349
  if (node.typ == 'Rule') {
@@ -1,7 +1,7 @@
1
1
  import { eq } from '../utils/eq.js';
2
2
  import { getConfig } from '../utils/config.js';
3
- import { renderToken } from '../../renderer/render.js';
4
3
  import { matchType } from '../utils/type.js';
4
+ import { renderToken } from '../../renderer/render.js';
5
5
  import { parseString } from '../parse.js';
6
6
  import { PropertySet } from './set.js';
7
7
 
@@ -19,6 +19,9 @@ class PropertyMap {
19
19
  this.pattern = config.pattern.split(/\s/);
20
20
  }
21
21
  add(declaration) {
22
+ for (const val of declaration.val) {
23
+ Object.defineProperty(val, 'propertyName', { enumerable: false, writable: true, value: declaration.nam });
24
+ }
22
25
  if (declaration.nam == this.config.shorthand) {
23
26
  this.declarations = new Map;
24
27
  this.declarations.set(declaration.nam, declaration);
@@ -52,7 +55,7 @@ class PropertyMap {
52
55
  i--;
53
56
  continue;
54
57
  }
55
- if (matchType(acc[i], props)) {
58
+ if (('propertyName' in acc[i] && acc[i].propertyName == property) || matchType(acc[i], props)) {
56
59
  if ('prefix' in props && props.previous != null && !(props.previous in tokens)) {
57
60
  return acc;
58
61
  }
@@ -186,10 +189,12 @@ class PropertyMap {
186
189
  }
187
190
  else {
188
191
  let count = 0;
192
+ let match;
189
193
  const separator = this.config.separator;
190
194
  const tokens = {};
191
195
  // @ts-ignore
192
- /* const valid: string[] =*/ Object.entries(this.config.properties).reduce((acc, curr) => {
196
+ /* const valid: string[] =*/
197
+ Object.entries(this.config.properties).reduce((acc, curr) => {
193
198
  if (!this.declarations.has(curr[0])) {
194
199
  if (curr[1].required) {
195
200
  acc.push(curr[0]);
@@ -198,33 +203,39 @@ class PropertyMap {
198
203
  }
199
204
  let current = 0;
200
205
  const props = this.config.properties[curr[0]];
201
- const declaration = this.declarations.get(curr[0]);
202
- // @ts-ignore
203
- for (const val of (declaration instanceof PropertySet ? [...declaration][0] : declaration).val) {
204
- if (separator != null && separator.typ == val.typ && eq(separator, val)) {
205
- current++;
206
- if (tokens[curr[0]].length == current) {
207
- tokens[curr[0]].push([]);
206
+ const properties = this.declarations.get(curr[0]);
207
+ for (const declaration of [(properties instanceof PropertySet ? [...properties][0] : properties)]) {
208
+ // @ts-ignore
209
+ for (const val of declaration.val) {
210
+ if (separator != null && separator.typ == val.typ && eq(separator, val)) {
211
+ current++;
212
+ if (tokens[curr[0]].length == current) {
213
+ tokens[curr[0]].push([]);
214
+ }
215
+ continue;
208
216
  }
209
- continue;
210
- }
211
- if (val.typ == 'Whitespace' || val.typ == 'Comment') {
212
- continue;
213
- }
214
- if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(props.separator, val)) {
215
- continue;
216
- }
217
- if (matchType(val, curr[1])) {
218
- if (!(curr[0] in tokens)) {
219
- tokens[curr[0]] = [[]];
217
+ if (val.typ == 'Whitespace' || val.typ == 'Comment') {
218
+ continue;
219
+ }
220
+ if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(props.separator, val)) {
221
+ continue;
222
+ }
223
+ match = matchType(val, curr[1]);
224
+ if (isShorthand) {
225
+ isShorthand = match;
226
+ }
227
+ if (('propertyName' in val && val.propertyName == property) || match) {
228
+ if (!(curr[0] in tokens)) {
229
+ tokens[curr[0]] = [[]];
230
+ }
231
+ // is default value
232
+ tokens[curr[0]][current].push(val);
233
+ // continue;
234
+ }
235
+ else {
236
+ acc.push(curr[0]);
237
+ break;
220
238
  }
221
- // is default value
222
- tokens[curr[0]][current].push(val);
223
- // continue;
224
- }
225
- else {
226
- acc.push(curr[0]);
227
- break;
228
239
  }
229
240
  }
230
241
  if (count == 0) {
@@ -233,7 +244,10 @@ class PropertyMap {
233
244
  return acc;
234
245
  }, []);
235
246
  count++;
236
- if (!Object.values(tokens).every(v => v.length == count)) {
247
+ if (!isShorthand || Object.entries(this.config.properties).some(entry => {
248
+ // missing required property
249
+ return entry[1].required && !(entry[0] in tokens);
250
+ }) || !Object.values(tokens).every(v => v.length == count)) {
237
251
  // @ts-ignore
238
252
  iterable = this.declarations.values();
239
253
  }