@eycraf/permission-kit-vite-plugin 0.0.1 → 0.0.2

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
@@ -114,25 +114,62 @@ var PermissionState = class {
114
114
  getUsedPermissions() {
115
115
  return [...new Set(this.getAllUsages().map((item) => item.permission))].sort();
116
116
  }
117
+ getSummary() {
118
+ const usages = this.getAllUsages();
119
+ return {
120
+ permissions: new Set(usages.map((item) => item.permission)).size,
121
+ usages: usages.length,
122
+ files: new Set(usages.map((item) => item.file)).size
123
+ };
124
+ }
117
125
  toManifest() {
118
- var _a;
119
- const result = {};
126
+ const grouped = /* @__PURE__ */ new Map();
120
127
  for (const usage of this.getAllUsages()) {
121
- const items = result[_a = usage.permission] ?? (result[_a] = []);
122
- const entry = {
123
- file: usage.file
124
- };
125
- if (usage.line !== void 0) {
126
- entry.line = usage.line;
127
- }
128
- if (usage.column !== void 0) {
129
- entry.column = usage.column;
130
- }
131
- items.push(entry);
128
+ const items = grouped.get(usage.permission) ?? [];
129
+ items.push(usage);
130
+ grouped.set(usage.permission, items);
132
131
  }
133
- return result;
132
+ return [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([permission, usages]) => {
133
+ const sortedUsages = [...usages].sort((left, right) => compareUsage(left, right));
134
+ const files = [...new Set(sortedUsages.map((item) => item.file))].sort(
135
+ (left, right) => left.localeCompare(right)
136
+ );
137
+ return {
138
+ permission,
139
+ count: sortedUsages.length,
140
+ files,
141
+ usages: sortedUsages.map(({ file, line, column, component }) => {
142
+ const entry = { file };
143
+ if (line !== void 0) {
144
+ entry.line = line;
145
+ }
146
+ if (column !== void 0) {
147
+ entry.column = column;
148
+ }
149
+ if (component !== void 0) {
150
+ entry.component = component;
151
+ }
152
+ return entry;
153
+ })
154
+ };
155
+ });
134
156
  }
135
157
  };
158
+ function compareUsage(left, right) {
159
+ const fileCompare = left.file.localeCompare(right.file);
160
+ if (fileCompare !== 0) {
161
+ return fileCompare;
162
+ }
163
+ const lineCompare = (left.line ?? 0) - (right.line ?? 0);
164
+ if (lineCompare !== 0) {
165
+ return lineCompare;
166
+ }
167
+ const columnCompare = (left.column ?? 0) - (right.column ?? 0);
168
+ if (columnCompare !== 0) {
169
+ return columnCompare;
170
+ }
171
+ return (left.component ?? "").localeCompare(right.component ?? "");
172
+ }
136
173
 
137
174
  // src/transformReact.ts
138
175
  var import_parser = require("@babel/parser");
@@ -192,7 +229,8 @@ function transformReactPermission(code, id, options) {
192
229
  if (permissionLiteral) {
193
230
  const usage = {
194
231
  permission: permissionLiteral,
195
- file: id
232
+ file: id,
233
+ component: componentName
196
234
  };
197
235
  if (permissionAttr.loc?.start.line !== void 0) {
198
236
  usage.line = permissionAttr.loc.start.line;
@@ -337,31 +375,57 @@ function isInsideCanElement(path4, componentName) {
337
375
  }
338
376
 
339
377
  // src/manifest.ts
378
+ function createManifest(state) {
379
+ return {
380
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
381
+ summary: state.getSummary(),
382
+ permissions: state.toManifest()
383
+ };
384
+ }
340
385
  function createManifestJson(state) {
341
- return JSON.stringify(
342
- {
343
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
344
- permissions: state.toManifest()
345
- },
346
- null,
347
- 2
348
- );
386
+ return JSON.stringify(createManifest(state), null, 2);
349
387
  }
350
388
 
351
389
  // src/dts.ts
352
390
  function createDts(permissions, typeName = "PermissionKey") {
353
- if (permissions.length === 0) {
354
- return `export type ${typeName} = string
355
- `;
356
- }
357
- const union = permissions.map((item) => ` | ${JSON.stringify(item)}`).join("\n");
391
+ const uniquePermissions = [...new Set(permissions)].sort(
392
+ (left, right) => left.localeCompare(right)
393
+ );
394
+ const permissionKeysType = uniquePermissions.length > 0 ? `readonly [${uniquePermissions.map((item) => JSON.stringify(item)).join(", ")}]` : "readonly string[]";
358
395
  return [
359
396
  "/* eslint-disable */",
360
397
  "// This file is generated by vite-plugin-permission.",
361
398
  "// Do not edit manually.",
362
399
  "",
363
- `export type ${typeName} =`,
364
- union,
400
+ `export declare const permissionKeys: ${permissionKeysType}`,
401
+ `export type ${typeName} = typeof permissionKeys[number]`,
402
+ "",
403
+ `export type PermissionUsage = {`,
404
+ ` permission: ${typeName}`,
405
+ " file: string",
406
+ " line?: number",
407
+ " column?: number",
408
+ " component?: string",
409
+ "}",
410
+ "",
411
+ `export type PermissionManifestEntry = {`,
412
+ ` permission: ${typeName}`,
413
+ " count: number",
414
+ " files: readonly string[]",
415
+ " usages: readonly PermissionUsage[]",
416
+ "}",
417
+ "",
418
+ "export type PermissionManifestSummary = {",
419
+ " permissions: number",
420
+ " usages: number",
421
+ " files: number",
422
+ "}",
423
+ "",
424
+ "export type PermissionManifest = {",
425
+ " generatedAt: string",
426
+ " summary: PermissionManifestSummary",
427
+ " permissions: readonly PermissionManifestEntry[]",
428
+ "}",
365
429
  ""
366
430
  ].join("\n");
367
431
  }
@@ -451,6 +515,50 @@ function toArray(value) {
451
515
  return Array.isArray(value) ? value : [value];
452
516
  }
453
517
 
518
+ // src/validate.ts
519
+ function validatePermissionUsages(usages, options, reporter) {
520
+ if (!options.enabled || options.unknownPermission === "off") {
521
+ return [];
522
+ }
523
+ const knownSet = new Set(options.permissions);
524
+ const grouped = /* @__PURE__ */ new Map();
525
+ for (const usage of usages) {
526
+ if (knownSet.has(usage.permission)) {
527
+ continue;
528
+ }
529
+ const items = grouped.get(usage.permission) ?? [];
530
+ items.push(usage);
531
+ grouped.set(usage.permission, items);
532
+ }
533
+ const unknownPermissions = [...grouped.keys()].sort((left, right) => left.localeCompare(right));
534
+ if (unknownPermissions.length === 0) {
535
+ return [];
536
+ }
537
+ const message = buildMessage(unknownPermissions, grouped);
538
+ if (options.unknownPermission === "error") {
539
+ throw new Error(message);
540
+ }
541
+ reporter?.warn(message);
542
+ return unknownPermissions;
543
+ }
544
+ function buildMessage(permissions, grouped) {
545
+ const lines = [`[vite-plugin-permission] Unknown permissions: ${permissions.join(", ")}`];
546
+ for (const permission of permissions) {
547
+ const usages = grouped.get(permission) ?? [];
548
+ for (const usage of usages.slice(0, 3)) {
549
+ lines.push(` - ${formatUsage(usage)}`);
550
+ }
551
+ }
552
+ return lines.join("\n");
553
+ }
554
+ function formatUsage(usage) {
555
+ const location = [usage.file, usage.line, usage.column].filter((item) => item !== void 0).join(":");
556
+ if (!usage.component) {
557
+ return `${usage.permission} (${location})`;
558
+ }
559
+ return `${usage.permission} (${location}, component=${usage.component})`;
560
+ }
561
+
454
562
  // src/index.ts
455
563
  var VIRTUAL_ID = "virtual:permission-manifest";
456
564
  var RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_ID;
@@ -504,7 +612,7 @@ function permissionPlugin(userOptions = {}) {
504
612
  },
505
613
  load(id) {
506
614
  if (id === RESOLVED_VIRTUAL_ID) {
507
- return `export default ${JSON.stringify(state.toManifest(), null, 2)}`;
615
+ return `export default ${JSON.stringify(createManifest(state), null, 2)}`;
508
616
  }
509
617
  return null;
510
618
  },
@@ -523,7 +631,7 @@ function permissionPlugin(userOptions = {}) {
523
631
  return null;
524
632
  }
525
633
  state.setFileUsage(id, result.usages);
526
- validatePermissions(result.usages.map((item) => item.permission));
634
+ validatePermissionUsages(result.usages, options.validate, transformContext);
527
635
  return {
528
636
  code: result.code,
529
637
  map: result.map
@@ -538,7 +646,7 @@ function permissionPlugin(userOptions = {}) {
538
646
  server = _server;
539
647
  server.middlewares.use("/__permission/manifest", async (_req, res) => {
540
648
  res.setHeader("Content-Type", "application/json");
541
- res.end(JSON.stringify(state.toManifest(), null, 2));
649
+ res.end(JSON.stringify(createManifest(state), null, 2));
542
650
  });
543
651
  },
544
652
  async handleHotUpdate(ctx) {
@@ -549,28 +657,10 @@ function permissionPlugin(userOptions = {}) {
549
657
  ctx.server.ws.send({
550
658
  type: "custom",
551
659
  event: "permission-manifest-update",
552
- data: state.toManifest()
660
+ data: createManifest(state)
553
661
  });
554
662
  }
555
663
  };
556
- function validatePermissions(usedPermissions) {
557
- if (!options.validate.enabled) {
558
- return;
559
- }
560
- if (options.validate.unknownPermission === "off") {
561
- return;
562
- }
563
- const knownSet = new Set(options.validate.permissions);
564
- const unknown = usedPermissions.filter((item) => !knownSet.has(item));
565
- if (unknown.length === 0) {
566
- return;
567
- }
568
- const message = `[vite-plugin-permission] Unknown permissions: ${unknown.join(", ")}`;
569
- if (options.validate.unknownPermission === "error") {
570
- throw new Error(message);
571
- }
572
- transformContext?.warn(message);
573
- }
574
664
  }
575
665
  async function emitManifestAndDts(root, options, state) {
576
666
  if (options.manifest.enabled) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/state.ts","../src/transformReact.ts","../src/manifest.ts","../src/dts.ts","../src/filter.ts","../src/rewrite.ts"],"sourcesContent":["// src/index.ts\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport { createFilter } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveOptions, type PermissionPluginOptions } from './options'\nimport { PermissionState } from './state'\nimport { transformReactPermission } from './transformReact'\nimport { createManifestJson } from './manifest'\nimport { createDts } from './dts'\nimport { createRootFilter } from './filter'\nimport { rewriteSourceFiles } from './rewrite'\n\nconst VIRTUAL_ID = 'virtual:permission-manifest'\nconst RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID\n\nexport default function permissionPlugin(userOptions: PermissionPluginOptions = {}): Plugin {\n const options = resolveOptions(userOptions)\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let rewriteExecuted = false\n let transformContext: { warn: (message: string) => void } | undefined\n let transformFilter: ReturnType<typeof createRootFilter> | undefined\n const state = new PermissionState()\n\n const filter = createFilter(\n options.include ?? [/\\.tsx$/, /\\.jsx$/, /\\.vue$/],\n options.exclude ?? [/node_modules/, /\\.git/]\n )\n return {\n name: 'vite-plugin-permission',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n\n transformFilter = createRootFilter(\n config.root,\n options.transform.include ?? options.include ?? ['src/**/*.{tsx,jsx}'],\n options.transform.exclude ??\n options.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n },\n\n async buildStart() {\n state.clear?.()\n if (!options.rewrite.enabled) {\n return\n }\n\n if (options.rewrite.once && rewriteExecuted) {\n return\n }\n\n rewriteExecuted = true\n\n await rewriteSourceFiles(config.root, options, this)\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return `export default ${JSON.stringify(state.toManifest(), null, 2)}`\n }\n\n return null\n },\n\n async transform(code, id) {\n transformContext = this\n\n if (!filter(id) || !transformFilter?.(id)) {\n return null\n }\n\n if (!options.transform.enabled) {\n return null\n }\n\n if (options.framework === 'react') {\n const result = transformReactPermission(code, id, options)\n\n if (!result) {\n state.removeFile(id)\n return null\n }\n\n state.setFileUsage(id, result.usages)\n\n validatePermissions(result.usages.map((item) => item.permission))\n\n return {\n code: result.code,\n map: result.map\n }\n }\n\n // Vue MVP 阶段建议只扫描,不强行 template 改写\n return null\n },\n\n async generateBundle() {\n await emitManifestAndDts(config.root, options, state)\n },\n\n configureServer(_server) {\n server = _server\n\n server.middlewares.use('/__permission/manifest', async (_req, res) => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(state.toManifest(), null, 2))\n })\n },\n\n async handleHotUpdate(ctx) {\n if (!filter(ctx.file)) {\n return\n }\n\n // 文件变化后,先删除旧记录,等待下一次 transform 写入新记录\n state.removeFile(ctx.file)\n\n // 通知前端或 devtools 权限 manifest 变了\n ctx.server.ws.send({\n type: 'custom',\n event: 'permission-manifest-update',\n data: state.toManifest()\n })\n }\n }\n\n function validatePermissions(usedPermissions: string[]) {\n if (!options.validate.enabled) {\n return\n }\n\n if (options.validate.unknownPermission === 'off') {\n return\n }\n\n const knownSet = new Set(options.validate.permissions)\n\n const unknown = usedPermissions.filter((item) => !knownSet.has(item))\n\n if (unknown.length === 0) {\n return\n }\n\n const message = `[vite-plugin-permission] Unknown permissions: ${unknown.join(', ')}`\n\n if (options.validate.unknownPermission === 'error') {\n throw new Error(message)\n }\n\n transformContext?.warn(message)\n }\n}\n\nasync function emitManifestAndDts(\n root: string,\n options: ReturnType<typeof resolveOptions>,\n state: PermissionState\n) {\n if (options.manifest.enabled) {\n const manifestPath = path.resolve(root, options.manifest.output)\n await fs.mkdir(path.dirname(manifestPath), { recursive: true })\n await fs.writeFile(manifestPath, createManifestJson(state), 'utf-8')\n }\n\n if (options.dts.enabled) {\n const dtsPath = path.resolve(root, options.dts.output)\n await fs.mkdir(path.dirname(dtsPath), { recursive: true })\n await fs.writeFile(\n dtsPath,\n createDts(state.getUsedPermissions(), options.dts.typeName),\n 'utf-8'\n )\n }\n}\n","// src/options.ts\nimport { z } from 'zod'\n\nconst FilterPatternSchema = z.custom<string | RegExp | Array<string | RegExp>>()\n\nconst GlobPatternSchema = z.union([z.string(), z.array(z.string())])\n\nexport const PluginOptionsSchema = z.object({\n framework: z.enum(['react', 'vue']).default('react'),\n\n componentName: z.string().default('Can'),\n\n importFrom: z.string().default('@eycraf/permission-kit-react'),\n\n /**\n * 全局 include/exclude。\n * transform/rewrite 没单独配置时,会回退使用这里。\n */\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n\n transform: z\n .object({\n enabled: z.boolean().default(true),\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n attributes: z.array(z.string()).default(['permission']),\n modeAttribute: z.string().default('permissionMode'),\n strategyAttribute: z.string().default('permissionStrategy'),\n allowNested: z.boolean().default(false)\n })\n .default({}),\n\n rewrite: z\n .object({\n enabled: z.boolean().default(false),\n\n /**\n * false = dry-run,只打印会修改哪些文件\n * true = 真实写回源文件\n */\n write: z.boolean().default(false),\n\n include: GlobPatternSchema.optional(),\n exclude: GlobPatternSchema.optional(),\n\n /**\n * rewrite 只在 serve/build 启动时跑一次。\n * 默认 true,避免 HMR 时反复改文件。\n */\n once: z.boolean().default(true)\n })\n .default({}),\n\n manifest: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission-manifest.json')\n })\n .default({}),\n\n dts: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission.d.ts'),\n typeName: z.string().default('PermissionKey')\n })\n .default({}),\n\n validate: z\n .object({\n enabled: z.boolean().default(false),\n permissions: z.array(z.string()).default([]),\n unknownPermission: z.enum(['off', 'warn', 'error']).default('warn')\n })\n .default({})\n})\n\nexport type PermissionPluginOptions = z.input<typeof PluginOptionsSchema>\nexport type NormalizedPermissionPluginOptions = z.output<typeof PluginOptionsSchema>\n\nexport function resolveOptions(options: PermissionPluginOptions) {\n return PluginOptionsSchema.parse(options)\n}\n","// src/state.ts\nexport type PermissionUsage = {\n permission: string\n file: string\n line?: number\n column?: number\n}\n\nexport class PermissionState {\n private fileUsageMap = new Map<string, PermissionUsage[]>()\n\n clear() {\n this.fileUsageMap.clear()\n }\n\n setFileUsage(file: string, usages: PermissionUsage[]) {\n this.fileUsageMap.set(file, usages)\n }\n\n removeFile(file: string) {\n this.fileUsageMap.delete(file)\n }\n\n getAllUsages() {\n return [...this.fileUsageMap.values()].flat()\n }\n\n getUsedPermissions() {\n return [...new Set(this.getAllUsages().map((item) => item.permission))].sort()\n }\n\n toManifest() {\n const result: Record<\n string,\n Array<{\n file: string\n line?: number\n column?: number\n }>\n > = {}\n\n for (const usage of this.getAllUsages()) {\n const items = (result[usage.permission] ??= [])\n const entry: {\n file: string\n line?: number\n column?: number\n } = {\n file: usage.file\n }\n\n if (usage.line !== undefined) {\n entry.line = usage.line\n }\n\n if (usage.column !== undefined) {\n entry.column = usage.column\n }\n\n items.push(entry)\n }\n\n return result\n }\n}\n","// src/transformReact.ts\nimport { parse } from '@babel/parser'\nimport traverse, { type NodePath } from '@babel/traverse'\nimport type {\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName\n} from '@babel/types'\nimport MagicString from 'magic-string'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype TransformResult = {\n code: string\n map: ReturnType<MagicString['generateMap']>\n usages: PermissionUsage[]\n}\n\ntype PendingWrap = {\n node: JSXElement\n permissionCode: string\n modeCode: string | undefined\n attrsToRemove: JSXAttribute[]\n}\n\nexport function transformReactPermission(\n code: string,\n id: string,\n options: NormalizedPermissionPluginOptions\n): TransformResult | null {\n if (!/\\.[jt]sx$/.test(id)) {\n return null\n }\n\n const attrs = options.transform.attributes\n const modeAttrName = options.transform.modeAttribute\n const componentName = options.componentName\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n errorRecovery: true\n })\n\n const ms = new MagicString(code)\n const wraps: PendingWrap[] = []\n const usages: PermissionUsage[] = []\n const removes: JSXAttribute[] = []\n\n let hasCanImport = false\n let lastImportEnd = 0\n\n traverse(ast, {\n ImportDeclaration(path) {\n lastImportEnd = Math.max(lastImportEnd, path.node.end ?? 0)\n\n if (path.node.source.value === options.importFrom) {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier' && specifier.local.name === componentName) {\n hasCanImport = true\n }\n }\n }\n },\n\n JSXElement(path) {\n const node = path.node\n\n // 避免 <Can permission=\"x\"> 被再次包裹\n const openingName = node.openingElement.name\n if (openingName.type === 'JSXIdentifier' && openingName.name === componentName) {\n return\n }\n\n const attributes = node.openingElement.attributes\n const permissionAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attrs.includes(attr.name.name)\n )\n })\n\n if (!permissionAttr) {\n return\n }\n\n const modeAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === modeAttrName\n )\n })\n\n const permissionCode = getJSXAttributeValueCode(code, permissionAttr)\n if (!permissionCode) {\n return\n }\n\n const modeCode = modeAttr ? getJSXAttributeValueCode(code, modeAttr) : undefined\n\n const permissionLiteral = getStaticStringValue(permissionAttr)\n if (permissionLiteral) {\n const usage: PermissionUsage = {\n permission: permissionLiteral,\n file: id\n }\n\n if (permissionAttr.loc?.start.line !== undefined) {\n usage.line = permissionAttr.loc.start.line\n }\n\n if (permissionAttr.loc?.start.column !== undefined) {\n usage.column = permissionAttr.loc.start.column\n }\n\n usages.push(usage)\n }\n\n const attrsToRemove = modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n\n // 2. 已经在 <Can> 内部:只删除 permission 属性,不再包裹\n if (isInsideCanElement(path, componentName)) {\n removes.push(...attrsToRemove)\n return\n }\n\n const resolvedModeCode = modeCode ?? undefined\n\n wraps.push({\n node,\n permissionCode,\n modeCode: resolvedModeCode,\n attrsToRemove: modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n })\n\n // 4. 可选:如果当前元素已经要被包裹,可以跳过它的子节点\n // 这样可以避免父子都有 permission 时产生嵌套。\n if (!options.transform.allowNested) {\n path.skip()\n }\n }\n })\n\n if (removes.length) {\n // 先删除在 <Can> 内部的冗余 permission 属性\n removes\n .sort((a, b) => (b.start ?? 0) - (a.start ?? 0))\n .forEach((attr) => {\n removeJSXAttribute(ms, code, attr)\n })\n }\n\n if (wraps.length === 0) {\n if (removes.length === 0) {\n return null\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n }\n\n // 倒序修改,避免位置偏移\n wraps\n .sort((a, b) => (b.node.start ?? 0) - (a.node.start ?? 0))\n .forEach((item) => {\n for (const attr of item.attrsToRemove) {\n removeJSXAttribute(ms, code, attr)\n }\n\n const start = item.node.start\n const end = item.node.end\n\n if (start == null || end == null) {\n return\n }\n\n const modePart = item.modeCode ? ` mode={${item.modeCode}}` : ''\n\n ms.prependLeft(start, `<${componentName} permission={${item.permissionCode}}${modePart}>`)\n\n ms.appendRight(end, `</${componentName}>`)\n })\n\n if (!hasCanImport) {\n const importCode = `import { ${componentName} } from '${options.importFrom}'\\n`\n\n if (lastImportEnd > 0) {\n ms.appendRight(lastImportEnd, `\\n${importCode}`)\n } else {\n ms.prepend(importCode)\n }\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n}\n\nfunction getJSXAttributeValueCode(code: string, attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return JSON.stringify(value.value)\n }\n\n if (value.type === 'JSXExpressionContainer') {\n const expr = value.expression\n\n if (expr.type === 'JSXEmptyExpression' || expr.start == null || expr.end == null) {\n return null\n }\n\n return code.slice(expr.start, expr.end)\n }\n\n return null\n}\n\nfunction getStaticStringValue(attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return value.value\n }\n\n if (value.type === 'JSXExpressionContainer' && value.expression.type === 'StringLiteral') {\n return value.expression.value\n }\n\n return null\n}\n\nfunction removeJSXAttribute(ms: MagicString, code: string, attr: JSXAttribute) {\n if (attr.start == null || attr.end == null) {\n return\n }\n\n let start = attr.start\n let end = attr.end\n\n // 顺手删除属性前面的空格,避免留下多余空白\n while (start > 0 && /\\s/.test(code.charAt(start - 1))) {\n start--\n }\n\n ms.remove(start, end)\n}\n\nfunction getJSXName(name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName): string {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n if (name.type === 'JSXMemberExpression') {\n return `${getJSXName(name.object)}.${getJSXName(name.property)}`\n }\n\n return `${name.namespace.name}:${name.name.name}`\n}\n\nfunction isCanElement(node: JSXElement, componentName: string) {\n const name = getJSXName(node.openingElement.name)\n\n return name === componentName\n}\n\nfunction isInsideCanElement(path: NodePath<JSXElement>, componentName: string) {\n return Boolean(\n path.findParent((parentPath) => {\n if (!parentPath.isJSXElement()) {\n return false\n }\n\n return isCanElement(parentPath.node, componentName)\n })\n )\n}\n","// src/manifest.ts\nimport type { PermissionState } from './state'\n\nexport function createManifestJson(state: PermissionState) {\n return JSON.stringify(\n {\n generatedAt: new Date().toISOString(),\n permissions: state.toManifest()\n },\n null,\n 2\n )\n}\n","// src/dts.ts\nexport function createDts(permissions: string[], typeName = 'PermissionKey') {\n if (permissions.length === 0) {\n return `export type ${typeName} = string\\n`\n }\n\n const union = permissions.map((item) => ` | ${JSON.stringify(item)}`).join('\\n')\n\n return [\n '/* eslint-disable */',\n '// This file is generated by vite-plugin-permission.',\n '// Do not edit manually.',\n '',\n `export type ${typeName} =`,\n union,\n ''\n ].join('\\n')\n}\n","// packages/vite-plugin/src/filter.ts\nimport path from 'node:path'\nimport { createFilter, normalizePath } from 'vite'\n\ntype Pattern = string | RegExp | Array<string | RegExp> | undefined\n\nexport function createRootFilter(root: string, include: Pattern, exclude: Pattern) {\n return createFilter(normalizePatterns(root, include), normalizePatterns(root, exclude))\n}\n\nfunction normalizePatterns(root: string, patterns: Pattern) {\n if (!patterns) {\n return undefined\n }\n\n const list = Array.isArray(patterns) ? patterns : [patterns]\n\n return list.map((item) => {\n if (item instanceof RegExp) {\n return item\n }\n\n // 绝对路径 glob:只做 POSIX 规范化\n if (path.isAbsolute(item)) {\n return normalizePath(item)\n }\n\n // 相对路径 glob:基于 Vite root 转绝对\n return normalizePath(path.resolve(root, item))\n })\n}\n\nexport function cleanId(id: string) {\n return normalizePath(id.split('?')[0] ?? id)\n}\n","// packages/vite-plugin/src/rewrite.ts\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport fg from 'fast-glob'\nimport { normalizePath } from 'vite'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport { transformReactPermission } from './transformReact'\n\ntype LoggerLike = {\n warn(message: string): void\n}\n\nexport type RewriteResult = {\n checked: number\n changed: number\n files: string[]\n}\n\nexport async function rewriteSourceFiles(\n root: string,\n options: NormalizedPermissionPluginOptions,\n context: LoggerLike\n): Promise<RewriteResult> {\n const include = toArray(options.rewrite.include ?? ['src/**/*.{tsx,jsx}'])\n\n const exclude = toArray(\n options.rewrite.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n\n const files = await fg(include, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore: exclude\n })\n\n let changed = 0\n const changedFiles: string[] = []\n\n for (const file of files) {\n const id = normalizePath(file)\n const code = await fs.readFile(file, 'utf-8')\n\n if (options.framework !== 'react') {\n continue\n }\n\n const result = transformReactPermission(code, id, options)\n\n if (!result || result.code === code) {\n continue\n }\n\n changed++\n changedFiles.push(path.relative(root, file))\n\n if (options.rewrite.write) {\n await fs.writeFile(file, result.code, 'utf-8')\n }\n }\n\n const mode = options.rewrite.write ? 'write' : 'dry-run'\n\n if (changedFiles.length > 0) {\n context.warn(\n [\n `[vite-plugin-permission] rewrite ${mode}: ${changed} file(s) would change`,\n ...changedFiles.map((file) => ` - ${file}`)\n ].join('\\n')\n )\n } else {\n context.warn(`[vite-plugin-permission] rewrite ${mode}: no files changed`)\n }\n\n return {\n checked: files.length,\n changed,\n files: changedFiles\n }\n}\n\nfunction toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n"],"mappings":"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","names":["import_vite","import_node_path","import_promises","MagicString","traverse","path","path","import_node_path","import_vite","fg","fs","path","path","fs"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/state.ts","../src/transformReact.ts","../src/manifest.ts","../src/dts.ts","../src/filter.ts","../src/rewrite.ts","../src/validate.ts"],"sourcesContent":["// src/index.ts\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport { createFilter } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveOptions, type PermissionPluginOptions } from './options'\nimport { PermissionState } from './state'\nimport { transformReactPermission } from './transformReact'\nimport { createManifest, createManifestJson } from './manifest'\nimport { createDts } from './dts'\nimport { createRootFilter } from './filter'\nimport { rewriteSourceFiles } from './rewrite'\nimport { validatePermissionUsages } from './validate'\n\nconst VIRTUAL_ID = 'virtual:permission-manifest'\nconst RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID\n\nexport default function permissionPlugin(userOptions: PermissionPluginOptions = {}): Plugin {\n const options = resolveOptions(userOptions)\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let rewriteExecuted = false\n let transformContext: { warn: (message: string) => void } | undefined\n let transformFilter: ReturnType<typeof createRootFilter> | undefined\n const state = new PermissionState()\n\n const filter = createFilter(\n options.include ?? [/\\.tsx$/, /\\.jsx$/, /\\.vue$/],\n options.exclude ?? [/node_modules/, /\\.git/]\n )\n return {\n name: 'vite-plugin-permission',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n\n transformFilter = createRootFilter(\n config.root,\n options.transform.include ?? options.include ?? ['src/**/*.{tsx,jsx}'],\n options.transform.exclude ??\n options.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n },\n\n async buildStart() {\n state.clear?.()\n if (!options.rewrite.enabled) {\n return\n }\n\n if (options.rewrite.once && rewriteExecuted) {\n return\n }\n\n rewriteExecuted = true\n\n await rewriteSourceFiles(config.root, options, this)\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return `export default ${JSON.stringify(createManifest(state), null, 2)}`\n }\n\n return null\n },\n\n async transform(code, id) {\n transformContext = this\n\n if (!filter(id) || !transformFilter?.(id)) {\n return null\n }\n\n if (!options.transform.enabled) {\n return null\n }\n\n if (options.framework === 'react') {\n const result = transformReactPermission(code, id, options)\n\n if (!result) {\n state.removeFile(id)\n return null\n }\n\n state.setFileUsage(id, result.usages)\n\n validatePermissionUsages(result.usages, options.validate, transformContext)\n\n return {\n code: result.code,\n map: result.map\n }\n }\n\n // Vue MVP 阶段建议只扫描,不强行 template 改写\n return null\n },\n\n async generateBundle() {\n await emitManifestAndDts(config.root, options, state)\n },\n\n configureServer(_server) {\n server = _server\n\n server.middlewares.use('/__permission/manifest', async (_req, res) => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(createManifest(state), null, 2))\n })\n },\n\n async handleHotUpdate(ctx) {\n if (!filter(ctx.file)) {\n return\n }\n\n // 文件变化后,先删除旧记录,等待下一次 transform 写入新记录\n state.removeFile(ctx.file)\n\n // 通知前端或 devtools 权限 manifest 变了\n ctx.server.ws.send({\n type: 'custom',\n event: 'permission-manifest-update',\n data: createManifest(state)\n })\n }\n }\n}\n\nasync function emitManifestAndDts(\n root: string,\n options: ReturnType<typeof resolveOptions>,\n state: PermissionState\n) {\n if (options.manifest.enabled) {\n const manifestPath = path.resolve(root, options.manifest.output)\n await fs.mkdir(path.dirname(manifestPath), { recursive: true })\n await fs.writeFile(manifestPath, createManifestJson(state), 'utf-8')\n }\n\n if (options.dts.enabled) {\n const dtsPath = path.resolve(root, options.dts.output)\n await fs.mkdir(path.dirname(dtsPath), { recursive: true })\n await fs.writeFile(\n dtsPath,\n createDts(state.getUsedPermissions(), options.dts.typeName),\n 'utf-8'\n )\n }\n}\n","// src/options.ts\nimport { z } from 'zod'\n\nconst FilterPatternSchema = z.custom<string | RegExp | Array<string | RegExp>>()\n\nconst GlobPatternSchema = z.union([z.string(), z.array(z.string())])\n\nexport const PluginOptionsSchema = z.object({\n framework: z.enum(['react', 'vue']).default('react'),\n\n componentName: z.string().default('Can'),\n\n importFrom: z.string().default('@eycraf/permission-kit-react'),\n\n /**\n * 全局 include/exclude。\n * transform/rewrite 没单独配置时,会回退使用这里。\n */\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n\n transform: z\n .object({\n enabled: z.boolean().default(true),\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n attributes: z.array(z.string()).default(['permission']),\n modeAttribute: z.string().default('permissionMode'),\n strategyAttribute: z.string().default('permissionStrategy'),\n allowNested: z.boolean().default(false)\n })\n .default({}),\n\n rewrite: z\n .object({\n enabled: z.boolean().default(false),\n\n /**\n * false = dry-run,只打印会修改哪些文件\n * true = 真实写回源文件\n */\n write: z.boolean().default(false),\n\n include: GlobPatternSchema.optional(),\n exclude: GlobPatternSchema.optional(),\n\n /**\n * rewrite 只在 serve/build 启动时跑一次。\n * 默认 true,避免 HMR 时反复改文件。\n */\n once: z.boolean().default(true)\n })\n .default({}),\n\n manifest: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission-manifest.json')\n })\n .default({}),\n\n dts: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission.d.ts'),\n typeName: z.string().default('PermissionKey')\n })\n .default({}),\n\n validate: z\n .object({\n enabled: z.boolean().default(false),\n permissions: z.array(z.string()).default([]),\n unknownPermission: z.enum(['off', 'warn', 'error']).default('warn')\n })\n .default({})\n})\n\nexport type PermissionPluginOptions = z.input<typeof PluginOptionsSchema>\nexport type NormalizedPermissionPluginOptions = z.output<typeof PluginOptionsSchema>\n\nexport function resolveOptions(options: PermissionPluginOptions) {\n return PluginOptionsSchema.parse(options)\n}\n","// src/state.ts\nexport type PermissionUsage = {\n permission: string\n file: string\n line?: number\n column?: number\n component?: string\n}\n\nexport type PermissionManifestUsage = {\n file: string\n line?: number\n column?: number\n component?: string\n}\n\nexport type PermissionManifestEntry = {\n permission: string\n count: number\n files: string[]\n usages: PermissionManifestUsage[]\n}\n\nexport type PermissionManifestSummary = {\n permissions: number\n usages: number\n files: number\n}\n\nexport type PermissionManifest = {\n generatedAt: string\n summary: PermissionManifestSummary\n permissions: PermissionManifestEntry[]\n}\n\nexport class PermissionState {\n private fileUsageMap = new Map<string, PermissionUsage[]>()\n\n clear() {\n this.fileUsageMap.clear()\n }\n\n setFileUsage(file: string, usages: PermissionUsage[]) {\n this.fileUsageMap.set(file, usages)\n }\n\n removeFile(file: string) {\n this.fileUsageMap.delete(file)\n }\n\n getAllUsages() {\n return [...this.fileUsageMap.values()].flat()\n }\n\n getUsedPermissions() {\n return [...new Set(this.getAllUsages().map((item) => item.permission))].sort()\n }\n\n getSummary(): PermissionManifestSummary {\n const usages = this.getAllUsages()\n\n return {\n permissions: new Set(usages.map((item) => item.permission)).size,\n usages: usages.length,\n files: new Set(usages.map((item) => item.file)).size\n }\n }\n\n toManifest() {\n const grouped = new Map<string, PermissionUsage[]>()\n\n for (const usage of this.getAllUsages()) {\n const items = grouped.get(usage.permission) ?? []\n items.push(usage)\n grouped.set(usage.permission, items)\n }\n\n return [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([permission, usages]) => {\n const sortedUsages = [...usages].sort((left, right) => compareUsage(left, right))\n const files = [...new Set(sortedUsages.map((item) => item.file))].sort((left, right) =>\n left.localeCompare(right)\n )\n\n return {\n permission,\n count: sortedUsages.length,\n files,\n usages: sortedUsages.map(({ file, line, column, component }) => {\n const entry: PermissionManifestUsage = { file }\n\n if (line !== undefined) {\n entry.line = line\n }\n\n if (column !== undefined) {\n entry.column = column\n }\n\n if (component !== undefined) {\n entry.component = component\n }\n\n return entry\n })\n } satisfies PermissionManifestEntry\n })\n }\n}\n\nfunction compareUsage(left: PermissionUsage, right: PermissionUsage) {\n const fileCompare = left.file.localeCompare(right.file)\n if (fileCompare !== 0) {\n return fileCompare\n }\n\n const lineCompare = (left.line ?? 0) - (right.line ?? 0)\n if (lineCompare !== 0) {\n return lineCompare\n }\n\n const columnCompare = (left.column ?? 0) - (right.column ?? 0)\n if (columnCompare !== 0) {\n return columnCompare\n }\n\n return (left.component ?? '').localeCompare(right.component ?? '')\n}\n","// src/transformReact.ts\nimport { parse } from '@babel/parser'\nimport traverse, { type NodePath } from '@babel/traverse'\nimport type {\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName\n} from '@babel/types'\nimport MagicString from 'magic-string'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype TransformResult = {\n code: string\n map: ReturnType<MagicString['generateMap']>\n usages: PermissionUsage[]\n}\n\ntype PendingWrap = {\n node: JSXElement\n permissionCode: string\n modeCode: string | undefined\n attrsToRemove: JSXAttribute[]\n}\n\nexport function transformReactPermission(\n code: string,\n id: string,\n options: NormalizedPermissionPluginOptions\n): TransformResult | null {\n if (!/\\.[jt]sx$/.test(id)) {\n return null\n }\n\n const attrs = options.transform.attributes\n const modeAttrName = options.transform.modeAttribute\n const componentName = options.componentName\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n errorRecovery: true\n })\n\n const ms = new MagicString(code)\n const wraps: PendingWrap[] = []\n const usages: PermissionUsage[] = []\n const removes: JSXAttribute[] = []\n\n let hasCanImport = false\n let lastImportEnd = 0\n\n traverse(ast, {\n ImportDeclaration(path) {\n lastImportEnd = Math.max(lastImportEnd, path.node.end ?? 0)\n\n if (path.node.source.value === options.importFrom) {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier' && specifier.local.name === componentName) {\n hasCanImport = true\n }\n }\n }\n },\n\n JSXElement(path) {\n const node = path.node\n\n // 避免 <Can permission=\"x\"> 被再次包裹\n const openingName = node.openingElement.name\n if (openingName.type === 'JSXIdentifier' && openingName.name === componentName) {\n return\n }\n\n const attributes = node.openingElement.attributes\n const permissionAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attrs.includes(attr.name.name)\n )\n })\n\n if (!permissionAttr) {\n return\n }\n\n const modeAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === modeAttrName\n )\n })\n\n const permissionCode = getJSXAttributeValueCode(code, permissionAttr)\n if (!permissionCode) {\n return\n }\n\n const modeCode = modeAttr ? getJSXAttributeValueCode(code, modeAttr) : undefined\n\n const permissionLiteral = getStaticStringValue(permissionAttr)\n if (permissionLiteral) {\n const usage: PermissionUsage = {\n permission: permissionLiteral,\n file: id,\n component: componentName\n }\n\n if (permissionAttr.loc?.start.line !== undefined) {\n usage.line = permissionAttr.loc.start.line\n }\n\n if (permissionAttr.loc?.start.column !== undefined) {\n usage.column = permissionAttr.loc.start.column\n }\n\n usages.push(usage)\n }\n\n const attrsToRemove = modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n\n // 2. 已经在 <Can> 内部:只删除 permission 属性,不再包裹\n if (isInsideCanElement(path, componentName)) {\n removes.push(...attrsToRemove)\n return\n }\n\n const resolvedModeCode = modeCode ?? undefined\n\n wraps.push({\n node,\n permissionCode,\n modeCode: resolvedModeCode,\n attrsToRemove: modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n })\n\n // 4. 可选:如果当前元素已经要被包裹,可以跳过它的子节点\n // 这样可以避免父子都有 permission 时产生嵌套。\n if (!options.transform.allowNested) {\n path.skip()\n }\n }\n })\n\n if (removes.length) {\n // 先删除在 <Can> 内部的冗余 permission 属性\n removes\n .sort((a, b) => (b.start ?? 0) - (a.start ?? 0))\n .forEach((attr) => {\n removeJSXAttribute(ms, code, attr)\n })\n }\n\n if (wraps.length === 0) {\n if (removes.length === 0) {\n return null\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n }\n\n // 倒序修改,避免位置偏移\n wraps\n .sort((a, b) => (b.node.start ?? 0) - (a.node.start ?? 0))\n .forEach((item) => {\n for (const attr of item.attrsToRemove) {\n removeJSXAttribute(ms, code, attr)\n }\n\n const start = item.node.start\n const end = item.node.end\n\n if (start == null || end == null) {\n return\n }\n\n const modePart = item.modeCode ? ` mode={${item.modeCode}}` : ''\n\n ms.prependLeft(start, `<${componentName} permission={${item.permissionCode}}${modePart}>`)\n\n ms.appendRight(end, `</${componentName}>`)\n })\n\n if (!hasCanImport) {\n const importCode = `import { ${componentName} } from '${options.importFrom}'\\n`\n\n if (lastImportEnd > 0) {\n ms.appendRight(lastImportEnd, `\\n${importCode}`)\n } else {\n ms.prepend(importCode)\n }\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n}\n\nfunction getJSXAttributeValueCode(code: string, attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return JSON.stringify(value.value)\n }\n\n if (value.type === 'JSXExpressionContainer') {\n const expr = value.expression\n\n if (expr.type === 'JSXEmptyExpression' || expr.start == null || expr.end == null) {\n return null\n }\n\n return code.slice(expr.start, expr.end)\n }\n\n return null\n}\n\nfunction getStaticStringValue(attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return value.value\n }\n\n if (value.type === 'JSXExpressionContainer' && value.expression.type === 'StringLiteral') {\n return value.expression.value\n }\n\n return null\n}\n\nfunction removeJSXAttribute(ms: MagicString, code: string, attr: JSXAttribute) {\n if (attr.start == null || attr.end == null) {\n return\n }\n\n let start = attr.start\n let end = attr.end\n\n // 顺手删除属性前面的空格,避免留下多余空白\n while (start > 0 && /\\s/.test(code.charAt(start - 1))) {\n start--\n }\n\n ms.remove(start, end)\n}\n\nfunction getJSXName(name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName): string {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n if (name.type === 'JSXMemberExpression') {\n return `${getJSXName(name.object)}.${getJSXName(name.property)}`\n }\n\n return `${name.namespace.name}:${name.name.name}`\n}\n\nfunction isCanElement(node: JSXElement, componentName: string) {\n const name = getJSXName(node.openingElement.name)\n\n return name === componentName\n}\n\nfunction isInsideCanElement(path: NodePath<JSXElement>, componentName: string) {\n return Boolean(\n path.findParent((parentPath) => {\n if (!parentPath.isJSXElement()) {\n return false\n }\n\n return isCanElement(parentPath.node, componentName)\n })\n )\n}\n","// src/manifest.ts\nimport type { PermissionManifest, PermissionState } from './state'\n\nexport function createManifest(state: PermissionState): PermissionManifest {\n return {\n generatedAt: new Date().toISOString(),\n summary: state.getSummary(),\n permissions: state.toManifest()\n }\n}\n\nexport function createManifestJson(state: PermissionState) {\n return JSON.stringify(createManifest(state), null, 2)\n}\n","// src/dts.ts\nexport function createDts(permissions: string[], typeName = 'PermissionKey') {\n const uniquePermissions = [...new Set(permissions)].sort((left, right) =>\n left.localeCompare(right)\n )\n\n const permissionKeysType =\n uniquePermissions.length > 0\n ? `readonly [${uniquePermissions.map((item) => JSON.stringify(item)).join(', ')}]`\n : 'readonly string[]'\n\n return [\n '/* eslint-disable */',\n '// This file is generated by vite-plugin-permission.',\n '// Do not edit manually.',\n '',\n `export declare const permissionKeys: ${permissionKeysType}`,\n `export type ${typeName} = typeof permissionKeys[number]`,\n '',\n `export type PermissionUsage = {`,\n ` permission: ${typeName}`,\n ' file: string',\n ' line?: number',\n ' column?: number',\n ' component?: string',\n '}',\n '',\n `export type PermissionManifestEntry = {`,\n ` permission: ${typeName}`,\n ' count: number',\n ' files: readonly string[]',\n ' usages: readonly PermissionUsage[]',\n '}',\n '',\n 'export type PermissionManifestSummary = {',\n ' permissions: number',\n ' usages: number',\n ' files: number',\n '}',\n '',\n 'export type PermissionManifest = {',\n ' generatedAt: string',\n ' summary: PermissionManifestSummary',\n ' permissions: readonly PermissionManifestEntry[]',\n '}',\n ''\n ].join('\\n')\n}\n","// packages/vite-plugin/src/filter.ts\nimport path from 'node:path'\nimport { createFilter, normalizePath } from 'vite'\n\ntype Pattern = string | RegExp | Array<string | RegExp> | undefined\n\nexport function createRootFilter(root: string, include: Pattern, exclude: Pattern) {\n return createFilter(normalizePatterns(root, include), normalizePatterns(root, exclude))\n}\n\nfunction normalizePatterns(root: string, patterns: Pattern) {\n if (!patterns) {\n return undefined\n }\n\n const list = Array.isArray(patterns) ? patterns : [patterns]\n\n return list.map((item) => {\n if (item instanceof RegExp) {\n return item\n }\n\n // 绝对路径 glob:只做 POSIX 规范化\n if (path.isAbsolute(item)) {\n return normalizePath(item)\n }\n\n // 相对路径 glob:基于 Vite root 转绝对\n return normalizePath(path.resolve(root, item))\n })\n}\n\nexport function cleanId(id: string) {\n return normalizePath(id.split('?')[0] ?? id)\n}\n","// packages/vite-plugin/src/rewrite.ts\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport fg from 'fast-glob'\nimport { normalizePath } from 'vite'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport { transformReactPermission } from './transformReact'\n\ntype LoggerLike = {\n warn(message: string): void\n}\n\nexport type RewriteResult = {\n checked: number\n changed: number\n files: string[]\n}\n\nexport async function rewriteSourceFiles(\n root: string,\n options: NormalizedPermissionPluginOptions,\n context: LoggerLike\n): Promise<RewriteResult> {\n const include = toArray(options.rewrite.include ?? ['src/**/*.{tsx,jsx}'])\n\n const exclude = toArray(\n options.rewrite.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n\n const files = await fg(include, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore: exclude\n })\n\n let changed = 0\n const changedFiles: string[] = []\n\n for (const file of files) {\n const id = normalizePath(file)\n const code = await fs.readFile(file, 'utf-8')\n\n if (options.framework !== 'react') {\n continue\n }\n\n const result = transformReactPermission(code, id, options)\n\n if (!result || result.code === code) {\n continue\n }\n\n changed++\n changedFiles.push(path.relative(root, file))\n\n if (options.rewrite.write) {\n await fs.writeFile(file, result.code, 'utf-8')\n }\n }\n\n const mode = options.rewrite.write ? 'write' : 'dry-run'\n\n if (changedFiles.length > 0) {\n context.warn(\n [\n `[vite-plugin-permission] rewrite ${mode}: ${changed} file(s) would change`,\n ...changedFiles.map((file) => ` - ${file}`)\n ].join('\\n')\n )\n } else {\n context.warn(`[vite-plugin-permission] rewrite ${mode}: no files changed`)\n }\n\n return {\n checked: files.length,\n changed,\n files: changedFiles\n }\n}\n\nfunction toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n","// src/validate.ts\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype ValidationReporter = {\n warn(message: string): void\n}\n\nexport function validatePermissionUsages(\n usages: PermissionUsage[],\n options: NormalizedPermissionPluginOptions['validate'],\n reporter?: ValidationReporter\n) {\n if (!options.enabled || options.unknownPermission === 'off') {\n return []\n }\n\n const knownSet = new Set(options.permissions)\n const grouped = new Map<string, PermissionUsage[]>()\n\n for (const usage of usages) {\n if (knownSet.has(usage.permission)) {\n continue\n }\n\n const items = grouped.get(usage.permission) ?? []\n items.push(usage)\n grouped.set(usage.permission, items)\n }\n\n const unknownPermissions = [...grouped.keys()].sort((left, right) => left.localeCompare(right))\n\n if (unknownPermissions.length === 0) {\n return []\n }\n\n const message = buildMessage(unknownPermissions, grouped)\n\n if (options.unknownPermission === 'error') {\n throw new Error(message)\n }\n\n reporter?.warn(message)\n\n return unknownPermissions\n}\n\nfunction buildMessage(permissions: string[], grouped: Map<string, PermissionUsage[]>) {\n const lines = [`[vite-plugin-permission] Unknown permissions: ${permissions.join(', ')}`]\n\n for (const permission of permissions) {\n const usages = grouped.get(permission) ?? []\n for (const usage of usages.slice(0, 3)) {\n lines.push(` - ${formatUsage(usage)}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction formatUsage(usage: PermissionUsage) {\n const location = [usage.file, usage.line, usage.column]\n .filter((item) => item !== undefined)\n .join(':')\n\n if (!usage.component) {\n return `${usage.permission} (${location})`\n }\n\n return `${usage.permission} (${location}, component=${usage.component})`\n}\n"],"mappings":"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","names":["import_vite","import_node_path","import_promises","MagicString","traverse","path","path","import_node_path","import_vite","fg","fs","path","path","fs"]}
package/dist/index.js CHANGED
@@ -80,25 +80,62 @@ var PermissionState = class {
80
80
  getUsedPermissions() {
81
81
  return [...new Set(this.getAllUsages().map((item) => item.permission))].sort();
82
82
  }
83
+ getSummary() {
84
+ const usages = this.getAllUsages();
85
+ return {
86
+ permissions: new Set(usages.map((item) => item.permission)).size,
87
+ usages: usages.length,
88
+ files: new Set(usages.map((item) => item.file)).size
89
+ };
90
+ }
83
91
  toManifest() {
84
- var _a;
85
- const result = {};
92
+ const grouped = /* @__PURE__ */ new Map();
86
93
  for (const usage of this.getAllUsages()) {
87
- const items = result[_a = usage.permission] ?? (result[_a] = []);
88
- const entry = {
89
- file: usage.file
90
- };
91
- if (usage.line !== void 0) {
92
- entry.line = usage.line;
93
- }
94
- if (usage.column !== void 0) {
95
- entry.column = usage.column;
96
- }
97
- items.push(entry);
94
+ const items = grouped.get(usage.permission) ?? [];
95
+ items.push(usage);
96
+ grouped.set(usage.permission, items);
98
97
  }
99
- return result;
98
+ return [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([permission, usages]) => {
99
+ const sortedUsages = [...usages].sort((left, right) => compareUsage(left, right));
100
+ const files = [...new Set(sortedUsages.map((item) => item.file))].sort(
101
+ (left, right) => left.localeCompare(right)
102
+ );
103
+ return {
104
+ permission,
105
+ count: sortedUsages.length,
106
+ files,
107
+ usages: sortedUsages.map(({ file, line, column, component }) => {
108
+ const entry = { file };
109
+ if (line !== void 0) {
110
+ entry.line = line;
111
+ }
112
+ if (column !== void 0) {
113
+ entry.column = column;
114
+ }
115
+ if (component !== void 0) {
116
+ entry.component = component;
117
+ }
118
+ return entry;
119
+ })
120
+ };
121
+ });
100
122
  }
101
123
  };
124
+ function compareUsage(left, right) {
125
+ const fileCompare = left.file.localeCompare(right.file);
126
+ if (fileCompare !== 0) {
127
+ return fileCompare;
128
+ }
129
+ const lineCompare = (left.line ?? 0) - (right.line ?? 0);
130
+ if (lineCompare !== 0) {
131
+ return lineCompare;
132
+ }
133
+ const columnCompare = (left.column ?? 0) - (right.column ?? 0);
134
+ if (columnCompare !== 0) {
135
+ return columnCompare;
136
+ }
137
+ return (left.component ?? "").localeCompare(right.component ?? "");
138
+ }
102
139
 
103
140
  // src/transformReact.ts
104
141
  import { parse } from "@babel/parser";
@@ -158,7 +195,8 @@ function transformReactPermission(code, id, options) {
158
195
  if (permissionLiteral) {
159
196
  const usage = {
160
197
  permission: permissionLiteral,
161
- file: id
198
+ file: id,
199
+ component: componentName
162
200
  };
163
201
  if (permissionAttr.loc?.start.line !== void 0) {
164
202
  usage.line = permissionAttr.loc.start.line;
@@ -303,31 +341,57 @@ function isInsideCanElement(path4, componentName) {
303
341
  }
304
342
 
305
343
  // src/manifest.ts
344
+ function createManifest(state) {
345
+ return {
346
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
347
+ summary: state.getSummary(),
348
+ permissions: state.toManifest()
349
+ };
350
+ }
306
351
  function createManifestJson(state) {
307
- return JSON.stringify(
308
- {
309
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
310
- permissions: state.toManifest()
311
- },
312
- null,
313
- 2
314
- );
352
+ return JSON.stringify(createManifest(state), null, 2);
315
353
  }
316
354
 
317
355
  // src/dts.ts
318
356
  function createDts(permissions, typeName = "PermissionKey") {
319
- if (permissions.length === 0) {
320
- return `export type ${typeName} = string
321
- `;
322
- }
323
- const union = permissions.map((item) => ` | ${JSON.stringify(item)}`).join("\n");
357
+ const uniquePermissions = [...new Set(permissions)].sort(
358
+ (left, right) => left.localeCompare(right)
359
+ );
360
+ const permissionKeysType = uniquePermissions.length > 0 ? `readonly [${uniquePermissions.map((item) => JSON.stringify(item)).join(", ")}]` : "readonly string[]";
324
361
  return [
325
362
  "/* eslint-disable */",
326
363
  "// This file is generated by vite-plugin-permission.",
327
364
  "// Do not edit manually.",
328
365
  "",
329
- `export type ${typeName} =`,
330
- union,
366
+ `export declare const permissionKeys: ${permissionKeysType}`,
367
+ `export type ${typeName} = typeof permissionKeys[number]`,
368
+ "",
369
+ `export type PermissionUsage = {`,
370
+ ` permission: ${typeName}`,
371
+ " file: string",
372
+ " line?: number",
373
+ " column?: number",
374
+ " component?: string",
375
+ "}",
376
+ "",
377
+ `export type PermissionManifestEntry = {`,
378
+ ` permission: ${typeName}`,
379
+ " count: number",
380
+ " files: readonly string[]",
381
+ " usages: readonly PermissionUsage[]",
382
+ "}",
383
+ "",
384
+ "export type PermissionManifestSummary = {",
385
+ " permissions: number",
386
+ " usages: number",
387
+ " files: number",
388
+ "}",
389
+ "",
390
+ "export type PermissionManifest = {",
391
+ " generatedAt: string",
392
+ " summary: PermissionManifestSummary",
393
+ " permissions: readonly PermissionManifestEntry[]",
394
+ "}",
331
395
  ""
332
396
  ].join("\n");
333
397
  }
@@ -417,6 +481,50 @@ function toArray(value) {
417
481
  return Array.isArray(value) ? value : [value];
418
482
  }
419
483
 
484
+ // src/validate.ts
485
+ function validatePermissionUsages(usages, options, reporter) {
486
+ if (!options.enabled || options.unknownPermission === "off") {
487
+ return [];
488
+ }
489
+ const knownSet = new Set(options.permissions);
490
+ const grouped = /* @__PURE__ */ new Map();
491
+ for (const usage of usages) {
492
+ if (knownSet.has(usage.permission)) {
493
+ continue;
494
+ }
495
+ const items = grouped.get(usage.permission) ?? [];
496
+ items.push(usage);
497
+ grouped.set(usage.permission, items);
498
+ }
499
+ const unknownPermissions = [...grouped.keys()].sort((left, right) => left.localeCompare(right));
500
+ if (unknownPermissions.length === 0) {
501
+ return [];
502
+ }
503
+ const message = buildMessage(unknownPermissions, grouped);
504
+ if (options.unknownPermission === "error") {
505
+ throw new Error(message);
506
+ }
507
+ reporter?.warn(message);
508
+ return unknownPermissions;
509
+ }
510
+ function buildMessage(permissions, grouped) {
511
+ const lines = [`[vite-plugin-permission] Unknown permissions: ${permissions.join(", ")}`];
512
+ for (const permission of permissions) {
513
+ const usages = grouped.get(permission) ?? [];
514
+ for (const usage of usages.slice(0, 3)) {
515
+ lines.push(` - ${formatUsage(usage)}`);
516
+ }
517
+ }
518
+ return lines.join("\n");
519
+ }
520
+ function formatUsage(usage) {
521
+ const location = [usage.file, usage.line, usage.column].filter((item) => item !== void 0).join(":");
522
+ if (!usage.component) {
523
+ return `${usage.permission} (${location})`;
524
+ }
525
+ return `${usage.permission} (${location}, component=${usage.component})`;
526
+ }
527
+
420
528
  // src/index.ts
421
529
  var VIRTUAL_ID = "virtual:permission-manifest";
422
530
  var RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_ID;
@@ -470,7 +578,7 @@ function permissionPlugin(userOptions = {}) {
470
578
  },
471
579
  load(id) {
472
580
  if (id === RESOLVED_VIRTUAL_ID) {
473
- return `export default ${JSON.stringify(state.toManifest(), null, 2)}`;
581
+ return `export default ${JSON.stringify(createManifest(state), null, 2)}`;
474
582
  }
475
583
  return null;
476
584
  },
@@ -489,7 +597,7 @@ function permissionPlugin(userOptions = {}) {
489
597
  return null;
490
598
  }
491
599
  state.setFileUsage(id, result.usages);
492
- validatePermissions(result.usages.map((item) => item.permission));
600
+ validatePermissionUsages(result.usages, options.validate, transformContext);
493
601
  return {
494
602
  code: result.code,
495
603
  map: result.map
@@ -504,7 +612,7 @@ function permissionPlugin(userOptions = {}) {
504
612
  server = _server;
505
613
  server.middlewares.use("/__permission/manifest", async (_req, res) => {
506
614
  res.setHeader("Content-Type", "application/json");
507
- res.end(JSON.stringify(state.toManifest(), null, 2));
615
+ res.end(JSON.stringify(createManifest(state), null, 2));
508
616
  });
509
617
  },
510
618
  async handleHotUpdate(ctx) {
@@ -515,28 +623,10 @@ function permissionPlugin(userOptions = {}) {
515
623
  ctx.server.ws.send({
516
624
  type: "custom",
517
625
  event: "permission-manifest-update",
518
- data: state.toManifest()
626
+ data: createManifest(state)
519
627
  });
520
628
  }
521
629
  };
522
- function validatePermissions(usedPermissions) {
523
- if (!options.validate.enabled) {
524
- return;
525
- }
526
- if (options.validate.unknownPermission === "off") {
527
- return;
528
- }
529
- const knownSet = new Set(options.validate.permissions);
530
- const unknown = usedPermissions.filter((item) => !knownSet.has(item));
531
- if (unknown.length === 0) {
532
- return;
533
- }
534
- const message = `[vite-plugin-permission] Unknown permissions: ${unknown.join(", ")}`;
535
- if (options.validate.unknownPermission === "error") {
536
- throw new Error(message);
537
- }
538
- transformContext?.warn(message);
539
- }
540
630
  }
541
631
  async function emitManifestAndDts(root, options, state) {
542
632
  if (options.manifest.enabled) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/state.ts","../src/transformReact.ts","../src/manifest.ts","../src/dts.ts","../src/filter.ts","../src/rewrite.ts"],"sourcesContent":["// src/index.ts\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport { createFilter } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveOptions, type PermissionPluginOptions } from './options'\nimport { PermissionState } from './state'\nimport { transformReactPermission } from './transformReact'\nimport { createManifestJson } from './manifest'\nimport { createDts } from './dts'\nimport { createRootFilter } from './filter'\nimport { rewriteSourceFiles } from './rewrite'\n\nconst VIRTUAL_ID = 'virtual:permission-manifest'\nconst RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID\n\nexport default function permissionPlugin(userOptions: PermissionPluginOptions = {}): Plugin {\n const options = resolveOptions(userOptions)\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let rewriteExecuted = false\n let transformContext: { warn: (message: string) => void } | undefined\n let transformFilter: ReturnType<typeof createRootFilter> | undefined\n const state = new PermissionState()\n\n const filter = createFilter(\n options.include ?? [/\\.tsx$/, /\\.jsx$/, /\\.vue$/],\n options.exclude ?? [/node_modules/, /\\.git/]\n )\n return {\n name: 'vite-plugin-permission',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n\n transformFilter = createRootFilter(\n config.root,\n options.transform.include ?? options.include ?? ['src/**/*.{tsx,jsx}'],\n options.transform.exclude ??\n options.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n },\n\n async buildStart() {\n state.clear?.()\n if (!options.rewrite.enabled) {\n return\n }\n\n if (options.rewrite.once && rewriteExecuted) {\n return\n }\n\n rewriteExecuted = true\n\n await rewriteSourceFiles(config.root, options, this)\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return `export default ${JSON.stringify(state.toManifest(), null, 2)}`\n }\n\n return null\n },\n\n async transform(code, id) {\n transformContext = this\n\n if (!filter(id) || !transformFilter?.(id)) {\n return null\n }\n\n if (!options.transform.enabled) {\n return null\n }\n\n if (options.framework === 'react') {\n const result = transformReactPermission(code, id, options)\n\n if (!result) {\n state.removeFile(id)\n return null\n }\n\n state.setFileUsage(id, result.usages)\n\n validatePermissions(result.usages.map((item) => item.permission))\n\n return {\n code: result.code,\n map: result.map\n }\n }\n\n // Vue MVP 阶段建议只扫描,不强行 template 改写\n return null\n },\n\n async generateBundle() {\n await emitManifestAndDts(config.root, options, state)\n },\n\n configureServer(_server) {\n server = _server\n\n server.middlewares.use('/__permission/manifest', async (_req, res) => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(state.toManifest(), null, 2))\n })\n },\n\n async handleHotUpdate(ctx) {\n if (!filter(ctx.file)) {\n return\n }\n\n // 文件变化后,先删除旧记录,等待下一次 transform 写入新记录\n state.removeFile(ctx.file)\n\n // 通知前端或 devtools 权限 manifest 变了\n ctx.server.ws.send({\n type: 'custom',\n event: 'permission-manifest-update',\n data: state.toManifest()\n })\n }\n }\n\n function validatePermissions(usedPermissions: string[]) {\n if (!options.validate.enabled) {\n return\n }\n\n if (options.validate.unknownPermission === 'off') {\n return\n }\n\n const knownSet = new Set(options.validate.permissions)\n\n const unknown = usedPermissions.filter((item) => !knownSet.has(item))\n\n if (unknown.length === 0) {\n return\n }\n\n const message = `[vite-plugin-permission] Unknown permissions: ${unknown.join(', ')}`\n\n if (options.validate.unknownPermission === 'error') {\n throw new Error(message)\n }\n\n transformContext?.warn(message)\n }\n}\n\nasync function emitManifestAndDts(\n root: string,\n options: ReturnType<typeof resolveOptions>,\n state: PermissionState\n) {\n if (options.manifest.enabled) {\n const manifestPath = path.resolve(root, options.manifest.output)\n await fs.mkdir(path.dirname(manifestPath), { recursive: true })\n await fs.writeFile(manifestPath, createManifestJson(state), 'utf-8')\n }\n\n if (options.dts.enabled) {\n const dtsPath = path.resolve(root, options.dts.output)\n await fs.mkdir(path.dirname(dtsPath), { recursive: true })\n await fs.writeFile(\n dtsPath,\n createDts(state.getUsedPermissions(), options.dts.typeName),\n 'utf-8'\n )\n }\n}\n","// src/options.ts\nimport { z } from 'zod'\n\nconst FilterPatternSchema = z.custom<string | RegExp | Array<string | RegExp>>()\n\nconst GlobPatternSchema = z.union([z.string(), z.array(z.string())])\n\nexport const PluginOptionsSchema = z.object({\n framework: z.enum(['react', 'vue']).default('react'),\n\n componentName: z.string().default('Can'),\n\n importFrom: z.string().default('@eycraf/permission-kit-react'),\n\n /**\n * 全局 include/exclude。\n * transform/rewrite 没单独配置时,会回退使用这里。\n */\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n\n transform: z\n .object({\n enabled: z.boolean().default(true),\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n attributes: z.array(z.string()).default(['permission']),\n modeAttribute: z.string().default('permissionMode'),\n strategyAttribute: z.string().default('permissionStrategy'),\n allowNested: z.boolean().default(false)\n })\n .default({}),\n\n rewrite: z\n .object({\n enabled: z.boolean().default(false),\n\n /**\n * false = dry-run,只打印会修改哪些文件\n * true = 真实写回源文件\n */\n write: z.boolean().default(false),\n\n include: GlobPatternSchema.optional(),\n exclude: GlobPatternSchema.optional(),\n\n /**\n * rewrite 只在 serve/build 启动时跑一次。\n * 默认 true,避免 HMR 时反复改文件。\n */\n once: z.boolean().default(true)\n })\n .default({}),\n\n manifest: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission-manifest.json')\n })\n .default({}),\n\n dts: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission.d.ts'),\n typeName: z.string().default('PermissionKey')\n })\n .default({}),\n\n validate: z\n .object({\n enabled: z.boolean().default(false),\n permissions: z.array(z.string()).default([]),\n unknownPermission: z.enum(['off', 'warn', 'error']).default('warn')\n })\n .default({})\n})\n\nexport type PermissionPluginOptions = z.input<typeof PluginOptionsSchema>\nexport type NormalizedPermissionPluginOptions = z.output<typeof PluginOptionsSchema>\n\nexport function resolveOptions(options: PermissionPluginOptions) {\n return PluginOptionsSchema.parse(options)\n}\n","// src/state.ts\nexport type PermissionUsage = {\n permission: string\n file: string\n line?: number\n column?: number\n}\n\nexport class PermissionState {\n private fileUsageMap = new Map<string, PermissionUsage[]>()\n\n clear() {\n this.fileUsageMap.clear()\n }\n\n setFileUsage(file: string, usages: PermissionUsage[]) {\n this.fileUsageMap.set(file, usages)\n }\n\n removeFile(file: string) {\n this.fileUsageMap.delete(file)\n }\n\n getAllUsages() {\n return [...this.fileUsageMap.values()].flat()\n }\n\n getUsedPermissions() {\n return [...new Set(this.getAllUsages().map((item) => item.permission))].sort()\n }\n\n toManifest() {\n const result: Record<\n string,\n Array<{\n file: string\n line?: number\n column?: number\n }>\n > = {}\n\n for (const usage of this.getAllUsages()) {\n const items = (result[usage.permission] ??= [])\n const entry: {\n file: string\n line?: number\n column?: number\n } = {\n file: usage.file\n }\n\n if (usage.line !== undefined) {\n entry.line = usage.line\n }\n\n if (usage.column !== undefined) {\n entry.column = usage.column\n }\n\n items.push(entry)\n }\n\n return result\n }\n}\n","// src/transformReact.ts\nimport { parse } from '@babel/parser'\nimport traverse, { type NodePath } from '@babel/traverse'\nimport type {\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName\n} from '@babel/types'\nimport MagicString from 'magic-string'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype TransformResult = {\n code: string\n map: ReturnType<MagicString['generateMap']>\n usages: PermissionUsage[]\n}\n\ntype PendingWrap = {\n node: JSXElement\n permissionCode: string\n modeCode: string | undefined\n attrsToRemove: JSXAttribute[]\n}\n\nexport function transformReactPermission(\n code: string,\n id: string,\n options: NormalizedPermissionPluginOptions\n): TransformResult | null {\n if (!/\\.[jt]sx$/.test(id)) {\n return null\n }\n\n const attrs = options.transform.attributes\n const modeAttrName = options.transform.modeAttribute\n const componentName = options.componentName\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n errorRecovery: true\n })\n\n const ms = new MagicString(code)\n const wraps: PendingWrap[] = []\n const usages: PermissionUsage[] = []\n const removes: JSXAttribute[] = []\n\n let hasCanImport = false\n let lastImportEnd = 0\n\n traverse(ast, {\n ImportDeclaration(path) {\n lastImportEnd = Math.max(lastImportEnd, path.node.end ?? 0)\n\n if (path.node.source.value === options.importFrom) {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier' && specifier.local.name === componentName) {\n hasCanImport = true\n }\n }\n }\n },\n\n JSXElement(path) {\n const node = path.node\n\n // 避免 <Can permission=\"x\"> 被再次包裹\n const openingName = node.openingElement.name\n if (openingName.type === 'JSXIdentifier' && openingName.name === componentName) {\n return\n }\n\n const attributes = node.openingElement.attributes\n const permissionAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attrs.includes(attr.name.name)\n )\n })\n\n if (!permissionAttr) {\n return\n }\n\n const modeAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === modeAttrName\n )\n })\n\n const permissionCode = getJSXAttributeValueCode(code, permissionAttr)\n if (!permissionCode) {\n return\n }\n\n const modeCode = modeAttr ? getJSXAttributeValueCode(code, modeAttr) : undefined\n\n const permissionLiteral = getStaticStringValue(permissionAttr)\n if (permissionLiteral) {\n const usage: PermissionUsage = {\n permission: permissionLiteral,\n file: id\n }\n\n if (permissionAttr.loc?.start.line !== undefined) {\n usage.line = permissionAttr.loc.start.line\n }\n\n if (permissionAttr.loc?.start.column !== undefined) {\n usage.column = permissionAttr.loc.start.column\n }\n\n usages.push(usage)\n }\n\n const attrsToRemove = modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n\n // 2. 已经在 <Can> 内部:只删除 permission 属性,不再包裹\n if (isInsideCanElement(path, componentName)) {\n removes.push(...attrsToRemove)\n return\n }\n\n const resolvedModeCode = modeCode ?? undefined\n\n wraps.push({\n node,\n permissionCode,\n modeCode: resolvedModeCode,\n attrsToRemove: modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n })\n\n // 4. 可选:如果当前元素已经要被包裹,可以跳过它的子节点\n // 这样可以避免父子都有 permission 时产生嵌套。\n if (!options.transform.allowNested) {\n path.skip()\n }\n }\n })\n\n if (removes.length) {\n // 先删除在 <Can> 内部的冗余 permission 属性\n removes\n .sort((a, b) => (b.start ?? 0) - (a.start ?? 0))\n .forEach((attr) => {\n removeJSXAttribute(ms, code, attr)\n })\n }\n\n if (wraps.length === 0) {\n if (removes.length === 0) {\n return null\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n }\n\n // 倒序修改,避免位置偏移\n wraps\n .sort((a, b) => (b.node.start ?? 0) - (a.node.start ?? 0))\n .forEach((item) => {\n for (const attr of item.attrsToRemove) {\n removeJSXAttribute(ms, code, attr)\n }\n\n const start = item.node.start\n const end = item.node.end\n\n if (start == null || end == null) {\n return\n }\n\n const modePart = item.modeCode ? ` mode={${item.modeCode}}` : ''\n\n ms.prependLeft(start, `<${componentName} permission={${item.permissionCode}}${modePart}>`)\n\n ms.appendRight(end, `</${componentName}>`)\n })\n\n if (!hasCanImport) {\n const importCode = `import { ${componentName} } from '${options.importFrom}'\\n`\n\n if (lastImportEnd > 0) {\n ms.appendRight(lastImportEnd, `\\n${importCode}`)\n } else {\n ms.prepend(importCode)\n }\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n}\n\nfunction getJSXAttributeValueCode(code: string, attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return JSON.stringify(value.value)\n }\n\n if (value.type === 'JSXExpressionContainer') {\n const expr = value.expression\n\n if (expr.type === 'JSXEmptyExpression' || expr.start == null || expr.end == null) {\n return null\n }\n\n return code.slice(expr.start, expr.end)\n }\n\n return null\n}\n\nfunction getStaticStringValue(attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return value.value\n }\n\n if (value.type === 'JSXExpressionContainer' && value.expression.type === 'StringLiteral') {\n return value.expression.value\n }\n\n return null\n}\n\nfunction removeJSXAttribute(ms: MagicString, code: string, attr: JSXAttribute) {\n if (attr.start == null || attr.end == null) {\n return\n }\n\n let start = attr.start\n let end = attr.end\n\n // 顺手删除属性前面的空格,避免留下多余空白\n while (start > 0 && /\\s/.test(code.charAt(start - 1))) {\n start--\n }\n\n ms.remove(start, end)\n}\n\nfunction getJSXName(name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName): string {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n if (name.type === 'JSXMemberExpression') {\n return `${getJSXName(name.object)}.${getJSXName(name.property)}`\n }\n\n return `${name.namespace.name}:${name.name.name}`\n}\n\nfunction isCanElement(node: JSXElement, componentName: string) {\n const name = getJSXName(node.openingElement.name)\n\n return name === componentName\n}\n\nfunction isInsideCanElement(path: NodePath<JSXElement>, componentName: string) {\n return Boolean(\n path.findParent((parentPath) => {\n if (!parentPath.isJSXElement()) {\n return false\n }\n\n return isCanElement(parentPath.node, componentName)\n })\n )\n}\n","// src/manifest.ts\nimport type { PermissionState } from './state'\n\nexport function createManifestJson(state: PermissionState) {\n return JSON.stringify(\n {\n generatedAt: new Date().toISOString(),\n permissions: state.toManifest()\n },\n null,\n 2\n )\n}\n","// src/dts.ts\nexport function createDts(permissions: string[], typeName = 'PermissionKey') {\n if (permissions.length === 0) {\n return `export type ${typeName} = string\\n`\n }\n\n const union = permissions.map((item) => ` | ${JSON.stringify(item)}`).join('\\n')\n\n return [\n '/* eslint-disable */',\n '// This file is generated by vite-plugin-permission.',\n '// Do not edit manually.',\n '',\n `export type ${typeName} =`,\n union,\n ''\n ].join('\\n')\n}\n","// packages/vite-plugin/src/filter.ts\nimport path from 'node:path'\nimport { createFilter, normalizePath } from 'vite'\n\ntype Pattern = string | RegExp | Array<string | RegExp> | undefined\n\nexport function createRootFilter(root: string, include: Pattern, exclude: Pattern) {\n return createFilter(normalizePatterns(root, include), normalizePatterns(root, exclude))\n}\n\nfunction normalizePatterns(root: string, patterns: Pattern) {\n if (!patterns) {\n return undefined\n }\n\n const list = Array.isArray(patterns) ? patterns : [patterns]\n\n return list.map((item) => {\n if (item instanceof RegExp) {\n return item\n }\n\n // 绝对路径 glob:只做 POSIX 规范化\n if (path.isAbsolute(item)) {\n return normalizePath(item)\n }\n\n // 相对路径 glob:基于 Vite root 转绝对\n return normalizePath(path.resolve(root, item))\n })\n}\n\nexport function cleanId(id: string) {\n return normalizePath(id.split('?')[0] ?? id)\n}\n","// packages/vite-plugin/src/rewrite.ts\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport fg from 'fast-glob'\nimport { normalizePath } from 'vite'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport { transformReactPermission } from './transformReact'\n\ntype LoggerLike = {\n warn(message: string): void\n}\n\nexport type RewriteResult = {\n checked: number\n changed: number\n files: string[]\n}\n\nexport async function rewriteSourceFiles(\n root: string,\n options: NormalizedPermissionPluginOptions,\n context: LoggerLike\n): Promise<RewriteResult> {\n const include = toArray(options.rewrite.include ?? ['src/**/*.{tsx,jsx}'])\n\n const exclude = toArray(\n options.rewrite.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n\n const files = await fg(include, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore: exclude\n })\n\n let changed = 0\n const changedFiles: string[] = []\n\n for (const file of files) {\n const id = normalizePath(file)\n const code = await fs.readFile(file, 'utf-8')\n\n if (options.framework !== 'react') {\n continue\n }\n\n const result = transformReactPermission(code, id, options)\n\n if (!result || result.code === code) {\n continue\n }\n\n changed++\n changedFiles.push(path.relative(root, file))\n\n if (options.rewrite.write) {\n await fs.writeFile(file, result.code, 'utf-8')\n }\n }\n\n const mode = options.rewrite.write ? 'write' : 'dry-run'\n\n if (changedFiles.length > 0) {\n context.warn(\n [\n `[vite-plugin-permission] rewrite ${mode}: ${changed} file(s) would change`,\n ...changedFiles.map((file) => ` - ${file}`)\n ].join('\\n')\n )\n } else {\n context.warn(`[vite-plugin-permission] rewrite ${mode}: no files changed`)\n }\n\n return {\n checked: files.length,\n changed,\n files: changedFiles\n }\n}\n\nfunction toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n"],"mappings":";AAEA,SAAS,gBAAAA,qBAAoB;AAC7B,OAAOC,WAAU;AACjB,OAAOC,SAAQ;;;ACHf,SAAS,SAAS;AAElB,IAAM,sBAAsB,EAAE,OAAiD;AAE/E,IAAM,oBAAoB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5D,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EAAE,KAAK,CAAC,SAAS,KAAK,CAAC,EAAE,QAAQ,OAAO;AAAA,EAEnD,eAAe,EAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EAEvC,YAAY,EAAE,OAAO,EAAE,QAAQ,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7D,SAAS,oBAAoB,SAAS;AAAA,EACtC,SAAS,oBAAoB,SAAS;AAAA,EAEtC,WAAW,EACR,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,SAAS,oBAAoB,SAAS;AAAA,IACtC,SAAS,oBAAoB,SAAS;AAAA,IACtC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC;AAAA,IACtD,eAAe,EAAE,OAAO,EAAE,QAAQ,gBAAgB;AAAA,IAClD,mBAAmB,EAAE,OAAO,EAAE,QAAQ,oBAAoB;AAAA,IAC1D,aAAa,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACxC,CAAC,EACA,QAAQ,CAAC,CAAC;AAAA,EAEb,SAAS,EACN,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,IAMlC,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAEhC,SAAS,kBAAkB,SAAS;AAAA,IACpC,SAAS,kBAAkB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAMpC,MAAM,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAChC,CAAC,EACA,QAAQ,CAAC,CAAC;AAAA,EAEb,UAAU,EACP,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,QAAQ,EAAE,OAAO,EAAE,QAAQ,wCAAwC;AAAA,EACrE,CAAC,EACA,QAAQ,CAAC,CAAC;AAAA,EAEb,KAAK,EACF,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,QAAQ,EAAE,OAAO,EAAE,QAAQ,+BAA+B;AAAA,IAC1D,UAAU,EAAE,OAAO,EAAE,QAAQ,eAAe;AAAA,EAC9C,CAAC,EACA,QAAQ,CAAC,CAAC;AAAA,EAEb,UAAU,EACP,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAClC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IAC3C,mBAAmB,EAAE,KAAK,CAAC,OAAO,QAAQ,OAAO,CAAC,EAAE,QAAQ,MAAM;AAAA,EACpE,CAAC,EACA,QAAQ,CAAC,CAAC;AACf,CAAC;AAKM,SAAS,eAAe,SAAkC;AAC/D,SAAO,oBAAoB,MAAM,OAAO;AAC1C;;;AC3EO,IAAM,kBAAN,MAAsB;AAAA,EAAtB;AACL,SAAQ,eAAe,oBAAI,IAA+B;AAAA;AAAA,EAE1D,QAAQ;AACN,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA,EAEA,aAAa,MAAc,QAA2B;AACpD,SAAK,aAAa,IAAI,MAAM,MAAM;AAAA,EACpC;AAAA,EAEA,WAAW,MAAc;AACvB,SAAK,aAAa,OAAO,IAAI;AAAA,EAC/B;AAAA,EAEA,eAAe;AACb,WAAO,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,EAAE,KAAK;AAAA,EAC9C;AAAA,EAEA,qBAAqB;AACnB,WAAO,CAAC,GAAG,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK;AAAA,EAC/E;AAAA,EAEA,aAAa;AA/Bf;AAgCI,UAAM,SAOF,CAAC;AAEL,eAAW,SAAS,KAAK,aAAa,GAAG;AACvC,YAAM,QAAS,YAAO,MAAM,gBAAb,aAA6B,CAAC;AAC7C,YAAM,QAIF;AAAA,QACF,MAAM,MAAM;AAAA,MACd;AAEA,UAAI,MAAM,SAAS,QAAW;AAC5B,cAAM,OAAO,MAAM;AAAA,MACrB;AAEA,UAAI,MAAM,WAAW,QAAW;AAC9B,cAAM,SAAS,MAAM;AAAA,MACvB;AAEA,YAAM,KAAK,KAAK;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AACF;;;AC/DA,SAAS,aAAa;AACtB,OAAO,cAAiC;AAQxC,OAAO,iBAAiB;AAiBjB,SAAS,yBACd,MACA,IACA,SACwB;AACxB,MAAI,CAAC,YAAY,KAAK,EAAE,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,QAAQ,UAAU;AAChC,QAAM,eAAe,QAAQ,UAAU;AACvC,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,MAAM,MAAM,MAAM;AAAA,IACtB,YAAY;AAAA,IACZ,SAAS,CAAC,OAAO,YAAY;AAAA,IAC7B,eAAe;AAAA,EACjB,CAAC;AAED,QAAM,KAAK,IAAI,YAAY,IAAI;AAC/B,QAAM,QAAuB,CAAC;AAC9B,QAAM,SAA4B,CAAC;AACnC,QAAM,UAA0B,CAAC;AAEjC,MAAI,eAAe;AACnB,MAAI,gBAAgB;AAEpB,WAAS,KAAK;AAAA,IACZ,kBAAkBC,OAAM;AACtB,sBAAgB,KAAK,IAAI,eAAeA,MAAK,KAAK,OAAO,CAAC;AAE1D,UAAIA,MAAK,KAAK,OAAO,UAAU,QAAQ,YAAY;AACjD,mBAAW,aAAaA,MAAK,KAAK,YAAY;AAC5C,cAAI,UAAU,SAAS,qBAAqB,UAAU,MAAM,SAAS,eAAe;AAClF,2BAAe;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,WAAWA,OAAM;AACf,YAAM,OAAOA,MAAK;AAGlB,YAAM,cAAc,KAAK,eAAe;AACxC,UAAI,YAAY,SAAS,mBAAmB,YAAY,SAAS,eAAe;AAC9E;AAAA,MACF;AAEA,YAAM,aAAa,KAAK,eAAe;AACvC,YAAM,iBAAiB,WAAW,KAAK,CAAC,SAA+B;AACrE,eACE,KAAK,SAAS,kBACd,KAAK,KAAK,SAAS,mBACnB,MAAM,SAAS,KAAK,KAAK,IAAI;AAAA,MAEjC,CAAC;AAED,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AAEA,YAAM,WAAW,WAAW,KAAK,CAAC,SAA+B;AAC/D,eACE,KAAK,SAAS,kBACd,KAAK,KAAK,SAAS,mBACnB,KAAK,KAAK,SAAS;AAAA,MAEvB,CAAC;AAED,YAAM,iBAAiB,yBAAyB,MAAM,cAAc;AACpE,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AAEA,YAAM,WAAW,WAAW,yBAAyB,MAAM,QAAQ,IAAI;AAEvE,YAAM,oBAAoB,qBAAqB,cAAc;AAC7D,UAAI,mBAAmB;AACrB,cAAM,QAAyB;AAAA,UAC7B,YAAY;AAAA,UACZ,MAAM;AAAA,QACR;AAEA,YAAI,eAAe,KAAK,MAAM,SAAS,QAAW;AAChD,gBAAM,OAAO,eAAe,IAAI,MAAM;AAAA,QACxC;AAEA,YAAI,eAAe,KAAK,MAAM,WAAW,QAAW;AAClD,gBAAM,SAAS,eAAe,IAAI,MAAM;AAAA,QAC1C;AAEA,eAAO,KAAK,KAAK;AAAA,MACnB;AAEA,YAAM,gBAAgB,WAAW,CAAC,gBAAgB,QAAQ,IAAI,CAAC,cAAc;AAG7E,UAAI,mBAAmBA,OAAM,aAAa,GAAG;AAC3C,gBAAQ,KAAK,GAAG,aAAa;AAC7B;AAAA,MACF;AAEA,YAAM,mBAAmB,YAAY;AAErC,YAAM,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,eAAe,WAAW,CAAC,gBAAgB,QAAQ,IAAI,CAAC,cAAc;AAAA,MACxE,CAAC;AAID,UAAI,CAAC,QAAQ,UAAU,aAAa;AAClC,QAAAA,MAAK,KAAK;AAAA,MACZ;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,QAAQ;AAElB,YACG,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,MAAM,EAAE,SAAS,EAAE,EAC9C,QAAQ,CAAC,SAAS;AACjB,yBAAmB,IAAI,MAAM,IAAI;AAAA,IACnC,CAAC;AAAA,EACL;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,MAAM,GAAG,SAAS;AAAA,MAClB,KAAK,GAAG,YAAY;AAAA,QAClB,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,OAAO;AAAA,MACT,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AAGA,QACG,KAAK,CAAC,GAAG,OAAO,EAAE,KAAK,SAAS,MAAM,EAAE,KAAK,SAAS,EAAE,EACxD,QAAQ,CAAC,SAAS;AACjB,eAAW,QAAQ,KAAK,eAAe;AACrC,yBAAmB,IAAI,MAAM,IAAI;AAAA,IACnC;AAEA,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,MAAM,KAAK,KAAK;AAEtB,QAAI,SAAS,QAAQ,OAAO,MAAM;AAChC;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,WAAW,UAAU,KAAK,QAAQ,MAAM;AAE9D,OAAG,YAAY,OAAO,IAAI,aAAa,gBAAgB,KAAK,cAAc,IAAI,QAAQ,GAAG;AAEzF,OAAG,YAAY,KAAK,KAAK,aAAa,GAAG;AAAA,EAC3C,CAAC;AAEH,MAAI,CAAC,cAAc;AACjB,UAAM,aAAa,YAAY,aAAa,YAAY,QAAQ,UAAU;AAAA;AAE1E,QAAI,gBAAgB,GAAG;AACrB,SAAG,YAAY,eAAe;AAAA,EAAK,UAAU,EAAE;AAAA,IACjD,OAAO;AACL,SAAG,QAAQ,UAAU;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,GAAG,SAAS;AAAA,IAClB,KAAK,GAAG,YAAY;AAAA,MAClB,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,OAAO;AAAA,IACT,CAAC;AAAA,IACD;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,MAAc,MAAmC;AACjF,QAAM,QAAQ,KAAK;AAEnB,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,SAAS,iBAAiB;AAClC,WAAO,KAAK,UAAU,MAAM,KAAK;AAAA,EACnC;AAEA,MAAI,MAAM,SAAS,0BAA0B;AAC3C,UAAM,OAAO,MAAM;AAEnB,QAAI,KAAK,SAAS,wBAAwB,KAAK,SAAS,QAAQ,KAAK,OAAO,MAAM;AAChF,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG;AAAA,EACxC;AAEA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAmC;AAC/D,QAAM,QAAQ,KAAK;AAEnB,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,SAAS,iBAAiB;AAClC,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,MAAM,SAAS,4BAA4B,MAAM,WAAW,SAAS,iBAAiB;AACxF,WAAO,MAAM,WAAW;AAAA,EAC1B;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,IAAiB,MAAc,MAAoB;AAC7E,MAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,MAAM;AAC1C;AAAA,EACF;AAEA,MAAI,QAAQ,KAAK;AACjB,MAAI,MAAM,KAAK;AAGf,SAAO,QAAQ,KAAK,KAAK,KAAK,KAAK,OAAO,QAAQ,CAAC,CAAC,GAAG;AACrD;AAAA,EACF;AAEA,KAAG,OAAO,OAAO,GAAG;AACtB;AAEA,SAAS,WAAW,MAAuE;AACzF,MAAI,KAAK,SAAS,iBAAiB;AACjC,WAAO,KAAK;AAAA,EACd;AAEA,MAAI,KAAK,SAAS,uBAAuB;AACvC,WAAO,GAAG,WAAW,KAAK,MAAM,CAAC,IAAI,WAAW,KAAK,QAAQ,CAAC;AAAA,EAChE;AAEA,SAAO,GAAG,KAAK,UAAU,IAAI,IAAI,KAAK,KAAK,IAAI;AACjD;AAEA,SAAS,aAAa,MAAkB,eAAuB;AAC7D,QAAM,OAAO,WAAW,KAAK,eAAe,IAAI;AAEhD,SAAO,SAAS;AAClB;AAEA,SAAS,mBAAmBA,OAA4B,eAAuB;AAC7E,SAAO;AAAA,IACLA,MAAK,WAAW,CAAC,eAAe;AAC9B,UAAI,CAAC,WAAW,aAAa,GAAG;AAC9B,eAAO;AAAA,MACT;AAEA,aAAO,aAAa,WAAW,MAAM,aAAa;AAAA,IACpD,CAAC;AAAA,EACH;AACF;;;ACzSO,SAAS,mBAAmB,OAAwB;AACzD,SAAO,KAAK;AAAA,IACV;AAAA,MACE,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,aAAa,MAAM,WAAW;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACXO,SAAS,UAAU,aAAuB,WAAW,iBAAiB;AAC3E,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,eAAe,QAAQ;AAAA;AAAA,EAChC;AAEA,QAAM,QAAQ,YAAY,IAAI,CAAC,SAAS,OAAO,KAAK,UAAU,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAEhF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,QAAQ;AAAA,IACvB;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;;;AChBA,OAAO,UAAU;AACjB,SAAS,cAAc,qBAAqB;AAIrC,SAAS,iBAAiB,MAAc,SAAkB,SAAkB;AACjF,SAAO,aAAa,kBAAkB,MAAM,OAAO,GAAG,kBAAkB,MAAM,OAAO,CAAC;AACxF;AAEA,SAAS,kBAAkB,MAAc,UAAmB;AAC1D,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AAE3D,SAAO,KAAK,IAAI,CAAC,SAAS;AACxB,QAAI,gBAAgB,QAAQ;AAC1B,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,aAAO,cAAc,IAAI;AAAA,IAC3B;AAGA,WAAO,cAAc,KAAK,QAAQ,MAAM,IAAI,CAAC;AAAA,EAC/C,CAAC;AACH;;;AC7BA,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB,OAAO,QAAQ;AACf,SAAS,iBAAAC,sBAAqB;AAc9B,eAAsB,mBACpB,MACA,SACA,SACwB;AACxB,QAAM,UAAU,QAAQ,QAAQ,QAAQ,WAAW,CAAC,oBAAoB,CAAC;AAEzE,QAAM,UAAU;AAAA,IACd,QAAQ,QAAQ,WAAW;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,GAAG,SAAS;AAAA,IAC9B,KAAK;AAAA,IACL,UAAU;AAAA,IACV,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,CAAC;AAED,MAAI,UAAU;AACd,QAAM,eAAyB,CAAC;AAEhC,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAKC,eAAc,IAAI;AAC7B,UAAM,OAAO,MAAM,GAAG,SAAS,MAAM,OAAO;AAE5C,QAAI,QAAQ,cAAc,SAAS;AACjC;AAAA,IACF;AAEA,UAAM,SAAS,yBAAyB,MAAM,IAAI,OAAO;AAEzD,QAAI,CAAC,UAAU,OAAO,SAAS,MAAM;AACnC;AAAA,IACF;AAEA;AACA,iBAAa,KAAKC,MAAK,SAAS,MAAM,IAAI,CAAC;AAE3C,QAAI,QAAQ,QAAQ,OAAO;AACzB,YAAM,GAAG,UAAU,MAAM,OAAO,MAAM,OAAO;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,OAAO,QAAQ,QAAQ,QAAQ,UAAU;AAE/C,MAAI,aAAa,SAAS,GAAG;AAC3B,YAAQ;AAAA,MACN;AAAA,QACE,oCAAoC,IAAI,KAAK,OAAO;AAAA,QACpD,GAAG,aAAa,IAAI,CAAC,SAAS,OAAO,IAAI,EAAE;AAAA,MAC7C,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF,OAAO;AACL,YAAQ,KAAK,oCAAoC,IAAI,oBAAoB;AAAA,EAC3E;AAEA,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAW,OAAqB;AACvC,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;;;AP9EA,IAAM,aAAa;AACnB,IAAM,sBAAsB,OAAO;AAEpB,SAAR,iBAAkC,cAAuC,CAAC,GAAW;AAC1F,QAAM,UAAU,eAAe,WAAW;AAE1C,MAAI;AACJ,MAAI;AACJ,MAAI,kBAAkB;AACtB,MAAI;AACJ,MAAI;AACJ,QAAM,QAAQ,IAAI,gBAAgB;AAElC,QAAM,SAASC;AAAA,IACb,QAAQ,WAAW,CAAC,UAAU,UAAU,QAAQ;AAAA,IAChD,QAAQ,WAAW,CAAC,gBAAgB,OAAO;AAAA,EAC7C;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,eAAe,gBAAgB;AAC7B,eAAS;AAET,wBAAkB;AAAA,QAChB,OAAO;AAAA,QACP,QAAQ,UAAU,WAAW,QAAQ,WAAW,CAAC,oBAAoB;AAAA,QACrE,QAAQ,UAAU,WAChB,QAAQ,WAAW;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACJ;AAAA,IACF;AAAA,IAEA,MAAM,aAAa;AACjB,YAAM,QAAQ;AACd,UAAI,CAAC,QAAQ,QAAQ,SAAS;AAC5B;AAAA,MACF;AAEA,UAAI,QAAQ,QAAQ,QAAQ,iBAAiB;AAC3C;AAAA,MACF;AAEA,wBAAkB;AAElB,YAAM,mBAAmB,OAAO,MAAM,SAAS,IAAI;AAAA,IACrD;AAAA,IAEA,UAAU,IAAI;AACZ,UAAI,OAAO,YAAY;AACrB,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,OAAO,qBAAqB;AAC9B,eAAO,kBAAkB,KAAK,UAAU,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC;AAAA,MACtE;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,UAAU,MAAM,IAAI;AACxB,yBAAmB;AAEnB,UAAI,CAAC,OAAO,EAAE,KAAK,CAAC,kBAAkB,EAAE,GAAG;AACzC,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,QAAQ,UAAU,SAAS;AAC9B,eAAO;AAAA,MACT;AAEA,UAAI,QAAQ,cAAc,SAAS;AACjC,cAAM,SAAS,yBAAyB,MAAM,IAAI,OAAO;AAEzD,YAAI,CAAC,QAAQ;AACX,gBAAM,WAAW,EAAE;AACnB,iBAAO;AAAA,QACT;AAEA,cAAM,aAAa,IAAI,OAAO,MAAM;AAEpC,4BAAoB,OAAO,OAAO,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC;AAEhE,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,KAAK,OAAO;AAAA,QACd;AAAA,MACF;AAGA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,iBAAiB;AACrB,YAAM,mBAAmB,OAAO,MAAM,SAAS,KAAK;AAAA,IACtD;AAAA,IAEA,gBAAgB,SAAS;AACvB,eAAS;AAET,aAAO,YAAY,IAAI,0BAA0B,OAAO,MAAM,QAAQ;AACpE,YAAI,UAAU,gBAAgB,kBAAkB;AAChD,YAAI,IAAI,KAAK,UAAU,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC;AAAA,MACrD,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,gBAAgB,KAAK;AACzB,UAAI,CAAC,OAAO,IAAI,IAAI,GAAG;AACrB;AAAA,MACF;AAGA,YAAM,WAAW,IAAI,IAAI;AAGzB,UAAI,OAAO,GAAG,KAAK;AAAA,QACjB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM,MAAM,WAAW;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,oBAAoB,iBAA2B;AACtD,QAAI,CAAC,QAAQ,SAAS,SAAS;AAC7B;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,sBAAsB,OAAO;AAChD;AAAA,IACF;AAEA,UAAM,WAAW,IAAI,IAAI,QAAQ,SAAS,WAAW;AAErD,UAAM,UAAU,gBAAgB,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,IAAI,CAAC;AAEpE,QAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,IACF;AAEA,UAAM,UAAU,iDAAiD,QAAQ,KAAK,IAAI,CAAC;AAEnF,QAAI,QAAQ,SAAS,sBAAsB,SAAS;AAClD,YAAM,IAAI,MAAM,OAAO;AAAA,IACzB;AAEA,sBAAkB,KAAK,OAAO;AAAA,EAChC;AACF;AAEA,eAAe,mBACb,MACA,SACA,OACA;AACA,MAAI,QAAQ,SAAS,SAAS;AAC5B,UAAM,eAAeC,MAAK,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAC/D,UAAMC,IAAG,MAAMD,MAAK,QAAQ,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9D,UAAMC,IAAG,UAAU,cAAc,mBAAmB,KAAK,GAAG,OAAO;AAAA,EACrE;AAEA,MAAI,QAAQ,IAAI,SAAS;AACvB,UAAM,UAAUD,MAAK,QAAQ,MAAM,QAAQ,IAAI,MAAM;AACrD,UAAMC,IAAG,MAAMD,MAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACzD,UAAMC,IAAG;AAAA,MACP;AAAA,MACA,UAAU,MAAM,mBAAmB,GAAG,QAAQ,IAAI,QAAQ;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;","names":["createFilter","path","fs","path","path","normalizePath","normalizePath","path","createFilter","path","fs"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/state.ts","../src/transformReact.ts","../src/manifest.ts","../src/dts.ts","../src/filter.ts","../src/rewrite.ts","../src/validate.ts"],"sourcesContent":["// src/index.ts\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport { createFilter } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs/promises'\nimport { resolveOptions, type PermissionPluginOptions } from './options'\nimport { PermissionState } from './state'\nimport { transformReactPermission } from './transformReact'\nimport { createManifest, createManifestJson } from './manifest'\nimport { createDts } from './dts'\nimport { createRootFilter } from './filter'\nimport { rewriteSourceFiles } from './rewrite'\nimport { validatePermissionUsages } from './validate'\n\nconst VIRTUAL_ID = 'virtual:permission-manifest'\nconst RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID\n\nexport default function permissionPlugin(userOptions: PermissionPluginOptions = {}): Plugin {\n const options = resolveOptions(userOptions)\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let rewriteExecuted = false\n let transformContext: { warn: (message: string) => void } | undefined\n let transformFilter: ReturnType<typeof createRootFilter> | undefined\n const state = new PermissionState()\n\n const filter = createFilter(\n options.include ?? [/\\.tsx$/, /\\.jsx$/, /\\.vue$/],\n options.exclude ?? [/node_modules/, /\\.git/]\n )\n return {\n name: 'vite-plugin-permission',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n\n transformFilter = createRootFilter(\n config.root,\n options.transform.include ?? options.include ?? ['src/**/*.{tsx,jsx}'],\n options.transform.exclude ??\n options.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n },\n\n async buildStart() {\n state.clear?.()\n if (!options.rewrite.enabled) {\n return\n }\n\n if (options.rewrite.once && rewriteExecuted) {\n return\n }\n\n rewriteExecuted = true\n\n await rewriteSourceFiles(config.root, options, this)\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return `export default ${JSON.stringify(createManifest(state), null, 2)}`\n }\n\n return null\n },\n\n async transform(code, id) {\n transformContext = this\n\n if (!filter(id) || !transformFilter?.(id)) {\n return null\n }\n\n if (!options.transform.enabled) {\n return null\n }\n\n if (options.framework === 'react') {\n const result = transformReactPermission(code, id, options)\n\n if (!result) {\n state.removeFile(id)\n return null\n }\n\n state.setFileUsage(id, result.usages)\n\n validatePermissionUsages(result.usages, options.validate, transformContext)\n\n return {\n code: result.code,\n map: result.map\n }\n }\n\n // Vue MVP 阶段建议只扫描,不强行 template 改写\n return null\n },\n\n async generateBundle() {\n await emitManifestAndDts(config.root, options, state)\n },\n\n configureServer(_server) {\n server = _server\n\n server.middlewares.use('/__permission/manifest', async (_req, res) => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(createManifest(state), null, 2))\n })\n },\n\n async handleHotUpdate(ctx) {\n if (!filter(ctx.file)) {\n return\n }\n\n // 文件变化后,先删除旧记录,等待下一次 transform 写入新记录\n state.removeFile(ctx.file)\n\n // 通知前端或 devtools 权限 manifest 变了\n ctx.server.ws.send({\n type: 'custom',\n event: 'permission-manifest-update',\n data: createManifest(state)\n })\n }\n }\n}\n\nasync function emitManifestAndDts(\n root: string,\n options: ReturnType<typeof resolveOptions>,\n state: PermissionState\n) {\n if (options.manifest.enabled) {\n const manifestPath = path.resolve(root, options.manifest.output)\n await fs.mkdir(path.dirname(manifestPath), { recursive: true })\n await fs.writeFile(manifestPath, createManifestJson(state), 'utf-8')\n }\n\n if (options.dts.enabled) {\n const dtsPath = path.resolve(root, options.dts.output)\n await fs.mkdir(path.dirname(dtsPath), { recursive: true })\n await fs.writeFile(\n dtsPath,\n createDts(state.getUsedPermissions(), options.dts.typeName),\n 'utf-8'\n )\n }\n}\n","// src/options.ts\nimport { z } from 'zod'\n\nconst FilterPatternSchema = z.custom<string | RegExp | Array<string | RegExp>>()\n\nconst GlobPatternSchema = z.union([z.string(), z.array(z.string())])\n\nexport const PluginOptionsSchema = z.object({\n framework: z.enum(['react', 'vue']).default('react'),\n\n componentName: z.string().default('Can'),\n\n importFrom: z.string().default('@eycraf/permission-kit-react'),\n\n /**\n * 全局 include/exclude。\n * transform/rewrite 没单独配置时,会回退使用这里。\n */\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n\n transform: z\n .object({\n enabled: z.boolean().default(true),\n include: FilterPatternSchema.optional(),\n exclude: FilterPatternSchema.optional(),\n attributes: z.array(z.string()).default(['permission']),\n modeAttribute: z.string().default('permissionMode'),\n strategyAttribute: z.string().default('permissionStrategy'),\n allowNested: z.boolean().default(false)\n })\n .default({}),\n\n rewrite: z\n .object({\n enabled: z.boolean().default(false),\n\n /**\n * false = dry-run,只打印会修改哪些文件\n * true = 真实写回源文件\n */\n write: z.boolean().default(false),\n\n include: GlobPatternSchema.optional(),\n exclude: GlobPatternSchema.optional(),\n\n /**\n * rewrite 只在 serve/build 启动时跑一次。\n * 默认 true,避免 HMR 时反复改文件。\n */\n once: z.boolean().default(true)\n })\n .default({}),\n\n manifest: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission-manifest.json')\n })\n .default({}),\n\n dts: z\n .object({\n enabled: z.boolean().default(true),\n output: z.string().default('src/generated/permission.d.ts'),\n typeName: z.string().default('PermissionKey')\n })\n .default({}),\n\n validate: z\n .object({\n enabled: z.boolean().default(false),\n permissions: z.array(z.string()).default([]),\n unknownPermission: z.enum(['off', 'warn', 'error']).default('warn')\n })\n .default({})\n})\n\nexport type PermissionPluginOptions = z.input<typeof PluginOptionsSchema>\nexport type NormalizedPermissionPluginOptions = z.output<typeof PluginOptionsSchema>\n\nexport function resolveOptions(options: PermissionPluginOptions) {\n return PluginOptionsSchema.parse(options)\n}\n","// src/state.ts\nexport type PermissionUsage = {\n permission: string\n file: string\n line?: number\n column?: number\n component?: string\n}\n\nexport type PermissionManifestUsage = {\n file: string\n line?: number\n column?: number\n component?: string\n}\n\nexport type PermissionManifestEntry = {\n permission: string\n count: number\n files: string[]\n usages: PermissionManifestUsage[]\n}\n\nexport type PermissionManifestSummary = {\n permissions: number\n usages: number\n files: number\n}\n\nexport type PermissionManifest = {\n generatedAt: string\n summary: PermissionManifestSummary\n permissions: PermissionManifestEntry[]\n}\n\nexport class PermissionState {\n private fileUsageMap = new Map<string, PermissionUsage[]>()\n\n clear() {\n this.fileUsageMap.clear()\n }\n\n setFileUsage(file: string, usages: PermissionUsage[]) {\n this.fileUsageMap.set(file, usages)\n }\n\n removeFile(file: string) {\n this.fileUsageMap.delete(file)\n }\n\n getAllUsages() {\n return [...this.fileUsageMap.values()].flat()\n }\n\n getUsedPermissions() {\n return [...new Set(this.getAllUsages().map((item) => item.permission))].sort()\n }\n\n getSummary(): PermissionManifestSummary {\n const usages = this.getAllUsages()\n\n return {\n permissions: new Set(usages.map((item) => item.permission)).size,\n usages: usages.length,\n files: new Set(usages.map((item) => item.file)).size\n }\n }\n\n toManifest() {\n const grouped = new Map<string, PermissionUsage[]>()\n\n for (const usage of this.getAllUsages()) {\n const items = grouped.get(usage.permission) ?? []\n items.push(usage)\n grouped.set(usage.permission, items)\n }\n\n return [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([permission, usages]) => {\n const sortedUsages = [...usages].sort((left, right) => compareUsage(left, right))\n const files = [...new Set(sortedUsages.map((item) => item.file))].sort((left, right) =>\n left.localeCompare(right)\n )\n\n return {\n permission,\n count: sortedUsages.length,\n files,\n usages: sortedUsages.map(({ file, line, column, component }) => {\n const entry: PermissionManifestUsage = { file }\n\n if (line !== undefined) {\n entry.line = line\n }\n\n if (column !== undefined) {\n entry.column = column\n }\n\n if (component !== undefined) {\n entry.component = component\n }\n\n return entry\n })\n } satisfies PermissionManifestEntry\n })\n }\n}\n\nfunction compareUsage(left: PermissionUsage, right: PermissionUsage) {\n const fileCompare = left.file.localeCompare(right.file)\n if (fileCompare !== 0) {\n return fileCompare\n }\n\n const lineCompare = (left.line ?? 0) - (right.line ?? 0)\n if (lineCompare !== 0) {\n return lineCompare\n }\n\n const columnCompare = (left.column ?? 0) - (right.column ?? 0)\n if (columnCompare !== 0) {\n return columnCompare\n }\n\n return (left.component ?? '').localeCompare(right.component ?? '')\n}\n","// src/transformReact.ts\nimport { parse } from '@babel/parser'\nimport traverse, { type NodePath } from '@babel/traverse'\nimport type {\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName\n} from '@babel/types'\nimport MagicString from 'magic-string'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype TransformResult = {\n code: string\n map: ReturnType<MagicString['generateMap']>\n usages: PermissionUsage[]\n}\n\ntype PendingWrap = {\n node: JSXElement\n permissionCode: string\n modeCode: string | undefined\n attrsToRemove: JSXAttribute[]\n}\n\nexport function transformReactPermission(\n code: string,\n id: string,\n options: NormalizedPermissionPluginOptions\n): TransformResult | null {\n if (!/\\.[jt]sx$/.test(id)) {\n return null\n }\n\n const attrs = options.transform.attributes\n const modeAttrName = options.transform.modeAttribute\n const componentName = options.componentName\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n errorRecovery: true\n })\n\n const ms = new MagicString(code)\n const wraps: PendingWrap[] = []\n const usages: PermissionUsage[] = []\n const removes: JSXAttribute[] = []\n\n let hasCanImport = false\n let lastImportEnd = 0\n\n traverse(ast, {\n ImportDeclaration(path) {\n lastImportEnd = Math.max(lastImportEnd, path.node.end ?? 0)\n\n if (path.node.source.value === options.importFrom) {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier' && specifier.local.name === componentName) {\n hasCanImport = true\n }\n }\n }\n },\n\n JSXElement(path) {\n const node = path.node\n\n // 避免 <Can permission=\"x\"> 被再次包裹\n const openingName = node.openingElement.name\n if (openingName.type === 'JSXIdentifier' && openingName.name === componentName) {\n return\n }\n\n const attributes = node.openingElement.attributes\n const permissionAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attrs.includes(attr.name.name)\n )\n })\n\n if (!permissionAttr) {\n return\n }\n\n const modeAttr = attributes.find((attr): attr is JSXAttribute => {\n return (\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === modeAttrName\n )\n })\n\n const permissionCode = getJSXAttributeValueCode(code, permissionAttr)\n if (!permissionCode) {\n return\n }\n\n const modeCode = modeAttr ? getJSXAttributeValueCode(code, modeAttr) : undefined\n\n const permissionLiteral = getStaticStringValue(permissionAttr)\n if (permissionLiteral) {\n const usage: PermissionUsage = {\n permission: permissionLiteral,\n file: id,\n component: componentName\n }\n\n if (permissionAttr.loc?.start.line !== undefined) {\n usage.line = permissionAttr.loc.start.line\n }\n\n if (permissionAttr.loc?.start.column !== undefined) {\n usage.column = permissionAttr.loc.start.column\n }\n\n usages.push(usage)\n }\n\n const attrsToRemove = modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n\n // 2. 已经在 <Can> 内部:只删除 permission 属性,不再包裹\n if (isInsideCanElement(path, componentName)) {\n removes.push(...attrsToRemove)\n return\n }\n\n const resolvedModeCode = modeCode ?? undefined\n\n wraps.push({\n node,\n permissionCode,\n modeCode: resolvedModeCode,\n attrsToRemove: modeAttr ? [permissionAttr, modeAttr] : [permissionAttr]\n })\n\n // 4. 可选:如果当前元素已经要被包裹,可以跳过它的子节点\n // 这样可以避免父子都有 permission 时产生嵌套。\n if (!options.transform.allowNested) {\n path.skip()\n }\n }\n })\n\n if (removes.length) {\n // 先删除在 <Can> 内部的冗余 permission 属性\n removes\n .sort((a, b) => (b.start ?? 0) - (a.start ?? 0))\n .forEach((attr) => {\n removeJSXAttribute(ms, code, attr)\n })\n }\n\n if (wraps.length === 0) {\n if (removes.length === 0) {\n return null\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n }\n\n // 倒序修改,避免位置偏移\n wraps\n .sort((a, b) => (b.node.start ?? 0) - (a.node.start ?? 0))\n .forEach((item) => {\n for (const attr of item.attrsToRemove) {\n removeJSXAttribute(ms, code, attr)\n }\n\n const start = item.node.start\n const end = item.node.end\n\n if (start == null || end == null) {\n return\n }\n\n const modePart = item.modeCode ? ` mode={${item.modeCode}}` : ''\n\n ms.prependLeft(start, `<${componentName} permission={${item.permissionCode}}${modePart}>`)\n\n ms.appendRight(end, `</${componentName}>`)\n })\n\n if (!hasCanImport) {\n const importCode = `import { ${componentName} } from '${options.importFrom}'\\n`\n\n if (lastImportEnd > 0) {\n ms.appendRight(lastImportEnd, `\\n${importCode}`)\n } else {\n ms.prepend(importCode)\n }\n }\n\n return {\n code: ms.toString(),\n map: ms.generateMap({\n source: id,\n includeContent: true,\n hires: true\n }),\n usages\n }\n}\n\nfunction getJSXAttributeValueCode(code: string, attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return JSON.stringify(value.value)\n }\n\n if (value.type === 'JSXExpressionContainer') {\n const expr = value.expression\n\n if (expr.type === 'JSXEmptyExpression' || expr.start == null || expr.end == null) {\n return null\n }\n\n return code.slice(expr.start, expr.end)\n }\n\n return null\n}\n\nfunction getStaticStringValue(attr: JSXAttribute): string | null {\n const value = attr.value\n\n if (!value) {\n return null\n }\n\n if (value.type === 'StringLiteral') {\n return value.value\n }\n\n if (value.type === 'JSXExpressionContainer' && value.expression.type === 'StringLiteral') {\n return value.expression.value\n }\n\n return null\n}\n\nfunction removeJSXAttribute(ms: MagicString, code: string, attr: JSXAttribute) {\n if (attr.start == null || attr.end == null) {\n return\n }\n\n let start = attr.start\n let end = attr.end\n\n // 顺手删除属性前面的空格,避免留下多余空白\n while (start > 0 && /\\s/.test(code.charAt(start - 1))) {\n start--\n }\n\n ms.remove(start, end)\n}\n\nfunction getJSXName(name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName): string {\n if (name.type === 'JSXIdentifier') {\n return name.name\n }\n\n if (name.type === 'JSXMemberExpression') {\n return `${getJSXName(name.object)}.${getJSXName(name.property)}`\n }\n\n return `${name.namespace.name}:${name.name.name}`\n}\n\nfunction isCanElement(node: JSXElement, componentName: string) {\n const name = getJSXName(node.openingElement.name)\n\n return name === componentName\n}\n\nfunction isInsideCanElement(path: NodePath<JSXElement>, componentName: string) {\n return Boolean(\n path.findParent((parentPath) => {\n if (!parentPath.isJSXElement()) {\n return false\n }\n\n return isCanElement(parentPath.node, componentName)\n })\n )\n}\n","// src/manifest.ts\nimport type { PermissionManifest, PermissionState } from './state'\n\nexport function createManifest(state: PermissionState): PermissionManifest {\n return {\n generatedAt: new Date().toISOString(),\n summary: state.getSummary(),\n permissions: state.toManifest()\n }\n}\n\nexport function createManifestJson(state: PermissionState) {\n return JSON.stringify(createManifest(state), null, 2)\n}\n","// src/dts.ts\nexport function createDts(permissions: string[], typeName = 'PermissionKey') {\n const uniquePermissions = [...new Set(permissions)].sort((left, right) =>\n left.localeCompare(right)\n )\n\n const permissionKeysType =\n uniquePermissions.length > 0\n ? `readonly [${uniquePermissions.map((item) => JSON.stringify(item)).join(', ')}]`\n : 'readonly string[]'\n\n return [\n '/* eslint-disable */',\n '// This file is generated by vite-plugin-permission.',\n '// Do not edit manually.',\n '',\n `export declare const permissionKeys: ${permissionKeysType}`,\n `export type ${typeName} = typeof permissionKeys[number]`,\n '',\n `export type PermissionUsage = {`,\n ` permission: ${typeName}`,\n ' file: string',\n ' line?: number',\n ' column?: number',\n ' component?: string',\n '}',\n '',\n `export type PermissionManifestEntry = {`,\n ` permission: ${typeName}`,\n ' count: number',\n ' files: readonly string[]',\n ' usages: readonly PermissionUsage[]',\n '}',\n '',\n 'export type PermissionManifestSummary = {',\n ' permissions: number',\n ' usages: number',\n ' files: number',\n '}',\n '',\n 'export type PermissionManifest = {',\n ' generatedAt: string',\n ' summary: PermissionManifestSummary',\n ' permissions: readonly PermissionManifestEntry[]',\n '}',\n ''\n ].join('\\n')\n}\n","// packages/vite-plugin/src/filter.ts\nimport path from 'node:path'\nimport { createFilter, normalizePath } from 'vite'\n\ntype Pattern = string | RegExp | Array<string | RegExp> | undefined\n\nexport function createRootFilter(root: string, include: Pattern, exclude: Pattern) {\n return createFilter(normalizePatterns(root, include), normalizePatterns(root, exclude))\n}\n\nfunction normalizePatterns(root: string, patterns: Pattern) {\n if (!patterns) {\n return undefined\n }\n\n const list = Array.isArray(patterns) ? patterns : [patterns]\n\n return list.map((item) => {\n if (item instanceof RegExp) {\n return item\n }\n\n // 绝对路径 glob:只做 POSIX 规范化\n if (path.isAbsolute(item)) {\n return normalizePath(item)\n }\n\n // 相对路径 glob:基于 Vite root 转绝对\n return normalizePath(path.resolve(root, item))\n })\n}\n\nexport function cleanId(id: string) {\n return normalizePath(id.split('?')[0] ?? id)\n}\n","// packages/vite-plugin/src/rewrite.ts\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport fg from 'fast-glob'\nimport { normalizePath } from 'vite'\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport { transformReactPermission } from './transformReact'\n\ntype LoggerLike = {\n warn(message: string): void\n}\n\nexport type RewriteResult = {\n checked: number\n changed: number\n files: string[]\n}\n\nexport async function rewriteSourceFiles(\n root: string,\n options: NormalizedPermissionPluginOptions,\n context: LoggerLike\n): Promise<RewriteResult> {\n const include = toArray(options.rewrite.include ?? ['src/**/*.{tsx,jsx}'])\n\n const exclude = toArray(\n options.rewrite.exclude ?? [\n '**/node_modules/**',\n '**/dist/**',\n '**/.vite/**',\n '**/.turbo/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*'\n ]\n )\n\n const files = await fg(include, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore: exclude\n })\n\n let changed = 0\n const changedFiles: string[] = []\n\n for (const file of files) {\n const id = normalizePath(file)\n const code = await fs.readFile(file, 'utf-8')\n\n if (options.framework !== 'react') {\n continue\n }\n\n const result = transformReactPermission(code, id, options)\n\n if (!result || result.code === code) {\n continue\n }\n\n changed++\n changedFiles.push(path.relative(root, file))\n\n if (options.rewrite.write) {\n await fs.writeFile(file, result.code, 'utf-8')\n }\n }\n\n const mode = options.rewrite.write ? 'write' : 'dry-run'\n\n if (changedFiles.length > 0) {\n context.warn(\n [\n `[vite-plugin-permission] rewrite ${mode}: ${changed} file(s) would change`,\n ...changedFiles.map((file) => ` - ${file}`)\n ].join('\\n')\n )\n } else {\n context.warn(`[vite-plugin-permission] rewrite ${mode}: no files changed`)\n }\n\n return {\n checked: files.length,\n changed,\n files: changedFiles\n }\n}\n\nfunction toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n","// src/validate.ts\nimport type { NormalizedPermissionPluginOptions } from './options'\nimport type { PermissionUsage } from './state'\n\ntype ValidationReporter = {\n warn(message: string): void\n}\n\nexport function validatePermissionUsages(\n usages: PermissionUsage[],\n options: NormalizedPermissionPluginOptions['validate'],\n reporter?: ValidationReporter\n) {\n if (!options.enabled || options.unknownPermission === 'off') {\n return []\n }\n\n const knownSet = new Set(options.permissions)\n const grouped = new Map<string, PermissionUsage[]>()\n\n for (const usage of usages) {\n if (knownSet.has(usage.permission)) {\n continue\n }\n\n const items = grouped.get(usage.permission) ?? []\n items.push(usage)\n grouped.set(usage.permission, items)\n }\n\n const unknownPermissions = [...grouped.keys()].sort((left, right) => left.localeCompare(right))\n\n if (unknownPermissions.length === 0) {\n return []\n }\n\n const message = buildMessage(unknownPermissions, grouped)\n\n if (options.unknownPermission === 'error') {\n throw new Error(message)\n }\n\n reporter?.warn(message)\n\n return unknownPermissions\n}\n\nfunction buildMessage(permissions: string[], grouped: Map<string, PermissionUsage[]>) {\n const lines = [`[vite-plugin-permission] Unknown permissions: ${permissions.join(', ')}`]\n\n for (const permission of permissions) {\n const usages = grouped.get(permission) ?? []\n for (const usage of usages.slice(0, 3)) {\n lines.push(` - ${formatUsage(usage)}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction formatUsage(usage: PermissionUsage) {\n const location = [usage.file, usage.line, usage.column]\n .filter((item) => item !== undefined)\n .join(':')\n\n if (!usage.component) {\n return `${usage.permission} (${location})`\n }\n\n return `${usage.permission} (${location}, component=${usage.component})`\n}\n"],"mappings":"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","names":["createFilter","path","fs","path","path","normalizePath","normalizePath","path","createFilter","path","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eycraf/permission-kit-vite-plugin",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.cjs",