|
|
|
@ -40,15 +40,7 @@ import {lintKeymap} from '@codemirror/lint' |
|
|
|
]) |
|
|
|
])()` |
|
|
|
|
|
|
|
function log(message, cls = 'cyan') { |
|
|
|
const el = document.createElement('pre') |
|
|
|
el.classList.add(cls) |
|
|
|
el.innerText = message |
|
|
|
document.body.append(el) |
|
|
|
;(el.scrollIntoViewIfNeeded ?? el.scrollIntoView).call(el) |
|
|
|
} |
|
|
|
|
|
|
|
class App { |
|
|
|
class Builder { |
|
|
|
jApiBaseUrl = 'https://data.jsdelivr.com/v1/' |
|
|
|
jCdnBaseUrl = 'https://cdn.jsdelivr.net/npm/' |
|
|
|
|
|
|
|
@ -73,9 +65,6 @@ class App { |
|
|
|
|
|
|
|
constructor() { |
|
|
|
this.downloads = [] |
|
|
|
this.run().catch(e => { |
|
|
|
log(`${e}`) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
checkOk(resp) { |
|
|
|
@ -104,7 +93,7 @@ class App { |
|
|
|
`${dep}@${version}/package.json` |
|
|
|
) |
|
|
|
this.checkOk(pkgResp) |
|
|
|
log(dep) |
|
|
|
this.log(dep) |
|
|
|
const pkg = await pkgResp.json() |
|
|
|
this.scripts[dep].path = ( |
|
|
|
pkg.module ?? pkg.main |
|
|
|
@ -118,18 +107,22 @@ class App { |
|
|
|
))) |
|
|
|
} |
|
|
|
|
|
|
|
async checkIntegrity(resp, name, script) { |
|
|
|
const blob = await resp.blob() |
|
|
|
const ab = await blob.arrayBuffer() |
|
|
|
async sha(ab) { |
|
|
|
const hash = await crypto.subtle.digest( |
|
|
|
"SHA-256", ab |
|
|
|
) |
|
|
|
const checkValue = 'sha256-' + btoa( |
|
|
|
return 'sha256-' + btoa( |
|
|
|
String.fromCharCode( |
|
|
|
...new Uint8Array(hash) |
|
|
|
) |
|
|
|
) |
|
|
|
if (checkValue !== script.sha) { |
|
|
|
} |
|
|
|
|
|
|
|
async checkIntegrity(resp, name, script) { |
|
|
|
const blob = await resp.blob() |
|
|
|
const ab = await blob.arrayBuffer() |
|
|
|
const sha = await this.sha(ab) |
|
|
|
if (sha !== script.sha) { |
|
|
|
throw new Error( |
|
|
|
'failed integrity check: ' + |
|
|
|
`${checkValue} !== ${script.sha}` |
|
|
|
@ -139,7 +132,7 @@ class App { |
|
|
|
} |
|
|
|
|
|
|
|
async getScript(name) { |
|
|
|
log('[downloading] ' + name, 'green') |
|
|
|
this.log('[downloading] ' + name, 'green') |
|
|
|
const script = this.scripts[name] |
|
|
|
if (script.text) { |
|
|
|
return script.text |
|
|
|
@ -159,7 +152,10 @@ class App { |
|
|
|
script.text = await resp.text() |
|
|
|
script.sha = resp.integrity |
|
|
|
} |
|
|
|
log('[downloaded] ' + url + ` [${script.text.length}]`, 'green') |
|
|
|
this.log( |
|
|
|
'[downloaded] ' + url + ` [${script.text.length}]`, |
|
|
|
'green' |
|
|
|
) |
|
|
|
return script.text |
|
|
|
} |
|
|
|
|
|
|
|
@ -180,29 +176,105 @@ class App { |
|
|
|
}, |
|
|
|
load: async id => { |
|
|
|
if (id === 'editor.js') { |
|
|
|
this.log(`[found] editor.js`) |
|
|
|
return editorSrc |
|
|
|
} else if (id in this.scripts) { |
|
|
|
log(`[found] ${id}`) |
|
|
|
this.log(`[found] ${id}`) |
|
|
|
return this.scripts[id].text |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async run() { |
|
|
|
await Promise.allSettled( |
|
|
|
async build() { |
|
|
|
const result = await Promise.all( |
|
|
|
this.topLevelDeps.map(dep => ( |
|
|
|
this.loadDep(dep) |
|
|
|
)) |
|
|
|
) |
|
|
|
await Promise.allSettled(this.downloads) |
|
|
|
await Promise.all(this.downloads) |
|
|
|
await this.loadScript('@rollup/browser') |
|
|
|
const { rollup } = window.rollup |
|
|
|
const input = 'editor.js' |
|
|
|
const plugins = [this.loaderPlugin] |
|
|
|
const bundle = await rollup({input, plugins}) |
|
|
|
const {output} = await bundle.generate({format: 'es'}) |
|
|
|
log(output[0].code) |
|
|
|
this.code = output[0].code |
|
|
|
this.sha = await this.sha( |
|
|
|
new TextEncoder().encode(this.code) |
|
|
|
) |
|
|
|
this.log(`built ${this.sha}`) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class BuildView extends HTMLElement { |
|
|
|
constructor() { |
|
|
|
super() |
|
|
|
this.attachShadow({mode: 'open'}) |
|
|
|
this.shadowRoot.adoptedStyleSheets = [ |
|
|
|
this.constructor.styleSheet |
|
|
|
] |
|
|
|
} |
|
|
|
|
|
|
|
log(message, cls = 'cyan') { |
|
|
|
const el = document.createElement('pre') |
|
|
|
el.classList.add(cls) |
|
|
|
el.innerText = message |
|
|
|
this.shadowRoot.append(el) |
|
|
|
;(el.scrollIntoViewIfNeeded ?? el.scrollIntoView).call(el) |
|
|
|
} |
|
|
|
|
|
|
|
static get styleSheet() { |
|
|
|
if (this._styleSheet === undefined) { |
|
|
|
this._styleSheet = new CSSStyleSheet() |
|
|
|
this._styleSheet.replaceSync(this.css) |
|
|
|
} |
|
|
|
return this._styleSheet |
|
|
|
} |
|
|
|
|
|
|
|
static css = ` |
|
|
|
:host { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: stretch; |
|
|
|
margin: 10px; |
|
|
|
gap: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
pre { |
|
|
|
padding: 8px; |
|
|
|
border-radius: 5px; |
|
|
|
margin: 0; |
|
|
|
overflow-x: auto; |
|
|
|
} |
|
|
|
|
|
|
|
pre.cyan { |
|
|
|
background: cyan; |
|
|
|
} |
|
|
|
|
|
|
|
pre.green { |
|
|
|
background: lightgreen; |
|
|
|
} |
|
|
|
` |
|
|
|
} |
|
|
|
|
|
|
|
customElements.define('m-build-view', BuildView) |
|
|
|
|
|
|
|
class App { |
|
|
|
constructor() { |
|
|
|
this.builder = new Builder() |
|
|
|
this.buildView = document.createElement('m-build-view') |
|
|
|
document.body.append(this.buildView) |
|
|
|
this.builder.log = this.buildView.log.bind(this.buildView) |
|
|
|
this.build() |
|
|
|
} |
|
|
|
|
|
|
|
async build() { |
|
|
|
try { |
|
|
|
await this.builder.build() |
|
|
|
} catch (e) { |
|
|
|
this.buildView.log(`${e}`) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|