@fangzhongya/icons 0.0.14 → 0.0.16

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.
@@ -1,77 +1,213 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-75ZPJI57.cjs');
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+ var _chunkOSHAEKZLcjs = require('../chunk-OSHAEKZL.cjs');
5
+ require('../chunk-IIVF4KK5.cjs');
6
+
7
+
8
+ var _chunk5NH4G6UJcjs = require('../chunk-5NH4G6UJ.cjs');
9
+ require('../chunk-75ZPJI57.cjs');
2
10
 
3
11
  // packages/vite/index2.ts
4
- var virtualModuleId = "virtual:fang-icon";
5
- function simpleFangIcon(options = {}) {
6
- const { type = "svg", directory = "./svg" } = options;
7
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
8
- return {
9
- name: "simple-fang-icon",
10
- resolveId(id) {
11
- if (id === virtualModuleId) {
12
- return resolvedVirtualModuleId;
12
+ function parseAttributes(attrString) {
13
+ const attributes = { name: "" };
14
+ const attrRegex = /(?:@|:|v-bind:)?([\w-]+)(?:="([^"]*)"|='([^']*)')/g;
15
+ let match;
16
+ while ((match = attrRegex.exec(attrString)) !== null) {
17
+ const name = match[1];
18
+ if (name) {
19
+ const value = match[2] || match[3] || "";
20
+ if (name === "name") {
21
+ attributes.name = value;
22
+ } else if (value === "true" || value === "false") {
23
+ attributes[name] = value === "true";
24
+ } else if (!isNaN(Number(value)) && value !== "") {
25
+ attributes[name] = Number(value);
26
+ } else {
27
+ attributes[name] = value;
13
28
  }
14
- return void 0;
15
- },
16
- load(id) {
17
- if (id === resolvedVirtualModuleId) {
18
- return `
19
- import { defineComponent, h, defineAsyncComponent, resolveComponent, computed } from 'vue'
20
- import FangIcon from '@fangzhongya/icons/icon/index'
21
-
22
- export default defineComponent({
23
- props: {
24
- name: {
25
- type: [String, Object],
26
- required: true
27
- },
28
- type: {
29
- type: String,
30
- default: '${type}'
31
- },
32
- directory: {
33
- type: String,
34
- default: '${directory}'
35
29
  }
36
- },
37
- setup(props, { attrs }) {
38
- const IconComponent = computed(() => {
39
- const iconName = props.name;
40
- // \u5982\u679C\u76F4\u63A5\u4F20\u9012\u4E86\u7EC4\u4EF6\uFF0C\u76F4\u63A5\u4F7F\u7528
41
- if (typeof iconName === 'string' && props.type === 'svg') {
42
- // SVG \u7C7B\u578B\uFF1A\u4ECE @fangzhongya/icons \u5E93\u5BFC\u5165
43
- return defineAsyncComponent(() =>
44
- import(/* @vite-ignore */'node_modules/@fangzhongya/icons/vue/' + iconName)
45
- .then(module => module.default)
46
- .catch(() => {
47
- // \u5982\u679C\u5BFC\u5165\u5931\u8D25\uFF0C\u5C1D\u8BD5\u89E3\u6790\u7EC4\u4EF6
48
- const component = resolveComponent(iconName);
49
- if (component) {
50
- return component;
51
- }
52
- // \u5982\u679C\u7EC4\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8FD4\u56DE\u5360\u4F4D\u7B26
53
- return {
54
- setup: () => () => h('span', { class: 'icon-error' }, \`Icon \${iconName} not found\`)
55
- };
56
- })
57
- );
30
+ }
31
+ return attributes;
32
+ }
33
+ function hasStringNameAttribute(attrString) {
34
+ const nameRegex = /(?:^|\s)name="[^"]*"/i;
35
+ const singleQuoteRegex = /(?:^|\s)name='[^']*'/i;
36
+ return nameRegex.test(attrString) || singleQuoteRegex.test(attrString);
37
+ }
38
+ function isOnlyWhitespace(content) {
39
+ return !content || /^\s*$/.test(content);
40
+ }
41
+ function findComponents(code, name) {
42
+ const components = [];
43
+ for (const componentName of name) {
44
+ let currentIndex = 0;
45
+ while (currentIndex < code.length) {
46
+ const startTagIndex = code.indexOf(
47
+ `<${componentName}`,
48
+ currentIndex
49
+ );
50
+ if (startTagIndex === -1) break;
51
+ let tagEndIndex = code.indexOf(">", startTagIndex);
52
+ if (tagEndIndex === -1) break;
53
+ const startTag = code.slice(startTagIndex, tagEndIndex + 1);
54
+ const attrString = startTag.slice(componentName.length + 1, -1).trim();
55
+ if (!hasStringNameAttribute(attrString)) {
56
+ currentIndex = startTagIndex + 1;
57
+ continue;
58
+ }
59
+ const attributes = parseAttributes(attrString);
60
+ if (!attributes.name) {
61
+ currentIndex = startTagIndex + 1;
62
+ continue;
58
63
  }
59
- return iconName;
60
- });
61
-
62
- return () => {
63
- return h(FangIcon, {
64
- ...attrs,
65
- type: props.type,
66
- name: IconComponent.value,
67
- directory: props.directory
64
+ const isSelfClosing = startTag.endsWith("/>");
65
+ let endIndex;
66
+ let fullMatch;
67
+ if (isSelfClosing) {
68
+ endIndex = tagEndIndex + 1;
69
+ fullMatch = startTag;
70
+ } else {
71
+ const endTag = `</${componentName}>`;
72
+ let endTagIndex = code.indexOf(endTag, tagEndIndex + 1);
73
+ if (endTagIndex === -1) {
74
+ currentIndex = startTagIndex + 1;
75
+ continue;
76
+ }
77
+ const content = code.slice(tagEndIndex + 1, endTagIndex);
78
+ if (!isOnlyWhitespace(content)) {
79
+ currentIndex = startTagIndex + 1;
80
+ continue;
81
+ }
82
+ endIndex = endTagIndex + endTag.length;
83
+ fullMatch = code.slice(startTagIndex, endIndex);
84
+ }
85
+ components.push({
86
+ componentName,
87
+ fullMatch,
88
+ start: startTagIndex,
89
+ end: endIndex,
90
+ attributes,
91
+ isSelfClosing
68
92
  });
69
- };
93
+ currentIndex = endIndex;
94
+ }
70
95
  }
71
- })
72
- `;
96
+ return components;
97
+ }
98
+ function getText(iconName, match) {
99
+ const svg = _chunkOSHAEKZLcjs.getIconifySVG.call(void 0, _chunk5NH4G6UJcjs.json_default, iconName, 'v-bind="scope"');
100
+ const s = match.fullMatch.replace(`name="${iconName}"`, "").replace(`name='${iconName}'`, "").replace(`</${match.componentName}>`, "");
101
+ const text = `${s}<template #default="scope">${svg}</template></${match.componentName}>`;
102
+ return { text, imptext: "" };
103
+ }
104
+ function getImportName(iconName) {
105
+ return _chunkOSHAEKZLcjs.lineToLargeHump.call(void 0, "fang-icon-" + iconName);
106
+ }
107
+ function getVue(iconName, match) {
108
+ const text = match.fullMatch.replace(`name="${iconName}"`, `:name="${getImportName(iconName)}"`).replace(`name='${iconName}'`, `:name='${getImportName(iconName)}'`);
109
+ return {
110
+ text,
111
+ imptext: `import ${getImportName(
112
+ iconName
113
+ )} from '@fangzhongya/icons/vue/${iconName}'`
114
+ };
115
+ }
116
+ function replaceComponent(match, type, dynamic, customReplacement) {
117
+ const { attributes } = match;
118
+ const iconName = attributes.name;
119
+ if (customReplacement) {
120
+ return customReplacement(iconName, attributes);
121
+ }
122
+ let svgContent = _chunk5NH4G6UJcjs.json_default.icons[iconName];
123
+ if (!svgContent) {
124
+ return { text: match.fullMatch, imptext: "" };
125
+ }
126
+ if (!attributes.type && type == "svg" || attributes.type === "svg") {
127
+ if (dynamic) {
128
+ return getVue(iconName, match);
129
+ } else {
130
+ return getText(iconName, match);
131
+ }
132
+ }
133
+ return { text: match.fullMatch, imptext: "" };
134
+ }
135
+ function shouldProcess(id) {
136
+ const validExtensions = [".vue", ".jsx", ".tsx", ".js", ".ts"];
137
+ const hasValidExtension = validExtensions.some((ext) => id.endsWith(ext));
138
+ if (!hasValidExtension) return false;
139
+ if (id.includes("/node_modules/")) return false;
140
+ return true;
141
+ }
142
+ function simpleFangIcon(options) {
143
+ const {
144
+ name = "FangIcon",
145
+ type = "svg",
146
+ dynamic = true,
147
+ customReplacement
148
+ } = options;
149
+ const targetComponents = Array.isArray(name) ? name : [name];
150
+ return {
151
+ name: "vite-plugin-fang-icon-replacer",
152
+ // 使用 enforce 确保在 Vue 插件之前执行
153
+ enforce: "pre",
154
+ // 转换代码
155
+ transform(code, id) {
156
+ if (!shouldProcess(id)) {
157
+ return null;
158
+ }
159
+ try {
160
+ const components = findComponents(code, targetComponents);
161
+ if (components.length === 0) {
162
+ return null;
163
+ }
164
+ let transformedCode = code;
165
+ let replacedCount = 0;
166
+ const imports = /* @__PURE__ */ new Set();
167
+ for (let i = components.length - 1; i >= 0; i--) {
168
+ const component = components[i];
169
+ if (component) {
170
+ const { text, imptext } = replaceComponent(
171
+ component,
172
+ type,
173
+ dynamic,
174
+ customReplacement
175
+ );
176
+ imports.add(imptext);
177
+ if (text !== component.fullMatch) {
178
+ transformedCode = transformedCode.slice(0, component.start) + text + transformedCode.slice(component.end);
179
+ replacedCount++;
180
+ }
181
+ }
182
+ }
183
+ if (/.vue$/.test(id)) {
184
+ const i = transformedCode.indexOf("</script>");
185
+ transformedCode = transformedCode.slice(0, i) + [...imports].join(";") + transformedCode.slice(i);
186
+ } else {
187
+ transformedCode = [...imports].join(";") + transformedCode;
188
+ }
189
+ if (replacedCount > 0) {
190
+ return {
191
+ code: transformedCode,
192
+ map: null
193
+ };
194
+ }
195
+ } catch (error) {
196
+ console.error(`\u5904\u7406\u6587\u4EF6 ${id} \u65F6\u51FA\u9519:`, error);
73
197
  }
74
198
  return null;
199
+ },
200
+ // 处理热更新
201
+ handleHotUpdate({
202
+ file,
203
+ server
204
+ }) {
205
+ if (shouldProcess(file)) {
206
+ server.ws.send({
207
+ type: "full-reload"
208
+ });
209
+ return [];
210
+ }
75
211
  }
76
212
  };
77
213
  }
@@ -1,9 +1,29 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
+ interface ComponentAttributes {
4
+ name: string;
5
+ [key: string]: string | boolean | number;
6
+ }
7
+ interface ComponentMatchInfo {
8
+ componentName: string;
9
+ fullMatch: string;
10
+ start: number;
11
+ end: number;
12
+ attributes: ComponentAttributes;
13
+ isSelfClosing: boolean;
14
+ }
15
+ type IconReplacement = (iconName: string, attributes: ComponentAttributes) => {
16
+ text: string;
17
+ imptext: string;
18
+ };
3
19
  interface PluginOptions {
20
+ name?: string;
4
21
  type?: string;
22
+ customReplacement?: IconReplacement;
5
23
  directory?: string;
24
+ mobile?: boolean;
25
+ dynamic?: boolean;
6
26
  }
7
- declare function simpleFangIcon(options?: PluginOptions): Plugin;
27
+ declare function simpleFangIcon(options: PluginOptions): Plugin;
8
28
 
9
- export { simpleFangIcon };
29
+ export { type ComponentAttributes, type ComponentMatchInfo, type IconReplacement, type PluginOptions, simpleFangIcon };
@@ -1,9 +1,29 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
+ interface ComponentAttributes {
4
+ name: string;
5
+ [key: string]: string | boolean | number;
6
+ }
7
+ interface ComponentMatchInfo {
8
+ componentName: string;
9
+ fullMatch: string;
10
+ start: number;
11
+ end: number;
12
+ attributes: ComponentAttributes;
13
+ isSelfClosing: boolean;
14
+ }
15
+ type IconReplacement = (iconName: string, attributes: ComponentAttributes) => {
16
+ text: string;
17
+ imptext: string;
18
+ };
3
19
  interface PluginOptions {
20
+ name?: string;
4
21
  type?: string;
22
+ customReplacement?: IconReplacement;
5
23
  directory?: string;
24
+ mobile?: boolean;
25
+ dynamic?: boolean;
6
26
  }
7
- declare function simpleFangIcon(options?: PluginOptions): Plugin;
27
+ declare function simpleFangIcon(options: PluginOptions): Plugin;
8
28
 
9
- export { simpleFangIcon };
29
+ export { type ComponentAttributes, type ComponentMatchInfo, type IconReplacement, type PluginOptions, simpleFangIcon };
@@ -1,77 +1,213 @@
1
+ import {
2
+ getIconifySVG,
3
+ lineToLargeHump
4
+ } from "../chunk-HSJ3RNOH.js";
5
+ import "../chunk-MOHILOKE.js";
6
+ import {
7
+ json_default
8
+ } from "../chunk-RDKCKIKJ.js";
1
9
  import "../chunk-MLKGABMK.js";
2
10
 
3
11
  // packages/vite/index2.ts
4
- var virtualModuleId = "virtual:fang-icon";
5
- function simpleFangIcon(options = {}) {
6
- const { type = "svg", directory = "./svg" } = options;
7
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
8
- return {
9
- name: "simple-fang-icon",
10
- resolveId(id) {
11
- if (id === virtualModuleId) {
12
- return resolvedVirtualModuleId;
12
+ function parseAttributes(attrString) {
13
+ const attributes = { name: "" };
14
+ const attrRegex = /(?:@|:|v-bind:)?([\w-]+)(?:="([^"]*)"|='([^']*)')/g;
15
+ let match;
16
+ while ((match = attrRegex.exec(attrString)) !== null) {
17
+ const name = match[1];
18
+ if (name) {
19
+ const value = match[2] || match[3] || "";
20
+ if (name === "name") {
21
+ attributes.name = value;
22
+ } else if (value === "true" || value === "false") {
23
+ attributes[name] = value === "true";
24
+ } else if (!isNaN(Number(value)) && value !== "") {
25
+ attributes[name] = Number(value);
26
+ } else {
27
+ attributes[name] = value;
13
28
  }
14
- return void 0;
15
- },
16
- load(id) {
17
- if (id === resolvedVirtualModuleId) {
18
- return `
19
- import { defineComponent, h, defineAsyncComponent, resolveComponent, computed } from 'vue'
20
- import FangIcon from '@fangzhongya/icons/icon/index'
21
-
22
- export default defineComponent({
23
- props: {
24
- name: {
25
- type: [String, Object],
26
- required: true
27
- },
28
- type: {
29
- type: String,
30
- default: '${type}'
31
- },
32
- directory: {
33
- type: String,
34
- default: '${directory}'
35
29
  }
36
- },
37
- setup(props, { attrs }) {
38
- const IconComponent = computed(() => {
39
- const iconName = props.name;
40
- // \u5982\u679C\u76F4\u63A5\u4F20\u9012\u4E86\u7EC4\u4EF6\uFF0C\u76F4\u63A5\u4F7F\u7528
41
- if (typeof iconName === 'string' && props.type === 'svg') {
42
- // SVG \u7C7B\u578B\uFF1A\u4ECE @fangzhongya/icons \u5E93\u5BFC\u5165
43
- return defineAsyncComponent(() =>
44
- import(/* @vite-ignore */'node_modules/@fangzhongya/icons/vue/' + iconName)
45
- .then(module => module.default)
46
- .catch(() => {
47
- // \u5982\u679C\u5BFC\u5165\u5931\u8D25\uFF0C\u5C1D\u8BD5\u89E3\u6790\u7EC4\u4EF6
48
- const component = resolveComponent(iconName);
49
- if (component) {
50
- return component;
51
- }
52
- // \u5982\u679C\u7EC4\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8FD4\u56DE\u5360\u4F4D\u7B26
53
- return {
54
- setup: () => () => h('span', { class: 'icon-error' }, \`Icon \${iconName} not found\`)
55
- };
56
- })
57
- );
30
+ }
31
+ return attributes;
32
+ }
33
+ function hasStringNameAttribute(attrString) {
34
+ const nameRegex = /(?:^|\s)name="[^"]*"/i;
35
+ const singleQuoteRegex = /(?:^|\s)name='[^']*'/i;
36
+ return nameRegex.test(attrString) || singleQuoteRegex.test(attrString);
37
+ }
38
+ function isOnlyWhitespace(content) {
39
+ return !content || /^\s*$/.test(content);
40
+ }
41
+ function findComponents(code, name) {
42
+ const components = [];
43
+ for (const componentName of name) {
44
+ let currentIndex = 0;
45
+ while (currentIndex < code.length) {
46
+ const startTagIndex = code.indexOf(
47
+ `<${componentName}`,
48
+ currentIndex
49
+ );
50
+ if (startTagIndex === -1) break;
51
+ let tagEndIndex = code.indexOf(">", startTagIndex);
52
+ if (tagEndIndex === -1) break;
53
+ const startTag = code.slice(startTagIndex, tagEndIndex + 1);
54
+ const attrString = startTag.slice(componentName.length + 1, -1).trim();
55
+ if (!hasStringNameAttribute(attrString)) {
56
+ currentIndex = startTagIndex + 1;
57
+ continue;
58
+ }
59
+ const attributes = parseAttributes(attrString);
60
+ if (!attributes.name) {
61
+ currentIndex = startTagIndex + 1;
62
+ continue;
63
+ }
64
+ const isSelfClosing = startTag.endsWith("/>");
65
+ let endIndex;
66
+ let fullMatch;
67
+ if (isSelfClosing) {
68
+ endIndex = tagEndIndex + 1;
69
+ fullMatch = startTag;
70
+ } else {
71
+ const endTag = `</${componentName}>`;
72
+ let endTagIndex = code.indexOf(endTag, tagEndIndex + 1);
73
+ if (endTagIndex === -1) {
74
+ currentIndex = startTagIndex + 1;
75
+ continue;
76
+ }
77
+ const content = code.slice(tagEndIndex + 1, endTagIndex);
78
+ if (!isOnlyWhitespace(content)) {
79
+ currentIndex = startTagIndex + 1;
80
+ continue;
81
+ }
82
+ endIndex = endTagIndex + endTag.length;
83
+ fullMatch = code.slice(startTagIndex, endIndex);
58
84
  }
59
- return iconName;
60
- });
61
-
62
- return () => {
63
- return h(FangIcon, {
64
- ...attrs,
65
- type: props.type,
66
- name: IconComponent.value,
67
- directory: props.directory
85
+ components.push({
86
+ componentName,
87
+ fullMatch,
88
+ start: startTagIndex,
89
+ end: endIndex,
90
+ attributes,
91
+ isSelfClosing
68
92
  });
69
- };
93
+ currentIndex = endIndex;
94
+ }
95
+ }
96
+ return components;
97
+ }
98
+ function getText(iconName, match) {
99
+ const svg = getIconifySVG(json_default, iconName, 'v-bind="scope"');
100
+ const s = match.fullMatch.replace(`name="${iconName}"`, "").replace(`name='${iconName}'`, "").replace(`</${match.componentName}>`, "");
101
+ const text = `${s}<template #default="scope">${svg}</template></${match.componentName}>`;
102
+ return { text, imptext: "" };
103
+ }
104
+ function getImportName(iconName) {
105
+ return lineToLargeHump("fang-icon-" + iconName);
106
+ }
107
+ function getVue(iconName, match) {
108
+ const text = match.fullMatch.replace(`name="${iconName}"`, `:name="${getImportName(iconName)}"`).replace(`name='${iconName}'`, `:name='${getImportName(iconName)}'`);
109
+ return {
110
+ text,
111
+ imptext: `import ${getImportName(
112
+ iconName
113
+ )} from '@fangzhongya/icons/vue/${iconName}'`
114
+ };
115
+ }
116
+ function replaceComponent(match, type, dynamic, customReplacement) {
117
+ const { attributes } = match;
118
+ const iconName = attributes.name;
119
+ if (customReplacement) {
120
+ return customReplacement(iconName, attributes);
121
+ }
122
+ let svgContent = json_default.icons[iconName];
123
+ if (!svgContent) {
124
+ return { text: match.fullMatch, imptext: "" };
125
+ }
126
+ if (!attributes.type && type == "svg" || attributes.type === "svg") {
127
+ if (dynamic) {
128
+ return getVue(iconName, match);
129
+ } else {
130
+ return getText(iconName, match);
131
+ }
70
132
  }
71
- })
72
- `;
133
+ return { text: match.fullMatch, imptext: "" };
134
+ }
135
+ function shouldProcess(id) {
136
+ const validExtensions = [".vue", ".jsx", ".tsx", ".js", ".ts"];
137
+ const hasValidExtension = validExtensions.some((ext) => id.endsWith(ext));
138
+ if (!hasValidExtension) return false;
139
+ if (id.includes("/node_modules/")) return false;
140
+ return true;
141
+ }
142
+ function simpleFangIcon(options) {
143
+ const {
144
+ name = "FangIcon",
145
+ type = "svg",
146
+ dynamic = true,
147
+ customReplacement
148
+ } = options;
149
+ const targetComponents = Array.isArray(name) ? name : [name];
150
+ return {
151
+ name: "vite-plugin-fang-icon-replacer",
152
+ // 使用 enforce 确保在 Vue 插件之前执行
153
+ enforce: "pre",
154
+ // 转换代码
155
+ transform(code, id) {
156
+ if (!shouldProcess(id)) {
157
+ return null;
158
+ }
159
+ try {
160
+ const components = findComponents(code, targetComponents);
161
+ if (components.length === 0) {
162
+ return null;
163
+ }
164
+ let transformedCode = code;
165
+ let replacedCount = 0;
166
+ const imports = /* @__PURE__ */ new Set();
167
+ for (let i = components.length - 1; i >= 0; i--) {
168
+ const component = components[i];
169
+ if (component) {
170
+ const { text, imptext } = replaceComponent(
171
+ component,
172
+ type,
173
+ dynamic,
174
+ customReplacement
175
+ );
176
+ imports.add(imptext);
177
+ if (text !== component.fullMatch) {
178
+ transformedCode = transformedCode.slice(0, component.start) + text + transformedCode.slice(component.end);
179
+ replacedCount++;
180
+ }
181
+ }
182
+ }
183
+ if (/.vue$/.test(id)) {
184
+ const i = transformedCode.indexOf("</script>");
185
+ transformedCode = transformedCode.slice(0, i) + [...imports].join(";") + transformedCode.slice(i);
186
+ } else {
187
+ transformedCode = [...imports].join(";") + transformedCode;
188
+ }
189
+ if (replacedCount > 0) {
190
+ return {
191
+ code: transformedCode,
192
+ map: null
193
+ };
194
+ }
195
+ } catch (error) {
196
+ console.error(`\u5904\u7406\u6587\u4EF6 ${id} \u65F6\u51FA\u9519:`, error);
73
197
  }
74
198
  return null;
199
+ },
200
+ // 处理热更新
201
+ handleHotUpdate({
202
+ file,
203
+ server
204
+ }) {
205
+ if (shouldProcess(file)) {
206
+ server.ws.send({
207
+ type: "full-reload"
208
+ });
209
+ return [];
210
+ }
75
211
  }
76
212
  };
77
213
  }