@nocobase/utils 2.1.0-beta.44 → 2.1.0-beta.45

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/utils",
3
- "version": "2.1.0-beta.44",
3
+ "version": "2.1.0-beta.45",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -21,5 +21,5 @@
21
21
  "object-path": "^0.11.8",
22
22
  "ses": "^1.14.0"
23
23
  },
24
- "gitHead": "540d4897b1696cc24c0754521b0b766978b4933c"
24
+ "gitHead": "42587115fc34c3eb01ef2b2549f1c998e5708318"
25
25
  }
@@ -0,0 +1,45 @@
1
+ export interface PluginPackageInfo {
2
+ name: string;
3
+ packageName: string;
4
+ origins: string[];
5
+ resolvedPath: string;
6
+ }
7
+
8
+ export interface ParsePluginNameOptions {
9
+ nodeModulesPath?: string;
10
+ pluginPackagePrefixes?: string[];
11
+ }
12
+
13
+ export interface PresetPackageJsonLike {
14
+ dependencies?: Record<string, string>;
15
+ builtIn?: string[];
16
+ deprecated?: string[];
17
+ }
18
+
19
+ export declare const DEFAULT_PLUGIN_PACKAGE_PREFIXES: string[];
20
+ export declare function splitPluginNames(value?: string): string[];
21
+ export declare function getPluginPackagePrefixes(): string[];
22
+ export declare function getPluginNameFromPackageName(packageName: string, prefixes?: string[]): string;
23
+ export declare function isValidPackageName(packageName: string): boolean;
24
+ export declare function looksLikePluginPackage(packageName: string, prefixes?: string[]): boolean;
25
+ export declare function parsePluginName(
26
+ nameOrPkg: string,
27
+ options?: ParsePluginNameOptions,
28
+ ): Promise<{ name: string; packageName: string }>;
29
+ export declare function getPresetNocoBasePackageJson(options?: {
30
+ nodeModulesPath?: string;
31
+ cwd?: string;
32
+ }): Promise<PresetPackageJsonLike | null>;
33
+ export declare function resolvePluginPackagePath(
34
+ packageName: string,
35
+ options?: {
36
+ nodeModulesPath?: string;
37
+ storagePluginsPath?: string;
38
+ },
39
+ ): Promise<string>;
40
+ export declare function discoverPluginPackages(options?: {
41
+ nodeModulesPath?: string;
42
+ storagePluginsPath?: string;
43
+ cwd?: string;
44
+ pluginPackagePrefixes?: string[];
45
+ }): Promise<PluginPackageInfo[]>;
@@ -0,0 +1,268 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const {
4
+ getPluginSourceRoots,
5
+ getStoragePluginNames,
6
+ resolvePluginSourcePath,
7
+ resolvePluginStoragePath,
8
+ } = require('./plugin-symlink');
9
+
10
+ const DEFAULT_PLUGIN_PACKAGE_PREFIXES = ['@nocobase/plugin-', '@nocobase/preset-'];
11
+ const PRESET_PACKAGE_NAME = '@nocobase/preset-nocobase';
12
+
13
+ function uniqStrings(values) {
14
+ return [...new Set(values.filter(Boolean))];
15
+ }
16
+
17
+ function splitPluginNames(value) {
18
+ return uniqStrings(
19
+ String(value || '')
20
+ .split(',')
21
+ .map((item) => item.trim())
22
+ .filter(Boolean),
23
+ );
24
+ }
25
+
26
+ function getPluginPackagePrefixes() {
27
+ const prefixes = splitPluginNames(process.env.PLUGIN_PACKAGE_PREFIX || DEFAULT_PLUGIN_PACKAGE_PREFIXES.join(','));
28
+ return prefixes.length > 0 ? prefixes : DEFAULT_PLUGIN_PACKAGE_PREFIXES;
29
+ }
30
+
31
+ function getPluginNameFromPackageName(packageName, prefixes = getPluginPackagePrefixes()) {
32
+ const prefix = prefixes.find((item) => packageName.startsWith(item));
33
+ return prefix ? packageName.slice(prefix.length) : packageName;
34
+ }
35
+
36
+ function isValidPackageName(packageName) {
37
+ if (!packageName || typeof packageName !== 'string') {
38
+ return false;
39
+ }
40
+
41
+ if (packageName.includes('\0')) {
42
+ return false;
43
+ }
44
+
45
+ if (path.isAbsolute(packageName)) {
46
+ return false;
47
+ }
48
+
49
+ if (packageName.includes('..') || packageName.includes('\\')) {
50
+ return false;
51
+ }
52
+
53
+ return /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i.test(packageName);
54
+ }
55
+
56
+ function looksLikePluginPackage(packageName) {
57
+ return isValidPackageName(packageName);
58
+ }
59
+
60
+ async function parsePluginName(nameOrPkg, options = {}) {
61
+ const input = String(nameOrPkg || '').trim();
62
+ const prefixes = options.pluginPackagePrefixes || getPluginPackagePrefixes();
63
+
64
+ if (!input) {
65
+ return { name: '', packageName: '' };
66
+ }
67
+
68
+ const matchedPrefix = prefixes.find((prefix) => input.startsWith(prefix));
69
+ if (matchedPrefix) {
70
+ return {
71
+ packageName: input,
72
+ name: input.slice(matchedPrefix.length),
73
+ };
74
+ }
75
+
76
+ const nodeModulesPath = String(options.nodeModulesPath || process.env.NODE_MODULES_PATH || '').trim();
77
+ if (nodeModulesPath) {
78
+ for (const prefix of prefixes) {
79
+ const candidate = `${prefix}${input}`;
80
+ if (await fs.pathExists(path.resolve(nodeModulesPath, candidate, 'package.json'))) {
81
+ return { name: input, packageName: candidate };
82
+ }
83
+ }
84
+ }
85
+
86
+ return { name: input, packageName: input };
87
+ }
88
+
89
+ function getPresetPackageJsonCandidates(options = {}) {
90
+ const candidates = [];
91
+ const nodeModulesPath = String(options.nodeModulesPath || process.env.NODE_MODULES_PATH || '').trim();
92
+
93
+ if (nodeModulesPath) {
94
+ candidates.push(path.resolve(nodeModulesPath, PRESET_PACKAGE_NAME, 'package.json'));
95
+ }
96
+
97
+ candidates.push(path.resolve(options.cwd || process.cwd(), 'packages/presets/nocobase/package.json'));
98
+ return uniqStrings(candidates);
99
+ }
100
+
101
+ async function getPresetNocoBasePackageJson(options = {}) {
102
+ for (const packageJsonPath of getPresetPackageJsonCandidates(options)) {
103
+ if (await fs.pathExists(packageJsonPath)) {
104
+ return fs.readJson(packageJsonPath);
105
+ }
106
+ }
107
+ return null;
108
+ }
109
+
110
+ async function getNodeModulesEntryType(linkPath) {
111
+ try {
112
+ const statResult = await fs.lstat(linkPath);
113
+ if (statResult.isSymbolicLink()) {
114
+ return 'symlink';
115
+ }
116
+ if (statResult.isDirectory()) {
117
+ return 'dir';
118
+ }
119
+ return 'other';
120
+ } catch (error) {
121
+ if (error.code === 'ENOENT') {
122
+ return 'missing';
123
+ }
124
+ return 'other';
125
+ }
126
+ }
127
+
128
+ async function resolvePluginPackagePath(packageName, options = {}) {
129
+ const normalizedPackageName = String(packageName || '').trim();
130
+ if (!normalizedPackageName) {
131
+ return '';
132
+ }
133
+
134
+ const nodeModulesPath = String(options.nodeModulesPath || process.env.NODE_MODULES_PATH || '').trim();
135
+ const storagePluginsPath = options.storagePluginsPath || resolvePluginStoragePath();
136
+ const nodeModulesPackagePath = nodeModulesPath ? path.resolve(nodeModulesPath, normalizedPackageName) : '';
137
+
138
+ if (nodeModulesPackagePath) {
139
+ const entryType = await getNodeModulesEntryType(nodeModulesPackagePath);
140
+ if (entryType === 'dir') {
141
+ return nodeModulesPackagePath;
142
+ }
143
+ }
144
+
145
+ const sourcePath = await resolvePluginSourcePath(normalizedPackageName, storagePluginsPath);
146
+ if (sourcePath) {
147
+ return sourcePath;
148
+ }
149
+
150
+ if (nodeModulesPackagePath && (await fs.pathExists(path.resolve(nodeModulesPackagePath, 'package.json')))) {
151
+ return nodeModulesPackagePath;
152
+ }
153
+
154
+ return '';
155
+ }
156
+
157
+ async function readPluginPackagesFromRoot(rootPath) {
158
+ if (!rootPath || !(await fs.pathExists(rootPath))) {
159
+ return [];
160
+ }
161
+
162
+ const relativePluginDirs = await getStoragePluginNames(rootPath);
163
+ const items = [];
164
+
165
+ for (const relativePluginDir of relativePluginDirs) {
166
+ const packageJsonPath = path.resolve(rootPath, relativePluginDir, 'package.json');
167
+ if (!(await fs.pathExists(packageJsonPath))) {
168
+ continue;
169
+ }
170
+ const packageJson = await fs.readJson(packageJsonPath);
171
+ const packageName = String(packageJson?.name || '').trim();
172
+
173
+ if (!looksLikePluginPackage(packageName)) {
174
+ continue;
175
+ }
176
+
177
+ items.push({
178
+ packageName,
179
+ packagePath: path.resolve(rootPath, relativePluginDir),
180
+ sourceRoot: rootPath,
181
+ });
182
+ }
183
+
184
+ return items;
185
+ }
186
+
187
+ function pushOrigin(targetMap, packageName, origin) {
188
+ if (!packageName) {
189
+ return;
190
+ }
191
+ if (!targetMap.has(packageName)) {
192
+ targetMap.set(packageName, new Set());
193
+ }
194
+ targetMap.get(packageName).add(origin);
195
+ }
196
+
197
+ async function discoverPluginPackages(options = {}) {
198
+ const nodeModulesPath = String(options.nodeModulesPath || process.env.NODE_MODULES_PATH || '').trim();
199
+ const storagePluginsPath = options.storagePluginsPath || resolvePluginStoragePath();
200
+ const prefixes = options.pluginPackagePrefixes || getPluginPackagePrefixes();
201
+ const originsByPackageName = new Map();
202
+
203
+ const presetPackageJson = await getPresetNocoBasePackageJson({ nodeModulesPath, cwd: options.cwd });
204
+ const presetDependencies = Object.keys(presetPackageJson?.dependencies || {}).filter((packageName) =>
205
+ packageName.startsWith('@nocobase/plugin-'),
206
+ );
207
+
208
+ for (const packageName of presetDependencies) {
209
+ pushOrigin(originsByPackageName, packageName, 'preset-dependency');
210
+ }
211
+
212
+ const sourceRoots = getPluginSourceRoots(storagePluginsPath);
213
+ for (const sourceRoot of sourceRoots) {
214
+ const packages = await readPluginPackagesFromRoot(sourceRoot);
215
+ for (const item of packages) {
216
+ pushOrigin(originsByPackageName, item.packageName, sourceRoot);
217
+ }
218
+ }
219
+
220
+ for (const packageNameOrName of splitPluginNames(process.env.APPEND_PRESET_BUILT_IN_PLUGINS)) {
221
+ const { packageName } = await parsePluginName(packageNameOrName, {
222
+ nodeModulesPath,
223
+ pluginPackagePrefixes: prefixes,
224
+ });
225
+ pushOrigin(originsByPackageName, packageName, 'append-built-in');
226
+ }
227
+
228
+ for (const packageNameOrName of splitPluginNames(process.env.APPEND_PRESET_LOCAL_PLUGINS)) {
229
+ const { packageName } = await parsePluginName(packageNameOrName, {
230
+ nodeModulesPath,
231
+ pluginPackagePrefixes: prefixes,
232
+ });
233
+ pushOrigin(originsByPackageName, packageName, 'append-local');
234
+ }
235
+
236
+ const items = [];
237
+ for (const [packageName, origins] of originsByPackageName.entries()) {
238
+ const resolvedPath = await resolvePluginPackagePath(packageName, {
239
+ nodeModulesPath,
240
+ storagePluginsPath,
241
+ });
242
+
243
+ if (!resolvedPath) {
244
+ continue;
245
+ }
246
+
247
+ const { name } = await parsePluginName(packageName, { nodeModulesPath, pluginPackagePrefixes: prefixes });
248
+ items.push({
249
+ name,
250
+ packageName,
251
+ origins: [...origins],
252
+ resolvedPath,
253
+ });
254
+ }
255
+
256
+ return items.sort((a, b) => a.packageName.localeCompare(b.packageName));
257
+ }
258
+
259
+ exports.DEFAULT_PLUGIN_PACKAGE_PREFIXES = DEFAULT_PLUGIN_PACKAGE_PREFIXES;
260
+ exports.getPluginPackagePrefixes = getPluginPackagePrefixes;
261
+ exports.getPluginNameFromPackageName = getPluginNameFromPackageName;
262
+ exports.getPresetNocoBasePackageJson = getPresetNocoBasePackageJson;
263
+ exports.isValidPackageName = isValidPackageName;
264
+ exports.looksLikePluginPackage = looksLikePluginPackage;
265
+ exports.parsePluginName = parsePluginName;
266
+ exports.resolvePluginPackagePath = resolvePluginPackagePath;
267
+ exports.discoverPluginPackages = discoverPluginPackages;
268
+ exports.splitPluginNames = splitPluginNames;
@@ -1,5 +1,7 @@
1
+ export declare function resolvePluginStoragePath(): string;
1
2
  export declare function getStoragePluginNames(target: any): Promise<any[]>;
2
- export declare function fsExists(path: any): Promise<boolean>;
3
+ export declare function getPluginSourceRoots(storagePluginsPath: string): string[];
4
+ export declare function resolvePluginSourcePath(pluginName: string, storagePluginsPath: string): Promise<string>;
3
5
  export declare function createStoragePluginSymLink(pluginName: any): Promise<void>;
4
6
  export declare function createStoragePluginsSymlink(): Promise<void>;
5
7
  export declare function createDevPluginSymLink(pluginName: any): Promise<void>;
package/plugin-symlink.js CHANGED
@@ -282,6 +282,9 @@ async function syncPluginSymlinks() {
282
282
  }
283
283
 
284
284
  exports.resolvePluginStoragePath = resolvePluginStoragePath;
285
+ exports.getStoragePluginNames = getStoragePluginNames;
286
+ exports.getPluginSourceRoots = getPluginSourceRoots;
287
+ exports.resolvePluginSourcePath = resolvePluginSourcePath;
285
288
  exports.createStoragePluginSymLink = createStoragePluginSymLink;
286
289
  exports.createStoragePluginsSymlink = createStoragePluginsSymlink;
287
290
  exports.createDevPluginSymLink = createDevPluginSymLink;