proscenium 0.5.0-x86_64-darwin → 0.6.0-x86_64-darwin

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f905fa040049f8ad4f5863b705c9f99f74cda1e38c3cbb9325e7bada262e36d
4
- data.tar.gz: 73ef3f88ab3a1c6510275be8df6c0ca982d483685deff51764c9ae4ae057acef
3
+ metadata.gz: 87f97093007fdb59a8a3d34075e2570f6871c63bb404d3263fb3b21fd25d6a4e
4
+ data.tar.gz: c6a5f64992acaa9bff23de20ae9c317db60c504fa2f62d00e8bbab991b430892
5
5
  SHA512:
6
- metadata.gz: da5cb634c091dba3d8a86e571dae54a1683b45620076ebbe74ac1f2990e1a5b934310704cd16cc364f4fc3b3edd6900561f5a11d20b0065379546af349a6ec17
7
- data.tar.gz: 2468099ba8d90572e876a54e7f1a66c1b1cf77c243edcbd57a9b89a25e71f06c501c9c61133b6249082efc12675a5a24fe6d43750c2ab12422bc688a6b73b2b2
6
+ metadata.gz: 3519fae0fb5c95d5cc50dbce5e665cdbef81c484236605ecbe7ea18f16a9803c65ba70051d33296bd7ea3ae2e4d9f1e32b7cf502467b985a9f3f607af749fea5
7
+ data.tar.gz: 351f524bbb591d39ebf823d9939932511da63d61e971f604c2660f64ca1dd3635a2ae6935064cad359a8fd1336859b77e98fd9598d95492d2c23bb36e2f7f635
data/README.md CHANGED
@@ -117,7 +117,10 @@ as you could end up swallowing everything, resulting in a very large file.
117
117
  ## Import Map
118
118
 
119
119
  Import map for both JS and CSS is supported out of the box, and works with no regard to the browser
120
- version being used. Just create `config/import_map.json`:
120
+ version being used. This is because the import map is parsed and resolved by Proscenium on the
121
+ server.
122
+
123
+ Just create `config/import_map.json`:
121
124
 
122
125
  ```json
123
126
  {
@@ -157,6 +160,18 @@ env => ({
157
160
  })
158
161
  ```
159
162
 
163
+ ### Aliasing
164
+
165
+ You can also use the import map to define aliases:
166
+
167
+ ```json
168
+ {
169
+ "imports": {
170
+ "react": "preact/compact",
171
+ }
172
+ }
173
+ ```
174
+
160
175
  ## Side Loading
161
176
 
162
177
  Proscenium has built in support for automatically side loading JS and CSS with your views and
data/bin/esbuild CHANGED
Binary file
@@ -1,12 +1,12 @@
1
1
  import { expandGlob } from 'std/fs/mod.ts'
2
- import postcss, { CssSyntaxError } from 'postcss'
2
+ import postcss from 'postcss'
3
3
 
4
4
  export default async (root, path) => {
5
5
  let tmpFile
6
6
  let contents
7
7
 
8
8
  const mixinFiles = []
9
- for await (const file of expandGlob(`lib/**/*.mixin.css`, { root })) {
9
+ for await (const file of expandGlob('lib/**/*.mixin.css', { root, globstar: true })) {
10
10
  mixinFiles.push(file.path)
11
11
  }
12
12
 
@@ -0,0 +1,178 @@
1
+ import { tryURLParse, tryURLLikeSpecifierParse } from './utils.js'
2
+
3
+ /**
4
+ * @param {ImportMap} input
5
+ * @param {URL} baseURL
6
+ * @returns {ParsedImportMap}
7
+ */
8
+ export function parse(input, baseURL) {
9
+ if (!isJSONObject(input)) {
10
+ throw new TypeError('Import map JSON must be an object.')
11
+ }
12
+
13
+ if (!(baseURL instanceof URL)) {
14
+ throw new TypeError('Missing base URL or base URL is not a URL')
15
+ }
16
+
17
+ let sortedAndNormalizedImports = {}
18
+ if ('imports' in input) {
19
+ if (!input.imports || !isJSONObject(input.imports)) {
20
+ throw new TypeError("Import map's imports value must be an object.")
21
+ }
22
+ sortedAndNormalizedImports = sortAndNormalizeSpecifierMap(input.imports, baseURL)
23
+ }
24
+
25
+ let sortedAndNormalizedScopes = {}
26
+ if ('scopes' in input) {
27
+ if (!input.scopes || !isJSONObject(input.scopes)) {
28
+ throw new TypeError("Import map's scopes value must be an object.")
29
+ }
30
+ sortedAndNormalizedScopes = sortAndNormalizeScopes(input.scopes, baseURL)
31
+ }
32
+
33
+ const badTopLevelKeys = new Set(Object.keys(input))
34
+ badTopLevelKeys.delete('imports')
35
+ badTopLevelKeys.delete('scopes')
36
+
37
+ for (const badKey of badTopLevelKeys) {
38
+ throw new TypeError(
39
+ `Invalid top-level key "${badKey}". Only "imports" and "scopes" can be present.`
40
+ )
41
+ }
42
+
43
+ // Always have these two keys, and exactly these two keys, in the result.
44
+ return {
45
+ imports: sortedAndNormalizedImports,
46
+ scopes: sortedAndNormalizedScopes
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @param {string} input
52
+ * @param {URL} baseURL
53
+ * @returns {ParsedImportMap}
54
+ */
55
+ export function parseFromString(input, baseURL) {
56
+ const importMap = JSON.parse(input)
57
+ return parse(importMap, baseURL)
58
+ }
59
+
60
+ /**
61
+ * @param {string} a
62
+ * @param {string} b
63
+ */
64
+ function codeUnitCompare(a, b) {
65
+ if (a > b) {
66
+ return 1
67
+ }
68
+
69
+ if (b > a) {
70
+ return -1
71
+ }
72
+
73
+ throw new Error('This should never be reached because this is only used on JSON object keys')
74
+ }
75
+
76
+ /**
77
+ * @param {string} specifierKey
78
+ * @param {URL} baseURL
79
+ * @returns {string | undefined}
80
+ */
81
+ function normalizeSpecifierKey(specifierKey, baseURL) {
82
+ // Ignore attempts to use the empty string as a specifier key
83
+ if (specifierKey === '') {
84
+ throw new TypeError(`Invalid empty string specifier key.`)
85
+ }
86
+
87
+ const url = tryURLLikeSpecifierParse(specifierKey, baseURL)
88
+ if (url) return url.href
89
+
90
+ return specifierKey
91
+ }
92
+
93
+ /**
94
+ * @param {SpecifierMap} obj
95
+ * @param {URL} baseURL
96
+ * @returns {ParsedSpecifierMap}
97
+ */
98
+ function sortAndNormalizeSpecifierMap(obj, baseURL) {
99
+ if (!isJSONObject(obj)) {
100
+ throw new TypeError('Expect map to be a JSON object.')
101
+ }
102
+
103
+ const normalized = {}
104
+
105
+ for (const [specifierKey, value] of Object.entries(obj)) {
106
+ const normalizedSpecifierKey = normalizeSpecifierKey(specifierKey, baseURL)
107
+ if (!normalizedSpecifierKey) continue
108
+
109
+ if (typeof value !== 'string') {
110
+ throw new TypeError(
111
+ `Invalid address ${JSON.stringify(value)} for the specifier key "${specifierKey}". ` +
112
+ `Addresses must be strings.`
113
+ )
114
+ }
115
+
116
+ const addressURL = tryURLLikeSpecifierParse(value, baseURL)
117
+ if (!addressURL) {
118
+ // Support aliases.
119
+ // console.warn(`Invalid address "${value}" for the specifier key "${specifierKey}".`)
120
+ normalized[normalizedSpecifierKey] = value
121
+ continue
122
+ }
123
+
124
+ if (specifierKey.endsWith('/') && !addressURL.href.endsWith('/')) {
125
+ throw new TypeError(
126
+ `Invalid address "${addressURL.href}" for package specifier key "${specifierKey}". ` +
127
+ `Package addresses must end with "/".`
128
+ )
129
+ }
130
+
131
+ normalized[normalizedSpecifierKey] = addressURL
132
+ }
133
+
134
+ const sortedAndNormalized = {}
135
+ const sortedKeys = Object.keys(normalized).sort((a, b) => codeUnitCompare(b, a))
136
+ for (const key of sortedKeys) {
137
+ sortedAndNormalized[key] = normalized[key]
138
+ }
139
+
140
+ return sortedAndNormalized
141
+ }
142
+
143
+ /**
144
+ * @param {ScopesMap} obj
145
+ * @param {URL} baseURL
146
+ */
147
+ function sortAndNormalizeScopes(obj, baseURL) {
148
+ const normalized = {}
149
+ for (const [scopePrefix, potentialSpecifierMap] of Object.entries(obj)) {
150
+ if (!isJSONObject(potentialSpecifierMap)) {
151
+ throw new TypeError(`The value for the "${scopePrefix}" scope prefix must be an object.`)
152
+ }
153
+
154
+ const scopePrefixURL = tryURLParse(scopePrefix, baseURL)
155
+ if (!scopePrefixURL) {
156
+ throw new TypeError(`Invalid scope "${scopePrefix}" (parsed against base URL "${baseURL}").`)
157
+ }
158
+
159
+ const normalizedScopePrefix = scopePrefixURL.href
160
+ normalized[normalizedScopePrefix] = sortAndNormalizeSpecifierMap(potentialSpecifierMap, baseURL)
161
+ }
162
+
163
+ const sortedAndNormalized = {}
164
+ const sortedKeys = Object.keys(normalized).sort((a, b) => codeUnitCompare(b, a))
165
+ for (const key of sortedKeys) {
166
+ sortedAndNormalized[key] = normalized[key]
167
+ }
168
+
169
+ return sortedAndNormalized
170
+ }
171
+
172
+ /**
173
+ * @param {*} value
174
+ * @returns {value is object}
175
+ */
176
+ function isJSONObject(value) {
177
+ return typeof value === 'object' && value != null && !Array.isArray(value)
178
+ }
@@ -1,5 +1,10 @@
1
+ //
2
+ // Taken almost verbatim from https://github.com/open-wc/open-wc/tree/master/packages/import-maps-resolve
3
+ // Slightly modified to support aliases.
4
+ //
5
+
1
6
  import { join } from 'std/path/mod.ts'
2
- import { parseFromString } from 'import-maps/resolve'
7
+ import { parseFromString } from './parser.js'
3
8
 
4
9
  const baseURL = new URL('file://')
5
10
 
@@ -16,7 +21,7 @@ class ImportMapError extends Error {
16
21
  }
17
22
  }
18
23
 
19
- export function readImportMap(fileName, rootDir) {
24
+ export default function (fileName, rootDir) {
20
25
  let importMap
21
26
 
22
27
  if (fileName) {
@@ -0,0 +1,95 @@
1
+ import { tryURLLikeSpecifierParse, tryURLParse } from './utils.js'
2
+
3
+ /**
4
+ * @param {string} specifier
5
+ * @param {ParsedImportMap} parsedImportMap
6
+ * @param {URL} scriptURL
7
+ * @returns {{ resolvedImport: URL | null, matched: boolean }}
8
+ */
9
+ export default function (specifier, parsedImportMap, scriptURL) {
10
+ const asURL = tryURLLikeSpecifierParse(specifier, scriptURL)
11
+ const normalizedSpecifier = asURL ? asURL.href : specifier
12
+ const scriptURLString = scriptURL.href
13
+
14
+ for (const [scopePrefix, scopeImports] of Object.entries(parsedImportMap.scopes || {})) {
15
+ if (
16
+ scopePrefix === scriptURLString ||
17
+ (scopePrefix.endsWith('/') && scriptURLString.startsWith(scopePrefix))
18
+ ) {
19
+ const scopeImportsMatch = resolveImportsMatch(normalizedSpecifier, scopeImports)
20
+
21
+ if (scopeImportsMatch) {
22
+ return { resolvedImport: scopeImportsMatch, matched: true }
23
+ }
24
+ }
25
+ }
26
+
27
+ const topLevelImportsMatch = resolveImportsMatch(
28
+ normalizedSpecifier,
29
+ parsedImportMap.imports || {}
30
+ )
31
+
32
+ if (topLevelImportsMatch) {
33
+ return { resolvedImport: topLevelImportsMatch, matched: true }
34
+ }
35
+
36
+ // The specifier was able to be turned into a URL, but wasn't remapped into anything.
37
+ if (asURL) {
38
+ return { resolvedImport: asURL, matched: false }
39
+ }
40
+
41
+ return { resolvedImport: null, matched: false }
42
+ }
43
+
44
+ /**
45
+ * @param {string} normalizedSpecifier
46
+ * @param {ParsedSpecifierMap} specifierMap
47
+ */
48
+ function resolveImportsMatch(normalizedSpecifier, specifierMap) {
49
+ for (const [specifierKey, resolutionResult] of Object.entries(specifierMap)) {
50
+ // Exact-match case
51
+ if (specifierKey === normalizedSpecifier) {
52
+ if (!resolutionResult) {
53
+ throw new TypeError(`Blocked by a null entry for "${specifierKey}"`)
54
+ }
55
+
56
+ if (!(resolutionResult instanceof URL)) {
57
+ // Support aliases.
58
+ // throw new TypeError(`Expected ${resolutionResult} to be a URL.`)
59
+ }
60
+
61
+ return resolutionResult
62
+ }
63
+
64
+ // Package prefix-match case
65
+ if (specifierKey.endsWith('/') && normalizedSpecifier.startsWith(specifierKey)) {
66
+ if (!resolutionResult) {
67
+ throw new TypeError(`Blocked by a null entry for "${specifierKey}"`)
68
+ }
69
+
70
+ if (!(resolutionResult instanceof URL)) {
71
+ throw new TypeError(`Expected ${resolutionResult} to be a URL.`)
72
+ }
73
+
74
+ const afterPrefix = normalizedSpecifier.substring(specifierKey.length)
75
+
76
+ // Enforced by parsing
77
+ if (!resolutionResult.href.endsWith('/')) {
78
+ throw new TypeError(`Expected ${resolutionResult.href} to end with a '/'.`)
79
+ }
80
+
81
+ const url = tryURLParse(afterPrefix, resolutionResult)
82
+ if (!url) {
83
+ throw new TypeError(`Failed to resolve prefix-match relative URL for "${specifierKey}"`)
84
+ }
85
+
86
+ if (!(url instanceof URL)) {
87
+ throw new TypeError(`Expected ${url} to be a URL.`)
88
+ }
89
+
90
+ return url
91
+ }
92
+ }
93
+
94
+ return undefined
95
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @param {string} string
3
+ * @param {URL} [baseURL]
4
+ * @returns {URL | undefined}
5
+ */
6
+ export function tryURLParse(string, baseURL) {
7
+ try {
8
+ return new URL(string, baseURL)
9
+ } catch (e) {
10
+ return undefined
11
+ }
12
+ }
13
+
14
+ /**
15
+ * @param {string} specifier
16
+ * @param {URL} baseURL
17
+ * @returns {URL | undefined}
18
+ */
19
+ export function tryURLLikeSpecifierParse(specifier, baseURL) {
20
+ if (specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../')) {
21
+ return tryURLParse(specifier, baseURL)
22
+ }
23
+
24
+ return tryURLParse(specifier)
25
+ }
@@ -1,8 +1,9 @@
1
1
  import { join, resolve } from 'std/path/mod.ts'
2
- import { resolve as resolveFromImportMap } from 'import-maps/resolve'
2
+ import resolveFromImportMap from './import_map/resolver.js'
3
3
  import { cache } from 'cache'
4
4
 
5
5
  import setup from './setup_plugin.js'
6
+ import { isBareModule } from '../../utils.js'
6
7
 
7
8
  const importKinds = ['import-statement', 'dynamic-import', 'require-call', 'import-rule']
8
9
 
@@ -108,16 +109,21 @@ export default setup('resolve', (build, options) => {
108
109
  }
109
110
 
110
111
  const { matched, resolvedImport } = resolveFromImportMap(params.path, importMap, baseURL)
112
+ // console.log({ importMap, matched, resolvedImport })
111
113
 
112
114
  if (matched) {
113
- if (resolvedImport.protocol === 'file:') {
114
- params.path = resolvedImport.pathname
115
- } else {
116
- if (params.importer.endsWith('.css')) {
117
- return { path: resolvedImport.href, external: true }
115
+ if (resolvedImport instanceof URL) {
116
+ if (resolvedImport.protocol === 'file:') {
117
+ params.path = resolvedImport.pathname
118
+ } else {
119
+ if (params.importer.endsWith('.css')) {
120
+ return { path: resolvedImport.href, external: true }
121
+ }
122
+
123
+ return { path: `/url:${encodeURIComponent(resolvedImport.href)}`, external: true }
118
124
  }
119
-
120
- return { path: `/url:${encodeURIComponent(resolvedImport.href)}`, external: true }
125
+ } else {
126
+ result.path = resolvedImport
121
127
  }
122
128
  }
123
129
  }
@@ -199,7 +205,3 @@ export default setup('resolve', (build, options) => {
199
205
  return result
200
206
  }
201
207
  })
202
-
203
- function isBareModule(mod) {
204
- return !mod.startsWith('/') && !mod.startsWith('.')
205
- }
@@ -4,7 +4,7 @@ import { expandGlob } from 'std/fs/mod.ts'
4
4
  import { join, isGlob, resolve, dirname, fromFileUrl } from 'std/path/mod.ts'
5
5
  import { build, stop } from 'esbuild'
6
6
 
7
- import { readImportMap } from './esbuild/import_map.js'
7
+ import readImportMap from './esbuild/import_map/read.js'
8
8
  import envPlugin from './esbuild/env_plugin.js'
9
9
  import cssPlugin from './esbuild/css_plugin.js'
10
10
  import resolvePlugin from './esbuild/resolve_plugin.js'
@@ -6,3 +6,7 @@ export async function fileExists(path) {
6
6
  return false
7
7
  }
8
8
  }
9
+
10
+ export function isBareModule(mod) {
11
+ return !mod.startsWith('/') && !mod.startsWith('.')
12
+ }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proscenium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Joel Moss
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2022-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actioncable
@@ -167,7 +167,10 @@ files:
167
167
  - lib/proscenium/compilers/esbuild/css_plugin.js
168
168
  - lib/proscenium/compilers/esbuild/env_plugin.js
169
169
  - lib/proscenium/compilers/esbuild/http_bundle_plugin.js
170
- - lib/proscenium/compilers/esbuild/import_map.js
170
+ - lib/proscenium/compilers/esbuild/import_map/parser.js
171
+ - lib/proscenium/compilers/esbuild/import_map/read.js
172
+ - lib/proscenium/compilers/esbuild/import_map/resolver.js
173
+ - lib/proscenium/compilers/esbuild/import_map/utils.js
171
174
  - lib/proscenium/compilers/esbuild/resolve_plugin.js
172
175
  - lib/proscenium/compilers/esbuild/setup_plugin.js
173
176
  - lib/proscenium/compilers/esbuild/solidjs_plugin.js