|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
17 | | -import path from 'node:path'; |
18 | | -import url from 'node:url'; |
19 | | -import { CommonUtils } from '@salesforce/lwc-dev-mobile-core'; |
| 17 | +import packageJson from '../../package.json' with { type: 'json' }; |
| 18 | +import { objectEntries } from './typeUtils.js'; |
20 | 19 |
|
21 | 20 | /** |
22 | 21 | * Resolves org API version to appropriate dependency channel |
23 | 22 | */ |
24 | | -export type VersionChannel = 'latest' | 'prerelease' | 'next'; |
| 23 | +export type VersionChannel = keyof typeof packageJson.apiVersionMetadata.channels; |
25 | 24 |
|
26 | | -export type ChannelConfig = { |
27 | | - supportedApiVersions: string[]; |
28 | | - dependencies: { |
29 | | - [key: string]: string; |
30 | | - }; |
31 | | -}; |
32 | | - |
33 | | -type CacheEntry = { |
34 | | - apiVersion: string; |
35 | | - channel: VersionChannel; |
36 | | - timestamp: number; |
37 | | -}; |
| 25 | +/** |
| 26 | + * Extracts major.minor from a version string (e.g., "65.0" from "65.0.1") |
| 27 | + */ |
| 28 | +function getMajorMinor(version: string): string { |
| 29 | + const parts = version.split('.'); |
| 30 | + return `${parts[0]}.${parts[1]}`; |
| 31 | +} |
38 | 32 |
|
39 | | -type PackageJson = { |
40 | | - apiVersionMetadata: { |
41 | | - channels: { |
42 | | - [key in VersionChannel]: ChannelConfig; |
43 | | - }; |
44 | | - defaultChannel: VersionChannel; |
45 | | - }; |
46 | | -}; |
| 33 | +/** |
| 34 | + * Returns a formatted list of all supported API versions |
| 35 | + */ |
| 36 | +function getSupportedVersionsList(): string { |
| 37 | + const channels = packageJson.apiVersionMetadata.channels; |
| 38 | + const allVersions: string[] = []; |
47 | 39 |
|
48 | | -export class VersionResolver { |
49 | | - private static channelMetadata: Map<VersionChannel, ChannelConfig> | null = null; |
50 | | - private static versionCache: Map<string, CacheEntry> = new Map(); |
51 | | - private static readonly CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes |
| 40 | + for (const config of Object.values(channels)) { |
| 41 | + allVersions.push(...config.supportedApiVersions); |
| 42 | + } |
52 | 43 |
|
53 | | - /** |
54 | | - * Given an org API version, returns the appropriate channel |
55 | | - * |
56 | | - * @param orgApiVersion - The API version from the org (e.g., "65.0") |
57 | | - * @returns The channel to use ('latest' or 'prerelease') |
58 | | - * @throws Error if the API version is not supported by any channel |
59 | | - */ |
60 | | - public static resolveChannel(orgApiVersion: string): VersionChannel { |
61 | | - const channels = this.loadChannelMetadata(); |
| 44 | + return allVersions.join(', '); |
| 45 | +} |
62 | 46 |
|
63 | | - for (const [channel, config] of channels.entries()) { |
64 | | - if (config.supportedApiVersions.includes(orgApiVersion)) { |
65 | | - return channel; |
66 | | - } |
67 | | - } |
| 47 | +/** |
| 48 | + * Given an org API version, returns the appropriate channel |
| 49 | + * |
| 50 | + * @param orgApiVersion - The API version from the org (e.g., "65.0") |
| 51 | + * @returns The channel to use ('latest' or 'prerelease') |
| 52 | + * @throws Error if the API version is not supported by any channel |
| 53 | + */ |
| 54 | +export function resolveChannel(orgApiVersion: string): VersionChannel { |
| 55 | + const channels = packageJson.apiVersionMetadata.channels; |
68 | 56 |
|
69 | | - // If no exact match, try to find by major.minor comparison |
70 | | - const orgMajorMinor = this.getMajorMinor(orgApiVersion); |
71 | | - for (const [channel, config] of channels.entries()) { |
72 | | - for (const supportedVersion of config.supportedApiVersions) { |
73 | | - if (this.getMajorMinor(supportedVersion) === orgMajorMinor) { |
74 | | - return channel; |
75 | | - } |
76 | | - } |
| 57 | + for (const [channel, config] of objectEntries(channels)) { |
| 58 | + if (config.supportedApiVersions.includes(orgApiVersion)) { |
| 59 | + return channel; |
77 | 60 | } |
78 | | - |
79 | | - throw new Error( |
80 | | - `Unsupported org API version: ${orgApiVersion}. This plugin supports: ${this.getSupportedVersionsList()}` |
81 | | - ); |
82 | 61 | } |
83 | 62 |
|
84 | | - /** |
85 | | - * Resolves channel with caching support |
86 | | - * |
87 | | - * @param orgId - Unique identifier for the org |
88 | | - * @param orgApiVersion - The API version from the org |
89 | | - * @returns The channel to use |
90 | | - */ |
91 | | - public static resolveChannelWithCache(orgId: string, orgApiVersion: string): VersionChannel { |
92 | | - // Check cache first |
93 | | - const cached = this.versionCache.get(orgId); |
94 | | - if (cached) { |
95 | | - const age = Date.now() - cached.timestamp; |
96 | | - if (age < this.CACHE_TTL_MS && cached.apiVersion === orgApiVersion) { |
97 | | - return cached.channel; |
| 63 | + // If no exact match, try to find by major.minor comparison |
| 64 | + const orgMajorMinor = getMajorMinor(orgApiVersion); |
| 65 | + for (const [channel, config] of objectEntries(channels)) { |
| 66 | + for (const supportedVersion of config.supportedApiVersions) { |
| 67 | + if (getMajorMinor(supportedVersion) === orgMajorMinor) { |
| 68 | + return channel; |
98 | 69 | } |
99 | | - // Cache expired or version changed, remove it |
100 | | - this.versionCache.delete(orgId); |
101 | | - } |
102 | | - |
103 | | - // Resolve and cache |
104 | | - const channel = this.resolveChannel(orgApiVersion); |
105 | | - this.versionCache.set(orgId, { |
106 | | - apiVersion: orgApiVersion, |
107 | | - channel, |
108 | | - timestamp: Date.now(), |
109 | | - }); |
110 | | - |
111 | | - return channel; |
112 | | - } |
113 | | - |
114 | | - /** |
115 | | - * Returns the default channel from package.json |
116 | | - */ |
117 | | - public static getDefaultChannel(): VersionChannel { |
118 | | - const packageJson = this.getPackageJson(); |
119 | | - return packageJson.apiVersionMetadata.defaultChannel; |
120 | | - } |
121 | | - |
122 | | - /** |
123 | | - * Clears the version cache (useful for testing or when orgs are upgraded) |
124 | | - */ |
125 | | - public static clearCache(): void { |
126 | | - this.versionCache.clear(); |
127 | | - this.channelMetadata = null; |
128 | | - } |
129 | | - |
130 | | - /** |
131 | | - * Removes a specific org from the cache |
132 | | - */ |
133 | | - public static removeCacheEntry(orgId: string): void { |
134 | | - this.versionCache.delete(orgId); |
135 | | - } |
136 | | - |
137 | | - /** |
138 | | - * Loads channel metadata from package.json |
139 | | - */ |
140 | | - private static loadChannelMetadata(): Map<VersionChannel, ChannelConfig> { |
141 | | - if (this.channelMetadata) { |
142 | | - return this.channelMetadata; |
143 | 70 | } |
144 | | - |
145 | | - const packageJson = this.getPackageJson(); |
146 | | - const channels = packageJson.apiVersionMetadata.channels; |
147 | | - |
148 | | - this.channelMetadata = new Map(); |
149 | | - for (const [channel, config] of Object.entries(channels)) { |
150 | | - this.channelMetadata.set(channel as VersionChannel, config); |
151 | | - } |
152 | | - |
153 | | - return this.channelMetadata; |
154 | 71 | } |
155 | 72 |
|
156 | | - /** |
157 | | - * Extracts major.minor from a version string (e.g., "65.0" from "65.0.1") |
158 | | - */ |
159 | | - private static getMajorMinor(version: string): string { |
160 | | - const parts = version.split('.'); |
161 | | - return `${parts[0]}.${parts[1]}`; |
162 | | - } |
163 | | - |
164 | | - /** |
165 | | - * Returns a formatted list of all supported API versions |
166 | | - */ |
167 | | - private static getSupportedVersionsList(): string { |
168 | | - const channels = this.loadChannelMetadata(); |
169 | | - const allVersions: string[] = []; |
170 | | - |
171 | | - for (const config of channels.values()) { |
172 | | - allVersions.push(...config.supportedApiVersions); |
173 | | - } |
174 | | - |
175 | | - return allVersions.join(', '); |
176 | | - } |
| 73 | + throw new Error(`Unsupported org API version: ${orgApiVersion}. This plugin supports: ${getSupportedVersionsList()}`); |
| 74 | +} |
177 | 75 |
|
178 | | - private static getPackageJson(): PackageJson { |
179 | | - const dirname = path.dirname(url.fileURLToPath(import.meta.url)); |
180 | | - const packageJsonFilePath = path.resolve(dirname, '../../package.json'); |
181 | | - return CommonUtils.loadJsonFromFile(packageJsonFilePath) as unknown as PackageJson; |
182 | | - } |
| 76 | +/** |
| 77 | + * Returns the default channel from package.json |
| 78 | + */ |
| 79 | +export function getDefaultChannel(): VersionChannel { |
| 80 | + return packageJson.apiVersionMetadata.defaultChannel as VersionChannel; |
183 | 81 | } |
0 commit comments