proscenium 0.5.0-x86_64-linux → 0.6.0-x86_64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -1
- data/bin/esbuild +0 -0
- data/lib/proscenium/compilers/esbuild/css/postcss.js +2 -2
- data/lib/proscenium/compilers/esbuild/import_map/parser.js +178 -0
- data/lib/proscenium/compilers/esbuild/{import_map.js → import_map/read.js} +7 -2
- data/lib/proscenium/compilers/esbuild/import_map/resolver.js +95 -0
- data/lib/proscenium/compilers/esbuild/import_map/utils.js +25 -0
- data/lib/proscenium/compilers/esbuild/resolve_plugin.js +14 -12
- data/lib/proscenium/compilers/esbuild.js +1 -1
- data/lib/proscenium/utils.js +4 -0
- data/lib/proscenium/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24989d48e852d009d61ca3407eb5c0eca0f56f9cbcd8411379deb9d3388158a7
|
4
|
+
data.tar.gz: 79f44652dda8cf067b5f1df01cb3a7abb408a84f340b6910b15f933109fa6658
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 765d537f7c14394e7aed909394161669fc3a3880b6285f5a0a7b3c42c5554b2835522a159cea97d9d241eea509035e334345547ae0c942df92cd9f15d56659d0
|
7
|
+
data.tar.gz: 3d12dd75c35affe07c46ad369360fd66104799dce799ee4075931179347f7073d29c34ef3adaa3e616f75c3b14b6df5d756ef9a796fa1159936cd2cf7ec15e99
|
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.
|
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
|
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(
|
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 '
|
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
|
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
|
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
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
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
|
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'
|
data/lib/proscenium/utils.js
CHANGED
data/lib/proscenium/version.rb
CHANGED
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.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: x86_64-linux
|
6
6
|
authors:
|
7
7
|
- Joel Moss
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
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
|