@contentful/field-editor-shared 2.16.0 → 2.17.0-alpha.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.
|
@@ -30,6 +30,9 @@ _export(exports, {
|
|
|
30
30
|
getFieldValue: function() {
|
|
31
31
|
return getFieldValue;
|
|
32
32
|
},
|
|
33
|
+
getResolvedImageUrl: function() {
|
|
34
|
+
return getResolvedImageUrl;
|
|
35
|
+
},
|
|
33
36
|
isAssetField: function() {
|
|
34
37
|
return isAssetField;
|
|
35
38
|
},
|
|
@@ -236,3 +239,33 @@ const getEntryImage = async ({ entry, contentType, localeCode }, getAsset)=>{
|
|
|
236
239
|
return null;
|
|
237
240
|
}
|
|
238
241
|
};
|
|
242
|
+
const DOWNLOADS_ENDPOINT = 'downloads.ctfassets.net';
|
|
243
|
+
const TRANSFORMATIONS_ENDPOINT = 'images.ctfassets.net';
|
|
244
|
+
const getResolvedImageUrl = (url, params)=>{
|
|
245
|
+
try {
|
|
246
|
+
const urlToParse = url.startsWith('//') ? `https:${url}` : url;
|
|
247
|
+
const parsedUrl = new URL(urlToParse);
|
|
248
|
+
if (parsedUrl.hostname === DOWNLOADS_ENDPOINT) {
|
|
249
|
+
parsedUrl.hostname = TRANSFORMATIONS_ENDPOINT;
|
|
250
|
+
}
|
|
251
|
+
if (params) {
|
|
252
|
+
Object.entries(params).forEach(([key, value])=>{
|
|
253
|
+
if (value !== undefined) {
|
|
254
|
+
parsedUrl.searchParams.set(key, value.toString());
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const result = parsedUrl.toString();
|
|
259
|
+
return url.startsWith('//') ? result.replace(/^https:/, '') : result;
|
|
260
|
+
} catch {
|
|
261
|
+
if (!params) return url;
|
|
262
|
+
const searchParams = new URLSearchParams();
|
|
263
|
+
Object.entries(params).forEach(([key, value])=>{
|
|
264
|
+
if (value !== undefined) {
|
|
265
|
+
searchParams.set(key, value.toString());
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
const queryString = searchParams.toString();
|
|
269
|
+
return queryString ? `${url}?${queryString}` : url;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
@@ -149,3 +149,118 @@ describe('getEntityStatus', ()=>{
|
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
|
+
describe('getResolvedImageUrl', ()=>{
|
|
153
|
+
describe('URL parsing and domain replacement', ()=>{
|
|
154
|
+
test('replaces downloads.ctfassets.net with images.ctfassets.net', ()=>{
|
|
155
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg');
|
|
156
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
157
|
+
});
|
|
158
|
+
test('handles protocol-relative URLs', ()=>{
|
|
159
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('//downloads.ctfassets.net/space/asset.jpg');
|
|
160
|
+
expect(result).toBe('//images.ctfassets.net/space/asset.jpg');
|
|
161
|
+
});
|
|
162
|
+
test('does not modify URLs that are not from downloads.ctfassets.net', ()=>{
|
|
163
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://example.com/image.jpg');
|
|
164
|
+
expect(result).toBe('https://example.com/image.jpg');
|
|
165
|
+
});
|
|
166
|
+
test('does not modify images.ctfassets.net URLs', ()=>{
|
|
167
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://images.ctfassets.net/space/asset.jpg');
|
|
168
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
describe('query parameters', ()=>{
|
|
172
|
+
test('adds width parameter', ()=>{
|
|
173
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
174
|
+
width: 100
|
|
175
|
+
});
|
|
176
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?width=100');
|
|
177
|
+
});
|
|
178
|
+
test('adds height parameter', ()=>{
|
|
179
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
180
|
+
height: 200
|
|
181
|
+
});
|
|
182
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?height=200');
|
|
183
|
+
});
|
|
184
|
+
test('adds fit parameter', ()=>{
|
|
185
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
186
|
+
fit: 'thumb'
|
|
187
|
+
});
|
|
188
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?fit=thumb');
|
|
189
|
+
});
|
|
190
|
+
test('adds multiple parameters', ()=>{
|
|
191
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
192
|
+
width: 100,
|
|
193
|
+
height: 200,
|
|
194
|
+
fit: 'thumb'
|
|
195
|
+
});
|
|
196
|
+
expect(result).toContain('width=100');
|
|
197
|
+
expect(result).toContain('height=200');
|
|
198
|
+
expect(result).toContain('fit=thumb');
|
|
199
|
+
expect(result).toContain('images.ctfassets.net');
|
|
200
|
+
});
|
|
201
|
+
test('skips undefined parameters', ()=>{
|
|
202
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
203
|
+
width: 100,
|
|
204
|
+
height: undefined,
|
|
205
|
+
fit: 'thumb'
|
|
206
|
+
});
|
|
207
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?width=100&fit=thumb');
|
|
208
|
+
});
|
|
209
|
+
test('returns URL without query string when no params provided', ()=>{
|
|
210
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg');
|
|
211
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
212
|
+
});
|
|
213
|
+
test('returns URL without query string when all params are undefined', ()=>{
|
|
214
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
215
|
+
width: undefined,
|
|
216
|
+
height: undefined,
|
|
217
|
+
fit: undefined
|
|
218
|
+
});
|
|
219
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
describe('relative URL fallback', ()=>{
|
|
223
|
+
test('returns relative URL unchanged when no params provided', ()=>{
|
|
224
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('/assets/image.jpg');
|
|
225
|
+
expect(result).toBe('/assets/image.jpg');
|
|
226
|
+
});
|
|
227
|
+
test('appends query params to relative URLs', ()=>{
|
|
228
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('/assets/image.jpg', {
|
|
229
|
+
width: 100,
|
|
230
|
+
height: 200
|
|
231
|
+
});
|
|
232
|
+
expect(result).toBe('/assets/image.jpg?width=100&height=200');
|
|
233
|
+
});
|
|
234
|
+
test('handles relative URLs with undefined params', ()=>{
|
|
235
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('/assets/image.jpg', {
|
|
236
|
+
width: 100,
|
|
237
|
+
height: undefined
|
|
238
|
+
});
|
|
239
|
+
expect(result).toBe('/assets/image.jpg?width=100');
|
|
240
|
+
});
|
|
241
|
+
test('returns relative URL unchanged when all params are undefined', ()=>{
|
|
242
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('/assets/image.jpg', {
|
|
243
|
+
width: undefined,
|
|
244
|
+
height: undefined
|
|
245
|
+
});
|
|
246
|
+
expect(result).toBe('/assets/image.jpg');
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe('edge cases', ()=>{
|
|
250
|
+
test('preserves existing query parameters', ()=>{
|
|
251
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg?foo=bar', {
|
|
252
|
+
width: 100
|
|
253
|
+
});
|
|
254
|
+
expect(result).toContain('foo=bar');
|
|
255
|
+
expect(result).toContain('width=100');
|
|
256
|
+
});
|
|
257
|
+
test('handles URLs with fragments', ()=>{
|
|
258
|
+
const result = (0, _entityHelpers.getResolvedImageUrl)('https://downloads.ctfassets.net/space/asset.jpg#section', {
|
|
259
|
+
width: 100
|
|
260
|
+
});
|
|
261
|
+
expect(result).toContain('images.ctfassets.net');
|
|
262
|
+
expect(result).toContain('width=100');
|
|
263
|
+
expect(result).toContain('#section');
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
@@ -189,3 +189,33 @@ export const getEntryImage = async ({ entry, contentType, localeCode }, getAsset
|
|
|
189
189
|
return null;
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
|
+
const DOWNLOADS_ENDPOINT = 'downloads.ctfassets.net';
|
|
193
|
+
const TRANSFORMATIONS_ENDPOINT = 'images.ctfassets.net';
|
|
194
|
+
export const getResolvedImageUrl = (url, params)=>{
|
|
195
|
+
try {
|
|
196
|
+
const urlToParse = url.startsWith('//') ? `https:${url}` : url;
|
|
197
|
+
const parsedUrl = new URL(urlToParse);
|
|
198
|
+
if (parsedUrl.hostname === DOWNLOADS_ENDPOINT) {
|
|
199
|
+
parsedUrl.hostname = TRANSFORMATIONS_ENDPOINT;
|
|
200
|
+
}
|
|
201
|
+
if (params) {
|
|
202
|
+
Object.entries(params).forEach(([key, value])=>{
|
|
203
|
+
if (value !== undefined) {
|
|
204
|
+
parsedUrl.searchParams.set(key, value.toString());
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const result = parsedUrl.toString();
|
|
209
|
+
return url.startsWith('//') ? result.replace(/^https:/, '') : result;
|
|
210
|
+
} catch {
|
|
211
|
+
if (!params) return url;
|
|
212
|
+
const searchParams = new URLSearchParams();
|
|
213
|
+
Object.entries(params).forEach(([key, value])=>{
|
|
214
|
+
if (value !== undefined) {
|
|
215
|
+
searchParams.set(key, value.toString());
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
const queryString = searchParams.toString();
|
|
219
|
+
return queryString ? `${url}?${queryString}` : url;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getEntityStatus } from './entityHelpers';
|
|
1
|
+
import { getEntityStatus, getResolvedImageUrl } from './entityHelpers';
|
|
2
2
|
describe('getEntityStatus', ()=>{
|
|
3
3
|
function createEntity(props) {
|
|
4
4
|
return props;
|
|
@@ -145,3 +145,118 @@ describe('getEntityStatus', ()=>{
|
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
|
+
describe('getResolvedImageUrl', ()=>{
|
|
149
|
+
describe('URL parsing and domain replacement', ()=>{
|
|
150
|
+
test('replaces downloads.ctfassets.net with images.ctfassets.net', ()=>{
|
|
151
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg');
|
|
152
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
153
|
+
});
|
|
154
|
+
test('handles protocol-relative URLs', ()=>{
|
|
155
|
+
const result = getResolvedImageUrl('//downloads.ctfassets.net/space/asset.jpg');
|
|
156
|
+
expect(result).toBe('//images.ctfassets.net/space/asset.jpg');
|
|
157
|
+
});
|
|
158
|
+
test('does not modify URLs that are not from downloads.ctfassets.net', ()=>{
|
|
159
|
+
const result = getResolvedImageUrl('https://example.com/image.jpg');
|
|
160
|
+
expect(result).toBe('https://example.com/image.jpg');
|
|
161
|
+
});
|
|
162
|
+
test('does not modify images.ctfassets.net URLs', ()=>{
|
|
163
|
+
const result = getResolvedImageUrl('https://images.ctfassets.net/space/asset.jpg');
|
|
164
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe('query parameters', ()=>{
|
|
168
|
+
test('adds width parameter', ()=>{
|
|
169
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
170
|
+
width: 100
|
|
171
|
+
});
|
|
172
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?width=100');
|
|
173
|
+
});
|
|
174
|
+
test('adds height parameter', ()=>{
|
|
175
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
176
|
+
height: 200
|
|
177
|
+
});
|
|
178
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?height=200');
|
|
179
|
+
});
|
|
180
|
+
test('adds fit parameter', ()=>{
|
|
181
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
182
|
+
fit: 'thumb'
|
|
183
|
+
});
|
|
184
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?fit=thumb');
|
|
185
|
+
});
|
|
186
|
+
test('adds multiple parameters', ()=>{
|
|
187
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
188
|
+
width: 100,
|
|
189
|
+
height: 200,
|
|
190
|
+
fit: 'thumb'
|
|
191
|
+
});
|
|
192
|
+
expect(result).toContain('width=100');
|
|
193
|
+
expect(result).toContain('height=200');
|
|
194
|
+
expect(result).toContain('fit=thumb');
|
|
195
|
+
expect(result).toContain('images.ctfassets.net');
|
|
196
|
+
});
|
|
197
|
+
test('skips undefined parameters', ()=>{
|
|
198
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
199
|
+
width: 100,
|
|
200
|
+
height: undefined,
|
|
201
|
+
fit: 'thumb'
|
|
202
|
+
});
|
|
203
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg?width=100&fit=thumb');
|
|
204
|
+
});
|
|
205
|
+
test('returns URL without query string when no params provided', ()=>{
|
|
206
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg');
|
|
207
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
208
|
+
});
|
|
209
|
+
test('returns URL without query string when all params are undefined', ()=>{
|
|
210
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg', {
|
|
211
|
+
width: undefined,
|
|
212
|
+
height: undefined,
|
|
213
|
+
fit: undefined
|
|
214
|
+
});
|
|
215
|
+
expect(result).toBe('https://images.ctfassets.net/space/asset.jpg');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
describe('relative URL fallback', ()=>{
|
|
219
|
+
test('returns relative URL unchanged when no params provided', ()=>{
|
|
220
|
+
const result = getResolvedImageUrl('/assets/image.jpg');
|
|
221
|
+
expect(result).toBe('/assets/image.jpg');
|
|
222
|
+
});
|
|
223
|
+
test('appends query params to relative URLs', ()=>{
|
|
224
|
+
const result = getResolvedImageUrl('/assets/image.jpg', {
|
|
225
|
+
width: 100,
|
|
226
|
+
height: 200
|
|
227
|
+
});
|
|
228
|
+
expect(result).toBe('/assets/image.jpg?width=100&height=200');
|
|
229
|
+
});
|
|
230
|
+
test('handles relative URLs with undefined params', ()=>{
|
|
231
|
+
const result = getResolvedImageUrl('/assets/image.jpg', {
|
|
232
|
+
width: 100,
|
|
233
|
+
height: undefined
|
|
234
|
+
});
|
|
235
|
+
expect(result).toBe('/assets/image.jpg?width=100');
|
|
236
|
+
});
|
|
237
|
+
test('returns relative URL unchanged when all params are undefined', ()=>{
|
|
238
|
+
const result = getResolvedImageUrl('/assets/image.jpg', {
|
|
239
|
+
width: undefined,
|
|
240
|
+
height: undefined
|
|
241
|
+
});
|
|
242
|
+
expect(result).toBe('/assets/image.jpg');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
describe('edge cases', ()=>{
|
|
246
|
+
test('preserves existing query parameters', ()=>{
|
|
247
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg?foo=bar', {
|
|
248
|
+
width: 100
|
|
249
|
+
});
|
|
250
|
+
expect(result).toContain('foo=bar');
|
|
251
|
+
expect(result).toContain('width=100');
|
|
252
|
+
});
|
|
253
|
+
test('handles URLs with fragments', ()=>{
|
|
254
|
+
const result = getResolvedImageUrl('https://downloads.ctfassets.net/space/asset.jpg#section', {
|
|
255
|
+
width: 100
|
|
256
|
+
});
|
|
257
|
+
expect(result).toContain('images.ctfassets.net');
|
|
258
|
+
expect(result).toContain('width=100');
|
|
259
|
+
expect(result).toContain('#section');
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
1
2
|
import { Asset, ContentType, ContentTypeField, Entry, File } from '../typesEntity';
|
|
2
3
|
export declare function getFieldValue({
|
|
3
4
|
/**
|
|
@@ -80,4 +81,9 @@ export declare const getEntryImage: ({ entry, contentType, localeCode, }: {
|
|
|
80
81
|
localeCode: string;
|
|
81
82
|
defaultLocaleCode: string;
|
|
82
83
|
}, getAsset: (assetId: string) => Promise<unknown>) => Promise<null | File>;
|
|
84
|
+
export declare const getResolvedImageUrl: (url: string, params?: {
|
|
85
|
+
width?: number;
|
|
86
|
+
height?: number;
|
|
87
|
+
fit?: string;
|
|
88
|
+
}) => string;
|
|
83
89
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/field-editor-shared",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.0-alpha.0",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"registry": "https://npm.pkg.github.com/"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "aae7ea3dcdc2010b1bc8c15a4d6ce3ddba9702e2"
|
|
64
64
|
}
|