对Babel的研究2
插件选项
注意:多次指定插件时,仅考虑第一个选项。
  decorators:
         decoratorsBeforeExport(boolean)
// decoratorsBeforeExport: true @dec export class C {} // decoratorsBeforeExport: false export @dec class C {}
 pipelineOperator:
  proposal(必需的,可接受的值:minimal,smart)管道操作员有不同的建议。此选项允许选择使用哪个。请参阅管道提案(|>)发生了什么?了解更多信息。
flow:
     all(boolean,默认值false:)在Flow和原始JavaScript中,某些代码具有不同的含义。例如,foo<T>(x)在Flow中将解析为带有类型参数的调用表达式,但将其解析为与foo < T > xECMAScript规范相对应的比较()。默认情况下,babel-parser仅当文件以// @flow编译指示开头时,才将这些歧义结构解析为Flow类型。将此选项设置true为始终解析文件,就像// @flow指定的一样。
常问问题
Babel解析器是否支持插件系统?
我们目前不愿意为插件或由此产生的生态系统提供支持的API(已经有足够的工作来维护Babel自己的插件系统)。目前尚不清楚如何使该API有效,这将限制我们重构和优化代码库的能力。
对于那些想要创建自己的自定义语法的用户,当前的建议是让用户分叉解析器。
要使用您的自定义解析器,您可以将一个插件添加到您的选项中,以通过其npm软件包名称来调用解析器;如果使用JavaScript,则需要使用该插件,
const parse = require("custom-fork-of-babel-parser-on-npm-here"); module.exports = { plugins: [{ parserOverride(code, opts) { return parse(code, opts); }, }] }
@babel/core
var babel = require("@babel/core"); import { transform } from "@babel/core"; import * as babel from "@babel/core";
所有转换将使用本地配置文件。
转变
babel.transform(代码:字符串,选项?:对象,回调:功能)
转换传入的code。使用具有生成的代码,源映射和AST的对象调用回调。
babel.transform(code, options, function(err, result) { result; // => { code, map, ast } });
例
babel.transform("code();", options, function(err, result) { result.code; result.map; result.ast; });
兼容说明:
在Babel 6中,此方法是同步的,transformSync并不存在。为了向后兼容,如果未提供回调,则此函数将同步运行。如果您从Babel 7开始并且需要同步行为,请使用,transformSync因为此向后兼容可能会在Babel的未来主要版本中删除。
transformSync
babel.transformSync(代码:字符串,选项?:对象)
转换传入的code。返回带有生成的代码,源映射和AST的对象。
babel.transformSync(code, options) // => { code, map, ast }
var result = babel.transformSync("code();", options); result.code; result.map; result.ast;
transformAsync
babel.transformAsync(代码:字符串,选项?:对象)
转换传入的code。使用生成的代码,源映射和AST返回对象的承诺。
babel.transformAsync(code, options) // => Promise<{ code, map, ast }>
babel.transformAsync("code();", options).then(result => { result.code; result.map; result.ast; });
transformFile
babel.transformFile(文件名:字符串,选项?:对象,回调:功能)
异步转换文件的全部内容。
babel.transformFile(filename, options, callback)
babel.transformFile("filename.js", options, function (err, result) { result; // => { code, map, ast } });
transformFileSync
babel.transformFileSync(文件名:字符串,选项?:对象)
的同步版本babel.transformFile。返回的转换后的内容filename。
babel.transformFileSync(filename, options) // => { code, map, ast }
babel.transformFileSync("filename.js", options).code;
transformFileAsync
babel.transformFileAsync(文件名:字符串,选项?:对象)
的无极版babel.transformFile。传回的已转换内容的Promise filename。
babel.transformFileAsync(filename, options) // => Promise<{ code, map, ast }>
babel.transformFileAsync("filename.js", options).then(result => { result.code; });
transformFromAst
babel.transformFromAst(ast:Object,code ?:字符串,选项?:Object,回调:函数):FileNode | 空值
给定AST,对其进行转换。
const sourceCode = "if (true) return;"; const parsedAst = babel.parse(sourceCode, { parserOpts: { allowReturnOutsideFunction: true } }); babel.transformFromAst(parsedAst, sourceCode, options, function(err, result) { const { code, map, ast } = result; });
兼容说明:
在Babel 6中,此方法是同步的,transformFromAstSync并不存在。为了向后兼容,如果未提供回调,则此函数将同步运行。如果您从Babel 7开始并且需要同步行为,请使用,transformFromAstSync因为此向后兼容可能会在Babel的未来主要版本中删除。
transformFromAstSync
babel.transformFromAstSync(ast:Object,code ?: string,options?:Object)
给定AST,对其进行转换。
const sourceCode = "if (true) return;"; const parsedAst = babel.parse(sourceCode, { parserOpts: { allowReturnOutsideFunction: true } }); const { code, map, ast } = babel.transformFromAstSync(parsedAst, sourceCode, options);
给定AST,对其进行转换。
const sourceCode = "if (true) return;"; babel.parseAsync(sourceCode, { parserOpts: { allowReturnOutsideFunction: true } }) .then(parsedAst => { return babel.transformFromAstAsync(parsedAst, sourceCode, options); }) .then(({ code, map, ast }) => { // ... });
解析
babel.parse(代码:字符串,选项?:对象,回调:功能)
给定一些代码,使用Babel的标准行为对其进行解析。将加载引用的预设和插件,以便自动启用可选的语法插件。
兼容说明:
在Babel 7的早期Beta中,此方法是同步的,parseSync并不存在。为了向后兼容,如果未提供回调,则此函数将同步运行。如果您从Babel 7稳定版开始并且需要同步行为,请使用parseSync此版本,因为在Babel的未来主要版本中可能会删除此向后兼容。
parseSync
babel.parseSync(代码:字符串,选项?:对象)
返回AST。
给定一些代码,使用Babel的标准行为对其进行解析。将加载引用的预设和插件,以便自动启用可选的语法插件。
parseAsync
babel.parseAsync(code:string,options?:Object)
返回AST的承诺。
给定一些代码,使用Babel的标准行为对其进行解析。将加载引用的预设和插件,以便自动启用可选的语法插件。
进阶API
许多包装Babel的系统都喜欢自动注入插件和预设,或覆盖选项。为了实现此目标,Babel公开了一些功能,这些功能有助于部分加载配置而不进行转换。
loadOptions
babel.loadOptions(options?:Object)
完全解析Babel的选项,产生一个options对象,其中:
- opts.plugins是- Plugin实例的完整列表。
- opts.presets为空,所有预设均被展平为- opts。
- 它可以安全地传递回Babel。字段"babelrc"已设置为,false这样以后对Babel的调用将不会再次尝试加载配置文件。
Plugin实例并不意味着可以直接进行操作,但是调用者通常会将其序列化为optsJSON,以将其用作表示Babel收到的选项的缓存键。不能保证100%正确地对此进行缓存,但这是我们目前拥有的最好方法。
loadPartialConfig
babel.loadPartialConfig(options?:Object):PartialConfig
为了使系统能够轻松地操纵和验证用户的配置,此功能可解析插件和预设,并且不再进行任何操作。期望的是,呼叫者将采用配置文件.options,在他们认为合适的情况下对其进行操作,然后将其再次传递回Babel。
- babelrc: string | void- 文件相对配置文件的路径(如果有)。
- babelignore: string | void-- .babelignore文件路径(如果有的话)。
- config: string | void- 项目范围的配置文件的路径(如果有的话)。
- options: ValidatedOptions-部分解决的选项,可以对其进行操作并再次传递回Babel。- plugins: Array<ConfigItem>- 见下文。
- presets: Array<ConfigItem>- 见下文。
- 它可以安全地传递回Babel。像这样的选项"babelrc"已设置为false,以便以后对Babel的调用不会再次尝试加载配置文件。
 
- hasFilesystemConfig(): boolean-检查解析的配置是否从文件系统加载了任何设置。
ConfigItem实例公开属性以对值进行内部检查,但每个项目都应视为不可变的。如果需要更改,则应从列表中删除该项目,并用常规的Babel配置值或用创建的替换项目替换babel.createConfigItem。有关该ConfigItem字段的信息,请参见该函数。
createConfigItem
babel.createConfigItem(值:字符串| {} |函数| [字符串| {} |函数,{} |无效],{目录名?:字符串,类型?:“预设” |“插件”}):ConfigItem
允许构建工具预先创建和缓存配置项。如果给定插件多次调用此函数,Babel将多次调用插件自身的函数。如果您有明确的预期插件集和要注入的预设,则建议预先构造配置项。
ConfigItem 类型
每个ConfigItem公开了Babel知道的所有信息。这些字段是:
- value: {} | Function-插件的解析值。
- options: {} | void-将选项对象传递给插件。
- dirname: string-选项相对的路径。
- name: string | void-用户为插件实例指定的名称,例如- plugins: [ ['env', {}, 'my-env'] ]
- file: Object | void-如果Babel知道,则有关插件文件的信息。- request: string-用户请求的文件,例如- "@babel/env"
- resolved: string-解析文件的完整路径,例如- "/tmp/node_modules/@babel/preset-env/lib/index.js"
 
DEFAULT_EXTENSIONS
babel.DEFAULT_EXTENSIONS:ReadonlyArray
babel支持的默认扩展列表(“ .js”,“。jsx”,“。es6”,“。es”,“。mjs”)。@ babel / register和@ babel / cli使用此列表来确定哪些文件需要转译。无法扩展此列表,但是@ babel / cli确实提供了使用来支持其他扩展的方法--extensions。
@babel/generator
安装
npm install --save-dev @babel/generator
用法
import {parse} from '@babel/parser'; import generate from '@babel/generator'; const code = 'class Example {}'; const ast = parse(code); const output = generate(ast, { /* options */ }, code);
选件
格式化输出的选项:
| 名称 | 类型 | 默认 | 描述 | 
|---|---|---|---|
| assistantCommentBefore | 串 | 在输出文件开始处添加为块注释的可选字符串 | |
| 辅助评论后 | 串 | 在输出文件末尾添加为块注释的可选字符串 | |
| 应该打印评论 | 功能 | opts.comments | 接受注释(作为字符串)并返回 true注释是否应包含在输出中的函数。默认情况下,所有注释,如果opts.comments是true,或者opts.minified是false和注释包含@preserve或@license | 
| keepLines | 布尔值 | false | 尝试在输出代码中使用与源代码中相同的行号(有助于保留堆栈跟踪) | 
| keepFunctionParens | 布尔值 | false | 保留函数表达式周围的括号(可用于更改引擎的解析行为) | 
| 注释 | 布尔值 | true | 输出中是否应包含注释 | 
| 紧凑 | 布尔值或 'auto' | opts.minified | 设置为 true避免添加空格以进行格式化 | 
| 缩小 | 布尔值 | false | 是否应缩小输出 | 
| 简洁 | 布尔值 | false | 设置为 true减少空白(但不超过opts.compact) | 
| 文件名 | 串 | 用于警告消息 | |
| jsonCompatibleStrings | 布尔值 | false | 设置为true以 jsesc与“ json” 一起运行:true以打印“ \ u00A9”与“©”; | 
源地图的选项:
| 名称 | 类型 | 默认 | 描述 | 
|---|---|---|---|
| sourceMaps | 布尔值 | false | 启用生成源地图 | 
| sourceRoot | 串 | 源映射中所有相对URL的根 | |
| sourceFileName | 串 | 源代码的文件名(即 code参数中的代码)。仅当code为字符串时才使用。 | 
来自多个来源的AST
在大多数情况下,Babel会将输入文件与输出文件进行1:1转换。但是,您可能正在处理由多个源(包括JS文件,模板等)构造的AST。如果是这种情况,并且您希望源映射反映正确的源,则需要将对象传递给generate作为code参数。键应该是源文件名,值应该是源内容。
这是一个可能看起来像的例子:
import {parse} from '@babel/parser'; import generate from '@babel/generator'; const a = 'var a = 1;'; const b = 'var b = 2;'; const astA = parse(a, { sourceFilename: 'a.js' }); const astB = parse(b, { sourceFilename: 'b.js' }); const ast = { type: 'Program', body: [].concat(astA.program.body, astB.program.body) }; const { code, map } = generate(ast, { sourceMaps: true }, { 'a.js': a, 'b.js': b }); // Sourcemap will point to both a.js and b.js where appropriate.
@babel/code-frame
npm install --save-dev @babel/code-frame
Usage
import { codeFrameColumns } from '@babel/code-frame'; const rawLines = `class Foo { constructor() }`; const location = { start: { line: 2, column: 16 } }; const result = codeFrameColumns(rawLines, location, { /* options */ }); console.log(result);
1 | class Foo { > 2 | constructor() | ^ 3 | }
如果列号未知,则可以省略。
您还可以在中传递end哈希值location。
import { codeFrameColumns } from '@babel/code-frame'; const rawLines = `class Foo { constructor() { console.log("hello"); } }`; const location = { start: { line: 2, column: 17 }, end: { line: 4, column: 3 } }; const result = codeFrameColumns(rawLines, location, { /* options */ }); console.log(result);
1 | class Foo { > 2 | constructor() { | ^ > 3 | console.log("hello"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ > 4 | } | ^^^ 5 | };
选件
highlightCode
boolean,默认为false。
切换突出显示代码的语法作为终端的JavaScript。
linesAbove
number,默认为2。
调整行数以在错误上方显示。
linesBelow
number,默认为3。
调整行数以在错误下方显示。
forceColor
boolean,默认为false。
启用它以强制语法将代码突出显示为JavaScript(对于非终端);覆盖highlightCode。
message
string,否则什么也没有
传递要在代码中突出显示的位置旁边内联显示的字符串(如果可能)。如果无法内联放置,它将被放置在代码框上方。
1 | class Foo { > 2 | constructor() | ^ Missing { 3 | };
从以前的版本升级
在版本7之前,此模块公开的唯一API是用于单行和可选的列指针。现在,旧的API将记录弃用警告。
新的API带有一个location对象,类似于AST中提供的对象。
这是已弃用(但仍可用)的API的示例:
import codeFrame from '@babel/code-frame'; const rawLines = `class Foo { constructor() }`; const lineNumber = 2; const colNumber = 16; const result = codeFrame(rawLines, lineNumber, colNumber, { /* options */ }); console.log(result);
要使用新的API获得相同的突出显示,请执行以下操作:
import { codeFrameColumns } from '@babel/code-frame'; const rawLines = `class Foo { constructor() { console.log("hello"); } }`; const location = { start: { line: 2, column: 16 } }; const result = codeFrameColumns(rawLines, location, { /* options */ }); console.log(result);
@babel/helpers
npm install --save-dev @babel/helpers
import * as helpers from '@babel/helpers'; import * as t from '@babel/types'; const typeofHelper = helpers.get('typeof'); t.isExpressionStatement(typeofHelper); // true
Inside a plugin:
export default { visitor: { UnaryExpression(path) { // The .addHelper function adds, if needed, the helper to the file // and returns an expression which references the helper const typeofHelper = this.addHelper("typeof"); t.isExpression(typeofHelper); // true } };
定义助手
注意:此软件包仅供该存储库中包含的软件包使用。当前,第三方插件无法定义助手。
帮助程序在src/helpers.js文件中定义,它们必须是遵循以下准则的有效模块:
- 它们必须具有默认导出,这是它们的入口点。
- 他们可以仅通过使用默认导入来导入其他帮助程序。
- 他们不能命名出口。
helpers.customHelper = defineHelper(` import dep from "dependency"; const foo = 2; export default function getFooTimesDepPlusX(x) { return foo * dep() + x; } `);
@ babel /运行时
npm install --save @babel/runtime
用法
它打算dependency与Babel插件一起用作运行时@babel/plugin-transform-runtime。
为什么
有时Babel可能会在输出中注入一些跨文件相同的代码,因此有可能被重用。
例如,使用类转换(无松散模式):
class Circle {}
function _classCallCheck(instance, Constructor) { //... } var Circle = function Circle() { _classCallCheck(this, Circle); };
这意味着每个包含类的文件都将具有_classCallCheck每次重复的功能。
使用@babel/plugin-transform-runtime,它将替换对@babel/runtime版本的功能的引用。
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck"); var Circle = function Circle() { _classCallCheck(this, Circle); };
@babel/runtime 只是包含以模块化方式实现功能的程序包。
@ babel /模板
安装
npm install --save-dev @babel/template
字符串用法
当template使用带有字符串参数的函数进行调用时,可以提供占位符,这些占位符将在使用模板时被替换。
您可以使用两种不同的占位符:语法占位符(例如%%name%%)或标识符占位符(例如NAME)。@babel/template默认情况下支持这两种方法,但是不能混用。如果需要明确说明所使用的语法,则可以使用该syntacticPlaceholders选项。
请注意,语法占位符是在Babel 7.4.0中引入的。如果您不控制@babel/template版本(例如,从@babel/core@^7.0.0对等依赖项导入版本),则必须使用标识符占位符。另一方面,句法占位符有一些优点:它们可用于标识符可能是语法错误的地方(例如,代替函数体或在导出声明中使用),并且它们不与大写变量(例如,new URL())冲突。
输入(语法占位符):
import template from "@babel/template"; import generate from "@babel/generator"; import * as t from "@babel/types"; const buildRequire = template(` var %%importName%% = require(%%source%%); `); const ast = buildRequire({ importName: t.identifier("myModule"), source: t.stringLiteral("my-module"), }); console.log(generate(ast).code);
输入(标识符占位符):
const buildRequire = template(` var IMPORT_NAME = require(SOURCE); `); const ast = buildRequire({ IMPORT_NAME: t.identifier("myModule"), SOURCE: t.stringLiteral("my-module"), });
const myModule = require("my-module");
.ast
如果没有使用占位符,并且您只想一种简单的方法将字符串解析为AST,则可以使用.ast模板的版本。
const ast = template.ast(` var myModule = require("my-module"); `);
它将解析并直接返回AST。
模板文字用法
import template from "@babel/template"; import generate from "@babel/generator"; import * as t from "@babel/types"; const source = "my-module"; const fn = template` var IMPORT_NAME = require('${source}'); `; const ast = fn({ IMPORT_NAME: t.identifier("myModule"), }); console.log(generate(ast).code);
请注意,可以将占位符作为模板文字的一部分直接传递,以使内容尽可能地可读,也可以将它们传递到模板函数中。
.ast
如果没有使用占位符,并且您只想一种简单的方法将字符串解析为AST,则可以使用.ast模板的版本。
const name = "my-module"; const mod = "myModule"; const ast = template.ast` var ${mod} = require("${name}"); `;
它将解析并直接返回AST。请注意,与前面提到的基于字符串的版本不同,由于这是模板文字,因此使用模板文字替换执行替换仍然有效。
AST结果
该@babel/templateAPI公开了一些灵活的API,以使其尽可能容易地创建具有预期结构的AST。这些中的每一个还具有上述.ast属性。
template
template 根据解析的结果返回一个语句或语句数组。
template.smart
这与默认templateAPI 相同,根据解析结果返回单个节点或节点数组。
template.statement
template.statement("foo;")() 返回单个语句节点,如果结果不是单个语句,则抛出异常。
template.statements
template.statements("foo;foo;")() 返回语句节点的数组。
template.expression
template.expression("foo")() 返回表达式节点。
template.program
template.program("foo;")()返回Program模板的节点。
API
template(code, [opts])
码
类型: string
选项
@babel/template接受Babel Parser的所有选项,并指定一些自己的默认值:
- allowReturnOutsideFunction- true默认设置为。
- allowSuperOutsideMethod- true默认设置为。
- sourceType- module默认设置为。
句法占位符
类型:boolean 默认值:true如果使用%%foo%%-style占位符;false除此以外。
如果此选项为true,则可以%%foo%%在模板中标记占位符。如果为false,则占位符是由placeholderWhitelist和placeholderPattern选项确定的标识符。
占位符
类型:Set<string> 默认值:undefined
该选项与
syntacticPlaceholders: true
一组自动接受的占位符名称。此列表中的项目不需要匹配给定的占位符模式。
占位符模式
类型:RegExp | false 默认值:/^[_$A-Z0-9]+$/
该选项与
syntacticPlaceholders: true
查找标识符和StringLiteral节点时应被视为占位符的搜索模式。“ false”将完全禁用占位符搜索,仅保留“ placeholderWhitelist”值来查找占位符。
reserveComments
类型:boolean 默认值:false
设置此选项可true保留code参数中的所有注释。
返回值
默认情况下,@babel/template返回a function,该替代对象由替换的可选对象调用。有关示例,请参见用法部分。
使用时.ast,AST将直接返回。
@ babel /遍历
用法
我们可以将其与babel解析器一起使用来遍历和更新节点:
import * as parser from "@babel/parser"; import traverse from "@babel/traverse"; const code = `function square(n) { return n * n; }`; const ast = parser.parse(code); traverse(ast, { enter(path) { if (path.isIdentifier({ name: "n" })) { path.node.name = "x"; } } });
另外,我们可以在语法树中定位特定的节点类型
traverse(ast, { FunctionDeclaration: function(path) { path.node.id.name = "x"; } })
@ babel /类型
npm install --save-dev @babel/types
API
anyTypeAnnotation
t.anyTypeAnnotation()
arrayExpression
t.arrayExpression(elements)
另请参阅t.isArrayExpression(node, opts)和t.assertArrayExpression(node, opts)。
别名: Expression
- elements:- Array<null | Expression | SpreadElement>(默认:- [])
argumentsPlaceholder
t.argumentPlaceholder()
另请参阅t.isArgumentPlaceholder(node, opts)和t.assertArgumentPlaceholder(node, opts)。
别名:无
arrayPattern
t.arrayPattern(elements)
另请参阅t.isArrayPattern(node, opts)和t.assertArrayPattern(node, opts)。
别名:Pattern,PatternLike,LVal
- elements:(- Array<PatternLike>必填)
- decorators:- Array<Decorator>(默认:- null)
- typeAnnotation:- TypeAnnotation | TSTypeAnnotation | Noop(默认:- null)
arrayTypeAnnotation
t.arrayTypeAnnotation(elementType)
另请参阅t.isArrayTypeAnnotation(node, opts)和t.assertArrayTypeAnnotation(node, opts)。
别名:Flow,FlowType
- elementType:(- FlowType必填)
arrowFunctionExpression
t.arrowFunctionExpression(params, body, async)
另请参阅t.isArrowFunctionExpression(node, opts)和t.assertArrowFunctionExpression(node, opts)。
别名:Scopable,Function,BlockParent,FunctionParent,Expression,Pureish
- params:(- Array<LVal>必填)
- body:(- BlockStatement | Expression必填)
- async:- boolean(默认:- false)
- expression:- boolean(默认:- null)
- generator:- boolean(默认:- false)
- returnType:- TypeAnnotation | TSTypeAnnotation | Noop(默认:- null)
- typeParameters:- TypeParameterDeclaration | TSTypeParameterDeclaration | Noop(默认:- null)
assignmentExpression
t.assignmentExpression(operator, left, right)
另请参阅t.isAssignmentExpression(node, opts)和t.assertAssignmentExpression(node, opts)。
别名: Expression
- operator:(- string必填)
- left:(- LVal必填)
- right:(- Expression必填)
AssignmentPattern
t.assignmentPattern(left, right)
另请参阅t.isAssignmentPattern(node, opts)和t.assertAssignmentPattern(node, opts)。
别名:Pattern,PatternLike,LVal
- left:(- Identifier | ObjectPattern | ArrayPattern必填)
- right:(- Expression必填)
- decorators:- Array<Decorator>(默认:- null)
- typeAnnotation:- TypeAnnotation | TSTypeAnnotation | Noop(默认:- null)
awaitExpression
t.awaitExpression(argument)
另请参阅t.isAwaitExpression(node, opts)和t.assertAwaitExpression(node, opts)。
别名:Expression,Terminatorless
- argument:(- Expression必填)
bigIntLiteral
t.bigIntLiteral(value)
另请参阅t.isBigIntLiteral(node, opts)和t.assertBigIntLiteral(node, opts)。
别名:Expression,Pureish,Literal,Immutable
- value:(- string必填)
binaryExpression
t.binaryExpression(operator, left, right)
另请参阅t.isBinaryExpression(node, opts)和t.assertBinaryExpression(node, opts)。
别名:Binary,Expression
- operator:(- "+" | "-" | "/" | "%" | "*" | "**" | "&" | "|" | ">>" | ">>>" | "<<" | "^" | "==" | "===" | "!=" | "!==" | "in" | "instanceof" | ">" | "<" | ">=" | "<="必填)
- left:(- Expression必填)
- right:(- Expression必填)
bindExpression
t.bindExpression(object, callee)
另请参阅t.isBindExpression(node, opts)和t.assertBindExpression(node, opts)。
别名: Expression
- object(需要)
- callee(需要)
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号