国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

淺析eslint原理

共 30165字,需瀏覽 61分鐘

 ·

2022-06-29 19:29

在前端開發(fā)過程中,eslint規(guī)范已經(jīng)成為必不可少的一環(huán),我們需要eslint來保證代碼規(guī)范,相對統(tǒng)一同學們的代碼風格,不然就會出現(xiàn)所有同學都隨意引入自己偏好的風格或者規(guī)范,讓所有人一起分擔引入規(guī)范的代價。

同時,有些lint規(guī)則可以避免bug的產(chǎn)生,在提高代碼可讀性的前提下,減少問題數(shù)量,將問題更多的暴露在開發(fā)階段。

一、eslint的規(guī)則

說起eslint,第一想到的就是eslints里面的每條規(guī)則,我們通過以下簡單的配置就可以來控制規(guī)則的開啟及關(guān)閉。其中:0 1 2 分別對應(yīng) 'off' 'warn' 'error';如果是個數(shù)組,第二個參數(shù)可以自定義配置。

{
  "rules": {
    "arrow-body-style" : 0, // 0 1 2
    "quotes" : [ "error" , "single" ]
  }
}

其中rules的每一個key就是對應(yīng)的一條規(guī)則,透過使用去思考,eslint如何去實現(xiàn)的這條規(guī)則呢???

eslint的核心rules

eslint 的核心就是 rules,理解一個 rule 的結(jié)構(gòu)對于理解 eslint 的原理和創(chuàng)建自定義規(guī)則非常重要。

我們看一下自定義eslint 規(guī)則[1] 再結(jié)合目前已有的某條規(guī)則來分析

看一下最簡單的一條規(guī)則 no-with

module.exports = {
    meta: {  // 包含規(guī)則的元數(shù)據(jù)
    // 指示規(guī)則的類型,值為 "problem"、"suggestion" 或 "layout"
        type"suggestion"
        
        docs: { // 對 ESLint 核心規(guī)則來說是必需的
            description: "disallow `with` statements", // 提供規(guī)則的簡短描述在規(guī)則首頁展示
            // category (string) 指定規(guī)則在規(guī)則首頁處于的分類
            recommended: true, // 配置文件中的 "extends""eslint:recommended"屬性是否啟用該規(guī)則
            url: "https://eslint.org/docs/rules/no-with" // 指定可以訪問完整文檔的 url
        },
        
        // fixable 如果沒有 fixable 屬性,即使規(guī)則實現(xiàn)了 fix 功能,ESLint 也不會進行修復。如果規(guī)則不是可修復的,就省略 fixable 屬性。

        schema: [], // 指定該選項 這樣的 ESLint 可以避免無效的規(guī)則配置
        
        // deprecated (boolean) 表明規(guī)則是已被棄用。如果規(guī)則尚未被棄用,你可以省略 deprecated 屬性。

        messages: {
            unexpectedWith: "Unexpected use of 'with' statement."
        }
    },
// create (function) 返回一個對象,其中包含了 ESLint 在遍歷 js 代碼的抽象語法樹 AST (ESTree 定義的 AST) 時,用來訪問節(jié)點的方法。
    create(context) {
// 如果一個 key 是個節(jié)點類型或 selector,在 向下 遍歷樹時,ESLint 調(diào)用 visitor 函數(shù)
// 如果一個 key 是個節(jié)點類型或 selector,并帶有 :exit,在 向上 遍歷樹時,ESLint 調(diào)用 visitor 函數(shù)
// 如果一個 key 是個事件名字,ESLint 為代碼路徑分析調(diào)用 handler 函數(shù)
// selector 類型可以到 estree 查找
        return {
            // 入?yún)楣?jié)點node
            WithStatement(node) {
                
                context.report({ node, messageId: "unexpectedWith" });
            }
        };

    }
};

有兩部分組成:meta create;

meta:(對象)包含規(guī)則的元數(shù)據(jù),包括 規(guī)則的類型,文檔,是否推薦規(guī)則,是否可修復等信息;

creat:(函數(shù))返回一個對象其中包含了 ESLint 在遍歷 JavaScript 代碼的抽象語法樹 AST (ESTree[2] 定義的 AST) 時,用來訪問節(jié)點的方法,入?yún)樵摴?jié)點。

  • 如果一個 key 是個節(jié)點類型或 selector[3],在 向下 遍歷樹時,ESLint 調(diào)用 visitor 函數(shù)
  • 如果一個 key 是個節(jié)點類型或 selector[4],并帶有 :exit,在 向上 遍歷樹時,ESLint 調(diào)用 visitor 函數(shù)
  • 如果一個 key 是個事件名字,ESLint 為代碼路徑分析[5]調(diào)用 handler 函數(shù)

二、eslint 命令的執(zhí)行

在package.json里配置bin

"bin": {
  "eslint""bin/eslint.js" // 告訴 npm 你的命令是什么
}

然后創(chuàng)建對應(yīng)的文件

#!/usr/bin/env node
console.log("console.log output")

這就是eslint命令行的入口

(async function main() {
    // 監(jiān)聽異常處理
    process.on("uncaughtException", onFatalError);
    process.on("unhandledRejection", onFatalError);

    // 如果參數(shù)有 --init 就執(zhí)行初始化
    if (process.argv.includes("--init")) {
        await require("../lib/init/config-initializer").initializeConfig();
        return;
    }

    // 否則就執(zhí)行 檢查代碼的代碼
    process.exitCode = await require("../lib/cli").execute(
        process.argv,
        process.argv.includes("--stdin") ? await readStdin() : null
    );
}()).catch(onFatalError);

代碼檢查的函數(shù)是 cli.execute() ****從lib中引入的cli對象。

三、eslint 執(zhí)行的調(diào)用棧

execute() 函數(shù)

這是 eslint 的主要代碼執(zhí)行邏輯,主要流程如下:

  1. 解析命令行參數(shù),校驗參數(shù)正確與否及打印相關(guān)信息;
  2. 初始化 根據(jù)配置實例一個engine對象CLIEngine 實例;
  3. engine.executeOnFiles 讀取源代碼進行檢查,返回報錯信息和修復結(jié)果。
execute(args, text) {
        if (Array.isArray(args)) {
            debug("CLI args: %o", args.slice(2));
        }
        let currentOptions;
        try {
        // 先校驗參數(shù) 如果輸入 --halp 提示 --help,并通過options的配置給默認值
            currentOptions = options.parse(args);
        } catch (error) {
            log.error(error.message);
            return 2;
        }

        const files = currentOptions._;
        const useStdin = typeof text === "string";

        // ---省略很多---參數(shù)校驗及輸出
        // ...
        // 根據(jù)配置實例一個engine對象
        const engine = new CLIEngine(translateOptions(currentOptions));
        // report 就是最后的結(jié)果
        const report = useStdin ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files);
        // ...
        // ---省略很多---參數(shù)校驗及輸出
       
        return 0;
    }

可以看到eslint就是在執(zhí)行 engine.executeOnFiles(files) 之后獲得檢查的結(jié)果

executeOnFiles (files) 函數(shù)

可以看到eslint就是在執(zhí)行 engine.executeOnFiles(files) 之后獲得檢查的結(jié)果;該函數(shù)主要作用是對一組文件和目錄名稱執(zhí)行當前配置。

簡單看一下 executeOnFile s ()

該函數(shù)輸入文件目錄,返回lint之后的結(jié)果

主要執(zhí)行邏輯如下:

  1. fileEnumerator 類,迭代所有的文件路徑及信息;
  2. 檢查是否忽略的文件,lint緩存 等等一堆操作;
  3. 調(diào)用 verifyText() 函數(shù)執(zhí)行檢查
  4. 儲存lint之后的結(jié)果
/**
 * Executes the current configuration on an array of file and directory names.
 * @param {string[]} patterns An array of file and directory names.
 * @returns {LintReport} The results for all files that were linted.
 */
executeOnFiles(patterns) {

    // .....
        // fileEnumerator 類,迭代所有的文件路徑及信息
        for (const { config, filePath, ignored } of fileEnumerator.iterateFiles(patterns)) {
        
        // ....... 檢查是否忽略的文件,緩存 等等一堆操作
        
            // Do lint.
            const result = verifyText({
                text: fs.readFileSync(filePath, "utf8"),
                filePath,
                config,
                cwd,
                fix,
                allowInlineConfig,
                reportUnusedDisableDirectives,
                extensionRegExp: fileEnumerator.extensionRegExp,
                linter
            });

            results.push(result);

            /*
             * Store the lint result in the LintResultCache.
             * NOTE: The LintResultCache will remove the file source and any
             * other properties that are difficult to serialize, and will
             * hydrate those properties back in on future lint runs.
             */
            if (lintResultCache) {
                lintResultCache.setCachedLintResults(filePath, config, result);
            }
        }
}

verifyText() 函數(shù)

其實就是調(diào)用了 linter.verifyAndFix() 函數(shù)

verifyAndFix() 函數(shù)

這個函數(shù)是核心函數(shù),顧名思義verify & fix

代碼核心處理邏輯是通過一個 do while 循環(huán)控制;以下兩個條件會打斷循環(huán)

  1. 沒有更多可以被fix的代碼了
  2. 循環(huán)超過十次
  3. 其中 verify 函數(shù)對源代碼文件進行代碼檢查,從規(guī)則維度返回檢查結(jié)果數(shù)組
  4. applyFixes 函數(shù)拿到上一步的返回,去fix代碼
  5. 如果設(shè)置了可以fix,那么使用fix之后的結(jié)果 代替原本的text
/**
         * This loop continues until one of the following is true:
         *
         * 1. No more fixes have been applied. 
         * 2. Ten passes have been made.
         * That means anytime a fix is successfully applied, there will be another pass.
         * Essentially, guaranteeing a minimum of two passes.
         */
        do {
            passNumber++; // 初始值0
            // 這個函數(shù)就是 verify  在 verify 過程中會把代碼轉(zhuǎn)換成ast
            debug(`Linting code for ${debugTextDescription} (pass ${passNumber})`);
            messages = this.verify(currentText, config, options);
            // 這個函數(shù)就是 fix 
            debug(`Generating fixed text for ${debugTextDescription} (pass ${passNumber})`);
            fixedResult = SourceCodeFixer.applyFixes(currentText, messages, shouldFix);

            /*
             * 如果有 syntax errors 就 break.
             * 'fixedResult.output' is a empty string.
             */
            if (messages.length === 1 && messages[0].fatal) {
                break;
            }

            // keep track if any fixes were ever applied - important for return value
            fixed = fixed || fixedResult.fixed;

            // 使用fix之后的結(jié)果 代替原本的text
            currentText = fixedResult.output;

        } while (
            fixedResult.fixed &&
            passNumber < MAX_AUTOFIX_PASSES // 10
        );

在verify過程中,會調(diào)用 parse 函數(shù),把代碼轉(zhuǎn)換成AST

// 默認的ast解析是espree
const espree = require("espree");
 
let parserName = DEFAULT_PARSER_NAME; // 'espree'
let parser = espree;
  • parse函數(shù)會返回兩種結(jié)果

    • {success: false, error: Problem} 解析AST成功
    • {success: true, sourceCode: SourceCode} 解析AST失敗

最終會調(diào)用 runRules() 函數(shù)

這個函數(shù)是代碼檢查和修復的核心方法,會對代碼進行規(guī)則校驗。

  1. 創(chuàng)建一個 eventEmitter 實例。是eslint自己實現(xiàn)的很簡單的一個事件觸發(fā)類 on監(jiān)聽 emit觸發(fā);
  2. 遞歸遍歷 AST,深度優(yōu)先搜索,把節(jié)點添加到 nodeQueue。一個node放入兩次,類似于A->B->C->...->C->B->A;
  3. 遍歷 rules,調(diào)用 rule.create()(rules中提到的meta和create函數(shù)) 拿到事件(selector)映射表,添加事件監(jiān)聽。
  4. 包裝一個 ruleContext 對象,會通過參數(shù),傳給 rule.create(),其中包含 report() 函數(shù),每個rule的 handler 都會執(zhí)行這個函數(shù),拋出問題;
  5. 調(diào)用 rule.create(ruleContext), 遍歷其返回的對象,添加事件監(jiān)聽;(如果需要lint計時,則調(diào)用process.hrtime()計時);
  6. 遍歷 nodeQueue,觸發(fā)當前節(jié)點事件的回調(diào),調(diào)用 NodeEventGenerator 實例里面的函數(shù),觸發(fā) emitter.emit()。
 // 1. 創(chuàng)建一個 eventEmitter 實例。是eslint自己實現(xiàn)的很簡單的一個事件觸發(fā)類 on監(jiān)聽 emit觸發(fā)
const emitter = createEmitter();

// 2. 遞歸遍歷 AST,把節(jié)點添加到 nodeQueue。一個node放入兩次 A->B->C->...->C->B->A
Traverser.traverse(sourceCode.ast, {
        enter(node, parent) {
            node.parent = parent;
            nodeQueue.push({ isEntering: true, node });
        },
        leave(node) {
            nodeQueue.push({ isEntering: false, node });
        },
        visitorKeys: sourceCode.visitorKeys
    });
    
 // 3. 遍歷 rules,調(diào)用 rule.create() 拿到事件(selector)映射表,添加事件監(jiān)聽。
 // (這里的 configuredRules 是我們在 .eslintrc.json 設(shè)置的 rules)
 Object.keys(configuredRules).forEach(ruleId => {
        const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
        
        // 通過ruleId拿到每個規(guī)則對應(yīng)的一個對象,里面有兩部分 meta & create 見 【編寫rule】
        const rule = ruleMapper(ruleId);
      
        // ....

        const messageIds = rule.meta && rule.meta.messages;
        let reportTranslator = null;
        // 這個對象比較重要,會傳給 每個規(guī)則里的 rule.create函數(shù)
        const ruleContext = Object.freeze(
            Object.assign(
                Object.create(sharedTraversalContext),
                {
                    id: ruleId,
                    options: getRuleOptions(configuredRules[ruleId]),
                    // 每個rule的 handler 都會執(zhí)行這個函數(shù),拋出問題
                    report(...args) {
                        if (reportTranslator === null) {
                            reportTranslator = createReportTranslator({
                                ruleId,
                                severity,
                                sourceCode,
                                messageIds,
                                disableFixes
                            });
                        }
                        const problem = reportTranslator(...args);
                        // 省略一堆錯誤校驗
                        // ....
                        // 省略一堆錯誤校驗
                        
                        // lint的結(jié)果
                        lintingProblems.push(problem);
                    }
                }
            )
        );
        // 包裝了一下,其實就是 執(zhí)行 rule.create(ruleContext);
        // rule.create(ruleContext) 會返回一個對象,key就是事件名稱
        const ruleListeners = createRuleListeners(rule, ruleContext);

        /**
         * 在錯誤信息中加入ruleId
         * @param {Function} ruleListener 監(jiān)聽到每個node,然后對應(yīng)的方法rule.create(ruleContext)返回的對象中對應(yīng)key的value
         * @returns {Function} ruleListener wrapped in error handler
         */
        function addRuleErrorHandler(ruleListener) {
            return function ruleErrorHandler(...listenerArgs) {
                try {
                    return ruleListener(...listenerArgs);
                } catch (e) {
                    e.ruleId = ruleId;
                    throw e;
                }
            };
        }

        // 遍歷 rule.create(ruleContext) 返回的對象,添加事件監(jiān)聽
        Object.keys(ruleListeners).forEach(selector => {
            const ruleListener = timing.enabled
                ? timing.time(ruleId, ruleListeners[selector]) // 調(diào)用process.hrtime()計時
                : ruleListeners[selector];
        // 對每一個 selector 進行監(jiān)聽,添加 callback
            emitter.on(
                selector,
                addRuleErrorHandler(ruleListener)
            );
        });
    });
   
  // 只有頂層node類型是Program才進行代碼路徑分析
  const eventGenerator = nodeQueue[0].node.type === "Program"
      ? new CodePathAnalyzer(new NodeEventGenerator(emitter, { visitorKeys: sourceCode.visitorKeys, fallback: Traverser.getKeys }))
      : new NodeEventGenerator(emitter, { visitorKeys: sourceCode.visitorKeys, fallback: Traverser.getKeys });
  
  // 4. 遍歷 nodeQueue,觸發(fā)當前節(jié)點事件的回調(diào)。
  // 這個 nodeQueue 是前面push進所有的node,分為 入口 和 離開
    nodeQueue.forEach(traversalInfo => {
        currentNode = traversalInfo.node;
        try {
            if (traversalInfo.isEntering) {
                // 調(diào)用 NodeEventGenerator 實例里面的函數(shù)
                // 在這里觸發(fā) emitter.emit()
                eventGenerator.enterNode(currentNode);
            } else {
                eventGenerator.leaveNode(currentNode);
            }
        } catch (err) {
            err.currentNode = currentNode;
            throw err;
        }
    });
 // lint的結(jié)果
 return lintingProblems;

執(zhí)行節(jié)點匹配 NodeEventGenerator

在該類里面,會根據(jù)前面 nodeQueque 分別調(diào)用 進入節(jié)點和離開節(jié)點,來區(qū)分不同的調(diào)用時機。

// 進入節(jié)點 把這個node的父節(jié)點push進去
    enterNode(node) {
        if (node.parent) {
            this.currentAncestry.unshift(node.parent);
        }
        this.applySelectors(node, false);
    }
    // 離開節(jié)點
    leaveNode(node) {
        this.applySelectors(node, true);
        this.currentAncestry.shift();
    }
    // 進入還是離開 都執(zhí)行的這個函數(shù)
    // 調(diào)用這個函數(shù),如果節(jié)點匹配,那么就觸發(fā)事件
    applySelector(node, selector) {
        if (esquery.matches(node, selector.parsedSelector, this.currentAncestry, this.esqueryOptions)) {
            // 觸發(fā)事件,執(zhí)行 handler
            this.emitter.emit(selector.rawSelector, node);
        }
    }

四、總體運行機制

概括來說就是,ESLint 會遍歷前面說到的 AST,然后在遍歷到「不同的節(jié)點」或者「特定的時機」的時候,觸發(fā)相應(yīng)的處理函數(shù),然后在函數(shù)中,可以拋出錯誤,給出提示。

Tips: espree需要更換解析器

問題:espree無法識別 TypeScript 的一些語法,所以在我們項目中的 .eslintrc.json 里才要配置

{
 "parser"'@typescript-eslint/parser'
}

給eslint指定解析器,替代掉默認的解析器。

eslint 中涉及到規(guī)則的校驗源碼調(diào)用棧大致就如上分析,但其實eslint遠不止這些,還有很多可以值得學習的點,如:迭代文件路徑、fix修復文本、報告錯誤及自定義格式等等,歡迎感興趣的同學一起討論交流,也歡迎同學批評指正~

參考資料

https://zhuanlan.zhihu.com/p/53680918

https://juejin.cn/post/7054741990558138376

https://www.teqng.com/2022/03/14/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3-eslint-%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86/#ESLint_shi_ru_he_gong_zuo_de

[1]

我們看一下自定義eslint 規(guī)則: https://eslint.bootcss.com/docs/developer-guide/working-with-rules

[2]

ESTree: https://github.com/estree/estree

[3]

selector: https://eslint.bootcss.com/docs/developer-guide/selectors

[4]

selector: https://eslint.bootcss.com/docs/developer-guide/selectors

[5]

代碼路徑分析: https://eslint.bootcss.com/docs/developer-guide/code-path-analysis



往期推薦


在頁面關(guān)閉時,前端上傳監(jiān)控數(shù)據(jù)的4個解決方案
Vue3 基礎(chǔ)難點總結(jié)
前端配置化真香~上班又多了60%的摸魚時間

最后


  • 歡迎加我微信,拉你進技術(shù)群,長期交流學習...

  • 歡迎關(guān)注「前端Q」,認真學前端,做個專業(yè)的技術(shù)人...

點個在看支持我吧
瀏覽 93
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 青青操天天干| 天天日天天色| 成人自拍视频| 可以看的三级网站| 国产精品一级a毛视频| 奇米无码| 爱爱视频天天干| 亚洲性爱无码| 影音先锋一区二区| 成人二区三区| 四虎成人精品永久免费AV九九| 五月天激情四射| 五月天在线观看| 久久久久久久免费视频| 国产日韩欧美在线观看| 91re| 夜夜嗨AⅤ一区二区三区| 波多在线视频| 大香蕉伊人av| 日韩aaa| 成人毛片在线大全免费| 100国产精品人妻无码| 国产女主播在线观看| 日韩欧美成人在线| 伊人成人在线| 色婷婷中文在线| 五月天婷婷影院影院| 日逼91| 天堂网在线视频| 久久久18禁一区二区三区精品 | 国产suv精品一区二区| 偷窥美鲍| 中文资源在线观看| 天天射天天射| 国产成人AⅤ| 曰本精品综合网在线| 91色色影院| 黄色免费一级片| 在线免费A片| 免费性爱视频| 日本熟妇在线| 一级黄色电影免费观看| 午夜精品久久久久久久99黑人| 菊花插综合网| 免费自拍视频| 午夜成人视频| 国产精品HongKong麻豆 | 色婷婷黄色| 操BBB操BBB| 2025天天操| 99精品视频免费观看| 精品人人人| 亚洲A片V一区二区三区| 久久综合99| 日韩高清一级免费| 亚洲色婷婷五月天| 国产精品TV| 91香蕉国产在线观看| 成人免费精品| 亚洲第一国产黄AV动漫软件| 精国产品一区二区三区A片| 亚洲在线无码| 国产精品TV| 91人妻一区二区三区无不码超满| 粗长哭叫打桩H体育生| 日日干日日| 久草视频免费在线播放| 成人无码日韩精品| 亚洲av电影在线观看| 亚洲色婷婷在线| 99热播| 免费中文资源在线观看| 青青草逼视频| 五月天丁香社区| 人人艹人人艹| 国产精品99久久久久久成人| 高清色色女网站| 91久久久久久久18| 无码高清一区二区| 特黄特色免费视频| 大香蕉伊人在线观看视频| 一级黄色AV片| 亚洲综合中文字幕在线| 波多野结衣黄色| 久久亚洲AV成人无码国产野外| 内射极品美女| 西西444WWW无码视频软件功能介绍| WWW久久| 亚洲www| 美女免费AV| 18禁91| 色播视频在线观看| www.五月婷婷| 天天夜夜有| 免费国产三级片| 成人免费观看的毛视频| 高清无码免费观看视频| 亚洲三级免费| 亚洲AV无码成人片在线| 亚洲秘无码一区二区三区av| 综合网操笔| www.超碰在线| 日韩中文无码电影| 亚洲热在线观看| 国产精品嫩草久久久久yw193 | 北条麻妃无码在线观看| 久久久久久久久久国产精品| 免费看成人747474九号视频在线观看| 丁香啪啪| 日韩中文字幕在线观看| 一本到免费视频| 91福利在线观看| 国产精品码一本A片| 一区二区三区免费观看| 成人精品123| 日韩中文字幕无码| 黄色片视频| 日本成人中文字幕在线观看| 青青草91视频| 先锋影音亚洲AV每日资源网站 | 久久国产一级片| 操bbbb| 学生妹一级| 在线色片| 精品免费一区二区三区四区| 免费看黄色片| 尤物在线免费视频| 天天玩夜夜玩天天玩国产99| 日韩中文字幕高清| 人妻少妇精品视频一区二区三区| 岛国无码在线观看| 自拍偷拍视频网| 亚洲综合区| 五月天乱伦小说| 欧美激情视频在线| 四虎高清无码| 99精品99| 91午夜福利| 无码精品成人观看A片| 欧美国产成人在线| 国内自拍一区| 激情无码在线观看| 99这里都是精品| 在线内射| 免费无码国产在线怀| 日韩无码激情| 日韩不卡AV| 日韩中文字幕成人| 亚洲精品偷拍| 另类欧美色图| 亚洲无码在线高清| 91亚洲成人| www.丁香五月| 精品人妻一区二区三区日产乱码| 午夜激情视频在线观看| 久草视频免费看| 在线v片| 免费A级毛片在线播放不收费| 亚洲精品国产成人AV在线 | 人人澡人人澡| 91三级电影| 人妻少妇精品视频一区二区三区| 77777免费观看电视剧推荐爱的教育| 欧美性爱视频免费观看| 无码网站内射| a在线视频| 91国语对白| 人人爽人人操人人爱| 天a堂8在线www| 国产嫩草精品A88AV| 精品一区二区免费视频| 久久黄色视频| 一级黄色电影在线观看| 日韩久久中文字幕| 吴梦梦无码| 黄片网站免费观看| 欧美成人午夜| a片一级片| 日本一区二区三区视频在线观看 | 国产污视频| 操逼99| 无码人妻精品一区二区三区蜜桃91| 国产无码自拍偷拍| 亚洲视频中文字母| 久草福利在线观看| 免费手机av| 香蕉午夜视频| 久久911| 欧美性爱一区| 玖玖爱国产| 黄色A毛片| VA电影| 91国产爽黄| 偷拍777| 牛牛在线精品视频| 北条麻妃二区三区| 性爱一区| 久久99深爱久久99精品| 怡红院欧美| 五月丁香婷婷基地| 欧美日韩视频免费观看| 2025AV中文字幕| 中日韩一级片| 黄片免费播放| 亚洲无码成人视频| 熟女人妻一区二区| 久久精品无码一区二区无码性色| 奶大丰满一乱一视频一区二区三区在 | 亚洲无码色| 成人免费乱码大片a毛片蜜芽| 久热中文在线观看精品视频| 精品國產一區二區三區久久蜜月| 在线观看国产视频| 少妇嫩搡BBBB搡BBBB| 亚洲黄色影视| 三级片网站在线观看| 亚洲无码免费网站| 日逼高清视频| 中文无码熟妇一区二区| 午夜3D动漫AV| 欧美精品久久久| 91人妻精| 777免费视频| 亚洲无套内射| 农村三级片| 日韩欧美三级在线| 欧美一级特黄A片免费观看| 专肏老妇人大逼| 欧美国产在线观看综合| 成人网站在线看| 中文毛片| 黄色成人在线视频| 亚洲在线无码视频| AV网站在线播放| 男人天堂视频网| 久久久久久久久久久成人| 亚洲无吗在线观看| 九一av| 爱草在线| 亚洲男女免费视频| 国产成人无码一区二区在线观看 | 超碰在线精品| 久热视频在线| 一级欧美黑人大战白妞| а中文在线天堂精品| 欧美熟妇一区二区| 天天爽日日澡| 亚洲精品视频免费在线观看| 黄色A片免费观看| 一个人看的视频www| 国产夫妻AV| 黄色动漫在线免费观看| 人操人操人操| 乱子伦国产精品视频一级毛| 精品无码人妻一区二区三区 | 激情五月天在线视频| 亚洲激情欧美激情| 热re99久久精品国产99热| 亚洲高清无码一区二区| 国产精品一区二区三区不卡| 国产在线精品自拍| 精品三级在线观看| 一级黄色视频片| 色情网站在线| 香蕉视频一区| 嫩BBB揍BBB揍BBB| xxx日韩| 97操逼| 毛片毛片毛片毛片| 国产无遮挡又黄又爽又色学生软件 | 日韩aaa| 欧美综合亚洲图片综合区| www.五月天婷婷| 久9久9| 日韩熟妇人妻中文字幕| 欧美亚洲精品在线| 婷婷看片| 丰满岳乱妇一区二区三区全文阅读| 一区二区三区四区在线播放| 91丝袜| 国产精品成人午夜福利| 豆花成人社区,视频| 日日干日日操| 人人操碰成人网| 国产乱伦熟女| 国产主播一区二区| 欧美女人日逼视频| 激情视频免费在线观看| 成人欧美视频| 日韩无码一二三| 欧美成人免费| 秋霞亚洲| 秘蜜桃色一区二区三区在线观看| 国产欧美岛国| 欧美日韩精品在线视频| 成人特级毛片全部免费播放| 国内精品无码| 艾操网| 中国老熟女2老女人| 国产小黄片在线| 久久久久无码国产精品不卡| 无码人妻精品一区二区三区99仓 | 丰满人妻一区二区三区免费 | 俺来俺也去| 91国产视频在线观看| 激情六月天| 国产精品久久久久久最猛| 一本到免费视频| 午夜综合| 青青草综合| 高清无码不卡在线观看| AV在线精品| 91蜜桃传媒| 豆花视频在线看| 久久久久亚洲AV成人网人人软件| 欧美一级a| 久久理论电影| 国产成人网站免费观看| 欧美性爱五月天| 你懂的在线观看| 国产精品视频免费观看| 久久w| 亚洲欧美日韩成人| 日韩欧美人妻| 天天日天天添| 日本色色视频| 国产最新在线视频| 在线播放91灌醉迷J高跟美女| 亚州天堂网| 免费看黄色视频| 午夜成人爽| 男人的天堂aa| 亚洲欧洲AV| a片在线免费观看| 天天插综合| 俺也去网站| 色婷婷国产| 欧美午夜精品一区二区蜜桃 | 国产狂喷水潮免费网站www| 国产色婷婷精品综合在线播放| 超碰免费人妻| 99综合| 亚洲一级一级黄色| 色婷婷影音| 欧美黄色一级视频| 热久久在线| 黑人精品欧美一区二区蜜桃| 91麻豆国产| 一区二区人妻| 亚洲成人AV电影| 91精品亚洲| 97福利导航| 婷婷激情av| 日韩无码国产精品| 国精产品九九国精产品| 欧美人人| 丁香五月天激情| 538在线观看| 91视频免费播放| 日本少妇视频| 国产1级a毛a毛1级a毛1级| 国产91福利| 阿拉伯三级片| 无码潮喷| 欧美三级片在线| 激情五月天开心网| 中文字幕在线观看高清| 中韩一区二区| 曰曰摸日日碰| 国内操逼视频| 国产AV剧情| 久久男人天堂| 一道本视频在线免费观看| 黄色一级视频网站| 免费黄片网站| 青青操b| 欧美综合激情| 波多野结衣无码AV专区| 国产又爽又黄免费网站在线看| 国产香蕉视屏| 免费久草视频| 亚洲无码激情| 新BBWBBWBBWBBW| 成人一级视频| 一本色道久久综合亚洲怎么玩| 91青青草视频| 韩日高清无码| 久操视频网站| 91精品国产成人www| 伊人大香蕉网站| 在线观看日本vs欧洲vs美洲| 国产精品嫩草久久久久yw193| 成年人A片| 黄色片基地| 五月婷婷婷婷| 欧洲三级片网站| 亚洲欧洲精品在线| 久久久老熟女一区二区三区91| 无码人妻av黄色一区二区三区| 精品一区二区免费| 少妇做爱视频| 日韩爱爱免费视频| 又粗又硬又爽18级A片| 国产成人综合网| 日韩无码视频播放| 国产偷拍| 中日韩特黄A片免费视频| 青青热视频| 一级a一级a爱片免费视频| 免费日批网站| 91无码精品久久久一区第1集| 亚洲AV中文无码| 午夜神马51| 天天撸在线视频| 在线观看的AV| 88av在线观看| 欧美人妻少妇| 亚洲视频精品| 尤物一区二区| 欧美久久久久久| 亚洲AV无码一区二区三区少妇| 性V天堂| 亚洲欧洲无码视频| 国精产品一区一区三区四区| 1024国产| 六月综合网| 韩国久久| 青草无码| 444444免费高清在线观看电视剧的注意 | 久久思热国产| 免费看无码一级A片在线播放| 成人黄网站免费视频| 欧美成人视频电影无码高清| 女人AV天堂| 人人操人人上| 日韩AAA| 国产色网站| 北条麻妃二区三区| 欧美日韩黄片| 免费A网站| 午夜91| www.蜜桃视频| 日韩黄色电影在线| 91亚洲一线产区二线产区| 97爱视频| 欧美一级A片在免费看| 另类日韩| 青青草原在线视频免费观看| 撸一撸成人在线做爱视频。| 久久AV秘一区二区三区水生 | 久久黄网| 影音先锋av网| 97精品国产| 亚洲成色A片77777在线小说| 亚洲AV永久无码国产精品久久| www黄片| 京东一热本色道久久爱| 黄A在线| 中出欧美亚洲| 国产在线导航| 免费国产三级片| www.伊人网| 久久性| 午夜天堂精品久久| 国产看色免费| 国产精品视频免费在线观看| 亚洲无遮挡| 成人精品18| 人人摸人人操人人爽| 四川女人毛多水多A片| 免费人成视频在线播放| 日韩免费高清在线视频| 欧美一级一区| 99视频精品视频| 激情操逼网| 中文亚洲视频| 国产操穴| 香蕉一区| 99伊人网| 久久免费视频,久久免费视频| 亚洲精品另类| 在线无码播放| 无码精品人妻一区二区三区漫画| 熟女AV888| 操屄视频免费观看| 欧美精品午夜福利无码| 无码人妻丰满熟妇bbbb| 2025av天堂| 亚洲三级视频在线播出| 自拍三级片| 久久另类TS人妖一区二区免费| 国产精品久久久久久久久久二区三区 | 欧美日韩精品一区| 成人国产无码| 日韩成人无码一区二区| A片免费在线| 亚洲精品视频免费在线观看| 影音先锋AV无码| 亚州加勒比无码| 少妇大战黑人46厘米| 色婷婷Av| 人人干人人干人人干| 国产黄片一区二区三区| 亚洲日韩精品在线视频| 奶大丰满一乱一视频一区二区三区在 | 九色91PORNY国产| 97欧美精品人妻系列| 人成在线免费视频| 黄片视频在线免费看| 农村新婚夜一级A片| 亚洲第一av| 日韩黄网| 青娱乐国产av| 亚洲乱码精品久久久久..| 黄色香蕉视频| 91视频在线免费观看| 国产精品你懂的| 囯产精品久久久久久久久| 精品99999| 国产视频h| 欧美日韩北条麻妃视频在线观看| 中文字幕免费中文| 三级片日本在线| 国产日韩欧美在线观看| 国产成人网| 青青草亚洲| 日韩一二三四区| 黄网在线播放| 大伊香蕉视频| 91香蕉视频免费| 久久香视频| 美女天天操| 在线www| 黄片视频在线免费播放| 最新日韩中文字幕| 国产区欧美去区在线| 高清无码网站在线观看| 大吊无码| 欧美性爱综合网| 午夜成人视频在线观看| 一级aa视频| 欧美成人精品无| 亚洲秘无码一区二区三区,| av婷婷在线| 91无码人妻一区二区成人AⅤ| 亚洲人操逼视频| 亚洲狼友视频| 精品码产区一区二亚洲国产| 中文字幕在线成人| 午夜天堂在线| 99精品在线播放| 狼友在线播放| 伊人三级片| 97人妻一区二区精品免费视频| 天天操天天射天天爽| 中字无码av| 免费无码成人| 免费在线观看中文字幕| 国产69精品久久久久久久久久久久 | 色综合色综合色综合| 婷婷五月亚洲精品AAA片在| 自拍偷拍一区二区三区| 91一区二区在线观看| 亚洲无码1区| 91青青视频| WWW.豆花视频精品| 国产成人精品AV| 极品无码| 一区视频在线| 精品无码一区二区Av蜜桃| 亚洲人人18XXX—20HD| 久久黄色视频免费看| 欧美一级特黄A片免费| 国产成人高清视频| 乱伦内射视频| 天天日AV| 人妻懂色av粉嫩av浪潮av| 婷婷免费| 高清无码免费| 操比视频| 日韩中文字幕AV| 欧美亚洲在线| 亚洲国产爱| 天天干无码| 性综合网| 欧美一级a| 97无码人妻| 欧美性爱-熊猫成人网| 日韩有码一区| 久久久青草| 欧美插菊花综合网| 天堂中文资源在线观看| 中文字幕自拍偷拍| 天堂AV色| 天堂在线www| 99热在线观看精品免费| 无码AV中文字幕| 青青超碰| 中文字幕无码AV| 水果派AV解说| 免费无码一区二区三区四区五区 | 婷婷亚洲精| 91蜜桃视频| 大香蕉性爱视频| 丁香色色网| 亚洲无码手机在线观看| 国产精品秘久久久久久| 三级成人视频| 台湾中文字幕网| 大香蕉伊人手机在线| 亚洲影视中文字幕| 91大神免费在线观看| 伊人大香蕉视频| 一区二区高清| 四虎精品影院| 加勒比无码高清| 日本不卡视频在线| 欧美丰满美乳XXⅩ高潮www| 尤物精品在线| 蜜桃系列一区二区精品| 日韩精品视频免费在线观看 | 中文字幕在线观看视频www| 人妻少妇无码| 免费精品视频| 中文无码电影| 国产美女啪啪视频| 免费肏逼视频| 亚洲电影AV| 婷婷激情视频| 国产无遮挡又黄又爽又色视频| 伊人久久无码| 在线国产激情视频| 日韩精品网址| 夜色精品视频| 亚洲女人天堂AV| 麻豆疯狂做受XXXX高潮视频| 澳门四虎影院| 另类毛片| 一级片免费观看| 一区在线看| 2021天天操| 久久久久无码国产精品不卡| 亚洲少妇一区| 欧美日韩国产尤物主播精品| 日本精品人妻| 亚洲无码av在线观看| 日本精品乱伦| 伊人青草视频9| 免费超碰| 国产小视频在线观看| 五月丁香综合| 久精品视频| 天天干天天操天天射| www.麻豆网91成人久久久| 青青草成人在线| 777久久| 中文字幕在线观看免费高清完整版在线观看 | 加勒比综合在线| 国产高清视频在线观看| 久久99久久99久久99国内少妇精品 | 一级黄色视频免费看| 偷拍777| 国产真实露脸乱子伦对白高清视频| 国产男女啪啪视频| 日韩精品一区二区三区中文在线| 口爆AV| 国产毛片在线视频| 青娱乐国产视频| 天天做夜夜操| 超碰97资源| 91亚洲精品乱码久久久久久蜜桃| 国产又爽又黄免费网站在线看| 久久精品视频99| 激情国产av| 亚洲视频免费完整版在线播放| 久久久亚洲熟妇熟女| 久久艹大香蕉| 亚洲精品在线观看视频| 亚洲视频免费在线播放| 日韩AV一区二区三区| 国产二区视频| 日本aa视频| 日韩无码中字| 日本免费黄色小视频| 黄色视频毛片| 亚洲中文字幕一区| av天堂小说网| 69av在线播放| 亚洲天堂网在线观看| JlZZJLZZ亚洲美女18| 91色秘乱码一区二区| 中文在线a∨在线| 亚洲Av无码成人专区擼| 日韩久久综合| 久热网| 婷婷成人电影| 日韩欧美中文字幕在线观看| 大鸡巴导航| 亚洲日本中文字幕| 日韩综合色视频导航| 女BBBBBB女BBB| 最新中文字幕在线播放| 中日韩中文字幕一区二区区别| 成人综合大香蕉| 秋霞午夜福利影院| 好逼天天有| 亚洲天堂视频在线播放| 亚洲免费观看高清完整版| 波多野结衣无码一区二区| 精品人妻午夜一区二区三区四区 | 一级片学生妹| 日本高清无码在线| 国产操比视频| 日韩福利在线| 无码一区二区三区免费| 东京热无码视频| 久久99影院| 日狠狠| 亚洲高清毛片一区二区| 激情网站在线| 色婷婷在线影院| 国产精品久久久久久久久久久久久| 大肉大捧一出免费观看| 香蕉91视频| 日韩成人综合| 逼特逼视频| 情趣视频网站| 亚洲成人第一网站| 18网站视频| 特级西西444www无码视频免费看 | 亚洲三级片免费观看| 色汉综合| 夜夜无码| 日韩精品人妻中文字幕| www超碰在线| 在线观看国产一区| 中国人妻HDbute熟睡| 日韩在线中文字幕视频| 各种BBwBBwBBwBBw| 奇米影视狠狠干| 丁香午夜| 天天天天天天天天操| 国产精品欧美一区二区三区苍井空| 国产AⅤ爽aV久久久久成人| 久久逼逼| 91视频在线| 波多野结衣高清av久久直播免| 永久免费叼嘿| 2024AV在线| 天堂AV在线免费观看| 99精品久久久久久无码| 久久丝袜| 免费高清无码| 粉嫩小泬BBBB免费看| 久久久女人| 亚洲AV成人网| 亚洲人妻无码视频| 国产AV一区二区三区四区| 婷婷综合网| 高清的日逼| 五月激情久久| 韩国一区二区三区| 精品免费在线观看| 亚洲视频二区| 日韩看片| 青草网在线观看| 丁香婷婷在线| а中文在线天堂精品| 免费在线观看a片| 色99999| 日韩本色一区| 国产乱子伦-区二区| 色播国产成人AV| 亚洲av自拍| 国产一级免费| 久草视频免费在线观看| 国产免费一区二区三区四区| 梁祝艳谭A级毛片| 亚洲国产欧美日韩在线| 国产毛片网| 怡红院av| 98在线++传媒麻豆的视频| 中文字幕av网站| jlzzzjlzzz国产免费观看| 国产Aⅴ| 天天av天天av天天爽| 日韩精品欧美一区二区三区| 日韩av电影免费在线观看| 亚洲另类图片小说| 欧美成人精品在线| 国产成人免费在线观看| 日韩经典视频在线播放| 午夜福利免费在线观看| 色欲大香蕉| 日韩AV免费电影| A片视频网站| 久久99精品国产.久久久久| 人妻熟女在线视频| 热久久伊人| xxxx国产| 人人操人人妻| 国产一精品一aⅴ一免费| 永久久久久久久| 激情深爱| 丁香五月在线观看| 亚洲一区日韩| 久热思思| 亚洲国产爱| 俺去俺来也www色视频| av福利在线观看| 在线性视频| 亚洲免费观看高清完整版在线| 操B在线观看| 国产精品久久久久久久免牛肉蒲| 久久久女人| 69er小视频| 国产女人18毛片18精品| 国产无码一| 大地影视官网第三页入口| 探花视频在线观看| 农村A片婬片AAA毛片| 久久亚洲Aⅴ成人无码国产丝袜| 成人自拍视频在线| 欧美黄色网址| 久热在线视频| 国产精品久久久久的角色| 男人视频网| 亚洲精品第一页| 国产无码AV| 欧洲a视频| 黄色免费看视频| 国产777777| 性猛交╳XXX乱大交| 人人干视频| 福利导航在线| 日韩免费在线视频| 青青操天天干| 中文区中文字幕免费看| 五十路在线视频| 欧美性BBwBBwBBwHD| 91热爆TS人妖系列| 台湾成人视频| AV一区二区三区| 精品尤物在线| 蜜桃精品视频在线观看| 一道本在线视频| 国产免看一级a一片成人aⅴ| 亚洲少妇免费| 久久激情视频| 色色色色色色网站| 国产在线看片| 亚州在线视频| 999日本不卡影院| 99精品在线播放| 日韩无码成人片| 日本高清久久| 三级无码视频在线观看| 婬乱欧美一二三区| 天天干天天操| 无码a片| 亚洲精品国偷拍自产在线观看蜜桃| 无码人妻一区二区三区蜜桃视频| 无码成人网| 国产做受精品网站在线观看| 丁香五月天堂网| 国产女18毛片多18精品| 免费黄色视频大全| 99免费在线观看视频| 日本一区二区三区在线观看网站| 色哟哟无码精品一区二区三区| 中文字幕国产综合| 欧美日韩亚洲一区二区三区| 曰本精品综合网在线| 色婷婷av| 操逼黄色视频| 欧美四区| 国产午夜视频在线观看| 亚洲精品大片| 日本免费a片| 欧美中出| 色婷婷在线免费视频| 成人看片| 大香蕉做爱| 97国产精品人人爽人人做| 草草浮力院| 影音先锋在线视频观看| 伊人久久无码| 久久激情av| 天天舔九色婷婷| AV天堂偷拍亂伦| 97人人爽人人爽人人爽| 久久私拍视频| 国内自拍网站| 青娱乐A片| 久久综合伊人7777777| 一级日韩一级欧美| 国产三级偷拍| 国产精品一级无码免费播放| 在线操B视频| 91吊逼|