@shgysk8zer0/importmap 1.2.5 → 1.3.1

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/CHANGELOG.md CHANGED
@@ -6,6 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [v1.3.1] - 2023-11-20
10
+
11
+ ### Changed
12
+ - Update imports
13
+
14
+ ### Fixed
15
+ - Convert JSON/YAML paths to `file:` URLs
16
+
17
+ ## [v1.3.0] - 2023-10-31
18
+
19
+ ### Added
20
+ - Auto-update from `unpkg.com` (no Firebase updates) by running `update.js`
21
+
22
+ ### Changed
23
+ - Importmap is now stored in `importmap.json`
24
+ - Update `exports`, etc.
25
+
26
+ ### Removed
27
+ - No more `versions.js` - It is directly in the JSON
28
+
9
29
  ## [v1.2.5] - 2023-09-08
10
30
 
11
31
  ### Fixed
package/cli.mjs CHANGED
@@ -5,7 +5,8 @@ import { readJSONFile, writeJSONFile } from '@shgysk8zer0/npm-utils/json';
5
5
  import { readYAMLFile, writeYAMLFile } from '@shgysk8zer0/npm-utils/yaml';
6
6
  import { program } from 'commander';
7
7
  import { extname } from 'node:path';
8
- import { importmap } from './index.js';
8
+ import { importmap } from './index.mjs';
9
+ import { updateImportMap } from './html.js';
9
10
 
10
11
  function guessFileType(file) {
11
12
  const ext = extname(file).toLowerCase();
@@ -18,6 +19,9 @@ function guessFileType(file) {
18
19
  case '.json':
19
20
  return 'json';
20
21
 
22
+ case '.html':
23
+ return 'html';
24
+
21
25
  default:
22
26
  throw new TypeError(`"${ext}" is not a supported file extension for file ${file}.`);
23
27
  }
@@ -35,7 +39,7 @@ async function parse(file, { encoding, signal } = {}) {
35
39
  }
36
40
 
37
41
  async function init() {
38
- const { version: VERSION } = await readJSONFile(new URL('./package.json', import.meta.url).pathname);
42
+ const { version: VERSION } = await readJSONFile(new URL('./package.json', import.meta.url));
39
43
 
40
44
  program
41
45
  .name('importmap-utils')
@@ -54,7 +58,6 @@ async function init() {
54
58
  }
55
59
 
56
60
  init().then(async ({ opts: { input, encoding, format, output }}) => {
57
- console.log({ input, encoding, format, output });
58
61
  const mod = typeof input === 'string'
59
62
  ? await parse(input, { encoding }).then(({ imports, scope = {}, ...rest }) => ({
60
63
  ...rest,
@@ -73,5 +76,9 @@ init().then(async ({ opts: { input, encoding, format, output }}) => {
73
76
  case 'yaml':
74
77
  await writeYAMLFile(output, mod, { encoding });
75
78
  break;
79
+
80
+ case 'html':
81
+ await updateImportMap(output, { spaces: null });
82
+ break;
76
83
  }
77
84
  });
package/importmap.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "imports": {
3
+ "@shgysk8zer0/kazoo/": "https://unpkg.com/@shgysk8zer0/kazoo@0.2.7/",
4
+ "@shgysk8zer0/konami": "https://unpkg.com/@shgysk8zer0/konami@1.1.1/konami.js",
5
+ "@shgysk8zer0/polyfills": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/all.min.js",
6
+ "@shgysk8zer0/polyfills/": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/",
7
+ "@shgysk8zer0/jswaggersheets": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/swagger.js",
8
+ "@shgysk8zer0/jswaggersheets/": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/",
9
+ "@shgysk8zer0/jss/": "https://unpkg.com/@shgysk8zer0/jss@1.0.1/",
10
+ "@shgysk8zer0/consts/": "https://unpkg.com/@shgysk8zer0/consts@1.0.8/",
11
+ "@shgysk8zer0/http/": "https://unpkg.com/@shgysk8zer0/http@1.0.5/",
12
+ "@shgysk8zer0/http-status": "https://unpkg.com/@shgysk8zer0/http-status@1.1.1/http-status.js",
13
+ "@shgysk8zer0/components/": "https://unpkg.com/@shgysk8zer0/components@0.1.5/",
14
+ "@kernvalley/components/": "https://unpkg.com/@kernvalley/components@1.1.0/",
15
+ "@webcomponents/custom-elements": "https://unpkg.com/@webcomponents/custom-elements@1.6.0/custom-elements.min.js",
16
+ "leaflet": "https://unpkg.com/leaflet@1.9.4/dist/leaflet-src.esm.js",
17
+ "urlpattern-polyfill": "https://unpkg.com/urlpattern-polyfill@9.0.0/index.js",
18
+ "highlight.js": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/es/highlight.min.js",
19
+ "highlight.js/": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/",
20
+ "marked": "https://unpkg.com/marked@10.0.0/lib/marked.esm.js",
21
+ "marked-highlight": "https://unpkg.com/marked-highlight@2.0.7/src/index.js",
22
+ "firebase/": "https://www.gstatic.com/firebasejs/9.23.0/"
23
+ },
24
+ "scope": {}
25
+ }
package/index.cjs CHANGED
@@ -2,48 +2,161 @@
2
2
 
3
3
  var promises = require('node:fs/promises');
4
4
  var node_crypto = require('node:crypto');
5
+ var yaml_js = require('@shgysk8zer0/npm-utils/yaml.js');
6
+ var json_js = require('@shgysk8zer0/npm-utils/json.js');
7
+ var path_js = require('@shgysk8zer0/npm-utils/path.js');
5
8
 
6
- const versions = {
7
- '@shgysk8zer0/kazoo': '0.2.3',
8
- '@shgysk8zer0/konami': '1.1.0',
9
- '@shgysk8zer0/polyfills': '0.2.4',
10
- '@shgysk8zer0/components': '0.1.3',
11
- '@shgysk8zer0/http-status': '1.1.1',
12
- '@shgysk8zer0/jswaggersheets': '1.1.0',
13
- '@shgysk8zer0/jss': '1.0.1',
14
- '@kernvalley/components': '1.1.0',
15
- '@webcomponents/custom-elements': '1.6.0',
16
- 'leaflet': '1.9.4',
17
- 'firebase': '9.23.0',
18
- 'urlpattern-polyfill': '9.0.0',
19
- 'highlight.js': '11.8.0',
20
- 'marked': '5.1.0',
21
- 'marked-highlight': '2.0.1',
9
+ const imports$1 = {
10
+ "@shgysk8zer0/kazoo/": "https://unpkg.com/@shgysk8zer0/kazoo@0.2.7/",
11
+ "@shgysk8zer0/konami": "https://unpkg.com/@shgysk8zer0/konami@1.1.1/konami.js",
12
+ "@shgysk8zer0/polyfills": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/all.min.js",
13
+ "@shgysk8zer0/polyfills/": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/",
14
+ "@shgysk8zer0/jswaggersheets": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/swagger.js",
15
+ "@shgysk8zer0/jswaggersheets/": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/",
16
+ "@shgysk8zer0/jss/": "https://unpkg.com/@shgysk8zer0/jss@1.0.1/",
17
+ "@shgysk8zer0/consts/": "https://unpkg.com/@shgysk8zer0/consts@1.0.8/",
18
+ "@shgysk8zer0/http/": "https://unpkg.com/@shgysk8zer0/http@1.0.5/",
19
+ "@shgysk8zer0/http-status": "https://unpkg.com/@shgysk8zer0/http-status@1.1.1/http-status.js",
20
+ "@shgysk8zer0/components/": "https://unpkg.com/@shgysk8zer0/components@0.1.5/",
21
+ "@kernvalley/components/": "https://unpkg.com/@kernvalley/components@1.1.0/",
22
+ "@webcomponents/custom-elements": "https://unpkg.com/@webcomponents/custom-elements@1.6.0/custom-elements.min.js",
23
+ leaflet: "https://unpkg.com/leaflet@1.9.4/dist/leaflet-src.esm.js",
24
+ "urlpattern-polyfill": "https://unpkg.com/urlpattern-polyfill@9.0.0/index.js",
25
+ "highlight.js": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/es/highlight.min.js",
26
+ "highlight.js/": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/",
27
+ marked: "https://unpkg.com/marked@10.0.0/lib/marked.esm.js",
28
+ "marked-highlight": "https://unpkg.com/marked-highlight@2.0.7/src/index.js",
29
+ "firebase/": "https://www.gstatic.com/firebasejs/9.23.0/"
22
30
  };
23
-
24
- const imports = {
25
- '@shgysk8zer0/kazoo/': `https://unpkg.com/@shgysk8zer0/kazoo@${versions['@shgysk8zer0/kazoo']}/`,
26
- '@shgysk8zer0/konami': `https://unpkg.com/@shgysk8zer0/konami@${versions['@shgysk8zer0/konami']}/konami.js`,
27
- '@shgysk8zer0/polyfills': `https://unpkg.com/@shgysk8zer0/polyfills@${versions['@shgysk8zer0/polyfills']}/all.min.js`,
28
- '@shgysk8zer0/polyfills/': `https://unpkg.com/@shgysk8zer0/polyfills@${versions['@shgysk8zer0/polyfills']}/`,
29
- '@shgysk8zer0/jswaggersheets': `https://unpkg.com/@shgysk8zer0/jswaggersheets@${versions['@shgysk8zer0/jswaggersheets']}/swagger.js`,
30
- '@shgysk8zer0/jswaggersheets/': `https://unpkg.com/@shgysk8zer0/jswaggersheets@${versions['@shgysk8zer0/jswaggersheets']}/`,
31
- '@shgysk8zer0/jss/': `https://unpkg.com/@shgysk8zer0/jss@${versions['@shgysk8zer0/jss']}/`,
32
- '@shgysk8zer0/http-status': `https://unpkg.com/@shgysk8zer0/http-status@${versions['@shgysk8zer0/http-status']}/http-status.js`,
33
- '@shgysk8zer0/components/': `https://unpkg.com/@shgysk8zer0/components@${versions['@shgysk8zer0/components']}/`,
34
- '@kernvalley/components/': `https://unpkg.com/@kernvalley/components@${versions['@kernvalley/components']}/`,
35
- '@webcomponents/custom-elements': `https://unpkg.com/@webcomponents/custom-elements@${versions['@webcomponents/custom-elements']}/custom-elements.min.js`,
36
- 'leaflet': `https://unpkg.com/leaflet@${versions.leaflet}/dist/leaflet-src.esm.js`,
37
- 'firebase/': `https://www.gstatic.com/firebasejs/${versions.firebase}/`,
38
- 'urlpattern-polyfill': `https://unpkg.com/urlpattern-polyfill@${versions['urlpattern-polyfill']}/index.js`,
39
- 'highlight.js': `https://unpkg.com/@highlightjs/cdn-assets@${versions['highlight.js']}/es/highlight.min.js`,
40
- 'highlight.js/': `https://unpkg.com/@highlightjs/cdn-assets@${versions['highlight.js']}/`,
41
- 'marked': `https://unpkg.com/marked@${versions.marked}/src/marked.js`,
42
- 'marked-highlight': `https://unpkg.com/marked-highlight@${versions['marked-highlight']}/src/index.js`
31
+ const scope$1 = {
32
+ };
33
+ var importmap = {
34
+ imports: imports$1,
35
+ scope: scope$1
43
36
  };
44
37
 
45
- const scope = {};
46
- const importmap = { imports, scope };
38
+ const UNPKG = 'https://unpkg.com/';
39
+
40
+ const cache = new Map();
41
+
42
+ function parseUnpkgURL(src) {
43
+ const url = new URL(src, UNPKG);
44
+
45
+ if (! url.hostname === UNPKG || url.pathname.length === 1 || url.pathname === '/[object%20Object]') {
46
+ throw new Error(`${src} is not an unpkg URL.`);
47
+ } else {
48
+ const path = url.pathname.substr(1).split('/');
49
+
50
+ if (path.length === 0) {
51
+ throw new Error(`Invalid unpkg URL: ${src}`);
52
+ } else if (path.length !== 1 && path[0].startsWith('@')) {
53
+ const [pkg, version = null] = path[1].split('@');
54
+ return { scope: path[0], pkg, version, module: path.splice(2).join('/') };
55
+ } else {
56
+ const [pkg, version = null] = path[0].split('@');
57
+ return { scope: null, pkg, version, module: path.splice(1).join('/') };
58
+ }
59
+ }
60
+ }
61
+
62
+ function getUnpkgURL({ scope, pkg, version, module = '' }) {
63
+ // console.log({ scope, pkg, version });
64
+ if (typeof pkg !== 'string' || pkg.length === 0) {
65
+ throw new TypeError('Package name must be a non-empty string.');
66
+ } else if (typeof version !== 'string' || version.length === 0) {
67
+ throw new TypeError('Version must be a non-empty string.');
68
+ } else if (typeof scope === 'string' && scope.length !== 0) {
69
+ return new URL(`/${scope}/${pkg}@${version}/${module}`, UNPKG).href;
70
+ } else {
71
+ return new URL(`/${pkg}@${version}/${module}`, UNPKG).href;
72
+ }
73
+ }
74
+
75
+ async function getLatestVersion({ scope, pkg, signal } = {}) {
76
+ const path = typeof scope === 'string' ? `/${scope}/${pkg}/` : `/${pkg}/`;
77
+
78
+ if (cache.has(path)) {
79
+ return await cache.get(path);
80
+ } else {
81
+ const url = new URL(path, 'https://unpkg.com/');
82
+ url.searchParams.set('meta', '');
83
+
84
+ const promise = fetch(url, { method: 'HEAD', signal }).then(resp => {
85
+ const { version } = parseUnpkgURL(resp.url);
86
+ return version;
87
+ });
88
+
89
+ cache.set(path, promise);
90
+ return promise;
91
+ }
92
+ }
93
+
94
+ async function update(imports) {
95
+ let updated = false;
96
+
97
+ const entries = await Promise.all(Object.entries(imports)
98
+ .filter(([,val]) => val.startsWith(UNPKG))
99
+ .map(async ([key, val]) => {
100
+ const { scope, pkg, version: oldVersion, module } = parseUnpkgURL(val);
101
+ const version = await getLatestVersion({ scope, pkg });
102
+
103
+ if (! updated && version > oldVersion) {
104
+ updated = true;
105
+ }
106
+
107
+ return [key, getUnpkgURL({ scope, pkg, version, module })];
108
+ })
109
+ );
110
+
111
+ return { imports: Object.fromEntries(entries), updated };
112
+ }
113
+
114
+ async function updateYAML(file) {
115
+ if (typeof file === 'string') {
116
+ return await updateJSON(path_js.getFileURL(file));
117
+ } else if (file instanceof URL && file.protocol === 'file:') {
118
+ const importmap = await yaml_js.readYAMLFile(file);
119
+ const { updated, imports } = await update(importmap.imports);
120
+
121
+ if (updated) {
122
+ await yaml_js.writeYAMLFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
123
+ return true;
124
+ } else {
125
+ return false;
126
+ }
127
+ } else {
128
+ throw new TypeError('File must be a path or file: URL.');
129
+ }
130
+
131
+ }
132
+
133
+ async function updateJSON(file) {
134
+ if (typeof file === 'string') {
135
+ return await updateJSON(path_js.getFileURL(file));
136
+ } else if (file instanceof URL && file.protocol === 'file:') {
137
+ const importmap = await json_js.readJSONFile(file);
138
+ const { updated, imports } = await update(importmap.imports);
139
+
140
+ if (updated) {
141
+ await json_js.writeJSONFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
142
+ return true;
143
+ } else {
144
+ return false;
145
+ }
146
+ } else {
147
+ throw new TypeError('File must be a path or file: URL.');
148
+ }
149
+ }
150
+
151
+ var unpkg = /*#__PURE__*/Object.freeze({
152
+ __proto__: null,
153
+ update: update,
154
+ updateJSON: updateJSON,
155
+ updateYAML: updateYAML
156
+ });
157
+
158
+ const { imports, scope } = importmap;
159
+
47
160
  const ENCODING = 'utf8';
48
161
  const ALGO = 'sha384';
49
162
 
@@ -76,12 +189,10 @@ function getImportmapIntegrity({
76
189
  function getImportMapScript({
77
190
  importmap = { imports, scope },
78
191
  algo = ALGO,
79
- encoding = ENCODING,
80
192
  spaces = 2,
81
193
  } = {}) {
82
- const integrity = getImportmapIntegrity({ importmap, algo, encoding, spaces });
83
- const json = JSON.stringify(importmap, null, spaces);
84
- return `<script type="importmap" integrity="${integrity}">${json}</script>`;
194
+ const integrity = getImportmapIntegrity({ importmap, algo, spaces });
195
+ return `<script type="importmap" integrity="${integrity}">${JSON.stringify(importmap, null, spaces)}</script>`;
85
196
  }
86
197
 
87
198
  exports.ALGO = ALGO;
@@ -93,3 +204,4 @@ exports.importmap = importmap;
93
204
  exports.imports = imports;
94
205
  exports.mergeWithImportmap = mergeWithImportmap;
95
206
  exports.scope = scope;
207
+ exports.unpkg = unpkg;
package/index.mjs ADDED
@@ -0,0 +1,196 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { createHash } from 'node:crypto';
3
+ import { readYAMLFile, writeYAMLFile } from '@shgysk8zer0/npm-utils/yaml.js';
4
+ import { readJSONFile, writeJSONFile } from '@shgysk8zer0/npm-utils/json.js';
5
+ import { getFileURL } from '@shgysk8zer0/npm-utils/path.js';
6
+
7
+ const imports$1 = {
8
+ "@shgysk8zer0/kazoo/": "https://unpkg.com/@shgysk8zer0/kazoo@0.2.7/",
9
+ "@shgysk8zer0/konami": "https://unpkg.com/@shgysk8zer0/konami@1.1.1/konami.js",
10
+ "@shgysk8zer0/polyfills": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/all.min.js",
11
+ "@shgysk8zer0/polyfills/": "https://unpkg.com/@shgysk8zer0/polyfills@0.2.6/",
12
+ "@shgysk8zer0/jswaggersheets": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/swagger.js",
13
+ "@shgysk8zer0/jswaggersheets/": "https://unpkg.com/@shgysk8zer0/jswaggersheets@1.1.0/",
14
+ "@shgysk8zer0/jss/": "https://unpkg.com/@shgysk8zer0/jss@1.0.1/",
15
+ "@shgysk8zer0/consts/": "https://unpkg.com/@shgysk8zer0/consts@1.0.8/",
16
+ "@shgysk8zer0/http/": "https://unpkg.com/@shgysk8zer0/http@1.0.5/",
17
+ "@shgysk8zer0/http-status": "https://unpkg.com/@shgysk8zer0/http-status@1.1.1/http-status.js",
18
+ "@shgysk8zer0/components/": "https://unpkg.com/@shgysk8zer0/components@0.1.5/",
19
+ "@kernvalley/components/": "https://unpkg.com/@kernvalley/components@1.1.0/",
20
+ "@webcomponents/custom-elements": "https://unpkg.com/@webcomponents/custom-elements@1.6.0/custom-elements.min.js",
21
+ leaflet: "https://unpkg.com/leaflet@1.9.4/dist/leaflet-src.esm.js",
22
+ "urlpattern-polyfill": "https://unpkg.com/urlpattern-polyfill@9.0.0/index.js",
23
+ "highlight.js": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/es/highlight.min.js",
24
+ "highlight.js/": "https://unpkg.com/@highlightjs/cdn-assets@11.9.0/",
25
+ marked: "https://unpkg.com/marked@10.0.0/lib/marked.esm.js",
26
+ "marked-highlight": "https://unpkg.com/marked-highlight@2.0.7/src/index.js",
27
+ "firebase/": "https://www.gstatic.com/firebasejs/9.23.0/"
28
+ };
29
+ const scope$1 = {
30
+ };
31
+ var importmap = {
32
+ imports: imports$1,
33
+ scope: scope$1
34
+ };
35
+
36
+ const UNPKG = 'https://unpkg.com/';
37
+
38
+ const cache = new Map();
39
+
40
+ function parseUnpkgURL(src) {
41
+ const url = new URL(src, UNPKG);
42
+
43
+ if (! url.hostname === UNPKG || url.pathname.length === 1 || url.pathname === '/[object%20Object]') {
44
+ throw new Error(`${src} is not an unpkg URL.`);
45
+ } else {
46
+ const path = url.pathname.substr(1).split('/');
47
+
48
+ if (path.length === 0) {
49
+ throw new Error(`Invalid unpkg URL: ${src}`);
50
+ } else if (path.length !== 1 && path[0].startsWith('@')) {
51
+ const [pkg, version = null] = path[1].split('@');
52
+ return { scope: path[0], pkg, version, module: path.splice(2).join('/') };
53
+ } else {
54
+ const [pkg, version = null] = path[0].split('@');
55
+ return { scope: null, pkg, version, module: path.splice(1).join('/') };
56
+ }
57
+ }
58
+ }
59
+
60
+ function getUnpkgURL({ scope, pkg, version, module = '' }) {
61
+ // console.log({ scope, pkg, version });
62
+ if (typeof pkg !== 'string' || pkg.length === 0) {
63
+ throw new TypeError('Package name must be a non-empty string.');
64
+ } else if (typeof version !== 'string' || version.length === 0) {
65
+ throw new TypeError('Version must be a non-empty string.');
66
+ } else if (typeof scope === 'string' && scope.length !== 0) {
67
+ return new URL(`/${scope}/${pkg}@${version}/${module}`, UNPKG).href;
68
+ } else {
69
+ return new URL(`/${pkg}@${version}/${module}`, UNPKG).href;
70
+ }
71
+ }
72
+
73
+ async function getLatestVersion({ scope, pkg, signal } = {}) {
74
+ const path = typeof scope === 'string' ? `/${scope}/${pkg}/` : `/${pkg}/`;
75
+
76
+ if (cache.has(path)) {
77
+ return await cache.get(path);
78
+ } else {
79
+ const url = new URL(path, 'https://unpkg.com/');
80
+ url.searchParams.set('meta', '');
81
+
82
+ const promise = fetch(url, { method: 'HEAD', signal }).then(resp => {
83
+ const { version } = parseUnpkgURL(resp.url);
84
+ return version;
85
+ });
86
+
87
+ cache.set(path, promise);
88
+ return promise;
89
+ }
90
+ }
91
+
92
+ async function update(imports) {
93
+ let updated = false;
94
+
95
+ const entries = await Promise.all(Object.entries(imports)
96
+ .filter(([,val]) => val.startsWith(UNPKG))
97
+ .map(async ([key, val]) => {
98
+ const { scope, pkg, version: oldVersion, module } = parseUnpkgURL(val);
99
+ const version = await getLatestVersion({ scope, pkg });
100
+
101
+ if (! updated && version > oldVersion) {
102
+ updated = true;
103
+ }
104
+
105
+ return [key, getUnpkgURL({ scope, pkg, version, module })];
106
+ })
107
+ );
108
+
109
+ return { imports: Object.fromEntries(entries), updated };
110
+ }
111
+
112
+ async function updateYAML(file) {
113
+ if (typeof file === 'string') {
114
+ return await updateJSON(getFileURL(file));
115
+ } else if (file instanceof URL && file.protocol === 'file:') {
116
+ const importmap = await readYAMLFile(file);
117
+ const { updated, imports } = await update(importmap.imports);
118
+
119
+ if (updated) {
120
+ await writeYAMLFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
121
+ return true;
122
+ } else {
123
+ return false;
124
+ }
125
+ } else {
126
+ throw new TypeError('File must be a path or file: URL.');
127
+ }
128
+
129
+ }
130
+
131
+ async function updateJSON(file) {
132
+ if (typeof file === 'string') {
133
+ return await updateJSON(getFileURL(file));
134
+ } else if (file instanceof URL && file.protocol === 'file:') {
135
+ const importmap = await readJSONFile(file);
136
+ const { updated, imports } = await update(importmap.imports);
137
+
138
+ if (updated) {
139
+ await writeJSONFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
140
+ return true;
141
+ } else {
142
+ return false;
143
+ }
144
+ } else {
145
+ throw new TypeError('File must be a path or file: URL.');
146
+ }
147
+ }
148
+
149
+ var unpkg = /*#__PURE__*/Object.freeze({
150
+ __proto__: null,
151
+ update: update,
152
+ updateJSON: updateJSON,
153
+ updateYAML: updateYAML
154
+ });
155
+
156
+ const { imports, scope } = importmap;
157
+
158
+ const ENCODING = 'utf8';
159
+ const ALGO = 'sha384';
160
+
161
+ function mergeWithImportmap({ imports = {}, scope = {}}) {
162
+ return {
163
+ imports: { ...importmap.imports, ...imports },
164
+ scope: { ...importmap.scope, ...scope },
165
+ };
166
+ }
167
+
168
+ async function createImportmapJSON(path = 'importmap.json', {
169
+ importmap = { imports, scope },
170
+ spaces = 2,
171
+ signal,
172
+ } = {}) {
173
+ await writeFile(path, JSON.stringify(importmap, null, spaces), { encoding: ENCODING, signal });
174
+ }
175
+
176
+ function getImportmapIntegrity({
177
+ importmap = { imports, scope },
178
+ algo = ALGO,
179
+ encoding = ENCODING,
180
+ spaces = 2,
181
+ } = {}) {
182
+ const hash = createHash(algo);
183
+ hash.update(JSON.stringify(importmap, null, spaces), encoding);
184
+ return `${algo}-${hash.digest('base64')}`;
185
+ }
186
+
187
+ function getImportMapScript({
188
+ importmap = { imports, scope },
189
+ algo = ALGO,
190
+ spaces = 2,
191
+ } = {}) {
192
+ const integrity = getImportmapIntegrity({ importmap, algo, spaces });
193
+ return `<script type="importmap" integrity="${integrity}">${JSON.stringify(importmap, null, spaces)}</script>`;
194
+ }
195
+
196
+ export { ALGO, ENCODING, createImportmapJSON, getImportMapScript, getImportmapIntegrity, importmap, imports, mergeWithImportmap, scope, unpkg };
package/package.json CHANGED
@@ -1,21 +1,31 @@
1
1
  {
2
2
  "name": "@shgysk8zer0/importmap",
3
- "version": "1.2.5",
3
+ "version": "1.3.1",
4
4
  "engines": {
5
5
  "node": ">=18.0.0"
6
6
  },
7
7
  "description": "Front-End dependencies based on `<script type=\"importmap\">`",
8
8
  "type": "module",
9
- "module": "./index.js",
9
+ "module": "./index.mjs",
10
10
  "main": "./index.cjs",
11
- "unpkg": "./index.js",
11
+ "unpkg": "./index.mjs",
12
12
  "exports": {
13
13
  ".": {
14
- "import": "./index.js",
14
+ "import": "./index.mjs",
15
15
  "require": "./index.cjs"
16
16
  },
17
+ "./*.js": {
18
+ "import": "./*.mjs",
19
+ "require": "./*.cjs"
20
+ },
21
+ "./*.mjs": {
22
+ "import": "./*.mjs"
23
+ },
24
+ "./*.cjs": {
25
+ "require": "./*.cjs"
26
+ },
17
27
  "./*": {
18
- "import": "./*.js",
28
+ "import": "./*.mjs",
19
29
  "require": "./*.cjs"
20
30
  }
21
31
  },
@@ -27,7 +37,7 @@
27
37
  "preversion": "npm test",
28
38
  "prepare": "npm run build",
29
39
  "lint:js": "eslint .",
30
- "fix:js": "eslint. --fix",
40
+ "fix:js": "eslint . --fix",
31
41
  "build": "npm run build:js",
32
42
  "build:js": "rollup -c",
33
43
  "test:imports": "rollup -c rollup.test.config.js",
@@ -48,11 +58,15 @@
48
58
  },
49
59
  "homepage": "https://github.com/shgysk8zer0/importmap#readme",
50
60
  "devDependencies": {
61
+ "@babel/eslint-parser": "^7.23.3",
62
+ "@babel/eslint-plugin": "^7.22.10",
63
+ "@babel/plugin-syntax-import-assertions": "^7.23.3",
64
+ "@rollup/plugin-json": "^6.0.1",
51
65
  "@shgysk8zer0/js-utils": "^1.0.1",
52
- "@shgysk8zer0/rollup-import": "^1.2.0"
66
+ "@shgysk8zer0/rollup-import": "^1.2.2"
53
67
  },
54
68
  "dependencies": {
55
- "@shgysk8zer0/npm-utils": "^1.1.0",
56
- "commander": "^11.0.0"
69
+ "@shgysk8zer0/npm-utils": "^1.1.2",
70
+ "commander": "^11.1.0"
57
71
  }
58
72
  }
package/unpkg.js ADDED
@@ -0,0 +1,61 @@
1
+ import { readYAMLFile, writeYAMLFile } from '@shgysk8zer0/npm-utils/yaml.js';
2
+ import { readJSONFile, writeJSONFile } from '@shgysk8zer0/npm-utils/json.js';
3
+ import { getFileURL } from '@shgysk8zer0/npm-utils/path.js';
4
+ import { parseUnpkgURL, getUnpkgURL, getLatestVersion, UNPKG } from './utils.js';
5
+
6
+ export async function update(imports) {
7
+ let updated = false;
8
+
9
+ const entries = await Promise.all(Object.entries(imports)
10
+ .filter(([,val]) => val.startsWith(UNPKG))
11
+ .map(async ([key, val]) => {
12
+ const { scope, pkg, version: oldVersion, module } = parseUnpkgURL(val);
13
+ const version = await getLatestVersion({ scope, pkg });
14
+
15
+ if (! updated && version > oldVersion) {
16
+ updated = true;
17
+ }
18
+
19
+ return [key, getUnpkgURL({ scope, pkg, version, module })];
20
+ })
21
+ );
22
+
23
+ return { imports: Object.fromEntries(entries), updated };
24
+ }
25
+
26
+ export async function updateYAML(file) {
27
+ if (typeof file === 'string') {
28
+ return await updateJSON(getFileURL(file));
29
+ } else if (file instanceof URL && file.protocol === 'file:') {
30
+ const importmap = await readYAMLFile(file);
31
+ const { updated, imports } = await update(importmap.imports);
32
+
33
+ if (updated) {
34
+ await writeYAMLFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
35
+ return true;
36
+ } else {
37
+ return false;
38
+ }
39
+ } else {
40
+ throw new TypeError('File must be a path or file: URL.');
41
+ }
42
+
43
+ }
44
+
45
+ export async function updateJSON(file) {
46
+ if (typeof file === 'string') {
47
+ return await updateJSON(getFileURL(file));
48
+ } else if (file instanceof URL && file.protocol === 'file:') {
49
+ const importmap = await readJSONFile(file);
50
+ const { updated, imports } = await update(importmap.imports);
51
+
52
+ if (updated) {
53
+ await writeJSONFile(file, { ...importmap, imports: { ...importmap.imports, ...imports }});
54
+ return true;
55
+ } else {
56
+ return false;
57
+ }
58
+ } else {
59
+ throw new TypeError('File must be a path or file: URL.');
60
+ }
61
+ }
package/update.js ADDED
@@ -0,0 +1,3 @@
1
+ import { unpkg } from '@shgysk8zer0/importmap';
2
+
3
+ await unpkg.updateJSON('importmap.json').catch(console.error);
package/utils.js ADDED
@@ -0,0 +1,55 @@
1
+ export const UNPKG = 'https://unpkg.com/';
2
+
3
+ const cache = new Map();
4
+
5
+ export function parseUnpkgURL(src) {
6
+ const url = new URL(src, UNPKG);
7
+
8
+ if (! url.hostname === UNPKG || url.pathname.length === 1 || url.pathname === '/[object%20Object]') {
9
+ throw new Error(`${src} is not an unpkg URL.`);
10
+ } else {
11
+ const path = url.pathname.substr(1).split('/');
12
+
13
+ if (path.length === 0) {
14
+ throw new Error(`Invalid unpkg URL: ${src}`);
15
+ } else if (path.length !== 1 && path[0].startsWith('@')) {
16
+ const [pkg, version = null] = path[1].split('@');
17
+ return { scope: path[0], pkg, version, module: path.splice(2).join('/') };
18
+ } else {
19
+ const [pkg, version = null] = path[0].split('@');
20
+ return { scope: null, pkg, version, module: path.splice(1).join('/') };
21
+ }
22
+ }
23
+ }
24
+
25
+ export function getUnpkgURL({ scope, pkg, version, module = '' }) {
26
+ // console.log({ scope, pkg, version });
27
+ if (typeof pkg !== 'string' || pkg.length === 0) {
28
+ throw new TypeError('Package name must be a non-empty string.');
29
+ } else if (typeof version !== 'string' || version.length === 0) {
30
+ throw new TypeError('Version must be a non-empty string.');
31
+ } else if (typeof scope === 'string' && scope.length !== 0) {
32
+ return new URL(`/${scope}/${pkg}@${version}/${module}`, UNPKG).href;
33
+ } else {
34
+ return new URL(`/${pkg}@${version}/${module}`, UNPKG).href;
35
+ }
36
+ }
37
+
38
+ export async function getLatestVersion({ scope, pkg, signal } = {}) {
39
+ const path = typeof scope === 'string' ? `/${scope}/${pkg}/` : `/${pkg}/`;
40
+
41
+ if (cache.has(path)) {
42
+ return await cache.get(path);
43
+ } else {
44
+ const url = new URL(path, 'https://unpkg.com/');
45
+ url.searchParams.set('meta', '');
46
+
47
+ const promise = fetch(url, { method: 'HEAD', signal }).then(resp => {
48
+ const { version } = parseUnpkgURL(resp.url);
49
+ return version;
50
+ });
51
+
52
+ cache.set(path, promise);
53
+ return promise;
54
+ }
55
+ }
package/index.js DELETED
@@ -1,66 +0,0 @@
1
- import { writeFile } from 'node:fs/promises';
2
- import { createHash } from 'node:crypto';
3
- import { versions } from './versions.js';
4
-
5
- export const imports = {
6
- '@shgysk8zer0/kazoo/': `https://unpkg.com/@shgysk8zer0/kazoo@${versions['@shgysk8zer0/kazoo']}/`,
7
- '@shgysk8zer0/konami': `https://unpkg.com/@shgysk8zer0/konami@${versions['@shgysk8zer0/konami']}/konami.js`,
8
- '@shgysk8zer0/polyfills': `https://unpkg.com/@shgysk8zer0/polyfills@${versions['@shgysk8zer0/polyfills']}/all.min.js`,
9
- '@shgysk8zer0/polyfills/': `https://unpkg.com/@shgysk8zer0/polyfills@${versions['@shgysk8zer0/polyfills']}/`,
10
- '@shgysk8zer0/jswaggersheets': `https://unpkg.com/@shgysk8zer0/jswaggersheets@${versions['@shgysk8zer0/jswaggersheets']}/swagger.js`,
11
- '@shgysk8zer0/jswaggersheets/': `https://unpkg.com/@shgysk8zer0/jswaggersheets@${versions['@shgysk8zer0/jswaggersheets']}/`,
12
- '@shgysk8zer0/jss/': `https://unpkg.com/@shgysk8zer0/jss@${versions['@shgysk8zer0/jss']}/`,
13
- '@shgysk8zer0/http-status': `https://unpkg.com/@shgysk8zer0/http-status@${versions['@shgysk8zer0/http-status']}/http-status.js`,
14
- '@shgysk8zer0/components/': `https://unpkg.com/@shgysk8zer0/components@${versions['@shgysk8zer0/components']}/`,
15
- '@kernvalley/components/': `https://unpkg.com/@kernvalley/components@${versions['@kernvalley/components']}/`,
16
- '@webcomponents/custom-elements': `https://unpkg.com/@webcomponents/custom-elements@${versions['@webcomponents/custom-elements']}/custom-elements.min.js`,
17
- 'leaflet': `https://unpkg.com/leaflet@${versions.leaflet}/dist/leaflet-src.esm.js`,
18
- 'firebase/': `https://www.gstatic.com/firebasejs/${versions.firebase}/`,
19
- 'urlpattern-polyfill': `https://unpkg.com/urlpattern-polyfill@${versions['urlpattern-polyfill']}/index.js`,
20
- 'highlight.js': `https://unpkg.com/@highlightjs/cdn-assets@${versions['highlight.js']}/es/highlight.min.js`,
21
- 'highlight.js/': `https://unpkg.com/@highlightjs/cdn-assets@${versions['highlight.js']}/`,
22
- 'marked': `https://unpkg.com/marked@${versions.marked}/src/marked.js`,
23
- 'marked-highlight': `https://unpkg.com/marked-highlight@${versions['marked-highlight']}/src/index.js`
24
- };
25
-
26
- export const scope = {};
27
- export const importmap = { imports, scope };
28
- export const ENCODING = 'utf8';
29
- export const ALGO = 'sha384';
30
-
31
- export function mergeWithImportmap({ imports = {}, scope = {}}) {
32
- return {
33
- imports: { ...importmap.imports, ...imports },
34
- scope: { ...importmap.scope, ...scope },
35
- };
36
- }
37
-
38
- export async function createImportmapJSON(path = 'importmap.json', {
39
- importmap = { imports, scope },
40
- spaces = 2,
41
- signal,
42
- } = {}) {
43
- await writeFile(path, JSON.stringify(importmap, null, spaces), { encoding: ENCODING, signal });
44
- }
45
-
46
- export function getImportmapIntegrity({
47
- importmap = { imports, scope },
48
- algo = ALGO,
49
- encoding = ENCODING,
50
- spaces = 2,
51
- } = {}) {
52
- const hash = createHash(algo);
53
- hash.update(JSON.stringify(importmap, null, spaces), encoding);
54
- return `${algo}-${hash.digest('base64')}`;
55
- }
56
-
57
- export function getImportMapScript({
58
- importmap = { imports, scope },
59
- algo = ALGO,
60
- encoding = ENCODING,
61
- spaces = 2,
62
- } = {}) {
63
- const integrity = getImportmapIntegrity({ importmap, algo, encoding, spaces });
64
- const json = JSON.stringify(importmap, null, spaces);
65
- return `<script type="importmap" integrity="${integrity}">${json}</script>`;
66
- }
package/versions.js DELETED
@@ -1,17 +0,0 @@
1
- export const versions = {
2
- '@shgysk8zer0/kazoo': '0.2.3',
3
- '@shgysk8zer0/konami': '1.1.0',
4
- '@shgysk8zer0/polyfills': '0.2.4',
5
- '@shgysk8zer0/components': '0.1.3',
6
- '@shgysk8zer0/http-status': '1.1.1',
7
- '@shgysk8zer0/jswaggersheets': '1.1.0',
8
- '@shgysk8zer0/jss': '1.0.1',
9
- '@kernvalley/components': '1.1.0',
10
- '@webcomponents/custom-elements': '1.6.0',
11
- 'leaflet': '1.9.4',
12
- 'firebase': '9.23.0',
13
- 'urlpattern-polyfill': '9.0.0',
14
- 'highlight.js': '11.8.0',
15
- 'marked': '5.1.0',
16
- 'marked-highlight': '2.0.1',
17
- };