@lvce-editor/extension-detail-view 3.7.0 → 3.8.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.
@@ -991,43 +991,49 @@ const getDisplaySize = size => {
991
991
  });
992
992
  };
993
993
 
994
+ const A$1 = 53;
995
+ const Abbr$1 = 54;
996
+ const Article$1 = 27;
997
+ const Aside$1 = 28;
998
+ const Br$1 = 55;
994
999
  const Button = 1;
1000
+ const Cite$1 = 56;
1001
+ const Data$1 = 57;
1002
+ const Dd$1 = 43;
995
1003
  const Div$1 = 4;
1004
+ const Dl$1 = 44;
1005
+ const Figcaption$1 = 45;
1006
+ const Figure$1 = 46;
1007
+ const Footer$1 = 29;
996
1008
  const H1$1 = 5;
997
- const Span$1 = 8;
998
- const Text$1 = 12;
999
- const Img$1 = 17;
1000
1009
  const H2$1 = 22;
1001
1010
  const H3$1 = 23;
1002
1011
  const H4$1 = 24;
1003
1012
  const H5$1 = 25;
1004
- const Article$1 = 27;
1005
- const Aside$1 = 28;
1006
- const Footer$1 = 29;
1007
1013
  const Header$1 = 30;
1008
- const Nav$1 = 40;
1009
- const Section$1 = 41;
1010
- const Search$1 = 42;
1011
- const Dd$1 = 43;
1012
- const Dl$1 = 44;
1013
- const Figcaption$1 = 45;
1014
- const Figure$1 = 46;
1015
1014
  const Hr$1 = 47;
1015
+ const Img$1 = 17;
1016
1016
  const Li$1 = 48;
1017
+ const Nav$1 = 40;
1017
1018
  const Ol$1 = 49;
1018
1019
  const P$1 = 50;
1019
1020
  const Pre$1 = 51;
1020
- const A$1 = 53;
1021
- const Abbr$1 = 54;
1022
- const Br$1 = 55;
1023
- const Cite$1 = 56;
1024
- const Data$1 = 57;
1025
- const Time$1 = 58;
1021
+ const Search$1 = 42;
1022
+ const Section$1 = 41;
1023
+ const Span$1 = 8;
1024
+ const Table = 9;
1025
+ const TBody = 10;
1026
+ const Td = 11;
1027
+ const Text$2 = 12;
1026
1028
  const Tfoot$1 = 59;
1029
+ const Th = 13;
1030
+ const THead = 14;
1031
+ const Time$1 = 58;
1032
+ const Tr = 15;
1027
1033
 
1028
1034
  const text = data => {
1029
1035
  return {
1030
- type: Text$1,
1036
+ type: Text$2,
1031
1037
  text: data,
1032
1038
  childCount: 0
1033
1039
  };
@@ -1329,7 +1335,7 @@ const Doctype = 16;
1329
1335
  const StartCommentDashes = 17;
1330
1336
  const Comment = 18;
1331
1337
  const EndCommentTag = 19;
1332
- const Text = 20;
1338
+ const Text$1 = 20;
1333
1339
  const CommentStart = 21;
1334
1340
 
1335
1341
  const isSelfClosingTag = tag => {
@@ -1412,7 +1418,7 @@ const tokenizeHtml = text => {
1412
1418
  token = Content;
1413
1419
  state = State.TopLevelContent;
1414
1420
  } else if (next = part.match(RE_ANGLE_BRACKET_OPEN)) {
1415
- token = Text;
1421
+ token = Text$1;
1416
1422
  state = State.TopLevelContent;
1417
1423
  } else {
1418
1424
  throw new UnexpectedTokenError();
@@ -1435,7 +1441,7 @@ const tokenizeHtml = text => {
1435
1441
  token = ExclamationMark;
1436
1442
  state = State.AfterExclamationMark;
1437
1443
  } else if (next = part.match(RE_ANY_TEXT)) {
1438
- token = Text;
1444
+ token = Text$1;
1439
1445
  state = State.TopLevelContent;
1440
1446
  } else {
1441
1447
  text.slice(index); // ?
@@ -1474,7 +1480,7 @@ const tokenizeHtml = text => {
1474
1480
  token = WhitespaceInsideOpeningTag;
1475
1481
  state = State.InsideOpeningTagAfterWhitespace;
1476
1482
  } else if (next = part.match(RE_TAG_TEXT)) {
1477
- token = Text;
1483
+ token = Text$1;
1478
1484
  state = State.TopLevelContent;
1479
1485
  } else {
1480
1486
  throw new UnexpectedTokenError();
@@ -1724,30 +1730,233 @@ const getDetailsVirtualDom = (sanitizedReadmeHtml, displaySize, extensionId, ext
1724
1730
  return dom;
1725
1731
  };
1726
1732
 
1727
- const getFeatureListItemVirtualDom = feature => {
1733
+ const Text = 1;
1734
+ const Code = 2;
1735
+
1736
+ const getCommandTableEntry = command => {
1737
+ // TODO watch out for command being null/undefined/number/string/array
1728
1738
  const {
1729
- label,
1730
- selected,
1731
- id
1732
- } = feature;
1733
- const className = selected ? 'Feature FeatureSelected' : Feature;
1739
+ id,
1740
+ label
1741
+ } = command;
1734
1742
  return [{
1735
- // TODO use role list item or tab
1736
- type: Button,
1737
- name: id,
1738
- className,
1743
+ type: Code,
1744
+ value: id
1745
+ }, {
1746
+ type: Text,
1747
+ value: label
1748
+ }];
1749
+ };
1750
+ const getCommandTableEntries = extension => {
1751
+ const commands = extension.commands || [];
1752
+ const rows = commands.map(getCommandTableEntry);
1753
+ return {
1754
+ headings: ['ID', 'Label'],
1755
+ rows
1756
+ };
1757
+ };
1758
+
1759
+ const getCellCodeVirtualDom = value => {
1760
+ return [{
1761
+ type: Td,
1739
1762
  childCount: 1
1740
- }, text(label)];
1763
+ }, {
1764
+ type: Div$1,
1765
+ // TODO use code tag
1766
+ childCount: 1
1767
+ }, text(value)];
1741
1768
  };
1742
1769
 
1743
- const getFeatureListVirtualDom = features => {
1770
+ const getCellTextVirtualDom = value => {
1771
+ return [{
1772
+ type: Td,
1773
+ childCount: 1
1774
+ }, text(value)];
1775
+ };
1776
+
1777
+ const getCellVirtualDom = entry => {
1778
+ const {
1779
+ value,
1780
+ type
1781
+ } = entry;
1782
+ switch (type) {
1783
+ case Code:
1784
+ return getCellCodeVirtualDom(value);
1785
+ default:
1786
+ return getCellTextVirtualDom(value);
1787
+ }
1788
+ };
1789
+
1790
+ const getTableHeadingVirtualDom = heading => {
1791
+ return [{
1792
+ type: Th,
1793
+ childCount: 1
1794
+ }, text(heading)];
1795
+ };
1796
+
1797
+ const getTableRowVirtualDom = entries => {
1798
+ return [{
1799
+ type: Tr,
1800
+ childCount: entries.length
1801
+ }, ...entries.flatMap(getCellVirtualDom)];
1802
+ };
1803
+ const getTableVirtualDom = tableInfo => {
1804
+ const {
1805
+ headings,
1806
+ rows
1807
+ } = tableInfo;
1808
+ return [{
1809
+ type: Table,
1810
+ className: 'Table',
1811
+ childCount: 2
1812
+ }, {
1813
+ type: THead,
1814
+ childCount: 1
1815
+ }, {
1816
+ type: Tr,
1817
+ childCount: headings.length
1818
+ }, ...headings.flatMap(getTableHeadingVirtualDom), {
1819
+ type: TBody,
1820
+ childCount: rows.length
1821
+ }, ...rows.flatMap(getTableRowVirtualDom)];
1822
+ };
1823
+
1824
+ const getFeatureCommandsVirtualDom = extension => {
1825
+ // TODO use i18n strings
1826
+ const heading = 'Commands';
1827
+ const tableInfo = getCommandTableEntries(extension);
1744
1828
  return [{
1745
- // TODO use either list or tabs role
1746
1829
  type: Div$1,
1747
- className: FeaturesList,
1748
- childCount: features.length,
1749
- onClick: HandleFeaturesClick
1750
- }, ...features.flatMap(getFeatureListItemVirtualDom)];
1830
+ className: 'FeatureCommands',
1831
+ childCount: 2
1832
+ }, {
1833
+ type: H1$1,
1834
+ childCount: 1
1835
+ }, text(heading), ...getTableVirtualDom(tableInfo)];
1836
+ };
1837
+
1838
+ const emptyObject = {};
1839
+ const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1840
+ const i18nString = (key, placeholders = emptyObject) => {
1841
+ if (placeholders === emptyObject) {
1842
+ return key;
1843
+ }
1844
+ const replacer = (match, rest) => {
1845
+ return placeholders[rest];
1846
+ };
1847
+ return key.replaceAll(RE_PLACEHOLDER, replacer);
1848
+ };
1849
+
1850
+ const Copy = 'Copy';
1851
+ const OpenInNewTab = 'Open in New Tab';
1852
+ const OpenImageInNewTab = 'Open Image in New Tab';
1853
+ const SaveImageAs = 'Save Image as';
1854
+ const FileMatch = 'File Match';
1855
+ const Schema = 'Schema';
1856
+
1857
+ const copy = () => {
1858
+ return i18nString(Copy);
1859
+ };
1860
+ const openInNewTab = () => {
1861
+ return i18nString(OpenInNewTab);
1862
+ };
1863
+ const openImageInNewTab = () => {
1864
+ return i18nString(OpenImageInNewTab);
1865
+ };
1866
+ const saveImageAs = () => {
1867
+ return i18nString(SaveImageAs);
1868
+ };
1869
+ const fileMatch = () => {
1870
+ return i18nString(FileMatch);
1871
+ };
1872
+ const schema = () => {
1873
+ return i18nString(Schema);
1874
+ };
1875
+
1876
+ const getJsonValidationTableEntry = validation => {
1877
+ const {
1878
+ fileMatch,
1879
+ schema
1880
+ } = validation;
1881
+ return [{
1882
+ type: Code,
1883
+ value: fileMatch
1884
+ }, {
1885
+ type: Code,
1886
+ value: schema
1887
+ }];
1888
+ };
1889
+ const getJsonValidationTableEntries = extension => {
1890
+ const validations = extension.jsonValidation || [];
1891
+ const rows = validations.map(getJsonValidationTableEntry);
1892
+ return {
1893
+ headings: [fileMatch(), schema()],
1894
+ rows
1895
+ };
1896
+ };
1897
+
1898
+ const getFeatureJsonValidationVirtualDom = extension => {
1899
+ // TODO use i18n
1900
+ const heading = 'Json Validation';
1901
+ const tableInfo = getJsonValidationTableEntries(extension);
1902
+ return [{
1903
+ type: Div$1,
1904
+ className: 'FeatureJsonValidation',
1905
+ childCount: 2
1906
+ }, {
1907
+ type: H1$1,
1908
+ childCount: 1
1909
+ }, text(heading), ...getTableVirtualDom(tableInfo)];
1910
+ };
1911
+
1912
+ const getFeatureProgrammingLanguagesVirtualDom = () => {
1913
+ // TODO use i18n string
1914
+ const heading = 'Programming Languages';
1915
+ // TODO
1916
+ return [{
1917
+ type: Div$1,
1918
+ className: 'FeatureProgrammingLanguages',
1919
+ childCount: 1
1920
+ }, {
1921
+ type: H1$1,
1922
+ childCount: 1
1923
+ }, text(heading)];
1924
+ };
1925
+
1926
+ const getSettingsTableEntry = setting => {
1927
+ const {
1928
+ id,
1929
+ label
1930
+ } = setting;
1931
+ // TODO watch out for null/undefined/number/string/array
1932
+ return [{
1933
+ type: Text,
1934
+ value: id
1935
+ }, {
1936
+ type: Text,
1937
+ value: label
1938
+ }];
1939
+ };
1940
+ const getSettingsTableEntries = extension => {
1941
+ const settings = extension.settings || [];
1942
+ const rows = settings.map(getSettingsTableEntry);
1943
+ return {
1944
+ headings: ['ID', 'Label'],
1945
+ rows
1946
+ };
1947
+ };
1948
+
1949
+ const getFeatureSettingsVirtualDom = extension => {
1950
+ const heading = 'Settings';
1951
+ const tableInfo = getSettingsTableEntries(extension);
1952
+ return [{
1953
+ type: Div$1,
1954
+ className: 'FeatureSettings',
1955
+ childCount: 2
1956
+ }, {
1957
+ type: H1$1,
1958
+ childCount: 1
1959
+ }, text(heading), ...getTableVirtualDom(tableInfo)];
1751
1960
  };
1752
1961
 
1753
1962
  const getFeatureThemesVirtualDom = themesHtml => {
@@ -1768,7 +1977,63 @@ const getFeatureThemesVirtualDom = themesHtml => {
1768
1977
  }, ...markdownDom];
1769
1978
  };
1770
1979
 
1771
- const getFeaturesVirtualDom = (features, themesHtml) => {
1980
+ const Changelog = 'Changelog';
1981
+ const Commands = 'Commands';
1982
+ const Details = 'Details';
1983
+ const Features = 'Features';
1984
+ const JsonValidation = 'JsonValidation';
1985
+ const ProgrammingLanguages = 'ProgrammingLanguages';
1986
+ const Settings = 'Settings';
1987
+ const Theme = 'Theme';
1988
+
1989
+ const getFeatureContentVirtualDom = (features, themesHtml, selectedFeature, extension) => {
1990
+ switch (selectedFeature) {
1991
+ case Theme:
1992
+ return getFeatureThemesVirtualDom(themesHtml);
1993
+ case Commands:
1994
+ return getFeatureCommandsVirtualDom(extension);
1995
+ case JsonValidation:
1996
+ return getFeatureJsonValidationVirtualDom(extension);
1997
+ case ProgrammingLanguages:
1998
+ return getFeatureProgrammingLanguagesVirtualDom();
1999
+ case Settings:
2000
+ return getFeatureSettingsVirtualDom(extension);
2001
+ default:
2002
+ return [{
2003
+ type: Div$1,
2004
+ className: 'FeatureContent',
2005
+ childCount: 1
2006
+ }, text('Not Implemented')];
2007
+ }
2008
+ };
2009
+
2010
+ const getFeatureListItemVirtualDom = feature => {
2011
+ const {
2012
+ label,
2013
+ selected,
2014
+ id
2015
+ } = feature;
2016
+ const className = selected ? 'Feature FeatureSelected' : Feature;
2017
+ return [{
2018
+ // TODO use role list item or tab
2019
+ type: Button,
2020
+ name: id,
2021
+ className,
2022
+ childCount: 1
2023
+ }, text(label)];
2024
+ };
2025
+
2026
+ const getFeatureListVirtualDom = features => {
2027
+ return [{
2028
+ // TODO use either list or tabs role
2029
+ type: Div$1,
2030
+ className: FeaturesList,
2031
+ childCount: features.length,
2032
+ onClick: HandleFeaturesClick
2033
+ }, ...features.flatMap(getFeatureListItemVirtualDom)];
2034
+ };
2035
+
2036
+ const getFeaturesVirtualDom = (features, themesHtml, selectedFeature, extension) => {
1772
2037
  return [{
1773
2038
  type: Div$1,
1774
2039
  className: Features$1,
@@ -1777,24 +2042,15 @@ const getFeaturesVirtualDom = (features, themesHtml) => {
1777
2042
  type: Div$1,
1778
2043
  className: 'Sash SashVertical',
1779
2044
  childCount: 0
1780
- }, ...getFeatureThemesVirtualDom(themesHtml)];
2045
+ }, ...getFeatureContentVirtualDom(features, themesHtml, selectedFeature, extension)];
1781
2046
  };
1782
2047
 
1783
- const Changelog = 'Changelog';
1784
- const Commands = 'Commands';
1785
- const Details = 'Details';
1786
- const Features = 'Features';
1787
- const JsonValidation = 'JsonValidation';
1788
- const ProgrammingLanguages = 'ProgrammingLanguages';
1789
- const Settings = 'Settings';
1790
- const Theme = 'Theme';
1791
-
1792
- const getExtensionDetailContentVirtualDom = (sanitizedReadmeHtml, themesHtml, selectedTab, features, displaySize, extensionId, extensionVersion) => {
2048
+ const getExtensionDetailContentVirtualDom = (sanitizedReadmeHtml, themesHtml, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, extension) => {
1793
2049
  switch (selectedTab) {
1794
2050
  case Details:
1795
2051
  return getDetailsVirtualDom(sanitizedReadmeHtml, displaySize, extensionId, extensionVersion);
1796
2052
  case Features:
1797
- return getFeaturesVirtualDom(features, themesHtml);
2053
+ return getFeaturesVirtualDom(features, themesHtml, selectedFeature, extension);
1798
2054
  case Changelog:
1799
2055
  return getChangelogVirtualDom();
1800
2056
  default:
@@ -1835,27 +2091,30 @@ const getExtensionDetailHeaderVirtualDom = extensionDetail => {
1835
2091
  return dom;
1836
2092
  };
1837
2093
 
1838
- const getFeatures = () => {
2094
+ const getFeatures = selectedFeature => {
2095
+ if (!selectedFeature) {
2096
+ selectedFeature = Theme;
2097
+ }
1839
2098
  const features = [{
1840
2099
  id: Theme,
1841
2100
  label: 'Theme',
1842
- selected: true
2101
+ selected: selectedFeature === Theme
1843
2102
  }, {
1844
2103
  id: Commands,
1845
2104
  label: 'Commands',
1846
- selected: false
2105
+ selected: selectedFeature === Commands
1847
2106
  }, {
1848
2107
  id: JsonValidation,
1849
2108
  label: 'Json Validation',
1850
- selected: false
2109
+ selected: selectedFeature === JsonValidation
1851
2110
  }, {
1852
2111
  id: ProgrammingLanguages,
1853
2112
  label: 'Programming Languages',
1854
- selected: false
2113
+ selected: selectedFeature === ProgrammingLanguages
1855
2114
  }, {
1856
2115
  id: Settings,
1857
2116
  label: 'Settings',
1858
- selected: false
2117
+ selected: selectedFeature === Settings
1859
2118
  }];
1860
2119
  return features;
1861
2120
  };
@@ -1918,51 +2177,28 @@ const getTabsVirtualDom = tabs => {
1918
2177
  };
1919
2178
 
1920
2179
  const getExtensionDetailVirtualDom = (extensionDetail, sanitizedReadmeHtml, selectedTab, newState) => {
2180
+ // TODO move this to view model so that rendering occurs like
2181
+ // 1. state
2182
+ // 2. view model
2183
+ // 3. virtual dom
2184
+ // 4. dom
1921
2185
  const themesHtml = newState?.selectedFeatureMarkdownDom || '';
1922
- const features = newState?.features || getFeatures();
2186
+ const selectedFeature = newState?.selectedFeature || '';
2187
+ const features = newState?.features || getFeatures(selectedFeature);
1923
2188
  const size = newState.folderSize || 0;
1924
2189
  const extensionId = newState?.extension?.id || 'n/a';
1925
2190
  const extensionVersion = newState?.extension?.version || 'n/a';
2191
+ const extension = newState?.extension || {};
1926
2192
  const displaySize = getDisplaySize(size);
1927
2193
  const tabs = getTabs(selectedTab);
1928
2194
  const dom = [{
1929
2195
  type: Div$1,
1930
2196
  className: mergeClassNames(Viewlet, ExtensionDetail),
1931
2197
  childCount: 3
1932
- }, ...getExtensionDetailHeaderVirtualDom(extensionDetail), ...getTabsVirtualDom(tabs), ...getExtensionDetailContentVirtualDom(sanitizedReadmeHtml, themesHtml, selectedTab, features, displaySize, extensionId, extensionVersion)];
2198
+ }, ...getExtensionDetailHeaderVirtualDom(extensionDetail), ...getTabsVirtualDom(tabs), ...getExtensionDetailContentVirtualDom(sanitizedReadmeHtml, themesHtml, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, extension)];
1933
2199
  return dom;
1934
2200
  };
1935
2201
 
1936
- const emptyObject = {};
1937
- const RE_PLACEHOLDER = /\{(PH\d+)\}/g;
1938
- const i18nString = (key, placeholders = emptyObject) => {
1939
- if (placeholders === emptyObject) {
1940
- return key;
1941
- }
1942
- const replacer = (match, rest) => {
1943
- return placeholders[rest];
1944
- };
1945
- return key.replaceAll(RE_PLACEHOLDER, replacer);
1946
- };
1947
-
1948
- const Copy = 'Copy';
1949
- const OpenInNewTab = 'Open in New Tab';
1950
- const OpenImageInNewTab = 'Open Image in New Tab';
1951
- const SaveImageAs = 'Save Image as';
1952
-
1953
- const copy = () => {
1954
- return i18nString(Copy);
1955
- };
1956
- const openInNewTab = () => {
1957
- return i18nString(OpenInNewTab);
1958
- };
1959
- const openImageInNewTab = () => {
1960
- return i18nString(OpenImageInNewTab);
1961
- };
1962
- const saveImageAs = () => {
1963
- return i18nString(SaveImageAs);
1964
- };
1965
-
1966
2202
  const None = 0;
1967
2203
 
1968
2204
  const getCopyMenuEntry = () => ({
@@ -4716,7 +4952,8 @@ const getAllExtensions = async platform => {
4716
4952
  }
4717
4953
  return invoke('ExtensionManagement.getAllExtensions');
4718
4954
  };
4719
- const getExtension = async (id, platform) => {
4955
+ const getExtension$1 = async (id, platform) => {
4956
+ // TODO only ask one extension from renderer worker instead of all
4720
4957
  const allExtensions = await getAllExtensions(platform);
4721
4958
  for (const extension of allExtensions) {
4722
4959
  if (extension.id === id) {
@@ -4726,6 +4963,17 @@ const getExtension = async (id, platform) => {
4726
4963
  return undefined;
4727
4964
  };
4728
4965
 
4966
+ const getExtensionNew = async id => {
4967
+ return invoke('ExtensionManagement.getExtension', id);
4968
+ };
4969
+ const getExtension = async (id, platform) => {
4970
+ try {
4971
+ return await getExtensionNew(id);
4972
+ } catch {
4973
+ return getExtension$1(id, platform);
4974
+ }
4975
+ };
4976
+
4729
4977
  const getRemoteSrc = uri => {
4730
4978
  const src = `/remote${uri}`;
4731
4979
  return src;
@@ -4749,6 +4997,13 @@ const getFolderSize = async uri => {
4749
4997
  }
4750
4998
  };
4751
4999
 
5000
+ const getSavedSelectedFeature = savedState => {
5001
+ if (savedState && typeof savedState === 'object' && 'selectedFeature' in savedState && typeof savedState.selectedFeature === 'string') {
5002
+ return savedState.selectedFeature;
5003
+ }
5004
+ return Details;
5005
+ };
5006
+
4752
5007
  const getSavedSelectedTab = savedState => {
4753
5008
  if (savedState && typeof savedState === 'object' && 'selectedTab' in savedState && typeof savedState.selectedTab === 'string') {
4754
5009
  return savedState.selectedTab;
@@ -4817,7 +5072,8 @@ const loadContent = async (state, platform, savedState) => {
4817
5072
  const name = getName(extension);
4818
5073
  const size = getViewletSize(width);
4819
5074
  const selectedTab = getSavedSelectedTab(savedState);
4820
- const features = getFeatures();
5075
+ const selectedFeature = getSavedSelectedFeature(savedState);
5076
+ const features = getFeatures(selectedFeature);
4821
5077
  const folderSize = await getFolderSize(extension.uri);
4822
5078
  const entries = [{
4823
5079
  key: 'Identifier',
@@ -4874,10 +5130,12 @@ const loadContent = async (state, platform, savedState) => {
4874
5130
 
4875
5131
  const saveState = state => {
4876
5132
  const {
4877
- selectedTab
5133
+ selectedTab,
5134
+ selectedFeature
4878
5135
  } = state;
4879
5136
  return {
4880
- selectedTab
5137
+ selectedTab,
5138
+ selectedFeature
4881
5139
  };
4882
5140
  };
4883
5141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-detail-view",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "Extension Detail View Worker",
5
5
  "keywords": [],
6
6
  "license": "MIT",