bejamas 0.2.12 → 0.3.1

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/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "bejamas",
3
- "version": "0.2.12",
3
+ "version": "0.3.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "default": "./dist/index.js"
9
+ },
10
+ "./tailwind.css": "./tailwind.css"
11
+ },
6
12
  "bin": {
7
13
  "bejamas": "./dist/index.js"
8
14
  },
9
15
  "files": [
10
- "dist/"
16
+ "dist/",
17
+ "tailwind.css",
18
+ "src/tailwind.css"
11
19
  ],
12
20
  "keywords": [
13
21
  "components",
@@ -25,6 +33,8 @@
25
33
  "scripts": {
26
34
  "build": "tsdown",
27
35
  "dev": "tsdown --watch",
36
+ "generate:schema": "bun run scripts/generate-schema.ts",
37
+ "smoke:init:local": "bun run scripts/smoke-init-local.ts",
28
38
  "prepublishOnly": "bun run build",
29
39
  "test": "bun run build && bun test"
30
40
  },
@@ -35,6 +45,8 @@
35
45
  },
36
46
  "bugs": "https://github.com/bejamas/ui/issues",
37
47
  "devDependencies": {
48
+ "@bejamas/create-config": "workspace:*",
49
+ "@bejamas/semantic-icons": "workspace:*",
38
50
  "tsdown": "^0.15.2"
39
51
  },
40
52
  "dependencies": {
@@ -48,7 +60,8 @@
48
60
  "kleur": "^4.1.5",
49
61
  "ora": "^9.0.0",
50
62
  "prompts": "^2.4.2",
51
- "shadcn": "3.8.5",
63
+ "shadcn": "4.1.1",
64
+ "tar": "^7.4.3",
52
65
  "ts-morph": "^27.0.0",
53
66
  "tsconfig-paths": "^4.2.0",
54
67
  "zod": "^4.1.9"
@@ -0,0 +1,104 @@
1
+ @theme inline {
2
+ @keyframes accordion-down {
3
+ from {
4
+ height: 0;
5
+ }
6
+ to {
7
+ height: var(
8
+ --radix-accordion-content-height,
9
+ var(--accordion-panel-height, auto)
10
+ );
11
+ }
12
+ }
13
+
14
+ @keyframes accordion-up {
15
+ from {
16
+ height: var(
17
+ --radix-accordion-content-height,
18
+ var(--accordion-panel-height, auto)
19
+ );
20
+ }
21
+ to {
22
+ height: 0;
23
+ }
24
+ }
25
+ }
26
+
27
+ /* Custom variants */
28
+ @custom-variant data-open {
29
+ &:where([data-state="open"]),
30
+ &:where([data-open]:not([data-open="false"])) {
31
+ @slot;
32
+ }
33
+ }
34
+
35
+ @custom-variant data-closed {
36
+ &:where([data-state="closed"]),
37
+ &:where([data-closed]:not([data-closed="false"])) {
38
+ @slot;
39
+ }
40
+ }
41
+
42
+ @custom-variant data-checked {
43
+ &:where([data-state="checked"]),
44
+ &:where([data-checked]:not([data-checked="false"])) {
45
+ @slot;
46
+ }
47
+ }
48
+
49
+ @custom-variant data-unchecked {
50
+ &:where([data-state="unchecked"]),
51
+ &:where([data-unchecked]:not([data-unchecked="false"])) {
52
+ @slot;
53
+ }
54
+ }
55
+
56
+ @custom-variant data-selected {
57
+ &:where([data-selected="true"]) {
58
+ @slot;
59
+ }
60
+ }
61
+
62
+ @custom-variant data-disabled {
63
+ &:where([data-disabled="true"]),
64
+ &:where([data-disabled]:not([data-disabled="false"])) {
65
+ @slot;
66
+ }
67
+ }
68
+
69
+ @custom-variant data-active {
70
+ &:where([data-state="active"]),
71
+ &:where([data-active]:not([data-active="false"])) {
72
+ @slot;
73
+ }
74
+ }
75
+
76
+ @custom-variant data-horizontal {
77
+ &:where([data-orientation="horizontal"]) {
78
+ @slot;
79
+ }
80
+ }
81
+
82
+ @custom-variant data-vertical {
83
+ &:where([data-orientation="vertical"]) {
84
+ @slot;
85
+ }
86
+ }
87
+
88
+ @utility no-scrollbar {
89
+ -ms-overflow-style: none;
90
+ scrollbar-width: none;
91
+
92
+ &::-webkit-scrollbar {
93
+ display: none;
94
+ }
95
+ }
96
+
97
+ /*.cn-button-group .cn-button {
98
+ background: red !important;
99
+ }*/
100
+ @custom-variant slot-siblings {
101
+ &:where(> [data-slot] ~ [data-slot] button) {
102
+ @slot;
103
+ }
104
+ }
package/tailwind.css ADDED
@@ -0,0 +1 @@
1
+ @import "./src/tailwind.css";
@@ -1,431 +0,0 @@
1
- import { createRequire } from "module";
2
- import path, { dirname, extname, join, posix } from "path";
3
- import fs from "fs-extra";
4
- import { z } from "zod";
5
- import { cyan, green, red, yellow } from "kleur/colors";
6
- import ora from "ora";
7
- import { configSchema, rawConfigSchema, workspaceConfigSchema } from "shadcn/schema";
8
- import fg from "fast-glob";
9
- import { createMatchPath, loadConfig } from "tsconfig-paths";
10
- import { cosmiconfig } from "cosmiconfig";
11
- import { existsSync } from "fs";
12
- import { readdir } from "fs/promises";
13
- import { Project, SyntaxKind } from "ts-morph";
14
-
15
- //#region src/utils/highlighter.ts
16
- const highlighter = {
17
- error: red,
18
- warn: yellow,
19
- info: cyan,
20
- success: green
21
- };
22
-
23
- //#endregion
24
- //#region src/utils/logger.ts
25
- const logger = {
26
- error(...args) {
27
- console.log(highlighter.error(args.join(" ")));
28
- },
29
- warn(...args) {
30
- console.log(highlighter.warn(args.join(" ")));
31
- },
32
- info(...args) {
33
- console.log(highlighter.info(args.join(" ")));
34
- },
35
- success(...args) {
36
- console.log(highlighter.success(args.join(" ")));
37
- },
38
- log(...args) {
39
- console.log(args.join(" "));
40
- },
41
- break() {
42
- console.log("");
43
- }
44
- };
45
-
46
- //#endregion
47
- //#region src/utils/spinner.ts
48
- function spinner(text, options) {
49
- return ora({
50
- text,
51
- isSilent: options?.silent
52
- });
53
- }
54
-
55
- //#endregion
56
- //#region src/registry/constants.ts
57
- const REGISTRY_URL = process.env.REGISTRY_URL ?? "https://ui.bejamas.com/r";
58
- const BUILTIN_REGISTRIES = { "@bejamas": `${REGISTRY_URL}/{name}.json` };
59
-
60
- //#endregion
61
- //#region src/utils/get-project-info.ts
62
- const TS_CONFIG_SCHEMA = z.object({ compilerOptions: z.object({ paths: z.record(z.string().or(z.array(z.string()))) }) });
63
-
64
- //#endregion
65
- //#region src/utils/resolve-import.ts
66
- async function resolveImport(importPath, config) {
67
- return createMatchPath(config.absoluteBaseUrl, config.paths)(importPath, void 0, () => true, [
68
- ".ts",
69
- ".tsx",
70
- ".jsx",
71
- ".js",
72
- ".css"
73
- ]);
74
- }
75
-
76
- //#endregion
77
- //#region src/utils/get-config.ts
78
- const explorer = cosmiconfig("components", { searchPlaces: ["components.json"] });
79
- async function getConfig(cwd) {
80
- const config = await getRawConfig(cwd);
81
- if (!config) return null;
82
- if (!config.iconLibrary) config.iconLibrary = config.style === "new-york" ? "radix" : "lucide";
83
- return await resolveConfigPaths(cwd, config);
84
- }
85
- async function resolveConfigPaths(cwd, config) {
86
- config.registries = {
87
- ...BUILTIN_REGISTRIES,
88
- ...config.registries || {}
89
- };
90
- const tsConfig = await loadConfig(cwd);
91
- if (tsConfig.resultType === "failed") throw new Error(`Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${tsConfig.message ?? ""}`.trim());
92
- return configSchema.parse({
93
- ...config,
94
- resolvedPaths: {
95
- cwd,
96
- tailwindConfig: config.tailwind.config ? path.resolve(cwd, config.tailwind.config) : "",
97
- tailwindCss: path.resolve(cwd, config.tailwind.css),
98
- utils: await resolveImport(config.aliases["utils"], tsConfig),
99
- components: await resolveImport(config.aliases["components"], tsConfig),
100
- ui: config.aliases["ui"] ? await resolveImport(config.aliases["ui"], tsConfig) : path.resolve(await resolveImport(config.aliases["components"], tsConfig) ?? cwd, "ui"),
101
- lib: config.aliases["lib"] ? await resolveImport(config.aliases["lib"], tsConfig) : path.resolve(await resolveImport(config.aliases["utils"], tsConfig) ?? cwd, ".."),
102
- hooks: config.aliases["hooks"] ? await resolveImport(config.aliases["hooks"], tsConfig) : path.resolve(await resolveImport(config.aliases["components"], tsConfig) ?? cwd, "..", "hooks")
103
- }
104
- });
105
- }
106
- async function getRawConfig(cwd) {
107
- try {
108
- const configResult = await explorer.search(cwd);
109
- if (!configResult) return null;
110
- const config = rawConfigSchema.parse(configResult.config);
111
- if (config.registries) {
112
- for (const registryName of Object.keys(config.registries)) if (registryName in BUILTIN_REGISTRIES) throw new Error(`"${registryName}" is a built-in registry and cannot be overridden.`);
113
- }
114
- return config;
115
- } catch (error) {
116
- const componentPath = `${cwd}/components.json`;
117
- if (error instanceof Error && error.message.includes("reserved registry")) throw error;
118
- throw new Error(`Invalid configuration found in ${highlighter.info(componentPath)}.`);
119
- }
120
- }
121
- async function getWorkspaceConfig(config) {
122
- let resolvedAliases = {};
123
- for (const key of Object.keys(config.aliases)) {
124
- if (!isAliasKey(key, config)) continue;
125
- const resolvedPath = config.resolvedPaths[key];
126
- const packageRoot = await findPackageRoot(config.resolvedPaths.cwd, resolvedPath);
127
- if (!packageRoot) {
128
- resolvedAliases[key] = config;
129
- continue;
130
- }
131
- resolvedAliases[key] = await getConfig(packageRoot);
132
- }
133
- const result = workspaceConfigSchema.safeParse(resolvedAliases);
134
- if (!result.success) return null;
135
- return result.data;
136
- }
137
- async function findPackageRoot(cwd, resolvedPath) {
138
- const commonRoot = findCommonRoot(cwd, resolvedPath);
139
- const relativePath = path.relative(commonRoot, resolvedPath);
140
- const matchingPackageRoot = (await fg.glob("**/package.json", {
141
- cwd: commonRoot,
142
- deep: 3,
143
- ignore: [
144
- "**/node_modules/**",
145
- "**/dist/**",
146
- "**/build/**",
147
- "**/public/**"
148
- ]
149
- })).map((pkgPath) => path.dirname(pkgPath)).find((pkgDir) => relativePath.startsWith(pkgDir));
150
- return matchingPackageRoot ? path.join(commonRoot, matchingPackageRoot) : null;
151
- }
152
- function isAliasKey(key, config) {
153
- return Object.keys(config.resolvedPaths).filter((key$1) => key$1 !== "utils").includes(key);
154
- }
155
- function findCommonRoot(cwd, resolvedPath) {
156
- const parts1 = cwd.split(path.sep);
157
- const parts2 = resolvedPath.split(path.sep);
158
- const commonParts = [];
159
- for (let i = 0; i < Math.min(parts1.length, parts2.length); i++) {
160
- if (parts1[i] !== parts2[i]) break;
161
- commonParts.push(parts1[i]);
162
- }
163
- return commonParts.join(path.sep);
164
- }
165
-
166
- //#endregion
167
- //#region src/docs/generate-mdx/utils.ts
168
- const RESERVED_COMPONENTS = new Set([
169
- "Fragment",
170
- "CodePackageManagers",
171
- "DocsTabs",
172
- "DocsTabItem",
173
- "DocsCodePackageManagers",
174
- "Tabs",
175
- "TabItem"
176
- ]);
177
- function slugify(input) {
178
- return input.replace(/\.(astro|md|mdx|tsx|ts|jsx|js)$/i, "").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/\s+/g, "-").replace(/_+/g, "-").toLowerCase();
179
- }
180
- function extractFrontmatter(source) {
181
- const match = source.match(/^---\n([\s\S]*?)\n---/);
182
- return match && match[1] || "";
183
- }
184
- function toIdentifier(name) {
185
- const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9]+/g, " ").trim().replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\s+/g, "");
186
- return /^[A-Za-z_]/.test(base) ? base : `Ex${base}`;
187
- }
188
- function parseJsDocMetadata(frontmatterCode) {
189
- const jsDocMatch = frontmatterCode.match(/\/\*\*([\s\S]*?)\*\//);
190
- if (!jsDocMatch) return {};
191
- const lines = jsDocMatch[1].split("\n").map((l) => l.replace(/^\s*\*\s?/, ""));
192
- const meta = {};
193
- let inUsage = false;
194
- let inExamples = false;
195
- let inPrimaryExample = false;
196
- let inApi = false;
197
- let captureDescriptionBody = false;
198
- const usageLines = [];
199
- const examplesLines = [];
200
- const primaryExampleLines = [];
201
- const apiLines = [];
202
- const descriptionBodyLines = [];
203
- for (const rawLine of lines) {
204
- const line = rawLine;
205
- if (inUsage) if (line.trim().startsWith("@")) inUsage = false;
206
- else {
207
- usageLines.push(line);
208
- continue;
209
- }
210
- if (inPrimaryExample) if (line.trim().startsWith("@")) inPrimaryExample = false;
211
- else {
212
- primaryExampleLines.push(line);
213
- continue;
214
- }
215
- if (inExamples) if (line.trim().startsWith("@")) inExamples = false;
216
- else {
217
- examplesLines.push(line);
218
- continue;
219
- }
220
- if (inApi) if (line.trim().startsWith("@")) inApi = false;
221
- else {
222
- apiLines.push(line);
223
- continue;
224
- }
225
- if (captureDescriptionBody) if (line.trim().startsWith("@")) captureDescriptionBody = false;
226
- else {
227
- descriptionBodyLines.push(line);
228
- continue;
229
- }
230
- if (line.trim().startsWith("@component")) meta.name = line.replace("@component", "").trim();
231
- else if (line.trim().startsWith("@title")) meta.title = line.replace("@title", "").trim();
232
- else if (line.trim().startsWith("@description")) {
233
- meta.description = line.replace("@description", "").trim();
234
- captureDescriptionBody = true;
235
- continue;
236
- } else if (line.trim().startsWith("@figmaUrl")) meta.figmaUrl = line.replace("@figmaUrl", "").trim();
237
- else if (line.trim().startsWith("@figma")) meta.figmaUrl = line.replace("@figma", "").trim();
238
- else if (line.trim().startsWith("@usage")) {
239
- inUsage = true;
240
- continue;
241
- } else if (line.trim().startsWith("@examples")) {
242
- inExamples = true;
243
- continue;
244
- } else if (line.trim().startsWith("@preview")) {
245
- inPrimaryExample = true;
246
- continue;
247
- } else if (line.trim().startsWith("@example")) {
248
- inPrimaryExample = true;
249
- continue;
250
- } else if (line.trim().startsWith("@api")) {
251
- inApi = true;
252
- continue;
253
- }
254
- }
255
- if (usageLines.length) meta.usageMDX = usageLines.join("\n").trim();
256
- if (examplesLines.length) meta.examplesMDX = examplesLines.join("\n").trim();
257
- if (primaryExampleLines.length) meta.primaryExampleMDX = primaryExampleLines.join("\n").trim();
258
- if (descriptionBodyLines.length) meta.descriptionBodyMDX = descriptionBodyLines.join("\n").trim();
259
- if (apiLines.length) meta.apiMDX = apiLines.join("\n").trim();
260
- return meta;
261
- }
262
- function extractPropsFromAstroProps(sourceFile) {
263
- function unwrapAstroProps(node) {
264
- let current = node;
265
- for (let i = 0; i < 10; i += 1) {
266
- const kind = current.getKind();
267
- if (kind === SyntaxKind.PropertyAccessExpression) {
268
- const expr = current.getExpression();
269
- if (expr && expr.getText() === "Astro" && current.getName() === "props") return current;
270
- return null;
271
- }
272
- if (kind === SyntaxKind.AsExpression || kind === SyntaxKind.TypeAssertion || kind === SyntaxKind.SatisfiesExpression || kind === SyntaxKind.NonNullExpression || kind === SyntaxKind.ParenthesizedExpression) {
273
- const next = current.getExpression && current.getExpression();
274
- if (!next) return null;
275
- current = next;
276
- continue;
277
- }
278
- return null;
279
- }
280
- return null;
281
- }
282
- const target = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration).find((decl) => {
283
- const init = decl.getInitializer();
284
- if (!init) return false;
285
- return !!unwrapAstroProps(init);
286
- });
287
- if (!target) return [];
288
- const nameNode = target.getNameNode();
289
- if (!nameNode || nameNode.getKind() !== SyntaxKind.ObjectBindingPattern) return [];
290
- return nameNode.asKindOrThrow(SyntaxKind.ObjectBindingPattern).getElements().map((el) => {
291
- if (!!el.getDotDotDotToken()) return {
292
- isRest: true,
293
- hasDefault: false,
294
- alias: el.getName()
295
- };
296
- const propertyNameNode = el.getPropertyNameNode();
297
- const name = el.getName();
298
- const propName = propertyNameNode ? propertyNameNode.getText() : name;
299
- const initializer = el.getInitializer();
300
- let defaultValue;
301
- if (initializer) defaultValue = initializer.getText();
302
- return {
303
- name: propName,
304
- hasDefault: initializer != null,
305
- defaultValue
306
- };
307
- });
308
- }
309
- function extractPropsFromDeclaredProps(sourceFile) {
310
- function normalizeTypeText(text) {
311
- if (!text) return "";
312
- return text.replace(/\s+/g, " ").replace(/;\s*$/, "").trim();
313
- }
314
- const iface = sourceFile.getInterface("Props");
315
- if (iface) return iface.getProperties().map((prop) => {
316
- const name = prop.getName();
317
- const typeNode = prop.getTypeNode();
318
- return {
319
- name,
320
- type: normalizeTypeText(typeNode ? typeNode.getText() : prop.getType().getText()),
321
- optional: prop.hasQuestionToken()
322
- };
323
- });
324
- const typeAlias = sourceFile.getTypeAlias("Props");
325
- if (typeAlias) {
326
- const typeNode = typeAlias.getTypeNode();
327
- if (typeNode && typeNode.getKind() === SyntaxKind.TypeLiteral) return typeNode.asKindOrThrow(SyntaxKind.TypeLiteral).getProperties().map((prop) => {
328
- const name = prop.getName();
329
- const tn = prop.getTypeNode();
330
- return {
331
- name,
332
- type: normalizeTypeText(tn ? tn.getText() : prop.getType().getText()),
333
- optional: prop.hasQuestionToken()
334
- };
335
- });
336
- }
337
- return [];
338
- }
339
- function resolveUiRoot(cwd) {
340
- const require = createRequire(import.meta.url);
341
- const envRoot = process.env.BEJAMAS_UI_ROOT;
342
- if (envRoot && existsSync(path.join(envRoot, "package.json"))) return envRoot;
343
- try {
344
- const pkgPath = require.resolve("@bejamas/ui/package.json", { paths: [cwd] });
345
- return path.dirname(pkgPath);
346
- } catch {}
347
- let current = cwd;
348
- for (let i = 0; i < 6; i += 1) {
349
- const candidate = path.join(current, "packages", "ui", "package.json");
350
- if (existsSync(candidate)) return path.dirname(candidate);
351
- const parent = path.dirname(current);
352
- if (parent === current) break;
353
- current = parent;
354
- }
355
- try {
356
- const anyEntry = require.resolve("@bejamas/ui/*", { paths: [cwd] });
357
- return path.resolve(anyEntry, "..", "..");
358
- } catch {}
359
- throw new Error("Unable to locate @bejamas/ui in the workspace");
360
- }
361
- function resolveOutDir(cwd) {
362
- const envOut = process.env.BEJAMAS_DOCS_OUT_DIR;
363
- if (envOut && envOut.length) return path.isAbsolute(envOut) ? envOut : path.resolve(cwd, envOut);
364
- return path.resolve(cwd, "../../apps/web/src/content/docs/components");
365
- }
366
- function detectHasImportTopLevel(block, pascalName) {
367
- if (!block) return false;
368
- let inFence = false;
369
- const importLineRegex = /* @__PURE__ */ new RegExp(`^\\s*import\\s+.*\\bfrom\\s+['"][^'"]+\\b${pascalName}\\.astro['"]`);
370
- for (const line of block.split("\n")) {
371
- if (line.trim().startsWith("```")) {
372
- inFence = !inFence;
373
- continue;
374
- }
375
- if (!inFence && importLineRegex.test(line)) return true;
376
- }
377
- return false;
378
- }
379
- function normalizeBlockMDX(block) {
380
- if (!block) return "";
381
- return block.replace(/from\s+['"]@\/ui\/components\//g, "from '@bejamas/ui/components/");
382
- }
383
- function normalizeUsageMDX(usageMDX, pascalName) {
384
- const normalized = normalizeBlockMDX(usageMDX);
385
- const hasImport = detectHasImportTopLevel(normalized, pascalName);
386
- return {
387
- text: normalized.trim(),
388
- hasImport
389
- };
390
- }
391
- function extractComponentTagsFromMDX(block) {
392
- if (!block) return [];
393
- let inFence = false;
394
- const found = /* @__PURE__ */ new Set();
395
- const tagRegex = /<([A-Z][A-Za-z0-9_]*)\b/g;
396
- for (const line of block.split("\n")) {
397
- if (line.trim().startsWith("```")) {
398
- inFence = !inFence;
399
- continue;
400
- }
401
- if (inFence) continue;
402
- let match;
403
- while ((match = tagRegex.exec(line)) !== null) {
404
- const name = match[1];
405
- found.add(name);
406
- }
407
- }
408
- return Array.from(found);
409
- }
410
- async function discoverExamples(componentFilePath, componentsDir) {
411
- const fileBase = path.basename(componentFilePath, path.extname(componentFilePath));
412
- const kebabBase = slugify(fileBase);
413
- const candidates = [join(dirname(componentFilePath), `${fileBase}.examples`), join(dirname(componentFilePath), `${kebabBase}.examples`)];
414
- const found = [];
415
- for (const dir of candidates) try {
416
- const items = await readdir(dir, { withFileTypes: true });
417
- for (const it of items) if (it.isFile() && extname(it.name).toLowerCase() === ".astro") {
418
- const abs = join(dir, it.name);
419
- const relFromComponents = path.relative(componentsDir, abs).split(path.sep).join(posix.sep);
420
- found.push(relFromComponents);
421
- }
422
- } catch {}
423
- return found;
424
- }
425
- function createSourceFileFromFrontmatter(frontmatterCode) {
426
- return new Project({ useInMemoryFileSystem: true }).createSourceFile("Component.ts", frontmatterCode, { overwrite: true });
427
- }
428
-
429
- //#endregion
430
- export { getWorkspaceConfig as _, extractComponentTagsFromMDX as a, highlighter as b, extractPropsFromDeclaredProps as c, parseJsDocMetadata as d, resolveOutDir as f, getConfig as g, toIdentifier as h, discoverExamples as i, normalizeBlockMDX as l, slugify as m, createSourceFileFromFrontmatter as n, extractFrontmatter as o, resolveUiRoot as p, detectHasImportTopLevel as r, extractPropsFromAstroProps as s, RESERVED_COMPONENTS as t, normalizeUsageMDX as u, spinner as v, logger as y };
431
- //# sourceMappingURL=utils-BfJTJvcy.js.map