Comparing version
@@ -70,19 +70,50 @@ import { CompilationContext, JsPlugin } from '@farmfe/core'; | ||
} | ||
type StringOrRegExp = string | RegExp; | ||
type FilterPattern = Arrayable<StringOrRegExp>; | ||
type StringFilter = FilterPattern | { | ||
include?: FilterPattern | ||
exclude?: FilterPattern | ||
}; | ||
interface HookFilter { | ||
id?: StringFilter; | ||
code?: StringFilter; | ||
} | ||
interface ObjectHook< | ||
T extends HookFnMap[keyof HookFnMap], | ||
F extends keyof HookFilter | ||
> { | ||
filter?: Pick<HookFilter, F>; | ||
handler: T; | ||
} | ||
type Hook< | ||
T extends HookFnMap[keyof HookFnMap], | ||
F extends keyof HookFilter | ||
> = T | ObjectHook<T, F>; | ||
interface HookFnMap { | ||
buildStart: (this: UnpluginBuildContext) => Thenable<void>; | ||
buildEnd: (this: UnpluginBuildContext) => Thenable<void>; | ||
transform: (this: UnpluginBuildContext & UnpluginContext, code: string, id: string) => Thenable<TransformResult>; | ||
load: (this: UnpluginBuildContext & UnpluginContext, id: string) => Thenable<TransformResult>; | ||
resolveId: (this: UnpluginBuildContext & UnpluginContext, id: string, importer: string | undefined, options: { | ||
isEntry: boolean | ||
}) => Thenable<string | ExternalIdResult | null | undefined>; | ||
writeBundle: (this: void) => Thenable<void>; | ||
} | ||
interface UnpluginOptions { | ||
name: string; | ||
enforce?: "post" | "pre" | undefined; | ||
buildStart?: (this: UnpluginBuildContext) => Promise<void> | void; | ||
buildEnd?: (this: UnpluginBuildContext) => Promise<void> | void; | ||
transform?: (this: UnpluginBuildContext & UnpluginContext, code: string, id: string) => Thenable<TransformResult>; | ||
load?: (this: UnpluginBuildContext & UnpluginContext, id: string) => Thenable<TransformResult>; | ||
resolveId?: (this: UnpluginBuildContext & UnpluginContext, id: string, importer: string | undefined, options: { | ||
isEntry: boolean | ||
}) => Thenable<string | ExternalIdResult | null | undefined>; | ||
buildStart?: HookFnMap["buildStart"]; | ||
buildEnd?: HookFnMap["buildEnd"]; | ||
transform?: Hook<HookFnMap["transform"], "code" | "id">; | ||
load?: Hook<HookFnMap["load"], "id">; | ||
resolveId?: Hook<HookFnMap["resolveId"], "id">; | ||
writeBundle?: HookFnMap["writeBundle"]; | ||
watchChange?: (this: UnpluginBuildContext, id: string, change: { | ||
event: "create" | "update" | "delete" | ||
}) => void; | ||
writeBundle?: (this: void) => Promise<void> | void; | ||
/** | ||
* Custom predicate function to filter modules to be loaded. | ||
* When omitted, all modules will be included (might have potential perf impact on Webpack). | ||
* | ||
* @deprecated Use `load.filter` instead. | ||
*/ | ||
@@ -93,2 +124,4 @@ loadInclude?: (id: string) => boolean | null | undefined; | ||
* When omitted, all modules will be included (might have potential perf impact on Webpack). | ||
* | ||
* @deprecated Use `transform.filter` instead. | ||
*/ | ||
@@ -191,3 +224,2 @@ transformInclude?: (id: string) => boolean | null | undefined; | ||
>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginInstance<UserOptions>["vite"]; | ||
/** @experimental do not use it in production */ | ||
declare function createRolldownPlugin< | ||
@@ -215,2 +247,2 @@ UserOptions, | ||
export { createEsbuildPlugin, createFarmPlugin, createRolldownPlugin, createRollupPlugin, createRspackPlugin, createUnloaderPlugin, createUnplugin, createVitePlugin, createWebpackPlugin }; | ||
export type { Arrayable, ExternalIdResult, NativeBuildContext, Nullable, ResolvedUnpluginOptions, SourceMapCompact, Thenable, TransformResult, UnpluginBuildContext, UnpluginContext, UnpluginContextMeta, UnpluginFactory, UnpluginFactoryOutput, UnpluginInstance, UnpluginMessage, UnpluginOptions }; | ||
export type { Arrayable, ExternalIdResult, FilterPattern, Hook, HookFilter, HookFnMap, NativeBuildContext, Nullable, ObjectHook, ResolvedUnpluginOptions, SourceMapCompact, StringFilter, StringOrRegExp, Thenable, TransformResult, UnpluginBuildContext, UnpluginContext, UnpluginContextMeta, UnpluginFactory, UnpluginFactoryOutput, UnpluginInstance, UnpluginMessage, UnpluginOptions }; |
@@ -1,6 +0,6 @@ | ||
import { parse } from "./context-CyqyI0ug.js"; | ||
import { normalizeAbsolutePath, transformUse } from "./webpack-like-CfLIv0IN.js"; | ||
import { createBuildContext$1 as createBuildContext, normalizeMessage$1 as normalizeMessage } from "./context-B_3zWGEx.js"; | ||
import { normalizeObjectHook, parse, toArray } from "./context-OdRhMf7r.js"; | ||
import { normalizeAbsolutePath, transformUse } from "./webpack-like-WvinrlST.js"; | ||
import { createBuildContext$1 as createBuildContext, normalizeMessage$1 as normalizeMessage } from "./context-ePjTIFka.js"; | ||
import { FakeVirtualModulesPlugin, decodeVirtualModuleId, encodeVirtualModuleId, isVirtualModuleId } from "./utils-BrnUOYYS.js"; | ||
import { contextOptionsFromCompilation, createBuildContext as createBuildContext$1, normalizeMessage as normalizeMessage$1 } from "./context-DvA_cJ4P.js"; | ||
import { contextOptionsFromCompilation, createBuildContext as createBuildContext$1, normalizeMessage as normalizeMessage$1 } from "./context-C3dRvvlN.js"; | ||
import fs from "node:fs"; | ||
@@ -14,10 +14,2 @@ import path, { extname, resolve } from "node:path"; | ||
//#region src/utils/general.ts | ||
function toArray(array) { | ||
array = array || []; | ||
if (Array.isArray(array)) return array; | ||
return [array]; | ||
} | ||
//#endregion | ||
//#region node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs | ||
@@ -1074,8 +1066,11 @@ const comma = ",".charCodeAt(0); | ||
if (plugin.resolveId) onResolve({ filter: onResolveFilter }, async (args) => { | ||
if (initialOptions.external?.includes(args.path)) return void 0; | ||
const id = args.path; | ||
if (initialOptions.external?.includes(id)) return; | ||
const { handler, filter } = normalizeObjectHook("resolveId", plugin.resolveId); | ||
if (!filter(id)) return; | ||
const { errors, warnings, mixedContext } = createPluginContext(context); | ||
const isEntry = args.kind === "entry-point"; | ||
const result = await plugin.resolveId.call( | ||
const result = await handler.call( | ||
mixedContext, | ||
args.path, | ||
id, | ||
// We explicitly have this if statement here for consistency with | ||
@@ -1105,16 +1100,18 @@ // the integration of other bundlers. | ||
if (plugin.load) onLoad({ filter: onLoadFilter }, async (args) => { | ||
const { handler, filter } = normalizeObjectHook("load", plugin.load); | ||
const id = args.path + (args.suffix || ""); | ||
if (plugin.loadInclude && !plugin.loadInclude(id)) return; | ||
if (!filter(id)) return; | ||
const { errors, warnings, mixedContext } = createPluginContext(context); | ||
const resolveDir = path.dirname(args.path); | ||
let code, map; | ||
if (plugin.load && (!plugin.loadInclude || plugin.loadInclude(id))) { | ||
const result = await plugin.load.call(mixedContext, id); | ||
if (typeof result === "string") code = result; | ||
else if (typeof result === "object" && result !== null) { | ||
code = result.code; | ||
map = result.map; | ||
} | ||
let code; | ||
let map; | ||
const result = await handler.call(mixedContext, id); | ||
if (typeof result === "string") code = result; | ||
else if (typeof result === "object" && result !== null) { | ||
code = result.code; | ||
map = result.map; | ||
} | ||
if (code === void 0) return null; | ||
if (map) code = processCodeWithSourceMap(map, code); | ||
const resolveDir = path.dirname(args.path); | ||
return { | ||
@@ -1130,9 +1127,11 @@ contents: code, | ||
if (plugin.transform) onTransform({ filter: onLoadFilter }, async (args) => { | ||
const { handler, filter } = normalizeObjectHook("transform", plugin.transform); | ||
const id = args.path + (args.suffix || ""); | ||
if (plugin.transformInclude && !plugin.transformInclude(id)) return; | ||
let code = await args.getContents(); | ||
if (!filter(id, code)) return; | ||
const { mixedContext, errors, warnings } = createPluginContext(context); | ||
const resolveDir = path.dirname(args.path); | ||
let code = await args.getContents(); | ||
let map; | ||
const result = await plugin.transform.call(mixedContext, code, id); | ||
const result = await handler.call(mixedContext, code, id); | ||
if (typeof result === "string") code = result; | ||
@@ -1370,2 +1369,5 @@ else if (typeof result === "object" && result !== null) { | ||
const resolvedIdPath = path.resolve(params.importer ?? ""); | ||
const id = decodeStr(params.source); | ||
const { handler, filter } = normalizeObjectHook("resolveId", _resolveId); | ||
if (!filter(id)) return null; | ||
let isEntry = false; | ||
@@ -1377,3 +1379,3 @@ if (isObject(params.kind) && "entry" in params.kind) { | ||
const farmContext = createFarmContext(context, resolvedIdPath); | ||
const resolveIdResult = await _resolveId.call(Object.assign(unpluginContext(context), farmContext), decodeStr(params.source), resolvedIdPath ?? null, { isEntry }); | ||
const resolveIdResult = await handler.call(Object.assign(unpluginContext(context), farmContext), id, resolvedIdPath ?? null, { isEntry }); | ||
if (isString(resolveIdResult)) return { | ||
@@ -1405,6 +1407,7 @@ resolvedPath: removeQuery(encodeStr(resolveIdResult)), | ||
const loader = formatTransformModuleType(id); | ||
const shouldLoadInclude = plugin.loadInclude?.(id); | ||
if (!shouldLoadInclude) return null; | ||
if (plugin.loadInclude && !plugin.loadInclude?.(id)) return null; | ||
const { handler, filter } = normalizeObjectHook("load", _load); | ||
if (!filter(id)) return null; | ||
const farmContext = createFarmContext(context, id); | ||
const content = await _load.call(Object.assign(unpluginContext(context), farmContext), id); | ||
const content = await handler.call(Object.assign(unpluginContext(context), farmContext), id); | ||
const loadFarmResult = { | ||
@@ -1429,6 +1432,7 @@ content: getContentValue(content), | ||
const loader = formatTransformModuleType(id); | ||
const shouldTransformInclude = plugin.transformInclude?.(id); | ||
if (plugin.transformInclude && !plugin.transformInclude(id)) return null; | ||
const { handler, filter } = normalizeObjectHook("transform", _transform); | ||
if (!filter(id, params.content)) return null; | ||
const farmContext = createFarmContext(context, id); | ||
if (!shouldTransformInclude) return null; | ||
const resource = await _transform.call(Object.assign(unpluginContext(context), farmContext), params.content, id); | ||
const resource = await handler.call(Object.assign(unpluginContext(context), farmContext), params.content, id); | ||
if (resource && typeof resource !== "string") { | ||
@@ -1480,19 +1484,48 @@ const transformFarmResult = { | ||
function toRollupPlugin(plugin, key) { | ||
if (plugin.transform && plugin.transformInclude) { | ||
const _transform = plugin.transform; | ||
plugin.transform = function(code, id, ...args) { | ||
if (plugin.transformInclude && !plugin.transformInclude(id)) return null; | ||
return _transform.call(this, code, id, ...args); | ||
}; | ||
const nativeFilter = key === "rolldown"; | ||
if (plugin.resolveId && !nativeFilter && typeof plugin.resolveId === "object" && plugin.resolveId.filter) { | ||
const resolveIdHook = plugin.resolveId; | ||
const { handler, filter } = normalizeObjectHook("load", resolveIdHook); | ||
replaceHookHandler("resolveId", resolveIdHook, function(...args) { | ||
const [id] = args; | ||
const supportFilter = supportNativeFilter(this); | ||
if (!supportFilter && !filter(id)) return; | ||
return handler.apply(this, args); | ||
}); | ||
} | ||
if (plugin.load && plugin.loadInclude) { | ||
const _load = plugin.load; | ||
plugin.load = function(id, ...args) { | ||
if (plugin.loadInclude && !plugin.loadInclude(id)) return null; | ||
return _load.call(this, id, ...args); | ||
}; | ||
if (plugin.load && (plugin.loadInclude || !nativeFilter && typeof plugin.load === "object" && plugin.load.filter)) { | ||
const loadHook = plugin.load; | ||
const { handler, filter } = normalizeObjectHook("load", loadHook); | ||
replaceHookHandler("load", loadHook, function(...args) { | ||
const [id] = args; | ||
if (plugin.loadInclude && !plugin.loadInclude(id)) return; | ||
const supportFilter = supportNativeFilter(this); | ||
if (!supportFilter && !filter(id)) return; | ||
return handler.apply(this, args); | ||
}); | ||
} | ||
if (plugin.transform && (plugin.transformInclude || !nativeFilter && typeof plugin.transform === "object" && plugin.transform.filter)) { | ||
const transformHook = plugin.transform; | ||
const { handler, filter } = normalizeObjectHook("transform", transformHook); | ||
replaceHookHandler("transform", transformHook, function(...args) { | ||
const [code, id] = args; | ||
if (plugin.transformInclude && !plugin.transformInclude(id)) return; | ||
const supportFilter = supportNativeFilter(this); | ||
if (!supportFilter && !filter(id, code)) return; | ||
return handler.apply(this, args); | ||
}); | ||
} | ||
if (plugin[key]) Object.assign(plugin, plugin[key]); | ||
return plugin; | ||
function replaceHookHandler(name, hook, handler) { | ||
if (typeof hook === "function") plugin[name] = handler; | ||
else hook.handler = handler; | ||
} | ||
} | ||
function supportNativeFilter(context) { | ||
const rollupVersion = context?.meta?.rollupVersion; | ||
if (!rollupVersion) return false; | ||
const [major, minor] = rollupVersion.split("."); | ||
return Number(major) > 4 || Number(major) === 4 && Number(minor) >= 38; | ||
} | ||
@@ -1514,3 +1547,3 @@ //#endregion | ||
//#endregion | ||
//#region node_modules/.pnpm/tsdown@0.6.9_publint@0.3.5_typescript@5.8.2_unplugin-unused@0.4.1/node_modules/tsdown/esm-shims.js | ||
//#region node_modules/.pnpm/tsdown@0.6.10_publint@0.3.5_typescript@5.8.3_unplugin-unused@0.4.1/node_modules/tsdown/esm-shims.js | ||
const getFilename = () => fileURLToPath(import.meta.url); | ||
@@ -1562,3 +1595,5 @@ const getDirname = () => path.dirname(getFilename()); | ||
}; | ||
const resolveIdResult = await plugin.resolveId.call({ | ||
const { handler, filter } = normalizeObjectHook("resolveId", plugin.resolveId); | ||
if (!filter(id)) return; | ||
const resolveIdResult = await handler.call({ | ||
...context, | ||
@@ -1588,2 +1623,4 @@ ...pluginContext | ||
if (plugin.loadInclude && !plugin.loadInclude(id)) return false; | ||
const { filter } = normalizeObjectHook("load", plugin.load); | ||
if (!filter(id)) return false; | ||
return !externalModules.has(id); | ||
@@ -1710,3 +1747,5 @@ }, | ||
}; | ||
const resolveIdResult = await plugin.resolveId.call({ | ||
const { handler, filter } = normalizeObjectHook("resolveId", plugin.resolveId); | ||
if (!filter(id)) return callback(); | ||
const resolveIdResult = await handler.call({ | ||
...context, | ||
@@ -1779,2 +1818,4 @@ ...pluginContext | ||
if (plugin.loadInclude && !plugin.loadInclude(id)) return false; | ||
const { filter } = normalizeObjectHook("load", plugin.load); | ||
if (!filter(id)) return false; | ||
return !externalModules.has(id); | ||
@@ -1781,0 +1822,0 @@ } |
@@ -1,4 +0,4 @@ | ||
import "../../context-CyqyI0ug.js"; | ||
import { normalizeAbsolutePath } from "../../webpack-like-CfLIv0IN.js"; | ||
import { createBuildContext$1 as createBuildContext, createContext$1 as createContext } from "../../context-B_3zWGEx.js"; | ||
import { normalizeObjectHook } from "../../context-OdRhMf7r.js"; | ||
import { normalizeAbsolutePath } from "../../webpack-like-WvinrlST.js"; | ||
import { createBuildContext$1 as createBuildContext, createContext$1 as createContext } from "../../context-ePjTIFka.js"; | ||
import { decodeVirtualModuleId, isVirtualModuleId } from "../../utils-BrnUOYYS.js"; | ||
@@ -14,3 +14,4 @@ | ||
const context = createContext(this); | ||
const res = await plugin.load.call(Object.assign({}, this._compilation && createBuildContext(this._compiler, this._compilation, this), context), normalizeAbsolutePath(id)); | ||
const { handler } = normalizeObjectHook("load", plugin.load); | ||
const res = await handler.call(Object.assign({}, this._compilation && createBuildContext(this._compiler, this._compilation, this), context), normalizeAbsolutePath(id)); | ||
if (res == null) callback(null, source, map); | ||
@@ -17,0 +18,0 @@ else if (typeof res !== "string") callback(null, res.code, res.map ?? map); |
@@ -1,3 +0,3 @@ | ||
import "../../context-CyqyI0ug.js"; | ||
import { createBuildContext$1 as createBuildContext, createContext$1 as createContext } from "../../context-B_3zWGEx.js"; | ||
import { normalizeObjectHook } from "../../context-OdRhMf7r.js"; | ||
import { createBuildContext$1 as createBuildContext, createContext$1 as createContext } from "../../context-ePjTIFka.js"; | ||
@@ -11,4 +11,6 @@ //#region src/rspack/loaders/transform.ts | ||
const context = createContext(this); | ||
const { handler, filter } = normalizeObjectHook("transform", plugin.transform); | ||
if (!filter(this.resource, source)) return callback(null, source, map); | ||
try { | ||
const res = await plugin.transform.call(Object.assign({}, this._compilation && createBuildContext(this._compiler, this._compilation, this), context), source, id); | ||
const res = await handler.call(Object.assign({}, this._compilation && createBuildContext(this._compiler, this._compilation, this), context), source, id); | ||
if (res == null) callback(null, source, map); | ||
@@ -15,0 +17,0 @@ else if (typeof res !== "string") callback(null, res.code, map == null ? map : res.map || map); |
@@ -1,4 +0,4 @@ | ||
import "../../context-CyqyI0ug.js"; | ||
import { normalizeAbsolutePath } from "../../webpack-like-CfLIv0IN.js"; | ||
import { createBuildContext, createContext } from "../../context-DvA_cJ4P.js"; | ||
import { normalizeObjectHook } from "../../context-OdRhMf7r.js"; | ||
import { normalizeAbsolutePath } from "../../webpack-like-WvinrlST.js"; | ||
import { createBuildContext, createContext } from "../../context-C3dRvvlN.js"; | ||
@@ -13,3 +13,4 @@ //#region src/webpack/loaders/load.ts | ||
const context = createContext(this); | ||
const res = await plugin.load.call(Object.assign({}, createBuildContext({ | ||
const { handler } = normalizeObjectHook("load", plugin.load); | ||
const res = await handler.call(Object.assign({}, createBuildContext({ | ||
addWatchFile: (file) => { | ||
@@ -16,0 +17,0 @@ this.addDependency(file); |
@@ -1,3 +0,3 @@ | ||
import "../../context-CyqyI0ug.js"; | ||
import { createBuildContext, createContext } from "../../context-DvA_cJ4P.js"; | ||
import { normalizeObjectHook } from "../../context-OdRhMf7r.js"; | ||
import { createBuildContext, createContext } from "../../context-C3dRvvlN.js"; | ||
@@ -10,4 +10,6 @@ //#region src/webpack/loaders/transform.ts | ||
const context = createContext(this); | ||
const { handler, filter } = normalizeObjectHook("transform", plugin.transform); | ||
if (!filter(this.resource, source)) return callback(null, source, map); | ||
try { | ||
const res = await plugin.transform.call(Object.assign({}, createBuildContext({ | ||
const res = await handler.call(Object.assign({}, createBuildContext({ | ||
addWatchFile: (file) => { | ||
@@ -14,0 +16,0 @@ this.addDependency(file); |
{ | ||
"name": "unplugin", | ||
"type": "module", | ||
"version": "2.2.2", | ||
"packageManager": "pnpm@10.6.5", | ||
"version": "2.3.0", | ||
"packageManager": "pnpm@10.8.0", | ||
"description": "Unified plugin system for build tools", | ||
@@ -46,2 +46,3 @@ "license": "MIT", | ||
"acorn": "^8.14.1", | ||
"picomatch": "^4.0.2", | ||
"webpack-virtual-modules": "^0.6.2" | ||
@@ -51,15 +52,17 @@ }, | ||
"@ampproject/remapping": "^2.3.0", | ||
"@antfu/eslint-config": "^4.10.2", | ||
"@antfu/eslint-config": "^4.11.0", | ||
"@antfu/ni": "^24.3.0", | ||
"@farmfe/cli": "^1.0.4", | ||
"@farmfe/core": "^1.7.1", | ||
"@rspack/cli": "^1.2.8", | ||
"@rspack/core": "^1.2.8", | ||
"@farmfe/core": "^1.7.2", | ||
"@rspack/cli": "^1.3.4", | ||
"@rspack/core": "^1.3.4", | ||
"@types/fs-extra": "^11.0.4", | ||
"@types/node": "^22.13.11", | ||
"@types/node": "^22.14.0", | ||
"@types/picomatch": "^3.0.2", | ||
"ansis": "^3.17.0", | ||
"bumpp": "^10.1.0", | ||
"esbuild": "^0.25.1", | ||
"esbuild": "^0.25.2", | ||
"esbuild-plugin-copy": "^2.1.1", | ||
"eslint": "^9.22.0", | ||
"eslint": "^9.24.0", | ||
"eslint-plugin-format": "^1.0.1", | ||
"fast-glob": "^3.3.3", | ||
@@ -70,19 +73,19 @@ "fs-extra": "^11.3.0", | ||
"magic-string": "^0.30.17", | ||
"rolldown": "^1.0.0-beta.6", | ||
"rollup": "^4.36.0", | ||
"rolldown": "^1.0.0-beta.7", | ||
"rollup": "^4.39.0", | ||
"simple-git-hooks": "^2.12.1", | ||
"tsdown": "^0.6.9", | ||
"typescript": "~5.8.2", | ||
"tsdown": "^0.6.10", | ||
"typescript": "~5.8.3", | ||
"unloader": "^0.4.3", | ||
"unplugin": "workspace:*", | ||
"vite": "^6.2.2", | ||
"vitest": "^3.0.9", | ||
"webpack": "^5.98.0", | ||
"vite": "^6.2.5", | ||
"vitest": "^3.1.1", | ||
"webpack": "^5.99.5", | ||
"webpack-cli": "^6.0.1" | ||
}, | ||
"resolutions": { | ||
"esbuild": "^0.25.1" | ||
"esbuild": "^0.25.2" | ||
}, | ||
"simple-git-hooks": { | ||
"pre-commit": "pnpm lint-staged" | ||
"pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged" | ||
}, | ||
@@ -89,0 +92,0 @@ "lint-staged": { |
@@ -11,3 +11,3 @@ # Unplugin | ||
- [Vite](https://vitejs.dev/) | ||
- [Vite](https://vite.dev/) | ||
- [Rollup](https://rollupjs.org/) | ||
@@ -17,3 +17,3 @@ - [Webpack](https://webpack.js.org/) | ||
- [Rspack](https://www.rspack.dev/) | ||
- [Rolldown](https://rolldown.rs/) (⚠️ experimental) | ||
- [Rolldown](https://rolldown.rs/) | ||
- [Farm](https://www.farmfe.org/) | ||
@@ -20,0 +20,0 @@ - And every framework built on top of them. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
183297
9.86%4858
8.7%3
50%32
6.67%+ Added
+ Added