Selaa lähdekoodia

feat: add scss var in #{} case

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup

chore:backup
DaiQiangReal 3 vuotta sitten
vanhempi
sitoutus
ffb9734d13

+ 14 - 3
packages/semi-scss-to-css-var/src/index.ts

@@ -3,7 +3,7 @@ import fs from 'fs-extra';
 import os from 'os';
 import postcss from "postcss";
 import postcssScss from 'postcss-scss';
-import transVarPlugin from "./transVarPlugin";
+import { getScssVariableNotUsedInSelectorSetPlugin,transVarPlugin } from "./transVarPlugin";
 
 export interface Options {
     sourcePath: string,
@@ -55,12 +55,19 @@ const getAllScssFilesInPath = (filePath: string) => {
 
 
 const transScssToCSSVar=(scssFilePathList:string[])=>{
-
+    //scssFilePathList=['./test/test.scss'];
+    let allCssDefine:{key:string,value:string}[] =[];
     for (const scssFilePath of scssFilePathList){
         try {
             const raw=fs.readFileSync(scssFilePath,{ encoding:'utf-8' });
-            const result=postcss([transVarPlugin()]).process(raw, { syntax: postcssScss });
+            const scssVariableInSelectorSet = new Set<string>();
+            postcss([getScssVariableNotUsedInSelectorSetPlugin(scssVariableInSelectorSet)]).process(raw, { syntax: postcssScss }).css;
+
+            const cssDefine :{key:string,value:string}[]=[];
+            const result=postcss([transVarPlugin(scssVariableInSelectorSet,cssDefine)]).process(raw, { syntax: postcssScss });
             fs.writeFileSync(scssFilePath,result.css,"utf8");
+            allCssDefine=[...allCssDefine,...cssDefine];
+
         } catch (e){
             console.error(e);
             console.error(`Error While processing ${scssFilePath}`);
@@ -68,6 +75,10 @@ const transScssToCSSVar=(scssFilePathList:string[])=>{
 
     }
 
+    fs.writeFileSync('allCSSVar.scss',(()=>{
+        return `.allCSSVar{\n${allCssDefine.map(({ key,value })=>{return `${key}:${value};`;}).join('\n')}\n}`;
+    })(),'utf-8');
+
 };
 
 

+ 42 - 14
packages/semi-scss-to-css-var/src/transVarPlugin/index.ts

@@ -1,4 +1,4 @@
-import { AcceptedPlugin, Declaration, Postcss, Root } from "postcss";
+import { AcceptedPlugin, Declaration, Postcss, Root, Rule } from "postcss";
 import fs from 'fs-extra';
 import parse from 'postcss-value-parser';
 import replaceWithCalc from "../utils/replaceWithCalc";
@@ -11,9 +11,33 @@ import { trimStart } from "lodash";
 // let extraScss="";
 
 
-const transVarPlugin=()=>{
 
 
+const getScssVariableNotUsedInSelectorSetPlugin=(scssVariableInSelectorSet:Set<string>)=>{
+    return {
+        postcssPlugin:"semi-scss-get-scss-var-in-selector-plugin",
+        Root(root:Root,postcss:Postcss){
+            //console.log(root)
+        },
+        Once(root:Root){
+            //  console.log(root)
+        },
+        Rule(rule){
+            if (/#\{\$[\w\d]+\}/.test(rule.selector)){
+                const matches=rule.selector.matchAll(/#\{(\$[\w\d]+)\}/g);
+                for (const match of matches){
+                    if (match[1]){
+                        scssVariableInSelectorSet.add(match[1]);
+                    }
+                }
+            }
+        }
+
+    } as AcceptedPlugin;
+};
+
+
+const transVarPlugin=(scssVariableInSelectorSet:Set<string>,extraCssVarDefineList:{key:string,value:string}[])=>{
 
     return {
         postcssPlugin:"semi-scss-to-css-var-plugin",
@@ -24,8 +48,6 @@ const transVarPlugin=()=>{
             //  console.log(root)
         },
         Declaration(decl:Declaration){
-
-
             //@ts-ignore
             if (!decl.isVisited){
                 let value = decl.value;
@@ -33,16 +55,18 @@ const transVarPlugin=()=>{
                 value = replaceWithCalc(value);
                 decl.value=value;
 
-
                 //inject css variable define
-                if (/\$[\w\d]+$/.test(decl.prop)){
-                    const scssVariable=trimStart(decl.prop,'$');
-                    const cssVariable =`--semi-css-${scssVariable}`;
-                    const cssDeclaration=new Declaration({ prop:cssVariable,value:decl.value });
-                    //@ts-ignore
-                    cssDeclaration.isVisited=true;
-                    decl.after(cssDeclaration);
-                    decl.value=`var(${cssVariable})`;
+                if (/\$[\w\d_-]+$/.test(decl.prop)){
+                    if (!scssVariableInSelectorSet.has(decl.prop)){
+                        const scssVariable=trimStart(decl.prop,'$');
+                        const cssVariable =`--semi-css-${scssVariable}`;
+                        // const cssDeclaration=new Declaration({ prop:cssVariable,value:decl.value });
+                        // //@ts-ignore
+                        // cssDeclaration.isVisited=true;
+                        // decl.after(cssDeclaration);
+                        extraCssVarDefineList.push({ key:cssVariable,value:decl.value });
+                        decl.value=`var(${cssVariable})`;
+                    }
                 }
                 //@ts-ignore
                 decl.isVisited=true;
@@ -55,8 +79,12 @@ const transVarPlugin=()=>{
 
 
 transVarPlugin.postcss=true;
+getScssVariableNotUsedInSelectorSetPlugin.postcss=true;
 
 
 
 
-export default transVarPlugin;
+export {
+    transVarPlugin,
+    getScssVariableNotUsedInSelectorSetPlugin
+};

+ 63 - 23
packages/semi-scss-to-css-var/src/utils/getReplaceCalcIndex.ts

@@ -65,32 +65,68 @@ const getReplaceCalcIndex = (str: string) => {
 
 
     const detectScssVar = (autoJump: boolean = false, variables: 'left' | 'right' = 'right'): [boolean, number] => {
-        let jumpCount = 0;
-        const startIndex = variables === 'left' ? left : right;
-        if (!str[startIndex]) {
-            return [false, 0];
-        }
-        if (str[startIndex] !== '$') {
-            return [false, jumpCount];
-        } else {
-            jumpCount++;
-        }
-        while (true) {
-            const char = str[startIndex + jumpCount];
-            if (char && /[a-zA-Z_\-0-9]/.test(char)) {
-                jumpCount++;
+        const detectBucketScssVar=(): [boolean, number]=>{
+            // #{$a} case
+            const startIndex=variables === 'left' ? left : right;
+            if (str.slice(startIndex).startsWith('#{')){
+                let jumpCount=2;
+                while (true){
+                    if (!str[startIndex + jumpCount]){
+                        throw  new Error(`Error: while find '} in ${str} for '#{', reach end.`);
+                    }
+                    if (str[startIndex + jumpCount]==='}'){
+                        jumpCount++;
+                        break;
+                    } else {
+                        jumpCount++;
+                    }
+                }
+                if (autoJump){
+                    if (variables === 'left') {
+                        left += jumpCount;
+                    } else {
+                        right += jumpCount;
+                    }
+                }
+                return [true,jumpCount];
+
             } else {
-                break;
+                return [false,0];
             }
-        }
-        if (autoJump) {
-            if (variables === 'left') {
-                left += jumpCount;
+        };
+        const detectCommonScssVar = (): [boolean, number]=>{
+            let jumpCount = 0;
+            const startIndex = variables === 'left' ? left : right;
+            if (!str[startIndex]) {
+                return [false, 0];
+            }
+            if (str[startIndex] !== '$') {
+                return [false, jumpCount];
             } else {
-                right += jumpCount;
+                jumpCount++;
             }
+            while (true) {
+                const char = str[startIndex + jumpCount];
+                if (char && /[a-zA-Z_\-0-9]/.test(char)) {
+                    jumpCount++;
+                } else {
+                    break;
+                }
+            }
+            if (autoJump) {
+                if (variables === 'left') {
+                    left += jumpCount;
+                } else {
+                    right += jumpCount;
+                }
+            }
+            return [true, jumpCount];
+        };
+        const [bucketScssVarFlag,bucketScssVarCount]=detectBucketScssVar();
+        if (bucketScssVarFlag){
+            return [bucketScssVarFlag,bucketScssVarCount];
         }
-        return [true, jumpCount];
+        return detectCommonScssVar();
     };
 
     const detectConst = (autoJump: boolean = false, variable: 'left' | 'right' = 'right'): [boolean, number] => {
@@ -106,7 +142,7 @@ const getReplaceCalcIndex = (str: string) => {
         }
         while (true) {
             const char = str[startIndex + jumpCount];
-            if (char && /\w|\d/.test(char)) {
+            if (char && /\w|\d|\.|%/.test(char)) {
                 jumpCount++;
             } else {
                 break;
@@ -283,7 +319,11 @@ const test_getReplaceCalcIndex = () => {
         "2px $a - ($b + ($x + $y)+ $c)": [{ start: 4, end: 28 }],
         "calc(1vh + 2px) (1 + $a - (1 + $c)) 2px calc(1vh + 3px)": [{ start: 5, end: 13 }, { start: 17, end: 33 }, { start: 45, end: 53 }],
         "$a + 1px + $b solid var(--semi-color-primary)": [{ start: 0, end: 12 }],
-        "$a + $b": [{ start: 0, end: 6 }]
+        "$a + $b": [{ start: 0, end: 6 }],
+        "calc( 1 + #{$a})":[{ start:6,end:14 }],
+        //todo  edge case
+        "($height-scrollList - $height-scrollList_item) / 2":[],
+        "calc(100% - 27px)":[],
     }));
     testUnit(testCase,getReplaceCalcIndex);
 

+ 344 - 1
packages/semi-scss-to-css-var/test/test.scss

@@ -1 +1,344 @@
-$a  :1px;
+$module: #{$prefix}-steps;
+$item: #{$module}-item;
+$basicType: #{$module}-basic;
+
+.#{$basicType} {
+
+  &.#{$module}-horizontal {
+    &.#{$module}-hasline {
+      .#{$item}-title {
+
+        &::after {
+          content: "";
+          position: absolute;
+          top: 50%;
+          left: 100%;
+          display: block;
+          width: $width-steps_title_after;
+          height: $height-steps_title_after;
+          background: $color-steps_title_after-bg;
+        }
+      }
+    }
+
+    display: flex;
+    flex-flow: row nowrap;
+
+    .#{$item} {
+      padding-left: $spacing-steps_basic_item-paddingLeft;
+
+      &:first-child {
+        padding-left: 0;
+      }
+
+      &:last-child {
+        flex: none;
+
+        .#{$item}-title {
+          max-width: 100%;
+          padding-right: 0;
+
+          &::after {
+            display: none;
+          }
+        }
+      }
+
+      &-done {
+        .#{$item}-container {
+          .#{$item}-title {
+
+            &::after {
+              background: $color-steps_item_done_after-bg;
+            }
+          }
+        }
+      }
+
+      .#{$item}-content {
+        flex: 1;
+      }
+
+      .#{$item}-description {
+        @include font-size-small;
+        color: $color-steps_minor-text-default;
+        width: $width-steps_basic_item_description;
+        max-width: $width-steps_basic_item_description-maxWidth;
+        @include text-overflow-hidden;
+      }
+
+      .#{$item}-title {
+        max-width: $width-steps_basic_item_title-maxWidth;
+
+        .#{$item}-title-text {
+          @include text-overflow-hidden;
+        }
+      }
+
+    }
+  }
+
+  &.#{$module}-vertical {
+    display: flex;
+    flex-flow: column nowrap;
+
+    &.#{$module}-small {
+      .#{$item} {
+        .#{$item}-content {
+          min-height: $height-steps_basic_vertical_small_item_content-minHeight;
+        }
+      }
+    }
+
+    &.#{$module}-hasline {
+      .#{$item}-icon {
+
+        &::after {
+          content: "";
+          position: absolute;
+          top: 100%;
+          left: 50%;
+          display: block;
+          width: $width-steps_vertical_icon_after;
+          height: $height-steps_vertical_icon_after;
+          background: $color-steps_icon_after-bg;
+        }
+      }
+    }
+
+    .#{$item} {
+      padding-top: $spacing-steps_basic_vertical_item-paddingTop;
+
+      &:first-child {
+        padding-top: 0;
+      }
+
+      &:last-child {
+        .#{$item}-icon {
+
+          &::after {
+            display: none;
+          }
+        }
+      }
+
+      &-done {
+        .#{$item}-icon {
+
+          &::after {
+            background: $color-steps_item_done_icon_after-bg;
+          }
+        }
+      }
+
+      .#{$item}-content {
+        min-height: $height-steps_basic_vertical_icon_content-minHeight;
+        padding-bottom: $spacing-steps_basic_vertical_item_content-paddingBottom;
+      }
+
+      .#{$item}-icon {
+        display: inline-flex;
+        position: relative;
+        padding-bottom: $spacing-steps_basic_vertical_item_icon-paddingBottom;
+      }
+
+      .#{$item}-description {
+        @include font-size-small;
+        color: $color-steps_minor-text-default;
+        width: $width-steps_basic_vertical_item_description;
+      }
+
+      .#{$item}-title {
+        max-width: $width-steps_basic_vertical_item_title-maxWidth;
+
+        .#{$item}-title-text {
+          @include text-overflow-hidden;
+        }
+      }
+    }
+  }
+
+  .#{$item} {
+    @include box-sizing;
+    position: relative;
+    display: inline-block;
+    vertical-align: top;
+    overflow: hidden;
+    flex: 1;
+    cursor: pointer;
+
+    &:hover {
+
+      .#{$item}-title {
+        color: $color-steps_item_title-text-hover;
+      }
+
+      .#{$item}-description {
+        color: $color-steps_item_description-text-hover;
+      }
+    }
+
+    .#{$item}-container {
+      display: flex;
+      align-items: flex-start;
+    }
+    .#{$item}-left {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      margin-right: $spacing-steps_basic_item_left-marginRight;
+
+
+      .#{$item}-icon {
+        display: flex;
+        height: $height-steps_basic_item_left-icon;
+        align-items: center;
+      }
+
+      .#{$item}-number-icon {
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        width: $width-steps_basic_item_left_number-icon;
+        height: $height-steps_basic_item_left_number-icon;
+        @include font-size-header-6;
+        font-weight: $font-steps_basic_item_left_number_icon-fontWeight;
+        background: $color-steps_item_left_number_icon-bg;
+        border-radius: $radius-steps_basic_item_left_number_icon;
+        color: $color-steps_item_left_number_icon-icon;
+
+      }
+    }
+
+
+    .#{$item}-title {
+      position: relative;
+      display: inline-block;
+      @include font-size-header-6;
+      line-height: $font-steps_basic_item_title-lineHeight;
+      font-weight: $font-steps_basic_item_title-fontWeight;
+      color: $color-steps_main-text-default;
+      vertical-align: top;
+      padding-right: $spacing-steps_basic_item_title-paddingRight;
+      padding-bottom: $spacing-steps_basic_item_title-paddingBottom;
+    }
+
+    // 完成状态的样式
+
+    &-finish {
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          color: $color-steps_item_finish-icon;
+
+          .#{$item}-number-icon {
+            color: $color-steps_item_finish_number-icon;
+          }
+        }
+      }
+
+
+    }
+
+    // 等待状态的样式
+
+    &-wait {
+      .#{$item}-title {
+        color: $color-steps_item_wait_title-text;
+      }
+
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          color: $color-steps_item_wait_left_icon-icon;
+
+          .#{$item}-number-icon {
+            background: $color-steps_item_wait_left_number_icon-bg;
+            color: $color-steps_item_wait_left_number_icon-icon;
+          }
+        }
+      }
+
+      &:hover {
+        .#{$item}-left {
+
+          .#{$item}-icon {
+
+            .#{$item}-number-icon {
+              background: $color-steps_item_wait_left_number_icon-bg-hover;
+              color: $color-steps_item_wait_left_number_icon-icon-hover;
+            }
+          }
+        }
+      }
+    }
+
+    // 进行状态的样式
+
+    &-process {
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          color: $color-steps_item_process_left-icon;
+
+          .#{$item}-number-icon {
+            color: $color-steps_item_process_left_number-icon;
+          }
+        }
+      }
+    }
+
+    // 错误状态的样式
+
+    &-error {
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          color: $color-steps_item_error_left-icon;
+
+          .#{$item}-number-icon {
+            color: $color-steps_item_error_left_number-icon;
+          }
+        }
+      }
+    }
+
+    // 警告状态的样式
+
+    &-warning {
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          color: $color-steps_item_warning_left-icon;
+
+          .#{$item}-number-icon {
+            color: $color-steps_item_warning_left_number-icon;
+          }
+        }
+      }
+    }
+  }
+
+  &.#{$module}-small {
+
+    .#{$item} {
+
+      .#{$item}-title {
+        @include font-size-regular;
+      }
+
+      .#{$item}-left {
+
+        .#{$item}-icon {
+          height: $height-steps_basic_small_item_left-icon;
+
+          .#{$item}-number-icon {
+            @include font-size-small;
+            width: $width-steps_basic_small_item_left_number-icon;
+            height: $width-steps_basic_small_item_left_number-icon;
+          }
+        }
+      }
+    }
+  }
+}