@lvce-editor/extension-detail-view 7.13.0 → 7.14.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.
@@ -23,6 +23,7 @@ const CopyLink = 'Copy Link';
23
23
  const Created = 'Created';
24
24
  const Details$1 = 'Details';
25
25
  const Disable$1 = 'Disable';
26
+ const DownloadCount = 'Downloads';
26
27
  const Elements = 'Elements';
27
28
  const EmptyCommandsArray = 'The extension contributes an empty commands array.';
28
29
  const Enable$1 = 'Enable';
@@ -36,6 +37,7 @@ const Identifier = 'Identifier';
36
37
  const ImportTime = 'Import Time: ';
37
38
  const Installation = 'Installation';
38
39
  const InvalidLink = 'Invalid link';
40
+ const ImageCannotBeLoaded = 'Image cannot be loaded';
39
41
  const Issues = 'Issues';
40
42
  const JsonValidation$1 = 'Json Validation';
41
43
  const Label$1 = 'Label';
@@ -51,6 +53,7 @@ const OpenInNewTab = 'Open in New Tab';
51
53
  const ProgrammingLanguages$1 = 'Programming Languages';
52
54
  const PropertyMustBeOfTypeString = 'Property must be a string';
53
55
  const Published = 'Published';
56
+ const Rating = 'Rating';
54
57
  const Repository = 'Repository';
55
58
  const Resources$1 = 'Resources';
56
59
  const RuntimeStatus$1 = 'Runtime Status';
@@ -175,6 +178,9 @@ const id$1 = () => {
175
178
  const name = () => {
176
179
  return i18nString(Name);
177
180
  };
181
+ const imageCannotBeLoaded = () => {
182
+ return i18nString(ImageCannotBeLoaded);
183
+ };
178
184
  const fileExtensions = () => {
179
185
  return i18nString(FileExtensions);
180
186
  };
@@ -255,6 +261,12 @@ const repository = () => {
255
261
  const license = () => {
256
262
  return i18nString(License);
257
263
  };
264
+ const downloadCount = () => {
265
+ return i18nString(DownloadCount);
266
+ };
267
+ const rating = () => {
268
+ return i18nString(Rating);
269
+ };
258
270
  const propertyMustBeOfTypeString = () => {
259
271
  return i18nString(PropertyMustBeOfTypeString);
260
272
  };
@@ -814,6 +826,7 @@ const DefinitionListItemHeading = 'DefinitionListItemHeading';
814
826
  const DefinitionListItemValue = 'DefinitionListItemValue';
815
827
  const ExtensionDetail = 'ExtensionDetail';
816
828
  const ExtensionDetailDescription = 'ExtensionDetailDescription';
829
+ const ExtensionDetailDownloadCount = 'ExtensionDetailDownloadCount';
817
830
  const ExtensionDetailError = 'ExtensionDetailError';
818
831
  const ExtensionDetailErrorCard = 'ExtensionDetailErrorCard';
819
832
  const ExtensionDetailErrorIcon = 'ExtensionDetailErrorIcon';
@@ -823,9 +836,12 @@ const ExtensionDetailHeader = 'ExtensionDetailHeader';
823
836
  const ExtensionDetailHeaderActions = 'ExtensionDetailHeaderActions';
824
837
  const ExtensionDetailHeaderDetails = 'ExtensionDetailHeaderDetails';
825
838
  const ExtensionDetailIcon = 'ExtensionDetailIcon';
839
+ const ExtensionDetailMetadata = 'ExtensionDetailMetadata';
826
840
  const ExtensionDetailName = 'ExtensionDetailName';
827
841
  const ExtensionDetailNameBadge = 'ExtensionDetailNameBadge';
828
842
  const ExtensionDetailPanel = 'ExtensionDetailPanel';
843
+ const ExtensionDetailRating = 'ExtensionDetailRating';
844
+ const ExtensionDetailStatistic = 'ExtensionDetailStatistic';
829
845
  const ExtensionDetailTab = 'ExtensionDetailTab';
830
846
  const ExtensionDetailTabs = 'ExtensionDetailTabs';
831
847
  const ExtensionDetailTabSelected = 'ExtensionDetailTabSelected';
@@ -837,6 +853,7 @@ const FeatureWebView = 'FeatureWebView';
837
853
  const Large$1 = 'Large';
838
854
  const Link$1 = 'Link';
839
855
  const Markdown = 'Markdown';
856
+ const MarkdownImageError = 'MarkdownImageError';
840
857
  const MoreInfo = 'MoreInfo';
841
858
  const MoreInfoEntry = 'MoreInfoEntry';
842
859
  const MoreInfoEntryKey = 'MoreInfoEntryKey';
@@ -2985,6 +3002,24 @@ const HandleResourceLinkClick = 19;
2985
3002
  const HandleMouseEnterEnable = 20;
2986
3003
  const HandleMouseLeaveEnable = 21;
2987
3004
  const HandleHeaderContextMenu = 22;
3005
+ const HandleMarkdownImageError = 23;
3006
+
3007
+ const addMarkdownImageErrorHandler = node => {
3008
+ if (node.type !== Img) {
3009
+ return node;
3010
+ }
3011
+ const {
3012
+ onError,
3013
+ ...rest
3014
+ } = node;
3015
+ return {
3016
+ onError: HandleMarkdownImageError,
3017
+ ...rest
3018
+ };
3019
+ };
3020
+ const addMarkdownImageErrorHandlers = dom => {
3021
+ return dom.map(addMarkdownImageErrorHandler);
3022
+ };
2988
3023
 
2989
3024
  const ActivationEvents = 'ActivationEvents';
2990
3025
  const Changelog = 'Changelog';
@@ -3039,7 +3074,7 @@ const addScrollToTopVirtualDom = dom => {
3039
3074
  };
3040
3075
  const getMarkdownVirtualDom = async (html, options) => {
3041
3076
  string(html);
3042
- const dom = await getVirtualDom(html);
3077
+ const dom = addMarkdownImageErrorHandlers(await getVirtualDom(html));
3043
3078
  if (options?.scrollToTopEnabled) {
3044
3079
  return addScrollToTopVirtualDom(dom);
3045
3080
  }
@@ -3401,10 +3436,67 @@ const toCommandId = key => {
3401
3436
  return key.slice(dotIndex + 1);
3402
3437
  };
3403
3438
  const create$1 = () => {
3439
+ const commandQueues = new Map();
3440
+ const generations = Object.create(null);
3404
3441
  const states = Object.create(null);
3405
3442
  const commandMapRef = {};
3443
+ const getGeneration = uid => generations[uid] || 0;
3444
+ const isCurrentGeneration = (uid, generation) => {
3445
+ return states[uid] !== undefined && getGeneration(uid) === generation;
3446
+ };
3447
+ const updateState = (uid, generation, fallbackState, updater) => {
3448
+ if (!isCurrentGeneration(uid, generation)) {
3449
+ return Promise.resolve(fallbackState);
3450
+ }
3451
+ const current = states[uid];
3452
+ const updatedState = updater(current.newState);
3453
+ if (updatedState !== current.newState) {
3454
+ states[uid] = {
3455
+ newState: updatedState,
3456
+ oldState: current.oldState,
3457
+ scheduledState: updatedState
3458
+ };
3459
+ }
3460
+ return Promise.resolve(updatedState);
3461
+ };
3462
+ const createAsyncCommandContext = (uid, generation) => {
3463
+ let latestState = states[uid].newState;
3464
+ return {
3465
+ getState: () => {
3466
+ if (isCurrentGeneration(uid, generation)) {
3467
+ latestState = states[uid].newState;
3468
+ }
3469
+ return latestState;
3470
+ },
3471
+ updateState: async updater => {
3472
+ latestState = await updateState(uid, generation, latestState, updater);
3473
+ return latestState;
3474
+ }
3475
+ };
3476
+ };
3477
+ const enqueueCommand = async (uid, command) => {
3478
+ const previous = commandQueues.get(uid) || Promise.resolve();
3479
+ const run = async () => {
3480
+ try {
3481
+ await previous;
3482
+ } catch {
3483
+ // The previous caller receives its error; later commands must still run.
3484
+ }
3485
+ await command();
3486
+ };
3487
+ const current = run();
3488
+ commandQueues.set(uid, current);
3489
+ try {
3490
+ await current;
3491
+ } finally {
3492
+ if (commandQueues.get(uid) === current) {
3493
+ commandQueues.delete(uid);
3494
+ }
3495
+ }
3496
+ };
3406
3497
  return {
3407
3498
  clear() {
3499
+ commandQueues.clear();
3408
3500
  for (const key of Object.keys(states)) {
3409
3501
  delete states[key];
3410
3502
  }
@@ -3424,6 +3516,7 @@ const create$1 = () => {
3424
3516
  return diffResult;
3425
3517
  },
3426
3518
  dispose(uid) {
3519
+ commandQueues.delete(uid);
3427
3520
  delete states[uid];
3428
3521
  },
3429
3522
  get(uid) {
@@ -3441,14 +3534,27 @@ const create$1 = () => {
3441
3534
  Object.assign(commandMapRef, commandMap);
3442
3535
  },
3443
3536
  set(uid, oldState, newState, scheduledState) {
3537
+ const current = states[uid];
3538
+ if (!current || oldState === newState && newState !== current.newState) {
3539
+ generations[uid] = getGeneration(uid) + 1;
3540
+ }
3444
3541
  states[uid] = {
3445
3542
  newState,
3446
3543
  oldState,
3447
3544
  scheduledState: scheduledState ?? newState
3448
3545
  };
3449
3546
  },
3547
+ wrapAsyncCommand(fn) {
3548
+ const wrapped = async (uid, ...args) => {
3549
+ const generation = getGeneration(uid);
3550
+ const context = createAsyncCommandContext(uid, generation);
3551
+ await fn(context, ...args);
3552
+ };
3553
+ return wrapped;
3554
+ },
3450
3555
  wrapCommand(fn) {
3451
3556
  const wrapped = async (uid, ...args) => {
3557
+ const generation = getGeneration(uid);
3452
3558
  const {
3453
3559
  newState,
3454
3560
  oldState
@@ -3457,6 +3563,9 @@ const create$1 = () => {
3457
3563
  if (oldState === newerState || newState === newerState) {
3458
3564
  return;
3459
3565
  }
3566
+ if (!isCurrentGeneration(uid, generation)) {
3567
+ return;
3568
+ }
3460
3569
  const latestOld = states[uid];
3461
3570
  const latestNew = {
3462
3571
  ...latestOld.newState,
@@ -3481,6 +3590,7 @@ const create$1 = () => {
3481
3590
  },
3482
3591
  wrapLoadContent(fn) {
3483
3592
  const wrapped = async (uid, ...args) => {
3593
+ const generation = getGeneration(uid);
3484
3594
  const {
3485
3595
  newState,
3486
3596
  oldState
@@ -3495,6 +3605,11 @@ const create$1 = () => {
3495
3605
  error
3496
3606
  };
3497
3607
  }
3608
+ if (!isCurrentGeneration(uid, generation)) {
3609
+ return {
3610
+ error
3611
+ };
3612
+ }
3498
3613
  const latestOld = states[uid];
3499
3614
  const latestNew = {
3500
3615
  ...latestOld.newState,
@@ -3510,6 +3625,51 @@ const create$1 = () => {
3510
3625
  };
3511
3626
  };
3512
3627
  return wrapped;
3628
+ },
3629
+ wrapSerialAsyncCommand(fn) {
3630
+ const wrapped = async (uid, ...args) => {
3631
+ await enqueueCommand(uid, async () => {
3632
+ if (!states[uid]) {
3633
+ return;
3634
+ }
3635
+ const generation = getGeneration(uid);
3636
+ const context = createAsyncCommandContext(uid, generation);
3637
+ await fn(context, ...args);
3638
+ });
3639
+ };
3640
+ return wrapped;
3641
+ },
3642
+ wrapSerialCommand(fn) {
3643
+ const wrapped = async (uid, ...args) => {
3644
+ await enqueueCommand(uid, async () => {
3645
+ if (!states[uid]) {
3646
+ return;
3647
+ }
3648
+ const generation = getGeneration(uid);
3649
+ const {
3650
+ newState,
3651
+ oldState
3652
+ } = states[uid];
3653
+ const newerState = await fn(newState, ...args);
3654
+ if (oldState === newerState || newState === newerState) {
3655
+ return;
3656
+ }
3657
+ if (!isCurrentGeneration(uid, generation)) {
3658
+ return;
3659
+ }
3660
+ const latestOld = states[uid];
3661
+ const latestNew = {
3662
+ ...latestOld.newState,
3663
+ ...newerState
3664
+ };
3665
+ states[uid] = {
3666
+ newState: latestNew,
3667
+ oldState: latestOld.oldState,
3668
+ scheduledState: latestNew
3669
+ };
3670
+ });
3671
+ };
3672
+ return wrapped;
3513
3673
  }
3514
3674
  };
3515
3675
  };
@@ -5298,6 +5458,51 @@ const handleImageContextMenu = async (state, eventX, eventY) => {
5298
5458
  return state;
5299
5459
  };
5300
5460
 
5461
+ const getMarkdownImageErrorVirtualDom = () => {
5462
+ return [{
5463
+ childCount: 1,
5464
+ className: MarkdownImageError,
5465
+ type: Span
5466
+ }, text(imageCannotBeLoaded())];
5467
+ };
5468
+
5469
+ const isMatchingImageSrc = (nodeSrc, failedSrc) => {
5470
+ if (typeof nodeSrc !== 'string' || !failedSrc) {
5471
+ return false;
5472
+ }
5473
+ const normalizedNodeSrc = nodeSrc.startsWith('./') ? nodeSrc.slice(2) : nodeSrc;
5474
+ return nodeSrc === failedSrc || failedSrc.endsWith(nodeSrc) || nodeSrc.endsWith(failedSrc) || failedSrc.endsWith(`/${normalizedNodeSrc}`);
5475
+ };
5476
+ const replaceMarkdownImageWithError = (dom, failedSrc) => {
5477
+ let replaced = false;
5478
+ const newDom = [];
5479
+ for (const node of dom) {
5480
+ if (node.type === Img && isMatchingImageSrc(node.src, failedSrc)) {
5481
+ newDom.push(...getMarkdownImageErrorVirtualDom());
5482
+ replaced = true;
5483
+ } else {
5484
+ newDom.push(node);
5485
+ }
5486
+ }
5487
+ if (!replaced) {
5488
+ return dom;
5489
+ }
5490
+ return newDom;
5491
+ };
5492
+
5493
+ const handleMarkdownImageError = (state, failedSrc) => {
5494
+ const detailsVirtualDom = replaceMarkdownImageWithError(state.detailsVirtualDom, failedSrc);
5495
+ const changelogVirtualDom = replaceMarkdownImageWithError(state.changelogVirtualDom, failedSrc);
5496
+ if (detailsVirtualDom === state.detailsVirtualDom && changelogVirtualDom === state.changelogVirtualDom) {
5497
+ return state;
5498
+ }
5499
+ return {
5500
+ ...state,
5501
+ changelogVirtualDom,
5502
+ detailsVirtualDom
5503
+ };
5504
+ };
5505
+
5301
5506
  const previewColorTheme = async colorThemeId => {
5302
5507
  await invoke$1('ColorTheme.previewColorTheme', colorThemeId);
5303
5508
  };
@@ -6360,6 +6565,24 @@ const getExtensionDetailIconVirtualDom = iconSrc => {
6360
6565
  };
6361
6566
  };
6362
6567
 
6568
+ const getStatisticVirtualDom = (label, value, className) => {
6569
+ const accessibleLabel = `${label}: ${value}`;
6570
+ return [{
6571
+ ariaLabel: accessibleLabel,
6572
+ childCount: 1,
6573
+ className: mergeClassNames(ExtensionDetailStatistic, className),
6574
+ title: accessibleLabel,
6575
+ type: Span
6576
+ }, text(value)];
6577
+ };
6578
+ const getExtensionDetailMetadataVirtualDom = (downloadCount$1, rating$1) => {
6579
+ return [{
6580
+ childCount: 2,
6581
+ className: ExtensionDetailMetadata,
6582
+ type: Div
6583
+ }, ...getStatisticVirtualDom(downloadCount(), downloadCount$1, ExtensionDetailDownloadCount), ...getStatisticVirtualDom(rating(), rating$1, ExtensionDetailRating)];
6584
+ };
6585
+
6363
6586
  const getNameBadgeVirtualDom = badge => {
6364
6587
  if (!badge) {
6365
6588
  return [];
@@ -6395,17 +6618,17 @@ const getExtensionDetailNameVirtualDom = (name, badge) => {
6395
6618
  return getExtensionDetailNameDefaultVirtualDom(name);
6396
6619
  };
6397
6620
 
6398
- const getExtensionDetailHeaderVirtualDom = (name, iconSrc, description, badge, buttonDefs, settingsButtonEnabled) => {
6621
+ const getExtensionDetailHeaderVirtualDom = (name, iconSrc, description, badge, buttonDefs, settingsButtonEnabled, downloadCount = 'n/a', rating = 'n/a') => {
6399
6622
  const dom = [{
6400
6623
  childCount: 2,
6401
6624
  className: ExtensionDetailHeader,
6402
6625
  type: Div
6403
6626
  }, getExtensionDetailIconVirtualDom(iconSrc), {
6404
- childCount: 3,
6627
+ childCount: 4,
6405
6628
  className: ExtensionDetailHeaderDetails,
6406
6629
  onContextMenu: HandleHeaderContextMenu,
6407
6630
  type: Div
6408
- }, ...getExtensionDetailNameVirtualDom(name, badge), ...getExtensionDetailDescriptionVirtualDom(description), ...getExtensionDetailHeaderActionsVirtualDom(buttonDefs, settingsButtonEnabled)];
6631
+ }, ...getExtensionDetailNameVirtualDom(name, badge), ...getExtensionDetailDescriptionVirtualDom(description), ...getExtensionDetailMetadataVirtualDom(downloadCount, rating), ...getExtensionDetailHeaderActionsVirtualDom(buttonDefs, settingsButtonEnabled)];
6409
6632
  return dom;
6410
6633
  };
6411
6634
 
@@ -6475,9 +6698,11 @@ const getExtensionDetailVirtualDom = (newState, selectedTab) => {
6475
6698
  changelogVirtualDom,
6476
6699
  description,
6477
6700
  detailsVirtualDom,
6701
+ downloadCount,
6478
6702
  focusedTabIndex,
6479
6703
  iconSrc,
6480
6704
  name,
6705
+ rating,
6481
6706
  resources,
6482
6707
  scrollToTopButtonEnabled,
6483
6708
  settingsButtonEnabled,
@@ -6491,7 +6716,7 @@ const getExtensionDetailVirtualDom = (newState, selectedTab) => {
6491
6716
  childCount: 3,
6492
6717
  className: mergeClassNames(Viewlet, ExtensionDetail, sizeClass),
6493
6718
  type: Div
6494
- }, ...getExtensionDetailHeaderVirtualDom(name, iconSrc, description, badge, buttons, settingsButtonEnabled), ...getTabsVirtualDom(tabs, focusedTabIndex), ...getExtensionDetailContentVirtualDom(detailsVirtualDom, selectedTab, width, scrollToTopButtonEnabled, categories, resources, showAdditionalDetailsBreakpoint, changelogVirtualDom, newState)];
6719
+ }, ...getExtensionDetailHeaderVirtualDom(name, iconSrc, description, badge, buttons, settingsButtonEnabled, downloadCount, rating), ...getTabsVirtualDom(tabs, focusedTabIndex), ...getExtensionDetailContentVirtualDom(detailsVirtualDom, selectedTab, width, scrollToTopButtonEnabled, categories, resources, showAdditionalDetailsBreakpoint, changelogVirtualDom, newState)];
6495
6720
  return dom;
6496
6721
  };
6497
6722
 
@@ -6633,6 +6858,9 @@ const renderEventListeners = () => {
6633
6858
  name: HandleHeaderContextMenu,
6634
6859
  params: ['handleHeaderContextMenu'],
6635
6860
  preventDefault: true
6861
+ }, {
6862
+ name: HandleMarkdownImageError,
6863
+ params: ['handleMarkdownImageError', 'event.currentTarget.src']
6636
6864
  }, {
6637
6865
  name: HandleReadmeScroll,
6638
6866
  params: ['handleScroll', 'event.target.scrollTop', User],
@@ -6688,6 +6916,10 @@ const renderEventListeners = () => {
6688
6916
  }];
6689
6917
  };
6690
6918
 
6919
+ const renderTitle = state => {
6920
+ return state.name;
6921
+ };
6922
+
6691
6923
  const resize = (state, dimensions) => {
6692
6924
  const padding = getPadding(dimensions.width);
6693
6925
  const sideBarWidth = getSideBarWidth(dimensions.width);
@@ -6748,6 +6980,7 @@ const commandMap = {
6748
6980
  'ExtensionDetail.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
6749
6981
  'ExtensionDetail.handleIconError': wrapCommand(handleIconError),
6750
6982
  'ExtensionDetail.handleImageContextMenu': wrapCommand(handleImageContextMenu),
6983
+ 'ExtensionDetail.handleMarkdownImageError': wrapCommand(handleMarkdownImageError),
6751
6984
  'ExtensionDetail.handleMouseEnterEnable': wrapCommand(handleMouseEnterEnable),
6752
6985
  'ExtensionDetail.handleMouseLeaveEnable': wrapCommand(handleMouseLeaveEnable),
6753
6986
  'ExtensionDetail.handleReadmeClick': wrapCommand(handleReadmeClick),
@@ -6766,6 +6999,7 @@ const commandMap = {
6766
6999
  'ExtensionDetail.openImageInNewTab': wrapCommand(openImageInNewTab),
6767
7000
  'ExtensionDetail.render2': render2,
6768
7001
  'ExtensionDetail.renderEventListeners': renderEventListeners,
7002
+ 'ExtensionDetail.renderTitle': wrapGetter(renderTitle),
6769
7003
  'ExtensionDetail.resetGithubApiMock': wrapCommand(handleResetGithubApiMock),
6770
7004
  'ExtensionDetail.resize': wrapCommand(resize),
6771
7005
  'ExtensionDetail.saveState': wrapGetter(saveState),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-detail-view",
3
- "version": "7.13.0",
3
+ "version": "7.14.0",
4
4
  "description": "Extension Detail View Worker",
5
5
  "repository": {
6
6
  "type": "git",