@aippy/vite-plugins 0.4.0-dev.4 → 0.4.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 +3 -3
- package/dist/aippy-preload/index.js +1 -1
- package/dist/{aippy-preload-BjhVTEKH.js → aippy-preload-DZsYdwMm.js} +62 -62
- package/dist/asset-constants/generator-utils.d.ts +4 -23
- package/dist/asset-constants/index.js +2 -391
- package/dist/asset-constants-UclgHOzp.js +423 -0
- package/dist/index/index.js +2 -2
- package/dist/{generator-utils-VznlFF00.js → wrapper-keys-BPP5iTGM.js} +1 -103
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,10 +104,10 @@ UNLICENSED - Aippy Team
|
|
|
104
104
|
|
|
105
105
|
## Asset files
|
|
106
106
|
|
|
107
|
-
`src/config/assets.json` is a flat URL dictionary. The plugin writes only that file. The project-root `assets-plan.json` is read-only input for reserved names and `implementation.path` exclusions. The plugin does not validate the plan; aippy-chat does. A missing or unreadable plan does not stop the build. Invalid dictionary JSON, a
|
|
107
|
+
`src/config/assets.json` is a flat URL dictionary. The plugin writes only that file. The project-root `assets-plan.json` is read-only input for reserved names and `implementation.path` exclusions. The plugin does not validate the plan; aippy-chat does. A missing or unreadable plan does not stop the build. Invalid dictionary JSON, a plan object stored in the dictionary, or a failed dictionary/wrapper write stops the build without overwriting the file. A source file the plugin cannot parse or rewrite only logs a warning.
|
|
108
108
|
|
|
109
109
|
Import the generated map from `@/config/assets`. It exports the dictionary's string values. `window.getReplacedAssets` still mutates that object in place. Preload reads those string values and URLs in other source files, not prompts inside the plan.
|
|
110
110
|
|
|
111
|
-
Source
|
|
111
|
+
Source writes the dictionary url. The build rewrites that literal to one dictionary key. A url owned by several keys uses the first key. The url may be any reference aippy-chat accepts (`ValidReference`): http(s), root-relative, or relative.
|
|
112
112
|
|
|
113
|
-
Version 0.4.0-dev.
|
|
113
|
+
Version 0.4.0-dev.5 is published. The `dev` dist-tag points at it. `latest` remains `0.3.0`.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "../aippy-preload-
|
|
1
|
+
import { t as e } from "../aippy-preload-DZsYdwMm.js";
|
|
2
2
|
export { e as aippyPreloadPlugin, e as default };
|
|
@@ -1,108 +1,108 @@
|
|
|
1
1
|
import { extractAssetsFromContent as e, isValidAsset as t } from "./utils/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import { promises as
|
|
4
|
-
import
|
|
2
|
+
import { n, s as r } from "./wrapper-keys-BPP5iTGM.js";
|
|
3
|
+
import { promises as i } from "fs";
|
|
4
|
+
import a from "path";
|
|
5
5
|
//#region src/aippy-preload/scanner-utils.ts
|
|
6
|
-
async function
|
|
7
|
-
let n = [], r = [
|
|
8
|
-
for (let
|
|
9
|
-
let r =
|
|
10
|
-
n.push(...
|
|
6
|
+
async function o(t) {
|
|
7
|
+
let n = [], r = [a.join(process.cwd(), "index.html")];
|
|
8
|
+
for (let a of r) try {
|
|
9
|
+
let r = await i.readFile(a, "utf-8"), o = e(r, "html", t);
|
|
10
|
+
n.push(...o);
|
|
11
11
|
} catch {
|
|
12
12
|
console.warn("⚠️ No index.html found in project root");
|
|
13
13
|
}
|
|
14
14
|
return n;
|
|
15
15
|
}
|
|
16
|
-
async function
|
|
17
|
-
let
|
|
16
|
+
async function s(t, o) {
|
|
17
|
+
let s = [], c = a.resolve(t, "config/assets.json"), l = /* @__PURE__ */ new Set();
|
|
18
18
|
try {
|
|
19
|
-
let e = JSON.parse(await
|
|
20
|
-
e && typeof e == "object" && !Array.isArray(e) && (
|
|
19
|
+
let e = JSON.parse(await i.readFile(c, "utf8"));
|
|
20
|
+
e && typeof e == "object" && !Array.isArray(e) && (l = new Set(Object.keys(e)));
|
|
21
21
|
} catch {}
|
|
22
|
-
let
|
|
22
|
+
let u = await r(t, [
|
|
23
23
|
".ts",
|
|
24
24
|
".tsx",
|
|
25
25
|
".js",
|
|
26
26
|
".jsx"
|
|
27
27
|
]);
|
|
28
|
-
for (let r of
|
|
29
|
-
let
|
|
30
|
-
|
|
28
|
+
for (let r of u) try {
|
|
29
|
+
let a = await i.readFile(r, "utf-8"), u = e(a, "js", o);
|
|
30
|
+
u.some((e) => l.has(e)) && (u = e(n(a, r, t, c), "js", o)), s.push(...u);
|
|
31
31
|
} catch (e) {
|
|
32
32
|
console.warn(`⚠️ Failed to read JS file: ${r}`, e);
|
|
33
33
|
}
|
|
34
|
-
return
|
|
34
|
+
return s;
|
|
35
35
|
}
|
|
36
|
-
async function
|
|
37
|
-
let
|
|
36
|
+
async function c(t, n) {
|
|
37
|
+
let a = [], o = await r(t, [
|
|
38
38
|
".css",
|
|
39
39
|
".scss",
|
|
40
40
|
".sass",
|
|
41
41
|
".less"
|
|
42
42
|
]);
|
|
43
|
-
for (let t of
|
|
44
|
-
let r =
|
|
45
|
-
|
|
43
|
+
for (let t of o) try {
|
|
44
|
+
let r = await i.readFile(t, "utf-8"), o = e(r, "css", n);
|
|
45
|
+
a.push(...o);
|
|
46
46
|
} catch (e) {
|
|
47
47
|
console.warn(`⚠️ Failed to read CSS file: ${t}`, e);
|
|
48
48
|
}
|
|
49
|
-
return
|
|
49
|
+
return a;
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function l(e, n) {
|
|
52
52
|
if (!t(e) || /["'<>\s`]/.test(e)) return !1;
|
|
53
53
|
let r = e.split(/[?#]/, 1)[0].toLowerCase();
|
|
54
54
|
return n.some((e) => r.endsWith(e.toLowerCase()));
|
|
55
55
|
}
|
|
56
|
-
async function
|
|
57
|
-
let
|
|
58
|
-
for (let r of
|
|
59
|
-
let
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
62
|
-
let e = JSON.parse(
|
|
56
|
+
async function u(t, n) {
|
|
57
|
+
let o = [], s = await r(t, [".json"]);
|
|
58
|
+
for (let r of s) try {
|
|
59
|
+
let s = await i.readFile(r, "utf-8");
|
|
60
|
+
if (a.basename(r) === "assets-plan.json") continue;
|
|
61
|
+
if (a.resolve(r) === a.resolve(t, "config/assets.json")) {
|
|
62
|
+
let e = JSON.parse(s);
|
|
63
63
|
if (e && typeof e == "object" && !Array.isArray(e)) {
|
|
64
|
-
for (let t of Object.values(e)) typeof t == "string" &&
|
|
64
|
+
for (let t of Object.values(e)) typeof t == "string" && l(t, n) && o.push(t);
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
let
|
|
69
|
-
|
|
68
|
+
let c = e(s, "js", n);
|
|
69
|
+
o.push(...c);
|
|
70
70
|
} catch (e) {
|
|
71
71
|
console.warn(`⚠️ Failed to read JSON file: ${r}`, e);
|
|
72
72
|
}
|
|
73
|
-
return
|
|
73
|
+
return o;
|
|
74
74
|
}
|
|
75
|
-
async function
|
|
75
|
+
async function d(e, t, n) {
|
|
76
76
|
console.log("🔍 Scanning source files for static assets...");
|
|
77
77
|
let r = [];
|
|
78
78
|
if (n) {
|
|
79
79
|
console.log("🔍 Deep scanning source file contents...");
|
|
80
|
-
let [n, i, a,
|
|
81
|
-
|
|
80
|
+
let [n, i, a, l] = await Promise.all([
|
|
81
|
+
o(t),
|
|
82
|
+
s(e, t),
|
|
82
83
|
c(e, t),
|
|
83
|
-
|
|
84
|
-
d(e, t)
|
|
84
|
+
u(e, t)
|
|
85
85
|
]);
|
|
86
|
-
r.push(...n, ...i, ...a, ...
|
|
86
|
+
r.push(...n, ...i, ...a, ...l);
|
|
87
87
|
}
|
|
88
88
|
return [...new Set(r)];
|
|
89
89
|
}
|
|
90
90
|
//#endregion
|
|
91
91
|
//#region src/aippy-preload/html-utils.ts
|
|
92
|
-
var
|
|
93
|
-
function
|
|
92
|
+
var f = "<head>", p = 6;
|
|
93
|
+
function m(e) {
|
|
94
94
|
return e.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
95
95
|
}
|
|
96
|
-
function
|
|
97
|
-
return e.map((e) => ` <meta content="${
|
|
96
|
+
function h(e) {
|
|
97
|
+
return e.map((e) => ` <meta content="${m(e)}" name="aippy:preload">`).join("\n");
|
|
98
98
|
}
|
|
99
|
-
function
|
|
100
|
-
let n = e.indexOf(
|
|
99
|
+
function g(e, t) {
|
|
100
|
+
let n = e.indexOf(f);
|
|
101
101
|
if (n === -1) throw Error("Could not find <head> tag in HTML");
|
|
102
|
-
let r = n +
|
|
102
|
+
let r = n + p;
|
|
103
103
|
return e.slice(0, r) + "\n" + t + "\n" + e.slice(r);
|
|
104
104
|
}
|
|
105
|
-
function
|
|
105
|
+
function _(e) {
|
|
106
106
|
let t = e.length;
|
|
107
107
|
if (console.log(`📁 Found ${t} static ${t === 1 ? "asset" : "assets"} in source files`), t === 0) {
|
|
108
108
|
console.log("⚠️ No static assets found in source files.");
|
|
@@ -110,22 +110,22 @@ function v(e) {
|
|
|
110
110
|
}
|
|
111
111
|
console.log(`📋 ${t === 1 ? "Asset" : "Assets"} found:`), e.forEach((e) => console.log(` - ${e}`));
|
|
112
112
|
}
|
|
113
|
-
function
|
|
113
|
+
function v(e) {
|
|
114
114
|
console.log(`✅ Injected ${e} preload meta ${e === 1 ? "tag" : "tags"} into index.html`);
|
|
115
115
|
}
|
|
116
116
|
//#endregion
|
|
117
117
|
//#region src/aippy-preload/index.ts
|
|
118
|
-
var
|
|
119
|
-
function
|
|
118
|
+
var y = 3, b = 1e3;
|
|
119
|
+
function x(e) {
|
|
120
120
|
return new Promise((t) => setTimeout(t, e));
|
|
121
121
|
}
|
|
122
|
-
async function
|
|
122
|
+
async function S(e, t = y, n = b) {
|
|
123
123
|
for (let r = 1; r <= t; r++) try {
|
|
124
|
-
return await
|
|
124
|
+
return await i.readFile(e, "utf-8");
|
|
125
125
|
} catch (e) {
|
|
126
126
|
if (e.code === "ENOENT") {
|
|
127
127
|
if (r < t) {
|
|
128
|
-
console.log(`⏳ index.html not found, waiting ${n}ms before retry (attempt ${r}/${t})...`), await
|
|
128
|
+
console.log(`⏳ index.html not found, waiting ${n}ms before retry (attempt ${r}/${t})...`), await x(n);
|
|
129
129
|
continue;
|
|
130
130
|
}
|
|
131
131
|
return console.log(`⚠️ index.html not found after ${t} attempts, skipping preload injection.`), null;
|
|
@@ -134,7 +134,7 @@ async function C(e, t = b, n = x) {
|
|
|
134
134
|
}
|
|
135
135
|
return null;
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function C(e = {}) {
|
|
138
138
|
let t = {
|
|
139
139
|
extensions: [
|
|
140
140
|
".png",
|
|
@@ -159,12 +159,12 @@ function w(e = {}) {
|
|
|
159
159
|
enforce: "post",
|
|
160
160
|
async writeBundle() {
|
|
161
161
|
try {
|
|
162
|
-
let e = await
|
|
163
|
-
if (
|
|
164
|
-
let n =
|
|
162
|
+
let e = await d(t.srcDir, t.extensions, t.deepScan);
|
|
163
|
+
if (_(e), e.length === 0) return;
|
|
164
|
+
let n = a.join(t.outDir, "index.html"), r = await S(n);
|
|
165
165
|
if (r === null) return;
|
|
166
|
-
let
|
|
167
|
-
await
|
|
166
|
+
let o = g(r, h(e));
|
|
167
|
+
await i.writeFile(n, o, "utf-8"), v(e.length);
|
|
168
168
|
} catch (e) {
|
|
169
169
|
console.error("❌ Error in aippy preload plugin:", e);
|
|
170
170
|
}
|
|
@@ -172,4 +172,4 @@ function w(e = {}) {
|
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
//#endregion
|
|
175
|
-
export {
|
|
175
|
+
export { C as t };
|
|
@@ -1,33 +1,14 @@
|
|
|
1
1
|
import { AssetInfo } from './types';
|
|
2
|
-
/** A
|
|
3
|
-
export declare function
|
|
4
|
-
export declare const ASSET_TOKEN_PREFIX = "aippy-asset:";
|
|
2
|
+
/** A plan has a numeric schemaVersion and an assets object. A string schemaVersion is an ordinary dictionary key. */
|
|
3
|
+
export declare function isAssetPlan(value: unknown): boolean;
|
|
5
4
|
/**
|
|
6
5
|
* Mirrors aippy-chat `assetmanifest.ValidReference`: every value the server
|
|
7
6
|
* puts in the inventory as a usable url must be accepted here, including
|
|
8
7
|
* root-relative and relative paths.
|
|
9
8
|
*/
|
|
10
9
|
export declare function isDictionaryResourceURL(value: string): boolean;
|
|
11
|
-
/**
|
|
12
|
-
export declare function dictionaryResourceOwners(flat: Record<string, unknown>): Map<string, string
|
|
13
|
-
/** Percent-encode a dictionary key so `:` and `$` cannot be read as separators. */
|
|
14
|
-
export declare function encodeAssetKey(key: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* `aippy-asset:<encodeURIComponent(key)>:<url>`.
|
|
17
|
-
* The key ends at the first raw colon. `hero:mobile` must be `hero%3Amobile`;
|
|
18
|
-
* splitting that unencoded form would name `hero` and is rejected because the
|
|
19
|
-
* remainder `mobile:https://...` is not a resource reference.
|
|
20
|
-
*/
|
|
21
|
-
export declare function parseAssetToken(value: string): {
|
|
22
|
-
key: string;
|
|
23
|
-
url: string;
|
|
24
|
-
} | undefined;
|
|
25
|
-
/**
|
|
26
|
-
* Drop the `aippy-asset:<key>:` prefix from any token the key rewrite did not
|
|
27
|
-
* reach (template literals, CSS, HTML, unknown keys), leaving the url itself.
|
|
28
|
-
* A literal token is never a loadable resource.
|
|
29
|
-
*/
|
|
30
|
-
export declare function stripAssetTokens(code: string): string;
|
|
10
|
+
/** First dictionary key for each usable URL. Several keys may share one URL. */
|
|
11
|
+
export declare function dictionaryResourceOwners(flat: Record<string, unknown>): Map<string, string>;
|
|
31
12
|
/**
|
|
32
13
|
* Write the flat dictionary. Existing keys and non-string values stay; scanned
|
|
33
14
|
* resources only add a key when that URL is not already present.
|
|
@@ -1,391 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { promises as y } from "fs";
|
|
4
|
-
import b from "path";
|
|
5
|
-
import { parse as x } from "@babel/parser";
|
|
6
|
-
import S from "@babel/traverse";
|
|
7
|
-
import * as C from "@babel/types";
|
|
8
|
-
import w from "@babel/generator";
|
|
9
|
-
//#region src/asset-constants/index.ts
|
|
10
|
-
var T = typeof S == "function" ? S : S.default, E = typeof w == "function" ? w : w.default, D = class extends Error {}, O = class {
|
|
11
|
-
constructor(e = {}) {
|
|
12
|
-
s(this, "options", void 0), s(this, "assets", /* @__PURE__ */ new Map()), s(this, "existingAssets", /* @__PURE__ */ new Map()), s(this, "flat", {}), s(this, "fileCache", new o()), s(this, "planKeys", void 0), s(this, "implementationPaths", /* @__PURE__ */ new Set()), s(this, "keyRefFiles", /* @__PURE__ */ new Set()), this.options = {
|
|
13
|
-
extensions: [
|
|
14
|
-
".png",
|
|
15
|
-
".jpg",
|
|
16
|
-
".jpeg",
|
|
17
|
-
".gif",
|
|
18
|
-
".svg",
|
|
19
|
-
".mp4",
|
|
20
|
-
".mp3",
|
|
21
|
-
".wav",
|
|
22
|
-
".ogg",
|
|
23
|
-
".webm"
|
|
24
|
-
],
|
|
25
|
-
srcDir: "src",
|
|
26
|
-
outputFile: "src/config/assets.json",
|
|
27
|
-
devMode: !1,
|
|
28
|
-
...e
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
clearCache() {
|
|
32
|
-
this.fileCache.clear();
|
|
33
|
-
}
|
|
34
|
-
generateConstantName(e) {
|
|
35
|
-
let n = /* @__PURE__ */ new Set([
|
|
36
|
-
...Array.from(this.assets.values()).map((e) => e.constantName),
|
|
37
|
-
...Array.from(this.existingAssets.values()),
|
|
38
|
-
...this.planKeys ?? []
|
|
39
|
-
]);
|
|
40
|
-
return t(e, n);
|
|
41
|
-
}
|
|
42
|
-
async scanTsFile(t) {
|
|
43
|
-
try {
|
|
44
|
-
let n = await this.fileCache.read(t), r = [], i = e(n, "js", this.options.extensions), a = /* @__PURE__ */ new Set([...Object.keys(this.flat), ...this.planKeys ?? []]);
|
|
45
|
-
if (i.some((e) => a.has(e))) {
|
|
46
|
-
let r = u(n, t, this.options.srcDir, this.options.outputFile);
|
|
47
|
-
i = e(r, "js", this.options.extensions);
|
|
48
|
-
}
|
|
49
|
-
let o = n.split("\n"), s = _(this.flat);
|
|
50
|
-
i = i.filter((e) => {
|
|
51
|
-
if (e.startsWith("aippy-asset:") || !n.includes(`"${e}"`) && !n.includes(`'${e}'`)) return !1;
|
|
52
|
-
let t = s.get(e);
|
|
53
|
-
return !t || t.length === 1;
|
|
54
|
-
}), i.forEach((e) => {
|
|
55
|
-
if (this.isImplementationReference(t, e)) return;
|
|
56
|
-
let n = this.generateConstantName(e), i = o.findIndex((t) => t.includes(e)) + 1;
|
|
57
|
-
r.push({
|
|
58
|
-
originalUri: e,
|
|
59
|
-
constantName: n,
|
|
60
|
-
filePath: t,
|
|
61
|
-
line: i,
|
|
62
|
-
column: 1
|
|
63
|
-
});
|
|
64
|
-
}), n.includes("aippy-asset:") && this.keyRefFiles.add(t);
|
|
65
|
-
let c = new Set(r.map((e) => e.originalUri));
|
|
66
|
-
for (let [e, i] of s) i.length !== 1 || c.has(e) || !n.includes(`"${e}"`) && !n.includes(`'${e}'`) || r.push({
|
|
67
|
-
originalUri: e,
|
|
68
|
-
constantName: i[0],
|
|
69
|
-
filePath: t,
|
|
70
|
-
line: 1,
|
|
71
|
-
column: 1
|
|
72
|
-
});
|
|
73
|
-
return r;
|
|
74
|
-
} catch (e) {
|
|
75
|
-
return console.warn(`Warning: Failed to scan ${t}:`, e), [];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async scanAllTsFiles() {
|
|
79
|
-
let e = this.options.srcDir;
|
|
80
|
-
try {
|
|
81
|
-
let t = await d(e, [".ts", ".tsx"]);
|
|
82
|
-
for (let e of t) {
|
|
83
|
-
if (e.endsWith("assets.json") || e.endsWith("assets.ts")) continue;
|
|
84
|
-
let t = await this.scanTsFile(e), n = _(this.flat);
|
|
85
|
-
t.forEach((e) => {
|
|
86
|
-
let t = n.get(e.originalUri);
|
|
87
|
-
if (t && t.length > 1) return;
|
|
88
|
-
t && t.length === 1 ? e.constantName = t[0] : this.existingAssets.has(e.originalUri) && (e.constantName = this.existingAssets.get(e.originalUri));
|
|
89
|
-
let r = e.originalUri;
|
|
90
|
-
this.assets.has(r) || this.assets.set(r, e);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error("Error scanning TypeScript files:", e);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
async readExistingAssetsFile() {
|
|
98
|
-
try {
|
|
99
|
-
return await y.readFile(this.options.outputFile, "utf-8");
|
|
100
|
-
} catch (e) {
|
|
101
|
-
if (e.code === "ENOENT") return "";
|
|
102
|
-
throw new D("Unable to read assets.json: " + String(e));
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
sidecarPath() {
|
|
106
|
-
return b.resolve(this.options.srcDir, "..", "assets-plan.json");
|
|
107
|
-
}
|
|
108
|
-
async parseExistingAssets() {
|
|
109
|
-
let e = await this.readExistingAssetsFile();
|
|
110
|
-
if (e.trim()) {
|
|
111
|
-
let t;
|
|
112
|
-
try {
|
|
113
|
-
t = JSON.parse(e);
|
|
114
|
-
} catch {
|
|
115
|
-
throw new D("assets: invalid JSON syntax");
|
|
116
|
-
}
|
|
117
|
-
if (h(t)) throw new D("assets: single-file asset plan is not supported");
|
|
118
|
-
if (!t || typeof t != "object" || Array.isArray(t)) throw new D("assets: URL dictionary object required");
|
|
119
|
-
this.flat = { ...t };
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
this.existingAssets = p(e);
|
|
123
|
-
} catch (e) {
|
|
124
|
-
throw new D(e instanceof Error ? e.message : "assets: invalid JSON syntax");
|
|
125
|
-
}
|
|
126
|
-
await this.readSidecar();
|
|
127
|
-
}
|
|
128
|
-
async readSidecar() {
|
|
129
|
-
let e = "";
|
|
130
|
-
try {
|
|
131
|
-
e = await y.readFile(this.sidecarPath(), "utf-8");
|
|
132
|
-
} catch (e) {
|
|
133
|
-
e.code !== "ENOENT" && console.warn("assets: unable to read assets-plan.json; continuing with the dictionary only");
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (!e.trim()) return;
|
|
137
|
-
let t;
|
|
138
|
-
try {
|
|
139
|
-
t = JSON.parse(e);
|
|
140
|
-
} catch {
|
|
141
|
-
console.warn("assets: assets-plan.json is not valid JSON; continuing with the dictionary only");
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (!h(t)) {
|
|
145
|
-
console.warn("assets: assets-plan.json is not a plan; continuing with the dictionary only");
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
let n = t.assets;
|
|
149
|
-
this.planKeys = Object.keys(n);
|
|
150
|
-
let r = b.resolve(this.options.srcDir, "..");
|
|
151
|
-
for (let e of Object.values(n)) {
|
|
152
|
-
let t = e?.implementation?.path;
|
|
153
|
-
typeof t == "string" && t && this.implementationPaths.add(b.resolve(r, t));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
isImplementationReference(e, t) {
|
|
157
|
-
if (!this.implementationPaths.size || /^[a-z][a-z0-9+.-]*:/i.test(t) || t.startsWith("//")) return !1;
|
|
158
|
-
let n = t.split(/[?#]/)[0], r = n.startsWith("@/") ? b.resolve(this.options.srcDir, n.slice(2)) : b.resolve(b.dirname(e), n);
|
|
159
|
-
return this.implementationPaths.has(r);
|
|
160
|
-
}
|
|
161
|
-
async generateAssetsFile() {
|
|
162
|
-
await this.parseExistingAssets(), await this.scanAllTsFiles();
|
|
163
|
-
let e = f(this.assets, this.existingAssets, this.flat);
|
|
164
|
-
try {
|
|
165
|
-
let t = b.dirname(this.options.outputFile);
|
|
166
|
-
await y.mkdir(t, { recursive: !0 }), await y.writeFile(this.options.outputFile, e, "utf-8"), await this.generateAssetsWrapper();
|
|
167
|
-
} catch (e) {
|
|
168
|
-
throw new D("Unable to write the asset dictionary or wrapper: " + String(e));
|
|
169
|
-
}
|
|
170
|
-
l(this.assets.size, this.existingAssets, this.assets, this.options.outputFile);
|
|
171
|
-
}
|
|
172
|
-
async generateAssetsWrapper() {
|
|
173
|
-
let e = this.options.outputFile.replace(/\.json$/, ".ts"), t = `// 🍎 Auto-generated wrapper for assets.json
|
|
174
|
-
// This file handles iOS image replacement via asset-interceptor.js
|
|
175
|
-
import assetsData from "./${b.basename(this.options.outputFile)}";
|
|
176
|
-
|
|
177
|
-
// Batch process all asset URLs for potential replacements
|
|
178
|
-
// sessionStorage may contain __aippy_asset_overrides__ with multiple image mappings
|
|
179
|
-
(window as any).getReplacedAssets?.(assetsData);
|
|
180
|
-
|
|
181
|
-
export default assetsData;
|
|
182
|
-
`;
|
|
183
|
-
await y.writeFile(e, t, "utf-8"), console.log(` ✓ Generated assets wrapper: ${b.relative(process.cwd(), e)}`);
|
|
184
|
-
}
|
|
185
|
-
getAssets() {
|
|
186
|
-
return Array.from(this.assets.values());
|
|
187
|
-
}
|
|
188
|
-
isReplacementCandidate(e, t) {
|
|
189
|
-
let i = r(e);
|
|
190
|
-
return i && Object.hasOwn(this.flat, i.key) ? !0 : t.has(n(e));
|
|
191
|
-
}
|
|
192
|
-
replaceLiteral(e, t, n) {
|
|
193
|
-
let r = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n), i = C.memberExpression(C.identifier(t), r ? C.identifier(n) : C.stringLiteral(n), !r);
|
|
194
|
-
if ((C.isObjectProperty(e.parent) || C.isObjectMethod(e.parent) || C.isClassProperty(e.parent) || C.isClassMethod(e.parent)) && e.key === "key" && (e.parent.computed = !0), e.parent && C.isJSXAttribute(e.parent)) return e.replaceWith(C.jsxExpressionContainer(i)), !0;
|
|
195
|
-
try {
|
|
196
|
-
C.validate(e.parent, e.key, i);
|
|
197
|
-
} catch {
|
|
198
|
-
return !1;
|
|
199
|
-
}
|
|
200
|
-
return e.replaceWith(i), !0;
|
|
201
|
-
}
|
|
202
|
-
async replaceUrisInFile(e, t) {
|
|
203
|
-
try {
|
|
204
|
-
let o = await this.fileCache.read(e), s = x(o, {
|
|
205
|
-
sourceType: "module",
|
|
206
|
-
plugins: [
|
|
207
|
-
"typescript",
|
|
208
|
-
"jsx",
|
|
209
|
-
"decorators-legacy"
|
|
210
|
-
]
|
|
211
|
-
}), c = !1, l = this.options.outputFile.replace(/\.json$/, ".ts"), u = m(l, this.options.srcDir), d = v(e, this.options.srcDir, this.options.outputFile), f = a(s, d), p = "assetsData", h = !1, g, _ = /* @__PURE__ */ new Set();
|
|
212
|
-
T(s, {
|
|
213
|
-
Identifier: (e) => {
|
|
214
|
-
_.add(e.node.name);
|
|
215
|
-
},
|
|
216
|
-
ImportDeclaration: (e) => {
|
|
217
|
-
if (!(!d.has(e.node.source.value) || e.node.importKind === "type")) for (let t of e.node.specifiers) {
|
|
218
|
-
if (t.importKind === "type") continue;
|
|
219
|
-
let n = e.scope.getBinding(t.local.name);
|
|
220
|
-
i(t) && (p = t.local.name, h = !0, g = n);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
let S = !1;
|
|
225
|
-
if (h && T(s, { StringLiteral: (n) => {
|
|
226
|
-
!C.isImportDeclaration(n.parent) && !f(n) && !this.isImplementationReference(e, n.node.value) && this.isReplacementCandidate(n.node.value, t) && n.scope.getBinding(p) !== g && (S = !0);
|
|
227
|
-
} }), !h && _.has(p) || S) {
|
|
228
|
-
let e = "aippyAssetsData";
|
|
229
|
-
for (let t = 2; _.has(e); t++) e = `aippyAssetsData${t}`;
|
|
230
|
-
S && g.scope.rename(p, e), p = e;
|
|
231
|
-
}
|
|
232
|
-
if (T(s, { StringLiteral: (i) => {
|
|
233
|
-
let a = i.node.value;
|
|
234
|
-
if (this.isImplementationReference(e, a) || f(i) || C.isImportDeclaration(i.parent) || C.isExportNamedDeclaration(i.parent) || C.isExportAllDeclaration(i.parent) || i.findParent((e) => C.isTSType(e.node) || C.isTSInterfaceBody(e.node))) return;
|
|
235
|
-
let o = r(a);
|
|
236
|
-
if (o && Object.hasOwn(this.flat, o.key)) {
|
|
237
|
-
this.replaceLiteral(i, p, o.key) && (i.skip(), c = !0);
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
let s = n(a);
|
|
241
|
-
if (t.has(s)) {
|
|
242
|
-
let e = t.get(s);
|
|
243
|
-
this.replaceLiteral(i, p, e) && (i.skip(), c = !0);
|
|
244
|
-
}
|
|
245
|
-
} }), !c) return;
|
|
246
|
-
if (!h) {
|
|
247
|
-
let e = C.importDeclaration([C.importDefaultSpecifier(C.identifier(p))], C.stringLiteral(u));
|
|
248
|
-
s.program.body.unshift(e);
|
|
249
|
-
}
|
|
250
|
-
let w = E(s, {
|
|
251
|
-
retainLines: !1,
|
|
252
|
-
comments: !0,
|
|
253
|
-
compact: !1
|
|
254
|
-
}, o);
|
|
255
|
-
await y.writeFile(e, w.code, "utf-8"), this.fileCache.invalidate(e), console.log(` ✓ Replaced URIs in ${b.relative(process.cwd(), e)}`);
|
|
256
|
-
} catch (t) {
|
|
257
|
-
console.warn(`Warning: Failed to replace URIs in ${e}:`, t);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
async replaceAllUris() {
|
|
261
|
-
let e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set();
|
|
262
|
-
for (let n of this.assets.values()) e.set(n.originalUri, n.constantName), t.add(n.filePath);
|
|
263
|
-
for (let e of this.keyRefFiles) t.add(e);
|
|
264
|
-
for (let n of t) await this.replaceUrisInFile(n, e);
|
|
265
|
-
}
|
|
266
|
-
needsRewrite() {
|
|
267
|
-
return this.assets.size > 0 || this.keyRefFiles.size > 0;
|
|
268
|
-
}
|
|
269
|
-
async cleanupUnusedConstants() {
|
|
270
|
-
if (!this.planKeys) try {
|
|
271
|
-
let e = await this.readExistingAssetsFile();
|
|
272
|
-
if (!e.trim()) return;
|
|
273
|
-
let t = /* @__PURE__ */ new Map();
|
|
274
|
-
try {
|
|
275
|
-
let n = JSON.parse(e);
|
|
276
|
-
for (let [e, r] of Object.entries(n)) typeof r == "string" && t.set(e, r);
|
|
277
|
-
} catch (e) {
|
|
278
|
-
console.warn("Warning: Failed to parse assets.json:", e);
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
if (t.size === 0) return;
|
|
282
|
-
let n = /* @__PURE__ */ new Set(), r = await d(this.options.srcDir, [".ts", ".tsx"]);
|
|
283
|
-
for (let e of r) if (!(e.endsWith("assets.json") || e.endsWith("assets.ts"))) try {
|
|
284
|
-
let r = await this.fileCache.read(e);
|
|
285
|
-
for (let e of t.keys()) r.includes(e) && n.add(e);
|
|
286
|
-
} catch (t) {
|
|
287
|
-
console.warn(`Warning: Failed to read ${e}:`, t);
|
|
288
|
-
}
|
|
289
|
-
let i = [];
|
|
290
|
-
for (let e of t.keys()) n.has(e) || i.push(e);
|
|
291
|
-
if (i.length > 0) {
|
|
292
|
-
console.log(`🧹 Removing ${i.length} unused constant(s):`), i.forEach((e) => {
|
|
293
|
-
console.log(` - ${e}`);
|
|
294
|
-
});
|
|
295
|
-
let e = [];
|
|
296
|
-
for (let n of i) {
|
|
297
|
-
let r = t.get(n);
|
|
298
|
-
r && e.push(r);
|
|
299
|
-
}
|
|
300
|
-
for (let t of e) this.assets.delete(t);
|
|
301
|
-
} else console.log("✅ All constants are in use");
|
|
302
|
-
} catch (e) {
|
|
303
|
-
console.warn("Warning: Failed to cleanup unused constants:", e);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
async upgradeJsonImportsToTs() {
|
|
307
|
-
let e = this.options.outputFile.replace(/\.json$/, ".ts"), t = m(e, this.options.srcDir), n = await d(this.options.srcDir, [".ts", ".tsx"]), r = 0;
|
|
308
|
-
for (let i of n) if (!(i.endsWith("assets.ts") || i.endsWith("assets.json"))) try {
|
|
309
|
-
let n = await this.fileCache.read(i), a = c(i, this.options.outputFile) + ".json", o = c(i, e), s = m(this.options.outputFile, this.options.srcDir) + ".json";
|
|
310
|
-
if (!n.includes(a) && !n.includes(o) && !n.includes(s)) continue;
|
|
311
|
-
let l = x(n, {
|
|
312
|
-
sourceType: "module",
|
|
313
|
-
plugins: [
|
|
314
|
-
"typescript",
|
|
315
|
-
"jsx",
|
|
316
|
-
"decorators-legacy"
|
|
317
|
-
]
|
|
318
|
-
}), u = !1;
|
|
319
|
-
if (T(l, { ImportDeclaration: (e) => {
|
|
320
|
-
let n = e.node.source.value;
|
|
321
|
-
(n === a || n === o || n === s) && (e.node.source.value = t, u = !0);
|
|
322
|
-
} }), u) {
|
|
323
|
-
let e = E(l, {
|
|
324
|
-
retainLines: !1,
|
|
325
|
-
comments: !0,
|
|
326
|
-
compact: !1
|
|
327
|
-
}, n);
|
|
328
|
-
await y.writeFile(i, e.code, "utf-8"), this.fileCache.invalidate(i), console.log(` ✓ Upgraded import in ${b.relative(process.cwd(), i)} → ${t}`), r++;
|
|
329
|
-
}
|
|
330
|
-
} catch (e) {
|
|
331
|
-
console.warn(`Warning: Failed to upgrade imports in ${i}:`, e);
|
|
332
|
-
}
|
|
333
|
-
r > 0 && console.log(`✅ Upgraded ${r} file(s) to use ${t}`);
|
|
334
|
-
}
|
|
335
|
-
async stripUnresolvedTokens() {
|
|
336
|
-
let e = await d(this.options.srcDir, [...k]);
|
|
337
|
-
e.push(b.resolve(this.options.srcDir, "..", "index.html"));
|
|
338
|
-
let t = b.resolve(this.options.outputFile);
|
|
339
|
-
for (let n of e) if (b.resolve(n) !== t) try {
|
|
340
|
-
let e = await y.readFile(n, "utf-8"), t = g(e);
|
|
341
|
-
if (t === e) continue;
|
|
342
|
-
await y.writeFile(n, t, "utf-8"), this.fileCache.invalidate(n), console.log(` ✓ Kept plain asset urls in ${b.relative(process.cwd(), n)}`);
|
|
343
|
-
} catch (e) {
|
|
344
|
-
if (e.code === "ENOENT") continue;
|
|
345
|
-
console.warn(`Warning: Failed to clean asset tokens in ${n}:`, e);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}, k = [
|
|
349
|
-
".ts",
|
|
350
|
-
".tsx",
|
|
351
|
-
".js",
|
|
352
|
-
".jsx",
|
|
353
|
-
".mjs",
|
|
354
|
-
".css",
|
|
355
|
-
".scss",
|
|
356
|
-
".sass",
|
|
357
|
-
".less",
|
|
358
|
-
".html",
|
|
359
|
-
".json"
|
|
360
|
-
];
|
|
361
|
-
function A(e = {}) {
|
|
362
|
-
return {
|
|
363
|
-
name: "vite-plugin-asset-constants",
|
|
364
|
-
apply: "build",
|
|
365
|
-
enforce: "pre",
|
|
366
|
-
async buildStart() {
|
|
367
|
-
if (!e.devMode) return;
|
|
368
|
-
let t = new O(e);
|
|
369
|
-
try {
|
|
370
|
-
await t.generateAssetsFile();
|
|
371
|
-
let e = t.getAssets();
|
|
372
|
-
t.needsRewrite() && (console.log(`📦 Found ${e.length} asset references:`), e.forEach((e) => {
|
|
373
|
-
console.log(` ${e.constantName} = '${e.originalUri}' (${b.relative(process.cwd(), e.filePath)}:${e.line})`);
|
|
374
|
-
}), console.log("\n🔄 Replacing URIs with constants..."), await t.replaceAllUris(), console.log("✅ URI replacement completed!")), console.log("\n🧹 Checking for unused constants..."), await t.cleanupUnusedConstants(), await t.generateAssetsFile(), console.log("\n🔄 Upgrading assets.json imports to assets.ts..."), await t.upgradeJsonImportsToTs(), await t.stripUnresolvedTokens(), console.log("✅ Asset constants finalized!\n"), t.clearCache();
|
|
375
|
-
} catch (e) {
|
|
376
|
-
console.error("❌ Error in asset constants plugin:", e), e instanceof D && this.error(e.message);
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
transform(e, t) {
|
|
380
|
-
return t.includes("/node_modules/") || !e.includes("aippy-asset:") ? null : {
|
|
381
|
-
code: g(e),
|
|
382
|
-
map: null
|
|
383
|
-
};
|
|
384
|
-
},
|
|
385
|
-
transformIndexHtml(e) {
|
|
386
|
-
return g(e);
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
//#endregion
|
|
391
|
-
export { A as assetConstantsPlugin, A as default };
|
|
1
|
+
import { t as e } from "../asset-constants-UclgHOzp.js";
|
|
2
|
+
export { e as assetConstantsPlugin, e as default };
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { extractAssetsFromContent as e, generateConstantName as t, processAssetURL as n } from "./utils/index.js";
|
|
2
|
+
import { a as r, c as i, i as a, l as o, n as s, o as c, r as l, s as u, t as d } from "./wrapper-keys-BPP5iTGM.js";
|
|
3
|
+
import { promises as f } from "fs";
|
|
4
|
+
import p from "path";
|
|
5
|
+
import { parse as m } from "@babel/parser";
|
|
6
|
+
import h from "@babel/traverse";
|
|
7
|
+
import * as g from "@babel/types";
|
|
8
|
+
import _ from "@babel/generator";
|
|
9
|
+
//#region src/asset-constants/generator-utils.ts
|
|
10
|
+
function v(e) {
|
|
11
|
+
if (!e || typeof e != "object" || Array.isArray(e)) return !1;
|
|
12
|
+
let t = e;
|
|
13
|
+
return typeof t.schemaVersion == "number" && !!t.assets && typeof t.assets == "object" && !Array.isArray(t.assets);
|
|
14
|
+
}
|
|
15
|
+
var y = [
|
|
16
|
+
"",
|
|
17
|
+
"-",
|
|
18
|
+
"--",
|
|
19
|
+
"tbd",
|
|
20
|
+
"todo",
|
|
21
|
+
"none",
|
|
22
|
+
"n/a",
|
|
23
|
+
"null",
|
|
24
|
+
"pending",
|
|
25
|
+
"not-generated",
|
|
26
|
+
"待生成",
|
|
27
|
+
"待制作"
|
|
28
|
+
];
|
|
29
|
+
function b(e) {
|
|
30
|
+
if (!e || Buffer.byteLength(e) > 4096 || /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f\uFEFF]/.test(e) || /[\s\\]/u.test(e) || e.startsWith("//") || /%(?![0-9a-f]{2})/i.test(e.split("?")[0]) || /%(?![0-9a-f]{2})/i.test(e.split("#")[1] ?? "")) return !1;
|
|
31
|
+
if (!/^[a-z][a-z0-9+.-]*:/i.test(e)) {
|
|
32
|
+
if (e.split(/[?#]/, 1)[0].split("/", 1)[0].includes(":")) return !1;
|
|
33
|
+
let t = e.split(/[?#]/, 1)[0].replace(/%([0-9a-f]{2})/gi, (e, t) => String.fromCharCode(Number.parseInt(t, 16)));
|
|
34
|
+
if (!t || t.endsWith("/") || y.includes(t.trim().toLowerCase())) return !1;
|
|
35
|
+
if (t.includes("/")) return !0;
|
|
36
|
+
let n = t.lastIndexOf(".");
|
|
37
|
+
return n > 0 && n < t.length - 1;
|
|
38
|
+
}
|
|
39
|
+
if (!/^https?:\/\//i.test(e)) return !1;
|
|
40
|
+
let t = e.slice(e.indexOf("://") + 3).split(/[/?#]/, 1)[0];
|
|
41
|
+
if (!t || t.includes("%")) return !1;
|
|
42
|
+
try {
|
|
43
|
+
let t = new URL(e);
|
|
44
|
+
return !!t.hostname && !t.username && !t.password;
|
|
45
|
+
} catch {
|
|
46
|
+
return !1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function x(e) {
|
|
50
|
+
let t = /* @__PURE__ */ new Map();
|
|
51
|
+
for (let [n, r] of Object.entries(e)) typeof r != "string" || !b(r) || t.has(r) || t.set(r, n);
|
|
52
|
+
return t;
|
|
53
|
+
}
|
|
54
|
+
function S(e, t, n = {}) {
|
|
55
|
+
let r = { ...n }, i = new Set(Object.keys(r));
|
|
56
|
+
for (let [e, n] of t.entries()) i.has(n) || Object.values(r).includes(e) || (r[n] = e, i.add(n));
|
|
57
|
+
for (let t of e.values()) {
|
|
58
|
+
let e = Object.entries(r).find(([, e]) => e === t.originalUri);
|
|
59
|
+
if (e) {
|
|
60
|
+
t.constantName = e[0];
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
let n = t.constantName, a = n, o = 2;
|
|
64
|
+
for (; i.has(a);) a = `${n}_${o++}`;
|
|
65
|
+
i.add(a), t.constantName = a, r[a] = t.originalUri;
|
|
66
|
+
}
|
|
67
|
+
return JSON.stringify(r, null, 2) + "\n";
|
|
68
|
+
}
|
|
69
|
+
function C(e) {
|
|
70
|
+
let t = /* @__PURE__ */ new Map();
|
|
71
|
+
try {
|
|
72
|
+
if (!e.trim()) return t;
|
|
73
|
+
let n = JSON.parse(e);
|
|
74
|
+
if (v(n)) throw Error("assets: URL dictionary must be a string map");
|
|
75
|
+
if (!n || typeof n != "object" || Array.isArray(n)) throw Error("assets: URL dictionary object required");
|
|
76
|
+
for (let [e, r] of Object.entries(n)) typeof r == "string" && t.set(r, e);
|
|
77
|
+
t.size > 0 && console.log(`📋 Found ${t.size} existing constants in assets.json`);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
throw e instanceof Error && e.message.startsWith("assets:") ? e : Error("assets: invalid JSON syntax");
|
|
80
|
+
}
|
|
81
|
+
return t;
|
|
82
|
+
}
|
|
83
|
+
function w(e, t, n, r) {
|
|
84
|
+
let i = Array.from(n.values()).filter((e) => t.has(e.originalUri)).length, a = e - i;
|
|
85
|
+
console.log(a > 0 ? `✅ Generated ${e} asset constants (${a} new, ${i} reused) in ${r}` : e > 0 ? `✅ Generated ${e} asset constants (all reused from existing) in ${r}` : "✅ No asset constants found");
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/asset-constants/index.ts
|
|
89
|
+
var T = typeof h == "function" ? h : h.default, E = typeof _ == "function" ? _ : _.default, D = class extends Error {}, O = class {
|
|
90
|
+
constructor(e = {}) {
|
|
91
|
+
o(this, "options", void 0), o(this, "assets", /* @__PURE__ */ new Map()), o(this, "existingAssets", /* @__PURE__ */ new Map()), o(this, "flat", {}), o(this, "fileCache", new r()), o(this, "planKeys", void 0), o(this, "implementationPaths", /* @__PURE__ */ new Set()), o(this, "referencedFiles", /* @__PURE__ */ new Set()), this.options = {
|
|
92
|
+
extensions: [
|
|
93
|
+
".png",
|
|
94
|
+
".jpg",
|
|
95
|
+
".jpeg",
|
|
96
|
+
".gif",
|
|
97
|
+
".svg",
|
|
98
|
+
".mp4",
|
|
99
|
+
".mp3",
|
|
100
|
+
".wav",
|
|
101
|
+
".ogg",
|
|
102
|
+
".webm"
|
|
103
|
+
],
|
|
104
|
+
srcDir: "src",
|
|
105
|
+
outputFile: "src/config/assets.json",
|
|
106
|
+
devMode: !1,
|
|
107
|
+
...e
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
clearCache() {
|
|
111
|
+
this.fileCache.clear();
|
|
112
|
+
}
|
|
113
|
+
generateConstantName(e) {
|
|
114
|
+
let n = /* @__PURE__ */ new Set([
|
|
115
|
+
...Array.from(this.assets.values()).map((e) => e.constantName),
|
|
116
|
+
...Array.from(this.existingAssets.values()),
|
|
117
|
+
...this.planKeys ?? []
|
|
118
|
+
]);
|
|
119
|
+
return t(e, n);
|
|
120
|
+
}
|
|
121
|
+
async scanTsFile(t) {
|
|
122
|
+
try {
|
|
123
|
+
let n = await this.fileCache.read(t), r = [], i = e(n, "js", this.options.extensions), a = /* @__PURE__ */ new Set([...Object.keys(this.flat), ...this.planKeys ?? []]);
|
|
124
|
+
if (i.some((e) => a.has(e))) {
|
|
125
|
+
let r = s(n, t, this.options.srcDir, this.options.outputFile);
|
|
126
|
+
i = e(r, "js", this.options.extensions);
|
|
127
|
+
}
|
|
128
|
+
let o = n.split("\n"), c = x(this.flat);
|
|
129
|
+
i = i.filter((e) => n.includes(`"${e}"`) || n.includes(`'${e}'`)), i.forEach((e) => {
|
|
130
|
+
if (this.isImplementationReference(t, e)) return;
|
|
131
|
+
let n = this.generateConstantName(e), i = o.findIndex((t) => t.includes(e)) + 1;
|
|
132
|
+
r.push({
|
|
133
|
+
originalUri: e,
|
|
134
|
+
constantName: n,
|
|
135
|
+
filePath: t,
|
|
136
|
+
line: i,
|
|
137
|
+
column: 1
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
let l = new Set(r.map((e) => e.originalUri));
|
|
141
|
+
for (let [e, i] of c) l.has(e) || !n.includes(`"${e}"`) && !n.includes(`'${e}'`) || r.push({
|
|
142
|
+
originalUri: e,
|
|
143
|
+
constantName: i,
|
|
144
|
+
filePath: t,
|
|
145
|
+
line: 1,
|
|
146
|
+
column: 1
|
|
147
|
+
});
|
|
148
|
+
return r;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
return console.warn(`Warning: Failed to scan ${t}:`, e), [];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async scanAllTsFiles() {
|
|
154
|
+
let e = this.options.srcDir;
|
|
155
|
+
this.referencedFiles.clear();
|
|
156
|
+
try {
|
|
157
|
+
let t = await u(e, [".ts", ".tsx"]);
|
|
158
|
+
for (let e of t) {
|
|
159
|
+
if (e.endsWith("assets.json") || e.endsWith("assets.ts")) continue;
|
|
160
|
+
let t = await this.scanTsFile(e), n = x(this.flat);
|
|
161
|
+
t.forEach((e) => {
|
|
162
|
+
let t = n.get(e.originalUri);
|
|
163
|
+
t ? e.constantName = t : this.existingAssets.has(e.originalUri) && (e.constantName = this.existingAssets.get(e.originalUri)), this.referencedFiles.add(e.filePath);
|
|
164
|
+
let r = e.originalUri;
|
|
165
|
+
this.assets.has(r) || this.assets.set(r, e);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error("Error scanning TypeScript files:", e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async readExistingAssetsFile() {
|
|
173
|
+
try {
|
|
174
|
+
return await f.readFile(this.options.outputFile, "utf-8");
|
|
175
|
+
} catch (e) {
|
|
176
|
+
if (e.code === "ENOENT") return "";
|
|
177
|
+
throw new D("Unable to read assets.json: " + String(e));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
sidecarPath() {
|
|
181
|
+
return p.resolve(this.options.srcDir, "..", "assets-plan.json");
|
|
182
|
+
}
|
|
183
|
+
async parseExistingAssets() {
|
|
184
|
+
let e = await this.readExistingAssetsFile();
|
|
185
|
+
if (e.trim()) {
|
|
186
|
+
let t;
|
|
187
|
+
try {
|
|
188
|
+
t = JSON.parse(e);
|
|
189
|
+
} catch {
|
|
190
|
+
throw new D("assets: invalid JSON syntax");
|
|
191
|
+
}
|
|
192
|
+
if (v(t)) throw new D("assets: URL dictionary must be a string map");
|
|
193
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw new D("assets: URL dictionary object required");
|
|
194
|
+
this.flat = { ...t };
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
this.existingAssets = C(e);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
throw new D(e instanceof Error ? e.message : "assets: invalid JSON syntax");
|
|
200
|
+
}
|
|
201
|
+
await this.readSidecar();
|
|
202
|
+
}
|
|
203
|
+
async readSidecar() {
|
|
204
|
+
let e = "";
|
|
205
|
+
try {
|
|
206
|
+
e = await f.readFile(this.sidecarPath(), "utf-8");
|
|
207
|
+
} catch (e) {
|
|
208
|
+
e.code !== "ENOENT" && console.warn("assets: unable to read assets-plan.json; continuing with the dictionary only");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!e.trim()) return;
|
|
212
|
+
let t;
|
|
213
|
+
try {
|
|
214
|
+
t = JSON.parse(e);
|
|
215
|
+
} catch {
|
|
216
|
+
console.warn("assets: assets-plan.json is not valid JSON; continuing with the dictionary only");
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!v(t)) {
|
|
220
|
+
console.warn("assets: assets-plan.json is not a plan; continuing with the dictionary only");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
let n = t.assets;
|
|
224
|
+
this.planKeys = Object.keys(n);
|
|
225
|
+
let r = p.resolve(this.options.srcDir, "..");
|
|
226
|
+
for (let e of Object.values(n)) {
|
|
227
|
+
let t = e?.implementation?.path;
|
|
228
|
+
typeof t == "string" && t && this.implementationPaths.add(p.resolve(r, t));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
isImplementationReference(e, t) {
|
|
232
|
+
if (!this.implementationPaths.size || /^[a-z][a-z0-9+.-]*:/i.test(t) || t.startsWith("//")) return !1;
|
|
233
|
+
let n = t.split(/[?#]/)[0], r = n.startsWith("@/") ? p.resolve(this.options.srcDir, n.slice(2)) : p.resolve(p.dirname(e), n);
|
|
234
|
+
return this.implementationPaths.has(r);
|
|
235
|
+
}
|
|
236
|
+
async generateAssetsFile() {
|
|
237
|
+
await this.parseExistingAssets(), await this.scanAllTsFiles();
|
|
238
|
+
let e = S(this.assets, this.existingAssets, this.flat);
|
|
239
|
+
try {
|
|
240
|
+
let t = p.dirname(this.options.outputFile);
|
|
241
|
+
await f.mkdir(t, { recursive: !0 }), await f.writeFile(this.options.outputFile, e, "utf-8"), await this.generateAssetsWrapper();
|
|
242
|
+
} catch (e) {
|
|
243
|
+
throw new D("Unable to write the asset dictionary or wrapper: " + String(e));
|
|
244
|
+
}
|
|
245
|
+
w(this.assets.size, this.existingAssets, this.assets, this.options.outputFile);
|
|
246
|
+
}
|
|
247
|
+
async generateAssetsWrapper() {
|
|
248
|
+
let e = this.options.outputFile.replace(/\.json$/, ".ts"), t = `// 🍎 Auto-generated wrapper for assets.json
|
|
249
|
+
// This file handles iOS image replacement via asset-interceptor.js
|
|
250
|
+
import assetsData from "./${p.basename(this.options.outputFile)}";
|
|
251
|
+
|
|
252
|
+
// Batch process all asset URLs for potential replacements
|
|
253
|
+
// sessionStorage may contain __aippy_asset_overrides__ with multiple image mappings
|
|
254
|
+
(window as any).getReplacedAssets?.(assetsData);
|
|
255
|
+
|
|
256
|
+
export default assetsData;
|
|
257
|
+
`;
|
|
258
|
+
await f.writeFile(e, t, "utf-8"), console.log(` ✓ Generated assets wrapper: ${p.relative(process.cwd(), e)}`);
|
|
259
|
+
}
|
|
260
|
+
getAssets() {
|
|
261
|
+
return Array.from(this.assets.values());
|
|
262
|
+
}
|
|
263
|
+
replaceLiteral(e, t, n) {
|
|
264
|
+
let r = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n), i = g.memberExpression(g.identifier(t), r ? g.identifier(n) : g.stringLiteral(n), !r);
|
|
265
|
+
if ((g.isObjectProperty(e.parent) || g.isObjectMethod(e.parent) || g.isClassProperty(e.parent) || g.isClassMethod(e.parent)) && e.key === "key" && (e.parent.computed = !0), e.parent && g.isJSXAttribute(e.parent)) return e.replaceWith(g.jsxExpressionContainer(i)), !0;
|
|
266
|
+
try {
|
|
267
|
+
g.validate(e.parent, e.key, i);
|
|
268
|
+
} catch {
|
|
269
|
+
return !1;
|
|
270
|
+
}
|
|
271
|
+
return e.replaceWith(i), !0;
|
|
272
|
+
}
|
|
273
|
+
async replaceUrisInFile(e, t) {
|
|
274
|
+
try {
|
|
275
|
+
let r = await this.fileCache.read(e), i = m(r, {
|
|
276
|
+
sourceType: "module",
|
|
277
|
+
plugins: [
|
|
278
|
+
"typescript",
|
|
279
|
+
"jsx",
|
|
280
|
+
"decorators-legacy"
|
|
281
|
+
]
|
|
282
|
+
}), o = !1, s = this.options.outputFile.replace(/\.json$/, ".ts"), u = c(s, this.options.srcDir), h = l(e, this.options.srcDir, this.options.outputFile), _ = a(i, h), v = "assetsData", y = !1, b, x = /* @__PURE__ */ new Set();
|
|
283
|
+
T(i, {
|
|
284
|
+
Identifier: (e) => {
|
|
285
|
+
x.add(e.node.name);
|
|
286
|
+
},
|
|
287
|
+
ImportDeclaration: (e) => {
|
|
288
|
+
if (!(!h.has(e.node.source.value) || e.node.importKind === "type")) for (let t of e.node.specifiers) {
|
|
289
|
+
if (t.importKind === "type") continue;
|
|
290
|
+
let n = e.scope.getBinding(t.local.name);
|
|
291
|
+
d(t) && (v = t.local.name, y = !0, b = n);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
let S = !1;
|
|
296
|
+
if (y && T(i, { StringLiteral: (r) => {
|
|
297
|
+
!g.isImportDeclaration(r.parent) && !_(r) && !this.isImplementationReference(e, r.node.value) && t.has(n(r.node.value)) && r.scope.getBinding(v) !== b && (S = !0);
|
|
298
|
+
} }), !y && x.has(v) || S) {
|
|
299
|
+
let e = "aippyAssetsData";
|
|
300
|
+
for (let t = 2; x.has(e); t++) e = `aippyAssetsData${t}`;
|
|
301
|
+
S && b.scope.rename(v, e), v = e;
|
|
302
|
+
}
|
|
303
|
+
if (T(i, { StringLiteral: (r) => {
|
|
304
|
+
let i = r.node.value;
|
|
305
|
+
if (this.isImplementationReference(e, i) || _(r) || g.isImportDeclaration(r.parent) || g.isExportNamedDeclaration(r.parent) || g.isExportAllDeclaration(r.parent) || r.findParent((e) => g.isTSType(e.node) || g.isTSInterfaceBody(e.node))) return;
|
|
306
|
+
let a = n(i);
|
|
307
|
+
if (t.has(a)) {
|
|
308
|
+
let e = t.get(a);
|
|
309
|
+
this.replaceLiteral(r, v, e) && (r.skip(), o = !0);
|
|
310
|
+
}
|
|
311
|
+
} }), !o) return;
|
|
312
|
+
if (!y) {
|
|
313
|
+
let e = g.importDeclaration([g.importDefaultSpecifier(g.identifier(v))], g.stringLiteral(u));
|
|
314
|
+
i.program.body.unshift(e);
|
|
315
|
+
}
|
|
316
|
+
let C = E(i, {
|
|
317
|
+
retainLines: !1,
|
|
318
|
+
comments: !0,
|
|
319
|
+
compact: !1
|
|
320
|
+
}, r);
|
|
321
|
+
await f.writeFile(e, C.code, "utf-8"), this.fileCache.invalidate(e), console.log(` ✓ Replaced URIs in ${p.relative(process.cwd(), e)}`);
|
|
322
|
+
} catch (t) {
|
|
323
|
+
console.warn(`Warning: Failed to replace URIs in ${e}:`, t);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async replaceAllUris() {
|
|
327
|
+
let e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set();
|
|
328
|
+
for (let t of this.assets.values()) e.set(t.originalUri, t.constantName);
|
|
329
|
+
for (let e of this.referencedFiles) t.add(e);
|
|
330
|
+
for (let n of t) await this.replaceUrisInFile(n, e);
|
|
331
|
+
}
|
|
332
|
+
needsRewrite() {
|
|
333
|
+
return this.assets.size > 0;
|
|
334
|
+
}
|
|
335
|
+
async cleanupUnusedConstants() {
|
|
336
|
+
if (!this.planKeys) try {
|
|
337
|
+
let e = await this.readExistingAssetsFile();
|
|
338
|
+
if (!e.trim()) return;
|
|
339
|
+
let t = /* @__PURE__ */ new Map();
|
|
340
|
+
try {
|
|
341
|
+
let n = JSON.parse(e);
|
|
342
|
+
for (let [e, r] of Object.entries(n)) typeof r == "string" && t.set(e, r);
|
|
343
|
+
} catch (e) {
|
|
344
|
+
console.warn("Warning: Failed to parse assets.json:", e);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (t.size === 0) return;
|
|
348
|
+
let n = /* @__PURE__ */ new Set(), r = await u(this.options.srcDir, [".ts", ".tsx"]);
|
|
349
|
+
for (let e of r) if (!(e.endsWith("assets.json") || e.endsWith("assets.ts"))) try {
|
|
350
|
+
let r = await this.fileCache.read(e);
|
|
351
|
+
for (let e of t.keys()) r.includes(e) && n.add(e);
|
|
352
|
+
} catch (t) {
|
|
353
|
+
console.warn(`Warning: Failed to read ${e}:`, t);
|
|
354
|
+
}
|
|
355
|
+
let i = [];
|
|
356
|
+
for (let e of t.keys()) n.has(e) || i.push(e);
|
|
357
|
+
if (i.length > 0) {
|
|
358
|
+
console.log(`🧹 Removing ${i.length} unused constant(s):`), i.forEach((e) => {
|
|
359
|
+
console.log(` - ${e}`);
|
|
360
|
+
});
|
|
361
|
+
let e = [];
|
|
362
|
+
for (let n of i) {
|
|
363
|
+
let r = t.get(n);
|
|
364
|
+
r && e.push(r);
|
|
365
|
+
}
|
|
366
|
+
for (let t of e) this.assets.delete(t);
|
|
367
|
+
} else console.log("✅ All constants are in use");
|
|
368
|
+
} catch (e) {
|
|
369
|
+
console.warn("Warning: Failed to cleanup unused constants:", e);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async upgradeJsonImportsToTs() {
|
|
373
|
+
let e = this.options.outputFile.replace(/\.json$/, ".ts"), t = c(e, this.options.srcDir), n = await u(this.options.srcDir, [".ts", ".tsx"]), r = 0;
|
|
374
|
+
for (let a of n) if (!(a.endsWith("assets.ts") || a.endsWith("assets.json"))) try {
|
|
375
|
+
let n = await this.fileCache.read(a), o = i(a, this.options.outputFile) + ".json", s = i(a, e), l = c(this.options.outputFile, this.options.srcDir) + ".json";
|
|
376
|
+
if (!n.includes(o) && !n.includes(s) && !n.includes(l)) continue;
|
|
377
|
+
let u = m(n, {
|
|
378
|
+
sourceType: "module",
|
|
379
|
+
plugins: [
|
|
380
|
+
"typescript",
|
|
381
|
+
"jsx",
|
|
382
|
+
"decorators-legacy"
|
|
383
|
+
]
|
|
384
|
+
}), d = !1;
|
|
385
|
+
if (T(u, { ImportDeclaration: (e) => {
|
|
386
|
+
let n = e.node.source.value;
|
|
387
|
+
(n === o || n === s || n === l) && (e.node.source.value = t, d = !0);
|
|
388
|
+
} }), d) {
|
|
389
|
+
let e = E(u, {
|
|
390
|
+
retainLines: !1,
|
|
391
|
+
comments: !0,
|
|
392
|
+
compact: !1
|
|
393
|
+
}, n);
|
|
394
|
+
await f.writeFile(a, e.code, "utf-8"), this.fileCache.invalidate(a), console.log(` ✓ Upgraded import in ${p.relative(process.cwd(), a)} → ${t}`), r++;
|
|
395
|
+
}
|
|
396
|
+
} catch (e) {
|
|
397
|
+
console.warn(`Warning: Failed to upgrade imports in ${a}:`, e);
|
|
398
|
+
}
|
|
399
|
+
r > 0 && console.log(`✅ Upgraded ${r} file(s) to use ${t}`);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
function k(e = {}) {
|
|
403
|
+
return {
|
|
404
|
+
name: "vite-plugin-asset-constants",
|
|
405
|
+
apply: "build",
|
|
406
|
+
enforce: "pre",
|
|
407
|
+
async buildStart() {
|
|
408
|
+
if (!e.devMode) return;
|
|
409
|
+
let t = new O(e);
|
|
410
|
+
try {
|
|
411
|
+
await t.generateAssetsFile();
|
|
412
|
+
let e = t.getAssets();
|
|
413
|
+
t.needsRewrite() && (console.log(`📦 Found ${e.length} asset references:`), e.forEach((e) => {
|
|
414
|
+
console.log(` ${e.constantName} = '${e.originalUri}' (${p.relative(process.cwd(), e.filePath)}:${e.line})`);
|
|
415
|
+
}), console.log("\n🔄 Replacing URIs with constants..."), await t.replaceAllUris(), console.log("✅ URI replacement completed!")), console.log("\n🧹 Checking for unused constants..."), await t.cleanupUnusedConstants(), await t.generateAssetsFile(), console.log("\n🔄 Upgrading assets.json imports to assets.ts..."), await t.upgradeJsonImportsToTs(), console.log("✅ Asset constants finalized!\n"), t.clearCache();
|
|
416
|
+
} catch (e) {
|
|
417
|
+
console.error("❌ Error in asset constants plugin:", e), e instanceof D && this.error(e.message);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
//#endregion
|
|
423
|
+
export { k as t };
|
package/dist/index/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { extractAssetsFromContent as e, findProjectRoot as t, generateConstantName as n, isValidAsset as r, processAssetURL as i } from "../utils/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import { t as o } from "../aippy-preload-
|
|
2
|
+
import { t as a } from "../asset-constants-UclgHOzp.js";
|
|
3
|
+
import { t as o } from "../aippy-preload-DZsYdwMm.js";
|
|
4
4
|
import { t as s } from "../aippy-tagger-By5socAS.js";
|
|
5
5
|
export { o as aippyPreloadPlugin, s as aippyTaggerPlugin, a as assetConstantsPlugin, a as default, e as extractAssetsFromContent, t as findProjectRoot, n as generateConstantName, r as isValidAsset, i as processAssetURL };
|
|
@@ -123,106 +123,4 @@ function _(e, t, r, i) {
|
|
|
123
123
|
return e;
|
|
124
124
|
}
|
|
125
125
|
//#endregion
|
|
126
|
-
|
|
127
|
-
function v(e) {
|
|
128
|
-
if (!e || typeof e != "object" || Array.isArray(e)) return !1;
|
|
129
|
-
let t = e;
|
|
130
|
-
return typeof t.schemaVersion == "number" && !!t.assets && typeof t.assets == "object" && !Array.isArray(t.assets);
|
|
131
|
-
}
|
|
132
|
-
var y = [
|
|
133
|
-
"",
|
|
134
|
-
"-",
|
|
135
|
-
"--",
|
|
136
|
-
"tbd",
|
|
137
|
-
"todo",
|
|
138
|
-
"none",
|
|
139
|
-
"n/a",
|
|
140
|
-
"null",
|
|
141
|
-
"pending",
|
|
142
|
-
"not-generated",
|
|
143
|
-
"待生成",
|
|
144
|
-
"待制作"
|
|
145
|
-
];
|
|
146
|
-
function b(e) {
|
|
147
|
-
if (!e || Buffer.byteLength(e) > 4096 || /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f\uFEFF]/.test(e) || /[\s\\]/u.test(e) || e.startsWith("//") || /%(?![0-9a-f]{2})/i.test(e.split("?")[0]) || /%(?![0-9a-f]{2})/i.test(e.split("#")[1] ?? "")) return !1;
|
|
148
|
-
if (!/^[a-z][a-z0-9+.-]*:/i.test(e)) {
|
|
149
|
-
if (e.split(/[?#]/, 1)[0].split("/", 1)[0].includes(":")) return !1;
|
|
150
|
-
let t = e.split(/[?#]/, 1)[0].replace(/%([0-9a-f]{2})/gi, (e, t) => String.fromCharCode(Number.parseInt(t, 16)));
|
|
151
|
-
if (!t || t.endsWith("/") || y.includes(t.trim().toLowerCase())) return !1;
|
|
152
|
-
if (t.includes("/")) return !0;
|
|
153
|
-
let n = t.lastIndexOf(".");
|
|
154
|
-
return n > 0 && n < t.length - 1;
|
|
155
|
-
}
|
|
156
|
-
if (!/^https?:\/\//i.test(e)) return !1;
|
|
157
|
-
let t = e.slice(e.indexOf("://") + 3).split(/[/?#]/, 1)[0];
|
|
158
|
-
if (!t || t.includes("%")) return !1;
|
|
159
|
-
try {
|
|
160
|
-
let t = new URL(e);
|
|
161
|
-
return !!t.hostname && !t.username && !t.password;
|
|
162
|
-
} catch {
|
|
163
|
-
return !1;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function x(e) {
|
|
167
|
-
let t = /* @__PURE__ */ new Map();
|
|
168
|
-
for (let [n, r] of Object.entries(e)) {
|
|
169
|
-
if (typeof r != "string" || !b(r)) continue;
|
|
170
|
-
let e = t.get(r) ?? [];
|
|
171
|
-
e.push(n), t.set(r, e);
|
|
172
|
-
}
|
|
173
|
-
return t;
|
|
174
|
-
}
|
|
175
|
-
function S(e) {
|
|
176
|
-
if (!e.startsWith("aippy-asset:")) return;
|
|
177
|
-
let t = e.slice(12), n = t.indexOf(":");
|
|
178
|
-
if (n <= 0 || n === t.length - 1) return;
|
|
179
|
-
let r;
|
|
180
|
-
try {
|
|
181
|
-
r = decodeURIComponent(t.slice(0, n));
|
|
182
|
-
} catch {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
let i = t.slice(n + 1);
|
|
186
|
-
if (!(!r || !b(i))) return {
|
|
187
|
-
key: r,
|
|
188
|
-
url: i
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
function C(e) {
|
|
192
|
-
return e.includes("aippy-asset:") ? e.replace(/aippy-asset:[^\s'"`<>()]*?:(?=https?:\/\/)/g, "").replace(/aippy-asset:[^:\s'"`<>()]+:/g, "") : e;
|
|
193
|
-
}
|
|
194
|
-
function w(e, t, n = {}) {
|
|
195
|
-
let r = { ...n }, i = new Set(Object.keys(r));
|
|
196
|
-
for (let [e, n] of t.entries()) i.has(n) || Object.values(r).includes(e) || (r[n] = e, i.add(n));
|
|
197
|
-
for (let t of e.values()) {
|
|
198
|
-
let e = Object.entries(r).find(([, e]) => e === t.originalUri);
|
|
199
|
-
if (e) {
|
|
200
|
-
t.constantName = e[0];
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
let n = t.constantName, a = n, o = 2;
|
|
204
|
-
for (; i.has(a);) a = `${n}_${o++}`;
|
|
205
|
-
i.add(a), t.constantName = a, r[a] = t.originalUri;
|
|
206
|
-
}
|
|
207
|
-
return JSON.stringify(r, null, 2) + "\n";
|
|
208
|
-
}
|
|
209
|
-
function T(e) {
|
|
210
|
-
let t = /* @__PURE__ */ new Map();
|
|
211
|
-
try {
|
|
212
|
-
if (!e.trim()) return t;
|
|
213
|
-
let n = JSON.parse(e);
|
|
214
|
-
if (v(n)) throw Error("assets: single-file asset plan is not supported");
|
|
215
|
-
if (!n || typeof n != "object" || Array.isArray(n)) throw Error("assets: URL dictionary object required");
|
|
216
|
-
for (let [e, r] of Object.entries(n)) typeof r == "string" && t.set(r, e);
|
|
217
|
-
t.size > 0 && console.log(`📋 Found ${t.size} existing constants in assets.json`);
|
|
218
|
-
} catch (e) {
|
|
219
|
-
throw e instanceof Error && e.message.startsWith("assets:") ? e : Error("assets: invalid JSON syntax");
|
|
220
|
-
}
|
|
221
|
-
return t;
|
|
222
|
-
}
|
|
223
|
-
function E(e, t, n, r) {
|
|
224
|
-
let i = Array.from(n.values()).filter((e) => t.has(e.originalUri)).length, a = e - i;
|
|
225
|
-
console.log(a > 0 ? `✅ Generated ${e} asset constants (${a} new, ${i} reused) in ${r}` : e > 0 ? `✅ Generated ${e} asset constants (all reused from existing) in ${r}` : "✅ No asset constants found");
|
|
226
|
-
}
|
|
227
|
-
//#endregion
|
|
228
|
-
export { S as a, m as c, h as d, f, c as g, u as h, E as i, _ as l, l as m, w as n, T as o, d as p, v as r, C as s, x as t, g as u };
|
|
126
|
+
export { f as a, u as c, h as i, c as l, _ as n, d as o, g as r, l as s, m as t };
|