vueless 0.0.577 → 0.0.578
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 +1 -1
- package/plugin-vite.js +5 -0
- package/ui.button/UButton.vue +3 -3
- package/ui.button/storybook/stories.ts +2 -2
- package/ui.button/types.ts +1 -1
- package/utils/node/dynamicProps.js +190 -0
- package/web-types.json +1 -1
package/package.json
CHANGED
package/plugin-vite.js
CHANGED
|
@@ -10,6 +10,7 @@ import { cacheIcons, removeIconsCache, copyIconsCache } from "./utils/node/loade
|
|
|
10
10
|
import { createTailwindSafelist, clearTailwindSafelist } from "./utils/node/tailwindSafelist.js";
|
|
11
11
|
import { getNuxtFiles, getVueFiles } from "./utils/node/helper.js";
|
|
12
12
|
import { componentResolver, directiveResolver } from "./utils/node/vuelessResolver.js";
|
|
13
|
+
import { setCustomPropTypes, removeCustomPropTypes } from "./utils/node/dynamicProps.js";
|
|
13
14
|
|
|
14
15
|
/* Automatically importing Vueless components on demand */
|
|
15
16
|
export const VuelessUnpluginComponents = (options) =>
|
|
@@ -34,6 +35,8 @@ export const Vueless = function (options = {}) {
|
|
|
34
35
|
|
|
35
36
|
/* if server stopped by developer (Ctrl+C) */
|
|
36
37
|
process.on("SIGINT", async () => {
|
|
38
|
+
await removeCustomPropTypes(isVuelessEnv);
|
|
39
|
+
|
|
37
40
|
/* remove cached icons */
|
|
38
41
|
await removeIconsCache(mirrorCacheDir, debug);
|
|
39
42
|
|
|
@@ -82,6 +85,8 @@ export const Vueless = function (options = {}) {
|
|
|
82
85
|
await cacheIcons({ mode: "vuelessIcons", env, debug, targetFiles });
|
|
83
86
|
/* copy vueless cache folder */
|
|
84
87
|
await copyIconsCache(mirrorCacheDir, debug);
|
|
88
|
+
|
|
89
|
+
await setCustomPropTypes(isVuelessEnv);
|
|
85
90
|
}
|
|
86
91
|
},
|
|
87
92
|
|
package/ui.button/UButton.vue
CHANGED
|
@@ -12,12 +12,12 @@ import UIcon from "../ui.image-icon/UIcon.vue";
|
|
|
12
12
|
import defaultConfig from "./config.ts";
|
|
13
13
|
import { UButton } from "./constants.ts";
|
|
14
14
|
|
|
15
|
-
import type {
|
|
15
|
+
import type { Props, LoaderSize, IconSize, Config } from "./types.ts";
|
|
16
16
|
|
|
17
17
|
defineOptions({ inheritAttrs: false });
|
|
18
18
|
|
|
19
|
-
const props = withDefaults(defineProps<
|
|
20
|
-
...getDefaults<
|
|
19
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
20
|
+
...getDefaults<Props>(defaultConfig, UButton),
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
const slots = useSlots();
|
|
@@ -15,9 +15,9 @@ import UCol from "../../ui.container-col/UCol.vue";
|
|
|
15
15
|
import { useDarkMode } from "../../composables/useDarkMode.ts";
|
|
16
16
|
|
|
17
17
|
import type { Meta, StoryFn } from "@storybook/vue3";
|
|
18
|
-
import type {
|
|
18
|
+
import type { Props } from "../types.ts";
|
|
19
19
|
|
|
20
|
-
interface UButtonArgs extends
|
|
20
|
+
interface UButtonArgs extends Props {
|
|
21
21
|
slotTemplate?: string;
|
|
22
22
|
enum: "variant" | "size";
|
|
23
23
|
}
|
package/ui.button/types.ts
CHANGED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { vuelessConfig } from "./vuelessConfig.js";
|
|
6
|
+
|
|
7
|
+
import { COMPONENTS, VUELESS_DIR, VUELESS_LOCAL_DIR } from "../../constants.js";
|
|
8
|
+
|
|
9
|
+
const OPTIONAL_MARK = "?";
|
|
10
|
+
const CLOSING_BRACKET = "}";
|
|
11
|
+
const IGNORE_PROP = "@ignore";
|
|
12
|
+
const CUSTOM_PROP = "@custom";
|
|
13
|
+
|
|
14
|
+
const VUELESS_SRC = path.join(VUELESS_DIR, VUELESS_LOCAL_DIR);
|
|
15
|
+
|
|
16
|
+
const PROPS_INTERFACE_REG_EXP = /export\s+interface\s+Props\s*{([^}]*)}/s;
|
|
17
|
+
const UNION_SYMBOLS_REG_EXP = /[?|:"|;]/g;
|
|
18
|
+
const WORD_IN_QUOTE_REG_EXP = /([^"]+)/;
|
|
19
|
+
|
|
20
|
+
async function cacheComponentTypes(filePath) {
|
|
21
|
+
const cacheDir = path.join(filePath, ".cache");
|
|
22
|
+
const sourceFile = path.join(filePath, "types.ts");
|
|
23
|
+
const destFile = path.join(cacheDir, "types.ts");
|
|
24
|
+
|
|
25
|
+
if (existsSync(cacheDir)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (existsSync(sourceFile)) {
|
|
30
|
+
await fs.mkdir(cacheDir);
|
|
31
|
+
await fs.cp(sourceFile, destFile);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function clearComponentTypesCache(filePath) {
|
|
36
|
+
await fs.rm(path.join(filePath, ".cache"), { force: true, recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function restoreComponentTypes(filePath) {
|
|
40
|
+
const cacheDir = path.join(filePath, ".cache");
|
|
41
|
+
const sourceFile = path.join(cacheDir, "types.ts");
|
|
42
|
+
const destFile = path.join(filePath, "types.ts");
|
|
43
|
+
|
|
44
|
+
if (existsSync(sourceFile)) {
|
|
45
|
+
await fs.cp(sourceFile, destFile);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getMultiLineUnionValues(lines, propIndex, propEndIndex) {
|
|
50
|
+
return lines
|
|
51
|
+
.slice(propIndex)
|
|
52
|
+
.slice(1, propEndIndex + 1)
|
|
53
|
+
.map((item) => item.replace(UNION_SYMBOLS_REG_EXP, "").trim());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getInlineUnionValues(lines, propIndex, propEndIndex) {
|
|
57
|
+
const types = lines
|
|
58
|
+
.slice(propIndex)
|
|
59
|
+
.slice(0, propEndIndex + 1)
|
|
60
|
+
.at(0)
|
|
61
|
+
.match(WORD_IN_QUOTE_REG_EXP);
|
|
62
|
+
|
|
63
|
+
return types ? types.map((value) => value.replace(/"/g, "")) : [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Updates or add a prop types dynamically.
|
|
68
|
+
* @param {string} filePath - The path to the TypeScript file.
|
|
69
|
+
* @param {Array} props - Array of prop objects to add or update.
|
|
70
|
+
*/
|
|
71
|
+
async function modifyComponentTypes(filePath, props) {
|
|
72
|
+
try {
|
|
73
|
+
const targetFile = path.join(filePath, "types.ts");
|
|
74
|
+
|
|
75
|
+
/* Read `types.ts` and split it by lines. */
|
|
76
|
+
let fileContent = await fs.readFile(targetFile, "utf-8");
|
|
77
|
+
const propsInterface = fileContent.match(PROPS_INTERFACE_REG_EXP)?.at(0)?.trim();
|
|
78
|
+
|
|
79
|
+
/* Remove props interface and double returns from fileContent */
|
|
80
|
+
fileContent = fileContent.replace(propsInterface, "").replace(/\n\s*\n/g, "\n");
|
|
81
|
+
|
|
82
|
+
const lines = propsInterface.split("\n");
|
|
83
|
+
|
|
84
|
+
for (const prop of props) {
|
|
85
|
+
const { name, type, values = [], description, required, ignore } = prop;
|
|
86
|
+
|
|
87
|
+
if (!name) return;
|
|
88
|
+
|
|
89
|
+
/* Find line with prop. */
|
|
90
|
+
const propRegex = new RegExp(`^\\s*${name}[?:]?\\s*:`);
|
|
91
|
+
const propIndex = lines.findIndex((line) => propRegex.test(line));
|
|
92
|
+
const propEndIndex = lines.slice(propIndex).findIndex((line) => line.endsWith(";"));
|
|
93
|
+
const propTypes = propEndIndex
|
|
94
|
+
? getMultiLineUnionValues(lines, propIndex, propEndIndex)
|
|
95
|
+
: getInlineUnionValues(lines, propIndex, propEndIndex);
|
|
96
|
+
|
|
97
|
+
const defaultUnionType = propTypes.map((value) => `"${value}"`).join(" | ");
|
|
98
|
+
|
|
99
|
+
/* Prepare prop params. */
|
|
100
|
+
const uniqueValues = [...new Set(values)];
|
|
101
|
+
const isAssignableValue = uniqueValues.every((value) => propTypes.includes(value));
|
|
102
|
+
const unionType = uniqueValues.map((value) => `"${value}"`).join(" | ");
|
|
103
|
+
const userOptionalMark = required ? "" : OPTIONAL_MARK;
|
|
104
|
+
const defaultOptionalMark = lines[propIndex]?.includes(OPTIONAL_MARK) ? OPTIONAL_MARK : "";
|
|
105
|
+
const optionalMark = required === undefined ? defaultOptionalMark : userOptionalMark;
|
|
106
|
+
|
|
107
|
+
const propDescription = description?.replaceAll(/[\n\s]+/g, " ").trim() || "–"; // removes new lines and double spaces.
|
|
108
|
+
const propType = unionType.length ? unionType : type;
|
|
109
|
+
|
|
110
|
+
/* Add ignore JSDoc property. */
|
|
111
|
+
if (ignore) {
|
|
112
|
+
const ignoreDefinition = [` * ${IGNORE_PROP}`, ` */`];
|
|
113
|
+
const deleteLinesCount = lines[propIndex - 2].includes(IGNORE_PROP) ? 2 : 1;
|
|
114
|
+
|
|
115
|
+
lines.splice(propIndex - deleteLinesCount, deleteLinesCount, ...ignoreDefinition);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Check if the prop type already exists. */
|
|
119
|
+
if (~propIndex) {
|
|
120
|
+
if (unionType.length && isAssignableValue) {
|
|
121
|
+
// Remove multiline union types;
|
|
122
|
+
lines.splice(propIndex + 1, propEndIndex);
|
|
123
|
+
|
|
124
|
+
lines.splice(propIndex, 1, ` ${name}${defaultOptionalMark}: ${propType};`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (unionType.length && !isAssignableValue) {
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.warn(`${unionType} is not assignable to type ${defaultUnionType}.`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const isCustomProp = lines[propIndex - 2].includes(CUSTOM_PROP);
|
|
133
|
+
|
|
134
|
+
if (!isCustomProp && (type || description || required)) {
|
|
135
|
+
// eslint-disable-next-line no-console, prettier/prettier
|
|
136
|
+
console.warn("Changing of prop type, description or required are not allowed for the default props.");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Add new prop. */
|
|
143
|
+
const closingBracketIndex = lines.findIndex((line) => line.trim() === CLOSING_BRACKET);
|
|
144
|
+
const propDefinition = [
|
|
145
|
+
"",
|
|
146
|
+
` /**`,
|
|
147
|
+
` * ${propDescription}`,
|
|
148
|
+
` * ${CUSTOM_PROP}`,
|
|
149
|
+
` */`,
|
|
150
|
+
` ${name}${optionalMark}: ${type};`,
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
lines.splice(closingBracketIndex, 0, ...propDefinition);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
lines.unshift(fileContent);
|
|
157
|
+
|
|
158
|
+
/* Update `types.ts` file. */
|
|
159
|
+
await fs.writeFile(targetFile, lines.join("\n"), "utf-8");
|
|
160
|
+
} catch (error) {
|
|
161
|
+
// eslint-disable-next-line no-console
|
|
162
|
+
console.error("Error updating file:", error.message);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function setCustomPropTypes(isVuelessEnv) {
|
|
167
|
+
const srcDir = isVuelessEnv ? VUELESS_LOCAL_DIR : VUELESS_SRC;
|
|
168
|
+
|
|
169
|
+
for await (const [componentName, componentDir] of Object.entries(COMPONENTS)) {
|
|
170
|
+
const customProps =
|
|
171
|
+
componentName in vuelessConfig.component && vuelessConfig.component[componentName].props;
|
|
172
|
+
|
|
173
|
+
if (customProps) {
|
|
174
|
+
await cacheComponentTypes(path.join(srcDir, componentDir));
|
|
175
|
+
await modifyComponentTypes(
|
|
176
|
+
path.join(srcDir, componentDir),
|
|
177
|
+
vuelessConfig.component[componentName].props,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export async function removeCustomPropTypes(isVuelessEnv) {
|
|
184
|
+
const srcDir = isVuelessEnv ? VUELESS_LOCAL_DIR : VUELESS_SRC;
|
|
185
|
+
|
|
186
|
+
for await (const componentDir of Object.values(COMPONENTS)) {
|
|
187
|
+
await restoreComponentTypes(path.join(srcDir, componentDir));
|
|
188
|
+
await clearComponentTypesCache(path.join(srcDir, componentDir));
|
|
189
|
+
}
|
|
190
|
+
}
|