@aippy/vite-plugins 0.2.0

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/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @aippy/vite-plugins
2
+
3
+ Vite plugins collection for Aippy projects, providing asset management and component tagging capabilities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add -D @aippy/vite-plugins
9
+ ```
10
+
11
+ ## Plugins
12
+
13
+ ### 1. Asset Constants Plugin
14
+
15
+ Generates constant references for static assets and replaces hardcoded paths.
16
+
17
+ ```typescript
18
+ import { assetConstantsPlugin } from '@aippy/vite-plugins/asset-constants'
19
+
20
+ export default defineConfig({
21
+ plugins: [
22
+ assetConstantsPlugin({
23
+ extensions: ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.mp3'],
24
+ srcDir: 'src',
25
+ outputFile: 'src/config/assets.json',
26
+ devMode: true
27
+ })
28
+ ]
29
+ })
30
+ ```
31
+
32
+ ### 2. Aippy Preload Plugin
33
+
34
+ Scans build output and generates preload meta tags for assets.
35
+
36
+ ```typescript
37
+ import { aippyPreloadPlugin } from '@aippy/vite-plugins/aippy-preload'
38
+
39
+ export default defineConfig({
40
+ plugins: [
41
+ aippyPreloadPlugin({
42
+ extensions: ['.js', '.css', '.png', '.jpg', '.svg'],
43
+ outDir: 'dist',
44
+ includeSubdirs: true
45
+ })
46
+ ]
47
+ })
48
+ ```
49
+
50
+ ### 3. Aippy Tagger Plugin
51
+
52
+ Tags React components with metadata for development tools and inspector.
53
+
54
+ ```typescript
55
+ import { aippyTaggerPlugin } from '@aippy/vite-plugins/aippy-tagger'
56
+
57
+ export default defineConfig({
58
+ plugins: [
59
+ aippyTaggerPlugin()
60
+ ]
61
+ })
62
+ ```
63
+
64
+ ### All-in-One Import
65
+
66
+ ```typescript
67
+ import { assetConstantsPlugin, aippyPreloadPlugin, aippyTaggerPlugin } from '@aippy/vite-plugins'
68
+ ```
69
+
70
+ ### Utility Functions
71
+
72
+ The package also exports utility functions that can be used independently:
73
+
74
+ ```typescript
75
+ import {
76
+ processAssetURL,
77
+ isValidAsset,
78
+ generateConstantName,
79
+ extractAssetsFromContent,
80
+ findProjectRoot
81
+ } from '@aippy/vite-plugins/utils'
82
+
83
+ // Process asset URLs
84
+ const processedUrl = processAssetURL('./image.png') // '/image.png'
85
+
86
+ // Validate asset paths
87
+ const isValid = isValidAsset('./image.png') // true
88
+
89
+ // Generate constant names
90
+ const constantName = generateConstantName('/image.png') // 'IMAGE_ABCD'
91
+
92
+ // Extract assets from content
93
+ const assets = extractAssetsFromContent(htmlContent, 'html', ['.png', '.jpg'])
94
+
95
+ // Find project root
96
+ const projectRoot = findProjectRoot() // '/path/to/project'
97
+ ```
98
+
99
+ ## License
100
+
101
+ UNLICENSED - Aippy Team
102
+
@@ -0,0 +1,11 @@
1
+ import { Plugin } from 'vite';
2
+ interface AssetPreloadOptions {
3
+ extensions?: string[];
4
+ includeFiles?: string[];
5
+ exclude?: string[];
6
+ outDir?: string;
7
+ includeSubdirs?: boolean;
8
+ deepScan?: boolean;
9
+ }
10
+ export declare function aippyPreloadPlugin(options?: AssetPreloadOptions): Plugin;
11
+ export default aippyPreloadPlugin;
@@ -0,0 +1,146 @@
1
+ var f = Object.defineProperty;
2
+ var g = (e, s, t) => s in e ? f(e, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[s] = t;
3
+ var p = (e, s, t) => g(e, typeof s != "symbol" ? s + "" : s, t);
4
+ import r from "fs/promises";
5
+ import a from "path";
6
+ import { glob as l } from "glob";
7
+ import { extractAssetsFromContent as c } from "../utils/index.js";
8
+ class F {
9
+ constructor(s = {}) {
10
+ p(this, "options");
11
+ this.options = {
12
+ extensions: [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf", ".eot"],
13
+ includeFiles: [],
14
+ exclude: ["*.map"],
15
+ outDir: "dist",
16
+ includeSubdirs: !0,
17
+ deepScan: !0,
18
+ ...s
19
+ };
20
+ }
21
+ /**
22
+ * Scan external file resources
23
+ */
24
+ async scanExternalFiles() {
25
+ const s = [], t = this.options.extensions.map(
26
+ (i) => this.options.includeSubdirs ? a.join(this.options.outDir, "**", `*${i}`) : a.join(this.options.outDir, `*${i}`)
27
+ ), n = await l(t, {
28
+ ignore: this.options.exclude,
29
+ absolute: !0
30
+ });
31
+ if (s.push(...n), this.options.includeFiles.length > 0) {
32
+ const i = this.options.includeFiles.map((h) => this.options.includeSubdirs ? a.join(this.options.outDir, "**", h) : a.join(this.options.outDir, h)), u = await l(i, {
33
+ ignore: this.options.exclude,
34
+ absolute: !0
35
+ });
36
+ s.push(...u);
37
+ }
38
+ return [...new Set(s)].map((i) => `/${a.relative(this.options.outDir, i).replace(/\\/g, "/")}`);
39
+ }
40
+ /**
41
+ * Scan HTML files
42
+ */
43
+ async scanHtmlFiles() {
44
+ const s = [], t = await l("**/*.html", { cwd: this.options.outDir, absolute: !0 });
45
+ for (const n of t)
46
+ try {
47
+ const o = await r.readFile(n, "utf-8"), i = c(o, "html", this.options.extensions);
48
+ s.push(...i);
49
+ } catch (o) {
50
+ console.warn(`⚠️ Failed to read HTML file: ${n}`, o);
51
+ }
52
+ return s;
53
+ }
54
+ /**
55
+ * Scan JS files
56
+ */
57
+ async scanJsFiles() {
58
+ const s = [], t = await l("**/*.js", { cwd: this.options.outDir, absolute: !0 });
59
+ for (const n of t)
60
+ try {
61
+ const o = await r.readFile(n, "utf-8"), i = c(o, "js", this.options.extensions);
62
+ s.push(...i);
63
+ } catch (o) {
64
+ console.warn(`⚠️ Failed to read JS file: ${n}`, o);
65
+ }
66
+ return s;
67
+ }
68
+ /**
69
+ * Scan CSS files
70
+ */
71
+ async scanCssFiles() {
72
+ const s = [], t = await l("**/*.css", { cwd: this.options.outDir, absolute: !0 });
73
+ for (const n of t)
74
+ try {
75
+ const o = await r.readFile(n, "utf-8"), i = c(o, "css", this.options.extensions);
76
+ s.push(...i);
77
+ } catch (o) {
78
+ console.warn(`⚠️ Failed to read CSS file: ${n}`, o);
79
+ }
80
+ return s;
81
+ }
82
+ /**
83
+ * Execute complete asset scanning
84
+ */
85
+ async scanAllAssets() {
86
+ console.log("🔍 Scanning for static assets...");
87
+ const s = [], t = await this.scanExternalFiles();
88
+ if (s.push(...t), this.options.deepScan) {
89
+ console.log("🔍 Deep scanning file contents...");
90
+ const [n, o, i] = await Promise.all([
91
+ this.scanHtmlFiles(),
92
+ this.scanJsFiles(),
93
+ this.scanCssFiles()
94
+ ]);
95
+ s.push(...n, ...o, ...i);
96
+ }
97
+ return [...new Set(s)];
98
+ }
99
+ }
100
+ function m(e) {
101
+ return e.map((s) => ` <meta content="${s}" name="aippy:preload">`).join(`
102
+ `);
103
+ }
104
+ const d = "<head>", w = d.length;
105
+ function j(e, s) {
106
+ const t = e.indexOf(d);
107
+ if (t === -1)
108
+ throw new Error("Could not find <head> tag in HTML");
109
+ const n = t + w;
110
+ return e.slice(0, n) + `
111
+ ` + s + `
112
+ ` + e.slice(n);
113
+ }
114
+ function x(e) {
115
+ if (console.log(`📁 Found ${e.length} static assets`), e.length === 0) {
116
+ console.log("⚠️ No static assets found. This might be because all assets are inlined.");
117
+ return;
118
+ }
119
+ console.log("📋 Assets found:"), e.forEach((s) => console.log(` - ${s}`));
120
+ }
121
+ function A(e) {
122
+ console.log(`✅ Injected ${e} preload meta tags into index.html`);
123
+ }
124
+ function P(e = {}) {
125
+ return {
126
+ name: "vite-plugin-aippy-preload",
127
+ apply: "build",
128
+ async closeBundle() {
129
+ try {
130
+ const t = await new F(e).scanAllAssets();
131
+ if (x(t), t.length === 0)
132
+ return;
133
+ const n = a.join(e.outDir || "dist", "index.html");
134
+ let o = await r.readFile(n, "utf-8");
135
+ const i = m(t);
136
+ o = j(o, i), await r.writeFile(n, o, "utf-8"), A(t.length);
137
+ } catch (s) {
138
+ console.error("❌ Error in asset preload plugin:", s);
139
+ }
140
+ }
141
+ };
142
+ }
143
+ export {
144
+ P as aippyPreloadPlugin,
145
+ P as default
146
+ };
@@ -0,0 +1,6 @@
1
+ export * from './aippy-preload/index'
2
+ export {}
3
+ import _default from './aippy-preload/index'
4
+ export default _default
5
+ export * from './aippy-preload/index'
6
+ export {}
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'vite';
2
+ export declare function aippyTaggerPlugin(): Plugin;
3
+ export default aippyTaggerPlugin;
@@ -0,0 +1,381 @@
1
+ import { parse as E } from "@babel/parser";
2
+ import * as A from "esbuild";
3
+ import G from "fs/promises";
4
+ import P from "magic-string";
5
+ import i from "path";
6
+ import { findProjectRoot as F } from "../utils/index.js";
7
+ const H = [
8
+ "object3D",
9
+ "audioListener",
10
+ "positionalAudio",
11
+ "mesh",
12
+ "batchedMesh",
13
+ "instancedMesh",
14
+ "scene",
15
+ "sprite",
16
+ "lOD",
17
+ "skinnedMesh",
18
+ "skeleton",
19
+ "bone",
20
+ "lineSegments",
21
+ "lineLoop",
22
+ "points",
23
+ "group",
24
+ "camera",
25
+ "perspectiveCamera",
26
+ "orthographicCamera",
27
+ "cubeCamera",
28
+ "arrayCamera",
29
+ "instancedBufferGeometry",
30
+ "bufferGeometry",
31
+ "boxBufferGeometry",
32
+ "circleBufferGeometry",
33
+ "coneBufferGeometry",
34
+ "cylinderBufferGeometry",
35
+ "dodecahedronBufferGeometry",
36
+ "extrudeBufferGeometry",
37
+ "icosahedronBufferGeometry",
38
+ "latheBufferGeometry",
39
+ "octahedronBufferGeometry",
40
+ "planeBufferGeometry",
41
+ "polyhedronBufferGeometry",
42
+ "ringBufferGeometry",
43
+ "shapeBufferGeometry",
44
+ "sphereBufferGeometry",
45
+ "tetrahedronBufferGeometry",
46
+ "torusBufferGeometry",
47
+ "torusKnotBufferGeometry",
48
+ "tubeBufferGeometry",
49
+ "wireframeGeometry",
50
+ "tetrahedronGeometry",
51
+ "octahedronGeometry",
52
+ "icosahedronGeometry",
53
+ "dodecahedronGeometry",
54
+ "polyhedronGeometry",
55
+ "tubeGeometry",
56
+ "torusKnotGeometry",
57
+ "torusGeometry",
58
+ "sphereGeometry",
59
+ "ringGeometry",
60
+ "planeGeometry",
61
+ "latheGeometry",
62
+ "shapeGeometry",
63
+ "extrudeGeometry",
64
+ "edgesGeometry",
65
+ "coneGeometry",
66
+ "cylinderGeometry",
67
+ "circleGeometry",
68
+ "boxGeometry",
69
+ "capsuleGeometry",
70
+ "material",
71
+ "shadowMaterial",
72
+ "spriteMaterial",
73
+ "rawShaderMaterial",
74
+ "shaderMaterial",
75
+ "pointsMaterial",
76
+ "meshPhysicalMaterial",
77
+ "meshStandardMaterial",
78
+ "meshPhongMaterial",
79
+ "meshToonMaterial",
80
+ "meshNormalMaterial",
81
+ "meshLambertMaterial",
82
+ "meshDepthMaterial",
83
+ "meshDistanceMaterial",
84
+ "meshBasicMaterial",
85
+ "meshMatcapMaterial",
86
+ "lineDashedMaterial",
87
+ "lineBasicMaterial",
88
+ "primitive",
89
+ "light",
90
+ "spotLightShadow",
91
+ "spotLight",
92
+ "pointLight",
93
+ "rectAreaLight",
94
+ "hemisphereLight",
95
+ "directionalLightShadow",
96
+ "directionalLight",
97
+ "ambientLight",
98
+ "lightShadow",
99
+ "ambientLightProbe",
100
+ "hemisphereLightProbe",
101
+ "lightProbe",
102
+ "spotLightHelper",
103
+ "skeletonHelper",
104
+ "pointLightHelper",
105
+ "hemisphereLightHelper",
106
+ "gridHelper",
107
+ "polarGridHelper",
108
+ "directionalLightHelper",
109
+ "cameraHelper",
110
+ "boxHelper",
111
+ "box3Helper",
112
+ "planeHelper",
113
+ "arrowHelper",
114
+ "axesHelper",
115
+ "texture",
116
+ "videoTexture",
117
+ "dataTexture",
118
+ "dataTexture3D",
119
+ "compressedTexture",
120
+ "cubeTexture",
121
+ "canvasTexture",
122
+ "depthTexture",
123
+ "raycaster",
124
+ "vector2",
125
+ "vector3",
126
+ "vector4",
127
+ "euler",
128
+ "matrix3",
129
+ "matrix4",
130
+ "quaternion",
131
+ "bufferAttribute",
132
+ "float16BufferAttribute",
133
+ "float32BufferAttribute",
134
+ "float64BufferAttribute",
135
+ "int8BufferAttribute",
136
+ "int16BufferAttribute",
137
+ "int32BufferAttribute",
138
+ "uint8BufferAttribute",
139
+ "uint16BufferAttribute",
140
+ "uint32BufferAttribute",
141
+ "instancedBufferAttribute",
142
+ "color",
143
+ "fog",
144
+ "fogExp2",
145
+ "shape",
146
+ "colorShiftMaterial"
147
+ ], R = [
148
+ "AsciiRenderer",
149
+ "Billboard",
150
+ "Clone",
151
+ "ComputedAttribute",
152
+ "Decal",
153
+ "Edges",
154
+ "Effects",
155
+ "GradientTexture",
156
+ "Image",
157
+ "MarchingCubes",
158
+ "Outlines",
159
+ "PositionalAudio",
160
+ "Sampler",
161
+ "ScreenSizer",
162
+ "ScreenSpace",
163
+ "Splat",
164
+ "Svg",
165
+ "Text",
166
+ "Text3D",
167
+ "Trail",
168
+ "CubeCamera",
169
+ "OrthographicCamera",
170
+ "PerspectiveCamera",
171
+ "CameraControls",
172
+ "FaceControls",
173
+ "KeyboardControls",
174
+ "MotionPathControls",
175
+ "PresentationControls",
176
+ "ScrollControls",
177
+ "DragControls",
178
+ "GizmoHelper",
179
+ "Grid",
180
+ "Helper",
181
+ "PivotControls",
182
+ "TransformControls",
183
+ "CubeTexture",
184
+ "Fbx",
185
+ "Gltf",
186
+ "Ktx2",
187
+ "Loader",
188
+ "Progress",
189
+ "ScreenVideoTexture",
190
+ "Texture",
191
+ "TrailTexture",
192
+ "VideoTexture",
193
+ "WebcamVideoTexture",
194
+ "CycleRaycast",
195
+ "DetectGPU",
196
+ "Example",
197
+ "FaceLandmarker",
198
+ "Fbo",
199
+ "Html",
200
+ "Select",
201
+ "SpriteAnimator",
202
+ "StatsGl",
203
+ "Stats",
204
+ "Trail",
205
+ "Wireframe",
206
+ "CurveModifier",
207
+ "AdaptiveDpr",
208
+ "AdaptiveEvents",
209
+ "BakeShadows",
210
+ "Bvh",
211
+ "Detailed",
212
+ "Instances",
213
+ "Merged",
214
+ "meshBounds",
215
+ "PerformanceMonitor",
216
+ "Points",
217
+ "Preload",
218
+ "Segments",
219
+ "Fisheye",
220
+ "Hud",
221
+ "Mask",
222
+ "MeshPortalMaterial",
223
+ "RenderCubeTexture",
224
+ "RenderTexture",
225
+ "View",
226
+ "MeshDiscardMaterial",
227
+ "MeshDistortMaterial",
228
+ "MeshReflectorMaterial",
229
+ "MeshRefractionMaterial",
230
+ "MeshTransmissionMaterial",
231
+ "MeshWobbleMaterial",
232
+ "PointMaterial",
233
+ "shaderMaterial",
234
+ "SoftShadows",
235
+ "CatmullRomLine",
236
+ "CubicBezierLine",
237
+ "Facemesh",
238
+ "Line",
239
+ "Mesh",
240
+ "QuadraticBezierLine",
241
+ "RoundedBox",
242
+ "ScreenQuad",
243
+ "AccumulativeShadows",
244
+ "Backdrop",
245
+ "BBAnchor",
246
+ "Bounds",
247
+ "CameraShake",
248
+ "Caustics",
249
+ "Center",
250
+ "Cloud",
251
+ "ContactShadows",
252
+ "Environment",
253
+ "Float",
254
+ "Lightformer",
255
+ "MatcapTexture",
256
+ "NormalTexture",
257
+ "RandomizedLight",
258
+ "Resize",
259
+ "ShadowAlpha",
260
+ "Shadow",
261
+ "Sky",
262
+ "Sparkles",
263
+ "SpotLightShadow",
264
+ "SpotLight",
265
+ "Stage",
266
+ "Stars",
267
+ "OrbitControls"
268
+ ];
269
+ function D(e) {
270
+ return !H.includes(e) && !R.includes(e);
271
+ }
272
+ const $ = /* @__PURE__ */ new Set([".jsx", ".tsx"]), b = F(), g = i.resolve(b, "./tailwind.config.ts"), j = i.resolve(b, "./src/tailwind.config.aippy.json"), y = i.resolve(b, "./.aippy.tailwind.config.js");
273
+ function X() {
274
+ const e = process.cwd(), l = {
275
+ totalFiles: 0,
276
+ processedFiles: 0,
277
+ totalElements: 0
278
+ };
279
+ return {
280
+ name: "vite-plugin-aippy-tagger",
281
+ enforce: "pre",
282
+ async transform(n, r) {
283
+ if (!$.has(i.extname(r)) || r.includes("node_modules"))
284
+ return null;
285
+ l.totalFiles++;
286
+ const d = i.relative(e, r);
287
+ try {
288
+ const B = E(n, {
289
+ sourceType: "module",
290
+ plugins: ["jsx", "typescript"]
291
+ }), f = new P(n);
292
+ let x = 0, c = null;
293
+ const { walk: C } = await import("estree-walker");
294
+ return C(B, {
295
+ enter(m) {
296
+ if (m.type === "JSXElement" && (c = m), m.type === "JSXOpeningElement") {
297
+ const a = m;
298
+ let s;
299
+ if (a.name.type === "JSXIdentifier")
300
+ s = a.name.name;
301
+ else if (a.name.type === "JSXMemberExpression") {
302
+ const t = a.name;
303
+ s = `${t.object.name}.${t.property.name}`;
304
+ } else
305
+ return;
306
+ if (s === "Fragment" || s === "React.Fragment")
307
+ return;
308
+ const u = a.attributes.reduce((t, o) => (o.type === "JSXAttribute" && (o.value?.type === "StringLiteral" ? t[o.name.name] = o.value.value : o.value?.type === "JSXExpressionContainer" && o.value.expression.type === "StringLiteral" && (t[o.name.name] = o.value.expression.value)), t), {});
309
+ let h = "";
310
+ c && c.children && (h = c.children.map((t) => t.type === "JSXText" ? t.value.trim() : t.type === "JSXExpressionContainer" && t.expression.type === "StringLiteral" ? t.expression.value : "").filter(Boolean).join(" ").trim());
311
+ const p = {};
312
+ h && (p.text = h), u.placeholder && (p.placeholder = u.placeholder), u.className && (p.className = u.className);
313
+ const M = a.loc?.start?.line ?? 0, v = a.loc?.start?.column ?? 0, T = `${d}:${M}:${v}`, L = i.basename(r);
314
+ if (D(s)) {
315
+ const t = ` data-component-path="${d}" data-component-line="${M}" data-component-file="${L}" data-component-name="${s}" data-component-content="${encodeURIComponent(
316
+ JSON.stringify(p)
317
+ )}"`;
318
+ f.appendLeft(
319
+ a.name.end ?? 0,
320
+ ` data-aippy-id="${T}" data-aippy-name="${s}" ${t}`
321
+ ), x++;
322
+ }
323
+ }
324
+ }
325
+ }), l.processedFiles++, l.totalElements += x, {
326
+ code: f.toString(),
327
+ map: f.generateMap({ hires: !0 })
328
+ };
329
+ } catch (S) {
330
+ return console.error(`Error processing file ${d}:`, S), l.processedFiles++, null;
331
+ }
332
+ },
333
+ async buildStart() {
334
+ try {
335
+ await w();
336
+ } catch (n) {
337
+ console.error("Error generating tailwind.config.aippy.json:", n);
338
+ }
339
+ },
340
+ configureServer(n) {
341
+ try {
342
+ n.watcher.add(g), n.watcher.on("change", async (r) => {
343
+ i.normalize(r) === i.normalize(g) && await w();
344
+ });
345
+ } catch (r) {
346
+ console.error("Error adding watcher:", r);
347
+ }
348
+ }
349
+ };
350
+ }
351
+ async function w() {
352
+ try {
353
+ await A.build({
354
+ entryPoints: [g],
355
+ outfile: y,
356
+ bundle: !0,
357
+ format: "esm",
358
+ banner: {
359
+ js: 'import { createRequire } from "module"; const require = createRequire(import.meta.url);'
360
+ }
361
+ });
362
+ try {
363
+ const e = await import(
364
+ y + "?update=" + Date.now()
365
+ // cache buster
366
+ );
367
+ if (!e || !e.default)
368
+ throw console.error("Invalid Tailwind config structure:", e), new Error("Invalid Tailwind config structure");
369
+ await G.writeFile(j, JSON.stringify(e.default, null, 2)), await G.unlink(y).catch(() => {
370
+ });
371
+ } catch (e) {
372
+ throw console.error("Error processing config:", e), e;
373
+ }
374
+ } catch (e) {
375
+ throw console.error("Error in generateConfig:", e), e;
376
+ }
377
+ }
378
+ export {
379
+ X as aippyTaggerPlugin,
380
+ X as default
381
+ };
@@ -0,0 +1,3 @@
1
+ export declare const threeFiberElems: string[];
2
+ export declare const dreiElems: string[];
3
+ export declare function shouldTagElement(elementName: string): boolean;
@@ -0,0 +1,6 @@
1
+ export * from './aippy-tagger/index'
2
+ export {}
3
+ import _default from './aippy-tagger/index'
4
+ export default _default
5
+ export * from './aippy-tagger/index'
6
+ export {}
@@ -0,0 +1,9 @@
1
+ import { Plugin } from 'vite';
2
+ interface AssetConstantsOptions {
3
+ extensions?: string[];
4
+ srcDir?: string;
5
+ outputFile?: string;
6
+ devMode?: boolean;
7
+ }
8
+ export declare function assetConstantsPlugin(options?: AssetConstantsOptions): Plugin;
9
+ export default assetConstantsPlugin;
@@ -0,0 +1,255 @@
1
+ var v = Object.defineProperty;
2
+ var $ = (l, s, t) => s in l ? v(l, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[s] = t;
3
+ var g = (l, s, t) => $(l, typeof s != "symbol" ? s + "" : s, t);
4
+ import { promises as f } from "fs";
5
+ import p from "path";
6
+ import { parse as F } from "@babel/parser";
7
+ import d from "@babel/traverse";
8
+ import * as u from "@babel/types";
9
+ import m from "@babel/generator";
10
+ import { generateConstantName as j, extractAssetsFromContent as N, processAssetURL as C } from "../utils/index.js";
11
+ const A = typeof d == "function" ? d : d.default, U = typeof m == "function" ? m : m.default;
12
+ class E {
13
+ constructor(s = {}) {
14
+ g(this, "options");
15
+ g(this, "assets", /* @__PURE__ */ new Map());
16
+ g(this, "existingAssets", /* @__PURE__ */ new Map());
17
+ this.options = {
18
+ extensions: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".mp4", ".mp3", ".wav", ".ogg", ".webm"],
19
+ srcDir: "src",
20
+ outputFile: "src/config/assets.json",
21
+ devMode: !1,
22
+ ...s
23
+ };
24
+ }
25
+ generateConstantName(s) {
26
+ const t = /* @__PURE__ */ new Set([
27
+ ...Array.from(this.assets.values()).map((e) => e.constantName),
28
+ ...Array.from(this.existingAssets.values())
29
+ ]);
30
+ return j(s, t);
31
+ }
32
+ async scanTsFile(s) {
33
+ try {
34
+ const t = await f.readFile(s, "utf-8");
35
+ F(t, {
36
+ sourceType: "module",
37
+ plugins: ["typescript", "jsx", "decorators-legacy"]
38
+ });
39
+ const e = [];
40
+ return N(t, "js", this.options.extensions).forEach((i) => {
41
+ const n = this.generateConstantName(i), a = t.split(`
42
+ `).findIndex((h) => h.includes(i)) + 1;
43
+ e.push({
44
+ originalUri: i,
45
+ constantName: n,
46
+ filePath: s,
47
+ line: a,
48
+ column: 1
49
+ });
50
+ }), e;
51
+ } catch (t) {
52
+ return console.warn(`Warning: Failed to parse ${s}:`, t), [];
53
+ }
54
+ }
55
+ async scanAllTsFiles() {
56
+ const s = this.options.srcDir;
57
+ try {
58
+ const t = await this.getAllTsFiles(s);
59
+ for (const e of t) {
60
+ if (e.endsWith("assets.json") || e.endsWith("assets.ts"))
61
+ continue;
62
+ (await this.scanTsFile(e)).forEach((i) => {
63
+ this.existingAssets.has(i.originalUri) && (i.constantName = this.existingAssets.get(i.originalUri));
64
+ const n = i.originalUri;
65
+ this.assets.has(n) || this.assets.set(n, i);
66
+ });
67
+ }
68
+ } catch (t) {
69
+ console.error("Error scanning TypeScript files:", t);
70
+ }
71
+ }
72
+ async getAllTsFiles(s) {
73
+ const t = [];
74
+ try {
75
+ const e = await f.readdir(s, { withFileTypes: !0 });
76
+ for (const o of e) {
77
+ const i = p.join(s, o.name);
78
+ if (o.isDirectory()) {
79
+ const n = await this.getAllTsFiles(i);
80
+ t.push(...n);
81
+ } else o.isFile() && /\.(ts|tsx)$/.test(o.name) && t.push(i);
82
+ }
83
+ } catch (e) {
84
+ console.warn(`Warning: Failed to read directory ${s}:`, e);
85
+ }
86
+ return t;
87
+ }
88
+ generateAssetsFileContent() {
89
+ const s = Array.from(this.assets.values()), t = {};
90
+ return s.forEach((e) => {
91
+ t[e.constantName] = e.originalUri;
92
+ }), JSON.stringify(t, null, 2) + `
93
+ `;
94
+ }
95
+ async readExistingAssetsFile() {
96
+ try {
97
+ return await f.readFile(this.options.outputFile, "utf-8");
98
+ } catch {
99
+ return "";
100
+ }
101
+ }
102
+ async parseExistingAssets() {
103
+ try {
104
+ const s = await this.readExistingAssetsFile();
105
+ if (!s.trim())
106
+ return;
107
+ const t = JSON.parse(s);
108
+ for (const [e, o] of Object.entries(t))
109
+ typeof o == "string" && this.existingAssets.set(o, e);
110
+ this.existingAssets.size > 0 && console.log(`📋 Found ${this.existingAssets.size} existing constants in assets.json`);
111
+ } catch (s) {
112
+ console.warn("Warning: Failed to parse existing assets.json:", s);
113
+ }
114
+ }
115
+ async generateAssetsFile() {
116
+ await this.parseExistingAssets(), await this.scanAllTsFiles();
117
+ const s = this.generateAssetsFileContent(), t = p.dirname(this.options.outputFile);
118
+ await f.mkdir(t, { recursive: !0 }), await f.writeFile(this.options.outputFile, s, "utf-8");
119
+ const e = Array.from(this.assets.values()).filter(
120
+ (i) => this.existingAssets.has(i.originalUri)
121
+ ).length, o = this.assets.size - e;
122
+ o > 0 ? console.log(`✅ Generated ${this.assets.size} asset constants (${o} new, ${e} reused) in ${this.options.outputFile}`) : this.assets.size > 0 ? console.log(`✅ Generated ${this.assets.size} asset constants (all reused from existing) in ${this.options.outputFile}`) : console.log("✅ No asset constants found");
123
+ }
124
+ getAssets() {
125
+ return Array.from(this.assets.values());
126
+ }
127
+ async replaceUrisInFile(s, t) {
128
+ try {
129
+ const e = await f.readFile(s, "utf-8"), o = F(e, {
130
+ sourceType: "module",
131
+ plugins: ["typescript", "jsx", "decorators-legacy"]
132
+ });
133
+ let i = !1;
134
+ if (A(o, {
135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
+ StringLiteral: (c) => {
137
+ const h = c.node.value, w = C(h);
138
+ if (t.has(w)) {
139
+ const x = t.get(w), y = u.memberExpression(
140
+ u.identifier("assetsData"),
141
+ u.identifier(x)
142
+ );
143
+ c.parent && u.isJSXAttribute(c.parent) ? c.replaceWith(u.jsxExpressionContainer(y)) : c.replaceWith(y), i = !0;
144
+ }
145
+ }
146
+ }), !i)
147
+ return;
148
+ const n = this.getRelativeImportPath(s, this.options.outputFile) + ".json";
149
+ let r = !1;
150
+ if (A(o, {
151
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
+ ImportDeclaration: (c) => {
153
+ c.node.source.value === n && (r = !0, c.stop());
154
+ }
155
+ }), !r) {
156
+ const c = u.importDeclaration(
157
+ [u.importDefaultSpecifier(u.identifier("assetsData"))],
158
+ u.stringLiteral(n)
159
+ );
160
+ o.program.body.unshift(c);
161
+ }
162
+ const a = U(o, {
163
+ retainLines: !1,
164
+ comments: !0,
165
+ compact: !1
166
+ }, e);
167
+ await f.writeFile(s, a.code, "utf-8"), console.log(` ✓ Replaced URIs in ${p.relative(process.cwd(), s)}`);
168
+ } catch (e) {
169
+ console.warn(`Warning: Failed to replace URIs in ${s}:`, e);
170
+ }
171
+ }
172
+ getRelativeImportPath(s, t) {
173
+ const o = p.relative(p.dirname(s), t).replace(/\.(ts|json)$/, "");
174
+ return o.startsWith(".") ? o : `./${o}`;
175
+ }
176
+ async replaceAllUris() {
177
+ const s = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set();
178
+ for (const e of this.assets.values())
179
+ s.set(e.originalUri, e.constantName), t.add(e.filePath);
180
+ for (const e of t)
181
+ await this.replaceUrisInFile(e, s);
182
+ }
183
+ async cleanupUnusedConstants() {
184
+ try {
185
+ const s = await this.readExistingAssetsFile();
186
+ if (!s.trim())
187
+ return;
188
+ const t = /* @__PURE__ */ new Map();
189
+ try {
190
+ const n = JSON.parse(s);
191
+ for (const [r, a] of Object.entries(n))
192
+ typeof a == "string" && t.set(r, a);
193
+ } catch (n) {
194
+ console.warn("Warning: Failed to parse assets.json:", n);
195
+ return;
196
+ }
197
+ if (t.size === 0)
198
+ return;
199
+ const e = /* @__PURE__ */ new Set(), o = await this.getAllTsFiles(this.options.srcDir);
200
+ for (const n of o)
201
+ if (!(n.endsWith("assets.json") || n.endsWith("assets.ts")))
202
+ try {
203
+ const r = await f.readFile(n, "utf-8");
204
+ for (const a of t.keys())
205
+ r.includes(a) && e.add(a);
206
+ } catch (r) {
207
+ console.warn(`Warning: Failed to read ${n}:`, r);
208
+ }
209
+ const i = [];
210
+ for (const n of t.keys())
211
+ e.has(n) || i.push(n);
212
+ if (i.length > 0) {
213
+ console.log(`🧹 Removing ${i.length} unused constant(s):`), i.forEach((r) => {
214
+ console.log(` - ${r}`);
215
+ });
216
+ const n = [];
217
+ for (const r of i) {
218
+ const a = t.get(r);
219
+ a && n.push(a);
220
+ }
221
+ for (const r of n)
222
+ this.assets.delete(r);
223
+ } else
224
+ console.log("✅ All constants are in use");
225
+ } catch (s) {
226
+ console.warn("Warning: Failed to cleanup unused constants:", s);
227
+ }
228
+ }
229
+ }
230
+ function z(l = {}) {
231
+ return {
232
+ name: "vite-plugin-asset-constants",
233
+ apply: "build",
234
+ async buildStart() {
235
+ if (l.devMode)
236
+ try {
237
+ const s = new E(l);
238
+ await s.generateAssetsFile();
239
+ const t = s.getAssets();
240
+ t.length > 0 && (console.log(`📦 Found ${t.length} asset references:`), t.forEach((e) => {
241
+ console.log(` ${e.constantName} = '${e.originalUri}' (${p.relative(process.cwd(), e.filePath)}:${e.line})`);
242
+ }), console.log(`
243
+ 🔄 Replacing URIs with constants...`), await s.replaceAllUris(), console.log("✅ URI replacement completed!")), console.log(`
244
+ 🧹 Checking for unused constants...`), await s.cleanupUnusedConstants(), await s.generateAssetsFile(), console.log(`✅ Asset constants finalized!
245
+ `);
246
+ } catch (s) {
247
+ console.error("❌ Error in asset constants plugin:", s);
248
+ }
249
+ }
250
+ };
251
+ }
252
+ export {
253
+ z as assetConstantsPlugin,
254
+ z as default
255
+ };
@@ -0,0 +1,6 @@
1
+ export * from './asset-constants/index'
2
+ export {}
3
+ import _default from './asset-constants/index'
4
+ export default _default
5
+ export * from './asset-constants/index'
6
+ export {}
@@ -0,0 +1,15 @@
1
+ import { assetConstantsPlugin as s, assetConstantsPlugin as o } from "../asset-constants/index.js";
2
+ import { aippyPreloadPlugin as r } from "../aippy-preload/index.js";
3
+ import { aippyTaggerPlugin as i } from "../aippy-tagger/index.js";
4
+ import { extractAssetsFromContent as g, findProjectRoot as l, generateConstantName as f, isValidAsset as m, processAssetURL as P } from "../utils/index.js";
5
+ export {
6
+ r as aippyPreloadPlugin,
7
+ i as aippyTaggerPlugin,
8
+ s as assetConstantsPlugin,
9
+ o as default,
10
+ g as extractAssetsFromContent,
11
+ l as findProjectRoot,
12
+ f as generateConstantName,
13
+ m as isValidAsset,
14
+ P as processAssetURL
15
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @aippy/vite-plugins
3
+ *
4
+ * Vite plugins collection for Aippy projects
5
+ * Provides asset management and component tagging capabilities
6
+ */
7
+ export { assetConstantsPlugin } from './asset-constants/index';
8
+ export { aippyPreloadPlugin } from './aippy-preload/index';
9
+ export { aippyTaggerPlugin } from './aippy-tagger/index';
10
+ export * from './utils/index';
11
+ export { assetConstantsPlugin as default } from './asset-constants/index';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Common utility functions for Aippy Vite plugins
3
+ */
4
+ /**
5
+ * Process asset URL to ensure it's properly formatted
6
+ * @param url - The asset URL to process
7
+ * @returns Processed URL
8
+ */
9
+ export declare function processAssetURL(url: string): string;
10
+ /**
11
+ * Validate if an asset path is valid (not in node_modules, not too short, etc.)
12
+ * @param path - The asset path to validate
13
+ * @returns True if the path is valid
14
+ */
15
+ export declare function isValidAsset(path: string): boolean;
16
+ /**
17
+ * Generate a constant name for an asset based on its file extension
18
+ * @param uri - The asset URI
19
+ * @param existingNames - Set of existing constant names to avoid duplicates
20
+ * @returns Generated constant name
21
+ */
22
+ export declare function generateConstantName(uri: string, existingNames?: Set<string>): string;
23
+ /**
24
+ * Extract asset URLs from text content using regex patterns
25
+ * @param content - The text content to scan
26
+ * @param fileType - The type of file (html, js, css)
27
+ * @param extensions - Array of file extensions to match
28
+ * @returns Array of found asset URLs
29
+ */
30
+ export declare function extractAssetsFromContent(content: string, fileType: 'html' | 'js' | 'css', extensions?: string[]): string[];
31
+ /**
32
+ * Find the project root directory by looking for package.json
33
+ * @param startPath - Starting path to search from
34
+ * @returns Project root path
35
+ */
36
+ export declare function findProjectRoot(startPath?: string): string;
@@ -0,0 +1,89 @@
1
+ import { existsSync as l } from "fs";
2
+ import g from "path";
3
+ const h = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"], m = [".mp4", ".webm", ".mov", ".avi"], w = [".mp3", ".wav", ".ogg", ".m4a"];
4
+ function p(e) {
5
+ return e.match(/^https?:\/\//) || e.match(/^data:/) || e.match(/^blob:/) || e.startsWith("/") ? e : `/${e}`;
6
+ }
7
+ function E(e) {
8
+ return !(e.includes("node_modules") || e.length < 4 || e.startsWith("./") && e.length < 10);
9
+ }
10
+ function R(e, t = /* @__PURE__ */ new Set()) {
11
+ let r = "ASSET";
12
+ h.some((n) => e.endsWith(n)) ? r = "IMAGE" : m.some((n) => e.endsWith(n)) ? r = "VIDEO" : w.some((n) => e.endsWith(n)) && (r = "AUDIO");
13
+ let o;
14
+ const s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
15
+ do {
16
+ let n = "";
17
+ for (let c = 0; c < 4; c++)
18
+ n += s[Math.floor(Math.random() * s.length)];
19
+ o = `${r}_${n}`;
20
+ } while (t.has(o));
21
+ return o;
22
+ }
23
+ function d(e, t, r = [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf", ".eot"]) {
24
+ const o = /* @__PURE__ */ new Set(), s = r.map((n) => n.replace(/^\./, "")).join("|");
25
+ if (t === "html")
26
+ [
27
+ // src/href attributes for img, script, link, video, audio tags
28
+ new RegExp(`(?:src|href)=["']([^"']*\\.(?:${s}))["']`, "g"),
29
+ // url() in CSS
30
+ new RegExp(`url\\(["']?([^"']*\\.(?:${s}))["']?\\)`, "g")
31
+ ].forEach((a) => {
32
+ let i;
33
+ for (; (i = a.exec(e)) !== null; )
34
+ i[1] && o.add(p(i[1]));
35
+ }), (e.match(/<script[^>]*>[\s\S]*?<\/script>/g) || []).forEach((a) => {
36
+ const i = a.replace(/<script[^>]*>/, "").replace(/<\/script>/, "");
37
+ d(i, "js", r).forEach((f) => o.add(f));
38
+ });
39
+ else if (t === "js")
40
+ [
41
+ // Dynamic import()
42
+ new RegExp(`import\\(["']([^"']*\\.(?:${s}))["']\\)`, "g"),
43
+ // fetch() requests
44
+ new RegExp(`fetch\\(["']([^"']*\\.(?:${s}))["']\\)`, "g"),
45
+ // new Image() creation
46
+ new RegExp(`new\\s+Image\\(\\)\\.src\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
47
+ // Direct src assignment
48
+ new RegExp(`\\.src\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
49
+ // Resource paths in variable assignments
50
+ new RegExp(`=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
51
+ // Resource paths in variable declarations
52
+ new RegExp(`const\\s+\\w+\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
53
+ // Variable assignments in minified code
54
+ new RegExp(`\\w+\\s*=\\s*["']([^"']*\\.(?:${s}))["']`, "g"),
55
+ // Resource paths in string literals (more precise matching)
56
+ new RegExp(`["']([^"']*\\.(?:${s}))["']`, "g")
57
+ ].forEach((c) => {
58
+ let a;
59
+ for (; (a = c.exec(e)) !== null; )
60
+ a[1] && E(a[1]) && o.add(p(a[1]));
61
+ });
62
+ else if (t === "css") {
63
+ const n = new RegExp(`url\\(["']?([^"']*\\.(?:${s}))["']?\\)`, "g");
64
+ let c;
65
+ for (; (c = n.exec(e)) !== null; )
66
+ c[1] && o.add(p(c[1]));
67
+ }
68
+ return Array.from(o);
69
+ }
70
+ function S(e = process.cwd()) {
71
+ try {
72
+ let t = e, r = 0;
73
+ for (; t !== g.parse(t).root && r < 20; ) {
74
+ if (l(g.join(t, "package.json")))
75
+ return t;
76
+ t = g.dirname(t), r++;
77
+ }
78
+ return process.cwd();
79
+ } catch (t) {
80
+ return console.error("Error finding project root:", t), process.cwd();
81
+ }
82
+ }
83
+ export {
84
+ d as extractAssetsFromContent,
85
+ S as findProjectRoot,
86
+ R as generateConstantName,
87
+ E as isValidAsset,
88
+ p as processAssetURL
89
+ };
@@ -0,0 +1,2 @@
1
+ export * from './utils/index'
2
+ export {}
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "@aippy/vite-plugins",
3
+ "version": "0.2.0",
4
+ "description": "Vite plugins for Aippy projects - Asset management and component tagging",
5
+ "private": false,
6
+ "type": "module",
7
+ "main": "./dist/index/index.js",
8
+ "module": "./dist/index/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./asset-constants": {
16
+ "import": "./dist/asset-constants/index.js",
17
+ "types": "./dist/asset-constants.d.ts"
18
+ },
19
+ "./aippy-preload": {
20
+ "import": "./dist/aippy-preload/index.js",
21
+ "types": "./dist/aippy-preload.d.ts"
22
+ },
23
+ "./aippy-tagger": {
24
+ "import": "./dist/aippy-tagger/index.js",
25
+ "types": "./dist/aippy-tagger.d.ts"
26
+ },
27
+ "./utils": {
28
+ "import": "./dist/utils/index.js",
29
+ "types": "./dist/utils.d.ts"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "keywords": [
40
+ "aippy",
41
+ "vite",
42
+ "vite-plugin",
43
+ "assets",
44
+ "preload",
45
+ "component-tagger",
46
+ "typescript"
47
+ ],
48
+ "author": "Aippy Team",
49
+ "license": "UNLICENSED",
50
+ "homepage": "https://aippy.ai",
51
+ "bugs": {
52
+ "url": "https://discord.com/invite/G94ZAx6gVq"
53
+ },
54
+ "dependencies": {
55
+ "@babel/generator": "^7.28.0",
56
+ "@babel/parser": "^7.28.0",
57
+ "@babel/traverse": "^7.28.0",
58
+ "@babel/types": "^7.28.2",
59
+ "esbuild": "^0.25.9",
60
+ "estree-walker": "^3.0.3",
61
+ "glob": "^11.0.3",
62
+ "magic-string": "^0.30.17"
63
+ },
64
+ "devDependencies": {
65
+ "@eslint/js": "^9.36.0",
66
+ "@types/babel__generator": "^7.6.8",
67
+ "@types/babel__traverse": "^7.20.6",
68
+ "@types/node": "^24.5.2",
69
+ "@typescript-eslint/eslint-plugin": "^8.44.1",
70
+ "@typescript-eslint/parser": "^8.44.1",
71
+ "eslint": "^9.36.0",
72
+ "prettier": "^3.6.2",
73
+ "typescript": "^5.9.2",
74
+ "vite": "^7.1.7",
75
+ "vite-plugin-dts": "^4.5.4"
76
+ },
77
+ "peerDependencies": {
78
+ "vite": "^7.0.0 || ^6.0.0 || ^5.0.0"
79
+ },
80
+ "engines": {
81
+ "node": ">=20.0.0",
82
+ "pnpm": ">=10.0.0"
83
+ },
84
+ "scripts": {
85
+ "dev": "vite build --watch",
86
+ "build": "vite build && find dist -name '*.d.ts.map' -delete",
87
+ "type-check": "tsc --noEmit",
88
+ "lint": "eslint src --ext .ts",
89
+ "lint:fix": "eslint src --ext .ts --fix",
90
+ "format": "prettier --write \"src/**/*.{ts,json,md}\"",
91
+ "format:check": "prettier --check \"src/**/*.{ts,json,md}\"",
92
+ "clean": "rm -rf dist",
93
+ "publish:patch": "pnpm version patch && pnpm publish --no-git-checks",
94
+ "publish:minor": "pnpm version minor && pnpm publish --no-git-checks",
95
+ "publish:major": "pnpm version major && pnpm publish --no-git-checks"
96
+ }
97
+ }