@openelement/create 0.41.0-alpha.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.
Files changed (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/cli.d.ts +0 -0
  4. package/cli.js +397 -0
  5. package/package.json +32 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zhi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # @openelement/create
2
+
3
+ Project scaffolding CLI for openElement applications.
4
+
5
+ > v0.39 surface: Framework product entry. This package is part of the
6
+ > first-run Framework story alongside `@openelement/app` and
7
+ > `@openelement/app/vite`.
8
+
9
+ `@openelement/create` generates a new openElement project with the recommended
10
+ directory structure, Deno configuration, Vite setup, and starter pages.
11
+
12
+ ## Usage
13
+
14
+ ```bash
15
+ deno run -A npm:@openelement/create my-app
16
+ cd my-app
17
+ deno task dev
18
+ ```
19
+
20
+ ## What It Creates
21
+
22
+ - `deno.json` - starter authoring imports and build tasks
23
+ - `vite.config.ts` - Vite build configuration with the openElement plugin
24
+ - `app/` - application directory with starter pages and islands
25
+ - `www/` - website output directory
26
+
27
+ The generated import map intentionally keeps protocol and build internals out of
28
+ the starter surface. Advanced contracts remain available through the published
29
+ workspace packages when a project needs them.
30
+
31
+ ## License
32
+
33
+ MIT
package/cli.d.ts ADDED
File without changes
package/cli.js ADDED
@@ -0,0 +1,397 @@
1
+ import { Deno } from "@deno/shim-deno";
2
+ /**
3
+ * @openelement/create - Minimal project scaffold for openElement framework.
4
+ *
5
+ * Usage: deno run -A npm:@openelement/create my-app
6
+ *
7
+ * openElement Architecture: Keep It Simple, Stupid.
8
+ * One template, zero prompts, instant start.
9
+ */ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { createLogger } from '@openelement/core/logger';
12
+ // ??? Package versions ??????????????????????????????????????????
13
+ // ADR 0016: Handle both local (workspace file://) and remote (npm registry) execution.
14
+ //
15
+ // - Local: read version from workspace deno.json (single source of truth)
16
+ // - Remote: query npm Registry API for latest version (zero hardcoding)
17
+ const NPM_SCOPE = '@openelement';
18
+ const log = createLogger('create');
19
+ const PKG_DIR_MAP = {
20
+ core: 'core',
21
+ adapterVite: 'adapter-vite',
22
+ app: 'app',
23
+ content: 'content',
24
+ ui: 'ui',
25
+ signal: 'signal',
26
+ element: 'element'
27
+ };
28
+ function loadWorkspaceVersion(pkg) {
29
+ const metaUrl = import.meta.url;
30
+ const selfPath = fileURLToPath(new URL('.', metaUrl));
31
+ const dir = PKG_DIR_MAP[pkg] || pkg;
32
+ const wsPath = resolve(selfPath, '..', '..', 'packages', dir, 'deno.json');
33
+ try {
34
+ const version = JSON.parse(Deno.readTextFileSync(wsPath)).version;
35
+ if (!version) throw new Error(`No version found in ${wsPath}`);
36
+ return version;
37
+ } catch (e) {
38
+ throw new Error(`Failed to read version for @openelement/${dir} from ${wsPath}. ` + `Run this script from the openElement workspace or ensure deno.json is accessible.\n` + `Original error: ${e}`);
39
+ }
40
+ }
41
+ /** Detect whether cli.ts is being run from the openElement workspace. */ function isWorkspace() {
42
+ try {
43
+ const selfPath = fileURLToPath(new URL('.', import.meta.url));
44
+ Deno.readTextFileSync(resolve(selfPath, '..', '..', 'packages', 'core', 'deno.json'));
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+ /** Fetch the latest version of an npm package from the Registry API. */ async function fetchNpmVersion(pkg) {
51
+ const resp = await fetch(`https://registry.npmjs.org/${NPM_SCOPE}/${pkg}`, {
52
+ headers: {
53
+ Accept: 'application/json'
54
+ }
55
+ });
56
+ if (!resp.ok) {
57
+ throw new Error(`Failed to fetch version for ${NPM_SCOPE}/${pkg} from npm registry (HTTP ${resp.status})`);
58
+ }
59
+ const meta = await resp.json();
60
+ // npm registry response has dist-tags.latest
61
+ const version = meta?.['dist-tags']?.latest;
62
+ if (!version) {
63
+ throw new Error(`No version found for ${NPM_SCOPE}/${pkg} in npm registry response`);
64
+ }
65
+ return version;
66
+ }
67
+ /** Resolve all package versions: local from workspace, remote from npm registry. */ async function resolveVersions() {
68
+ const keys = Object.keys(PKG_DIR_MAP);
69
+ if (isWorkspace()) {
70
+ // Local: synchronous read from workspace
71
+ const v = {};
72
+ for (const k of keys)v[k] = loadWorkspaceVersion(k);
73
+ return v;
74
+ }
75
+ // Remote: fetch all versions from npm in parallel
76
+ console.info('Resolving package versions from npm...');
77
+ const entries = await Promise.all(keys.map(async (k)=>[
78
+ k,
79
+ await fetchNpmVersion(PKG_DIR_MAP[k])
80
+ ]));
81
+ return Object.fromEntries(entries);
82
+ }
83
+ /** Build the template map with resolved version numbers. */ function buildTemplates(v) {
84
+ return {
85
+ '.gitignore': `dist/
86
+ node_modules/
87
+ `,
88
+ 'public/openelement-mark.svg': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" role="img" aria-label="openElement mark">
89
+ <rect width="96" height="96" rx="18" fill="#212529"/>
90
+ <path d="M26 58V38l22-13 22 13v20L48 71 26 58Z" fill="none" stroke="#f8f9fa" stroke-width="6" stroke-linejoin="round"/>
91
+ <path d="M36 48h24" stroke="#7cc7ff" stroke-width="6" stroke-linecap="round"/>
92
+ </svg>
93
+ `,
94
+ 'deno.json': `{
95
+ "imports": {
96
+ "@preact/signals-core": "npm:@preact/signals-core@^1.12.1",
97
+ "@deno/vite-plugin": "npm:@deno/vite-plugin",
98
+ "entities": "npm:entities@^4.5.0",
99
+ "hono": "npm:hono@4.12.23",
100
+ "hono/cors": "npm:hono@4.12.23/cors",
101
+ "hono/logger": "npm:hono@4.12.23/logger",
102
+ "hono/request-id": "npm:hono@4.12.23/request-id",
103
+ "hono/secure-headers": "npm:hono@4.12.23/secure-headers",
104
+ "marked": "npm:marked@15.0.12",
105
+ "@openelement/app": "npm:@openelement/app@^${v.app}",
106
+ "@openelement/app/vite": "npm:@openelement/app@^${v.app}/vite",
107
+ "@openelement/core": "npm:@openelement/core@^${v.core}",
108
+ "@openelement/core/jsx-runtime": "npm:@openelement/core@^${v.core}/jsx-runtime",
109
+ "@openelement/element": "npm:@openelement/element@^${v.element}",
110
+ "@openelement/ui": "npm:@openelement/ui@^${v.ui}",
111
+ "vite": "npm:vite@8.0.10"
112
+ },
113
+ "nodeModulesDir": "auto",
114
+ "tasks": {
115
+ "dev": "deno run --config deno.json -A npm:vite",
116
+ "build": "deno run --config deno.json -A npm:@openelement/adapter-vite@^${v.adapterVite}/cli/build",
117
+ "build:ssr": "deno run --config deno.json -A npm:vite build",
118
+ "build:client": "deno run --config deno.json -A npm:@openelement/adapter-vite@^${v.adapterVite}/cli/build-client",
119
+ "build:ssg": "deno run --config deno.json -A npm:@openelement/adapter-vite@^${v.adapterVite}/cli/build-ssg",
120
+ "preview": "deno run --config deno.json -A npm:vite preview"
121
+ },
122
+ "compilerOptions": { "lib": ["ES2022", "DOM", "DOM.Iterable"], "jsx": "react-jsx", "jsxImportSource": "@openelement/core" }
123
+ }
124
+ `,
125
+ 'vite.config.ts': `import { openElement } from '@openelement/app/vite';
126
+ import { defineConfig } from 'vite';
127
+ import deno from '@deno/vite-plugin';
128
+
129
+ // Design tokens (from Open Props)
130
+ const colorTokensStyle =
131
+ '<style>' +
132
+ '--gray-0:#f8f9fa;--gray-1:#f1f3f5;--gray-3:#dee2e6;--gray-5:#adb5bd;--gray-7:#495057;--gray-9:#212529;' +
133
+ '--brand:#534ab7;--size-1:4px;--size-2:8px;--size-3:12px;--size-4:16px;--border-size-1:1px;--radius-2:8px;' +
134
+ '--font-sans:system-ui,-apple-system,sans-serif;--font-size-0:0.875rem;--font-weight-5:500;' +
135
+ '--shadow-1:0 1px 3px 0 rgb(0 0 0 / 0.1);' +
136
+ 'body{margin:0;background:var(--gray-1);color:var(--gray-9);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}</style>';
137
+
138
+ export default defineConfig({
139
+ plugins: [
140
+ // SOP-015: Virtual module passthrough — @deno/vite-plugin doesn't
141
+ // support the "virtual:" scheme. This resolve hook intercepts virtual
142
+ // module IDs before @deno/vite-plugin, letting the openElement plugin handle them.
143
+ { name: 'virtual-passthrough', resolveId(id) { if (id.startsWith('virtual:')) return '\0' + id; }, enforce: 'pre' },
144
+ deno(),
145
+ openElement({
146
+ html: { title: 'My openElement App' },
147
+ appShell: {
148
+ tagName: 'app-shell',
149
+ import: './app/components/app-shell.tsx',
150
+ props: {
151
+ siteName: 'My openElement App',
152
+ },
153
+ },
154
+ // Use pre-built UI components from @openelement/ui
155
+ // (npm distributes compiled JS - no decorator errors)
156
+ packageIslands: ['@openelement/ui'],
157
+ // SSR must bundle @openelement/ui (decorators need compilation)
158
+ ssr: {
159
+ noExternal: ['@openelement/ui'],
160
+ },
161
+ inject: {
162
+ headFragments: [
163
+ // Design tokens - DRY: values from @openelement/ui/open-props-tokens.ts
164
+ colorTokensStyle,
165
+ ],
166
+ },
167
+ // Blog + Navigation + Sitemap (from @openelement/content)
168
+ content: {
169
+ blog: {
170
+ contentDir: 'content/blog',
171
+ basePath: '/blog',
172
+ },
173
+ nav: {
174
+ routesDir: 'app/routes',
175
+ headerNav: [
176
+ { href: '/', label: 'Home' },
177
+ { href: '/blog', label: 'Blog' },
178
+ ],
179
+ },
180
+ },
181
+ })],
182
+ });
183
+ `,
184
+ 'app/components/app-shell.tsx': `/** @jsxImportSource @openelement/core */
185
+ import { defineLayout } from '@openelement/app';
186
+ import { StyleSheet } from '@openelement/element';
187
+
188
+ export const tagName = 'app-shell';
189
+
190
+ const styles = new StyleSheet();
191
+ styles.replaceSync(\`
192
+ :host { display: block; min-height: 100vh; background: var(--gray-1); }
193
+ header, main, footer { max-width: 860px; margin: 0 auto; padding: 1rem; }
194
+ header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--gray-3); }
195
+ footer { color: var(--gray-7); font-size: 0.875rem; border-top: 1px solid var(--gray-3); }
196
+ a { color: var(--brand); text-decoration: none; font-weight: 600; }
197
+ \`);
198
+
199
+ export default defineLayout(tagName, {
200
+ styles,
201
+ render(props: { siteName?: string }) {
202
+ return (
203
+ <>
204
+ <header data-open-layout="app-shell">
205
+ <a href="/">{props.siteName ?? 'openElement'}</a>
206
+ <nav>
207
+ <a href="/freshness">Freshness</a>
208
+ <a href="/api/health">API health</a>
209
+ </nav>
210
+ </header>
211
+ <main>
212
+ <slot></slot>
213
+ </main>
214
+ <footer>Generated by @openelement/create.</footer>
215
+ </>
216
+ );
217
+ },
218
+ });
219
+ `,
220
+ 'app/routes/index.tsx': `/** @jsxImportSource @openelement/core */
221
+ import { defineElement, definePage } from '@openelement/app';
222
+ import { StyleSheet } from '@openelement/element';
223
+
224
+ export const tagName = 'home-page';
225
+
226
+ const styles = new StyleSheet();
227
+ styles.replaceSync(\`
228
+ :host { display: block; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
229
+ h1 { font-size: 2rem; margin-bottom: 0.5rem; }
230
+ p { color: var(--text-secondary, #666); }
231
+ img { width: 64px; height: 64px; }
232
+ \`);
233
+
234
+ defineElement(tagName, {
235
+ styles,
236
+ render() {
237
+ return (
238
+ <>
239
+ <h1>Hello from openElement!</h1>
240
+ <p>
241
+ Your openElement app is running. Edit <code>app/routes/index.tsx</code> to
242
+ get started.
243
+ </p>
244
+ <img src="/openelement-mark.svg" alt="openElement mark" />
245
+ <my-counter></my-counter>
246
+ </>
247
+ );
248
+ },
249
+ });
250
+
251
+ export default definePage({
252
+ route: { path: '/' },
253
+ head: {
254
+ title: 'My openElement App',
255
+ description: 'Generated openElement starter app',
256
+ },
257
+ renderIntent: {
258
+ mode: 'static',
259
+ streaming: 'auto',
260
+ revalidate: false,
261
+ },
262
+ render() {
263
+ return <home-page />;
264
+ },
265
+ });
266
+ `,
267
+ 'app/routes/freshness.tsx': `/** @jsxImportSource @openelement/core */
268
+ import { defineElement, definePage } from '@openelement/app';
269
+ import { StyleSheet } from '@openelement/element';
270
+
271
+ export const tagName = 'freshness-page';
272
+
273
+ const styles = new StyleSheet();
274
+ styles.replaceSync(\`
275
+ :host { display: block; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
276
+ p { color: var(--text-secondary, #666); }
277
+ \`);
278
+
279
+ defineElement(tagName, {
280
+ styles,
281
+ render() {
282
+ return (
283
+ <>
284
+ <h1>Freshness proof</h1>
285
+ <p>This page records ISR/cache intent with a 300 second revalidate window.</p>
286
+ </>
287
+ );
288
+ },
289
+ });
290
+
291
+ export default definePage({
292
+ route: { path: '/freshness' },
293
+ head: {
294
+ title: 'Freshness proof',
295
+ description: 'Generated openElement ISR intent route',
296
+ },
297
+ renderIntent: {
298
+ mode: 'static',
299
+ streaming: 'auto',
300
+ revalidate: 300,
301
+ },
302
+ render() {
303
+ return <freshness-page />;
304
+ },
305
+ });
306
+ `,
307
+ 'app/routes/api/health.ts': `export default function health() {
308
+ return Response.json({
309
+ ok: true,
310
+ framework: 'openElement',
311
+ route: '/api/health',
312
+ });
313
+ }
314
+ `,
315
+ 'app/islands/my-counter.tsx': `/** @jsxImportSource @openelement/core */
316
+ import { defineIsland, defineIslandConfig } from '@openelement/app';
317
+ import { signal, StyleSheet } from '@openelement/element';
318
+
319
+ export const tagName = 'my-counter';
320
+ export const openElement = defineIslandConfig({ hydrate: 'idle', ssr: true, dsd: true });
321
+
322
+ const styles = new StyleSheet();
323
+ styles.replaceSync(\`
324
+ :host { display: inline-flex; gap: 0.5rem; align-items: center; margin-top: 1rem; }
325
+ button { padding: 0.25rem 0.75rem; cursor: pointer; }
326
+ \`);
327
+
328
+ const count = signal(0);
329
+
330
+ export default defineIsland(tagName, {
331
+ styles,
332
+ render() {
333
+ return (
334
+ <>
335
+ <button onClick={() => count.value--}>-</button>
336
+ <span>{count.value}</span>
337
+ <button onClick={() => count.value++}>+</button>
338
+ </>
339
+ );
340
+ },
341
+ }, { hydrate: openElement.hydrate, dsd: openElement.dsd, ssr: openElement.ssr });
342
+ `
343
+ };
344
+ }
345
+ async function main() {
346
+ const name = Deno.args[0];
347
+ if (!name || name === '--help' || name === '-h') {
348
+ console.log('Usage: deno run -A npm:@openelement/create <project-name>');
349
+ Deno.exit(name ? 0 : 1);
350
+ }
351
+ // H-14 fix: Validate project name format to prevent path traversal
352
+ if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
353
+ log.error(`Invalid project name: "${name}". Project name must only contain letters, numbers, underscores, and hyphens.`);
354
+ Deno.exit(1);
355
+ }
356
+ const cwd = Deno.cwd();
357
+ const targetDir = resolve(cwd, name);
358
+ const relativeTarget = relative(cwd, targetDir);
359
+ if (!relativeTarget || relativeTarget === '..' || relativeTarget.startsWith(`..${sep}`) || isAbsolute(relativeTarget)) {
360
+ log.error(`Refusing to create project outside the current directory: ${name}`);
361
+ Deno.exit(1);
362
+ }
363
+ try {
364
+ await Deno.stat(targetDir);
365
+ log.error(`Directory "${name}" already exists.`);
366
+ Deno.exit(1);
367
+ } catch (e) {
368
+ if (!(e instanceof Deno.errors.NotFound)) {
369
+ log.error(`Failed to inspect target directory "${name}": ${e}`);
370
+ Deno.exit(1);
371
+ }
372
+ }
373
+ // Resolve package versions before generating templates
374
+ const v = await resolveVersions();
375
+ try {
376
+ await Deno.mkdir(targetDir, {
377
+ recursive: true
378
+ });
379
+ } catch (e) {
380
+ log.error(`Failed to create directory "${name}": ${e}`);
381
+ Deno.exit(1);
382
+ }
383
+ const TPL = buildTemplates(v);
384
+ for (const [path, content] of Object.entries(TPL)){
385
+ const fullPath = join(targetDir, path);
386
+ await Deno.mkdir(dirname(fullPath), {
387
+ recursive: true
388
+ });
389
+ await Deno.writeTextFile(fullPath, content);
390
+ console.info(` created ${path}`);
391
+ }
392
+ console.info(`\nopenElement project created at ./${relativeTarget}/`);
393
+ console.info(`\n cd ${relativeTarget}`);
394
+ console.info(' deno task dev');
395
+ }
396
+ main();
397
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9jcmVhdGUvY2xpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlbm8gfSBmcm9tIFwiQGRlbm8vc2hpbS1kZW5vXCI7XG4vKipcbiAqIEBvcGVuZWxlbWVudC9jcmVhdGUgLSBNaW5pbWFsIHByb2plY3Qgc2NhZmZvbGQgZm9yIG9wZW5FbGVtZW50IGZyYW1ld29yay5cbiAqXG4gKiBVc2FnZTogZGVubyBydW4gLUEgbnBtOkBvcGVuZWxlbWVudC9jcmVhdGUgbXktYXBwXG4gKlxuICogb3BlbkVsZW1lbnQgQXJjaGl0ZWN0dXJlOiBLZWVwIEl0IFNpbXBsZSwgU3R1cGlkLlxuICogT25lIHRlbXBsYXRlLCB6ZXJvIHByb21wdHMsIGluc3RhbnQgc3RhcnQuXG4gKi9cblxuaW1wb3J0IHsgZGlybmFtZSwgaXNBYnNvbHV0ZSwgam9pbiwgcmVsYXRpdmUsIHJlc29sdmUsIHNlcCB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAnbm9kZTp1cmwnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQG9wZW5lbGVtZW50L2NvcmUvbG9nZ2VyJztcblxuLy8gPz8/IFBhY2thZ2UgdmVyc2lvbnMgPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/XG4vLyBBRFIgMDAxNjogSGFuZGxlIGJvdGggbG9jYWwgKHdvcmtzcGFjZSBmaWxlOi8vKSBhbmQgcmVtb3RlIChucG0gcmVnaXN0cnkpIGV4ZWN1dGlvbi5cbi8vXG4vLyAtIExvY2FsOiAgcmVhZCB2ZXJzaW9uIGZyb20gd29ya3NwYWNlIGRlbm8uanNvbiAoc2luZ2xlIHNvdXJjZSBvZiB0cnV0aClcbi8vIC0gUmVtb3RlOiBxdWVyeSBucG0gUmVnaXN0cnkgQVBJIGZvciBsYXRlc3QgdmVyc2lvbiAoemVybyBoYXJkY29kaW5nKVxuXG5jb25zdCBOUE1fU0NPUEUgPSAnQG9wZW5lbGVtZW50JztcbmNvbnN0IGxvZyA9IGNyZWF0ZUxvZ2dlcignY3JlYXRlJyk7XG5jb25zdCBQS0dfRElSX01BUDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgY29yZTogJ2NvcmUnLFxuICBhZGFwdGVyVml0ZTogJ2FkYXB0ZXItdml0ZScsXG4gIGFwcDogJ2FwcCcsXG4gIGNvbnRlbnQ6ICdjb250ZW50JyxcbiAgdWk6ICd1aScsXG4gIHNpZ25hbDogJ3NpZ25hbCcsXG4gIGVsZW1lbnQ6ICdlbGVtZW50Jyxcbn07XG5cbmZ1bmN0aW9uIGxvYWRXb3Jrc3BhY2VWZXJzaW9uKHBrZzogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgbWV0YVVybCA9IGltcG9ydC5tZXRhLnVybDtcbiAgY29uc3Qgc2VsZlBhdGggPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBtZXRhVXJsKSk7XG4gIGNvbnN0IGRpciA9IFBLR19ESVJfTUFQW3BrZ10gfHwgcGtnO1xuICBjb25zdCB3c1BhdGggPSByZXNvbHZlKHNlbGZQYXRoLCAnLi4nLCAnLi4nLCAncGFja2FnZXMnLCBkaXIsICdkZW5vLmpzb24nKTtcbiAgdHJ5IHtcbiAgICBjb25zdCB2ZXJzaW9uID0gSlNPTi5wYXJzZShEZW5vLnJlYWRUZXh0RmlsZVN5bmMod3NQYXRoKSkudmVyc2lvbjtcbiAgICBpZiAoIXZlcnNpb24pIHRocm93IG5ldyBFcnJvcihgTm8gdmVyc2lvbiBmb3VuZCBpbiAke3dzUGF0aH1gKTtcbiAgICByZXR1cm4gdmVyc2lvbjtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBGYWlsZWQgdG8gcmVhZCB2ZXJzaW9uIGZvciBAb3BlbmVsZW1lbnQvJHtkaXJ9IGZyb20gJHt3c1BhdGh9LiBgICtcbiAgICAgICAgYFJ1biB0aGlzIHNjcmlwdCBmcm9tIHRoZSBvcGVuRWxlbWVudCB3b3Jrc3BhY2Ugb3IgZW5zdXJlIGRlbm8uanNvbiBpcyBhY2Nlc3NpYmxlLlxcbmAgK1xuICAgICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZX1gLFxuICAgICk7XG4gIH1cbn1cblxuLyoqIERldGVjdCB3aGV0aGVyIGNsaS50cyBpcyBiZWluZyBydW4gZnJvbSB0aGUgb3BlbkVsZW1lbnQgd29ya3NwYWNlLiAqL1xuZnVuY3Rpb24gaXNXb3Jrc3BhY2UoKTogYm9vbGVhbiB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc2VsZlBhdGggPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcbiAgICBEZW5vLnJlYWRUZXh0RmlsZVN5bmMocmVzb2x2ZShzZWxmUGF0aCwgJy4uJywgJy4uJywgJ3BhY2thZ2VzJywgJ2NvcmUnLCAnZGVuby5qc29uJykpO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqIEZldGNoIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBhbiBucG0gcGFja2FnZSBmcm9tIHRoZSBSZWdpc3RyeSBBUEkuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaE5wbVZlcnNpb24ocGtnOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCByZXNwID0gYXdhaXQgZmV0Y2goYGh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnLyR7TlBNX1NDT1BFfS8ke3BrZ31gLCB7XG4gICAgaGVhZGVyczogeyBBY2NlcHQ6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxuICB9KTtcbiAgaWYgKCFyZXNwLm9rKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEZhaWxlZCB0byBmZXRjaCB2ZXJzaW9uIGZvciAke05QTV9TQ09QRX0vJHtwa2d9IGZyb20gbnBtIHJlZ2lzdHJ5IChIVFRQICR7cmVzcC5zdGF0dXN9KWAsXG4gICAgKTtcbiAgfVxuICBjb25zdCBtZXRhID0gYXdhaXQgcmVzcC5qc29uKCk7XG4gIC8vIG5wbSByZWdpc3RyeSByZXNwb25zZSBoYXMgZGlzdC10YWdzLmxhdGVzdFxuICBjb25zdCB2ZXJzaW9uID0gbWV0YT8uWydkaXN0LXRhZ3MnXT8ubGF0ZXN0O1xuICBpZiAoIXZlcnNpb24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgTm8gdmVyc2lvbiBmb3VuZCBmb3IgJHtOUE1fU0NPUEV9LyR7cGtnfSBpbiBucG0gcmVnaXN0cnkgcmVzcG9uc2VgLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHZlcnNpb247XG59XG5cbi8qKiBSZXNvbHZlIGFsbCBwYWNrYWdlIHZlcnNpb25zOiBsb2NhbCBmcm9tIHdvcmtzcGFjZSwgcmVtb3RlIGZyb20gbnBtIHJlZ2lzdHJ5LiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZVZlcnNpb25zKCk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4ge1xuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoUEtHX0RJUl9NQVApO1xuICBpZiAoaXNXb3Jrc3BhY2UoKSkge1xuICAgIC8vIExvY2FsOiBzeW5jaHJvbm91cyByZWFkIGZyb20gd29ya3NwYWNlXG4gICAgY29uc3QgdjogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIGZvciAoY29uc3QgayBvZiBrZXlzKSB2W2tdID0gbG9hZFdvcmtzcGFjZVZlcnNpb24oayk7XG4gICAgcmV0dXJuIHY7XG4gIH1cblxuICAvLyBSZW1vdGU6IGZldGNoIGFsbCB2ZXJzaW9ucyBmcm9tIG5wbSBpbiBwYXJhbGxlbFxuICBjb25zb2xlLmluZm8oJ1Jlc29sdmluZyBwYWNrYWdlIHZlcnNpb25zIGZyb20gbnBtLi4uJyk7XG4gIGNvbnN0IGVudHJpZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICBrZXlzLm1hcChhc3luYyAoaykgPT4gW2ssIGF3YWl0IGZldGNoTnBtVmVyc2lvbihQS0dfRElSX01BUFtrXSldKSxcbiAgKTtcbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhlbnRyaWVzKTtcbn1cblxuLyoqIEJ1aWxkIHRoZSB0ZW1wbGF0ZSBtYXAgd2l0aCByZXNvbHZlZCB2ZXJzaW9uIG51bWJlcnMuICovXG5mdW5jdGlvbiBidWlsZFRlbXBsYXRlcyh2OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIHJldHVybiB7XG4gICAgJy5naXRpZ25vcmUnOiBgZGlzdC9cbm5vZGVfbW9kdWxlcy9cbmAsXG4gICAgJ3B1YmxpYy9vcGVuZWxlbWVudC1tYXJrLnN2Zyc6XG4gICAgICBgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCA5NiA5NlwiIHJvbGU9XCJpbWdcIiBhcmlhLWxhYmVsPVwib3BlbkVsZW1lbnQgbWFya1wiPlxuICA8cmVjdCB3aWR0aD1cIjk2XCIgaGVpZ2h0PVwiOTZcIiByeD1cIjE4XCIgZmlsbD1cIiMyMTI1MjlcIi8+XG4gIDxwYXRoIGQ9XCJNMjYgNThWMzhsMjItMTMgMjIgMTN2MjBMNDggNzEgMjYgNThaXCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCIjZjhmOWZhXCIgc3Ryb2tlLXdpZHRoPVwiNlwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICA8cGF0aCBkPVwiTTM2IDQ4aDI0XCIgc3Ryb2tlPVwiIzdjYzdmZlwiIHN0cm9rZS13aWR0aD1cIjZcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIvPlxuPC9zdmc+XG5gLFxuICAgICdkZW5vLmpzb24nOiBge1xuICBcImltcG9ydHNcIjoge1xuICAgIFwiQHByZWFjdC9zaWduYWxzLWNvcmVcIjogXCJucG06QHByZWFjdC9zaWduYWxzLWNvcmVAXjEuMTIuMVwiLFxuICAgIFwiQGRlbm8vdml0ZS1wbHVnaW5cIjogXCJucG06QGRlbm8vdml0ZS1wbHVnaW5cIixcbiAgICBcImVudGl0aWVzXCI6IFwibnBtOmVudGl0aWVzQF40LjUuMFwiLFxuICAgIFwiaG9ub1wiOiBcIm5wbTpob25vQDQuMTIuMjNcIixcbiAgICBcImhvbm8vY29yc1wiOiBcIm5wbTpob25vQDQuMTIuMjMvY29yc1wiLFxuICAgIFwiaG9uby9sb2dnZXJcIjogXCJucG06aG9ub0A0LjEyLjIzL2xvZ2dlclwiLFxuICAgIFwiaG9uby9yZXF1ZXN0LWlkXCI6IFwibnBtOmhvbm9ANC4xMi4yMy9yZXF1ZXN0LWlkXCIsXG4gICAgXCJob25vL3NlY3VyZS1oZWFkZXJzXCI6IFwibnBtOmhvbm9ANC4xMi4yMy9zZWN1cmUtaGVhZGVyc1wiLFxuICAgIFwibWFya2VkXCI6IFwibnBtOm1hcmtlZEAxNS4wLjEyXCIsXG4gICAgXCJAb3BlbmVsZW1lbnQvYXBwXCI6IFwibnBtOkBvcGVuZWxlbWVudC9hcHBAXiR7di5hcHB9XCIsXG4gICAgXCJAb3BlbmVsZW1lbnQvYXBwL3ZpdGVcIjogXCJucG06QG9wZW5lbGVtZW50L2FwcEBeJHt2LmFwcH0vdml0ZVwiLFxuICAgIFwiQG9wZW5lbGVtZW50L2NvcmVcIjogXCJucG06QG9wZW5lbGVtZW50L2NvcmVAXiR7di5jb3JlfVwiLFxuICAgIFwiQG9wZW5lbGVtZW50L2NvcmUvanN4LXJ1bnRpbWVcIjogXCJucG06QG9wZW5lbGVtZW50L2NvcmVAXiR7di5jb3JlfS9qc3gtcnVudGltZVwiLFxuICAgIFwiQG9wZW5lbGVtZW50L2VsZW1lbnRcIjogXCJucG06QG9wZW5lbGVtZW50L2VsZW1lbnRAXiR7di5lbGVtZW50fVwiLFxuICAgIFwiQG9wZW5lbGVtZW50L3VpXCI6IFwibnBtOkBvcGVuZWxlbWVudC91aUBeJHt2LnVpfVwiLFxuICAgIFwidml0ZVwiOiBcIm5wbTp2aXRlQDguMC4xMFwiXG4gIH0sXG4gIFwibm9kZU1vZHVsZXNEaXJcIjogXCJhdXRvXCIsXG4gIFwidGFza3NcIjoge1xuICAgIFwiZGV2XCI6IFwiZGVubyBydW4gLS1jb25maWcgZGVuby5qc29uIC1BIG5wbTp2aXRlXCIsXG4gICAgXCJidWlsZFwiOiBcImRlbm8gcnVuIC0tY29uZmlnIGRlbm8uanNvbiAtQSBucG06QG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZUBeJHt2LmFkYXB0ZXJWaXRlfS9jbGkvYnVpbGRcIixcbiAgICBcImJ1aWxkOnNzclwiOiBcImRlbm8gcnVuIC0tY29uZmlnIGRlbm8uanNvbiAtQSBucG06dml0ZSBidWlsZFwiLFxuICAgIFwiYnVpbGQ6Y2xpZW50XCI6IFwiZGVubyBydW4gLS1jb25maWcgZGVuby5qc29uIC1BIG5wbTpAb3BlbmVsZW1lbnQvYWRhcHRlci12aXRlQF4ke3YuYWRhcHRlclZpdGV9L2NsaS9idWlsZC1jbGllbnRcIixcbiAgICBcImJ1aWxkOnNzZ1wiOiBcImRlbm8gcnVuIC0tY29uZmlnIGRlbm8uanNvbiAtQSBucG06QG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZUBeJHt2LmFkYXB0ZXJWaXRlfS9jbGkvYnVpbGQtc3NnXCIsXG4gICAgXCJwcmV2aWV3XCI6IFwiZGVubyBydW4gLS1jb25maWcgZGVuby5qc29uIC1BIG5wbTp2aXRlIHByZXZpZXdcIlxuICB9LFxuICBcImNvbXBpbGVyT3B0aW9uc1wiOiB7IFwibGliXCI6IFtcIkVTMjAyMlwiLCBcIkRPTVwiLCBcIkRPTS5JdGVyYWJsZVwiXSwgXCJqc3hcIjogXCJyZWFjdC1qc3hcIiwgXCJqc3hJbXBvcnRTb3VyY2VcIjogXCJAb3BlbmVsZW1lbnQvY29yZVwiIH1cbn1cbmAsXG4gICAgJ3ZpdGUuY29uZmlnLnRzJzogYGltcG9ydCB7IG9wZW5FbGVtZW50IH0gZnJvbSAnQG9wZW5lbGVtZW50L2FwcC92aXRlJztcbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnO1xuaW1wb3J0IGRlbm8gZnJvbSAnQGRlbm8vdml0ZS1wbHVnaW4nO1xuXG4vLyBEZXNpZ24gdG9rZW5zIChmcm9tIE9wZW4gUHJvcHMpXG5jb25zdCBjb2xvclRva2Vuc1N0eWxlID1cbiAgJzxzdHlsZT4nICtcbiAgJy0tZ3JheS0wOiNmOGY5ZmE7LS1ncmF5LTE6I2YxZjNmNTstLWdyYXktMzojZGVlMmU2Oy0tZ3JheS01OiNhZGI1YmQ7LS1ncmF5LTc6IzQ5NTA1NzstLWdyYXktOTojMjEyNTI5OycgK1xuICAnLS1icmFuZDojNTM0YWI3Oy0tc2l6ZS0xOjRweDstLXNpemUtMjo4cHg7LS1zaXplLTM6MTJweDstLXNpemUtNDoxNnB4Oy0tYm9yZGVyLXNpemUtMToxcHg7LS1yYWRpdXMtMjo4cHg7JyArXG4gICctLWZvbnQtc2FuczpzeXN0ZW0tdWksLWFwcGxlLXN5c3RlbSxzYW5zLXNlcmlmOy0tZm9udC1zaXplLTA6MC44NzVyZW07LS1mb250LXdlaWdodC01OjUwMDsnICtcbiAgJy0tc2hhZG93LTE6MCAxcHggM3B4IDAgcmdiKDAgMCAwIC8gMC4xKTsnICtcbiAgJ2JvZHl7bWFyZ2luOjA7YmFja2dyb3VuZDp2YXIoLS1ncmF5LTEpO2NvbG9yOnZhcigtLWdyYXktOSk7Zm9udC1mYW1pbHk6dmFyKC0tZm9udC1zYW5zKTstd2Via2l0LWZvbnQtc21vb3RoaW5nOmFudGlhbGlhc2VkOy1tb3otb3N4LWZvbnQtc21vb3RoaW5nOmdyYXlzY2FsZX08L3N0eWxlPic7XG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFtcbiAgICAvLyBTT1AtMDE1OiBWaXJ0dWFsIG1vZHVsZSBwYXNzdGhyb3VnaCDigJQgQGRlbm8vdml0ZS1wbHVnaW4gZG9lc24ndFxuICAgIC8vIHN1cHBvcnQgdGhlIFwidmlydHVhbDpcIiBzY2hlbWUuIFRoaXMgcmVzb2x2ZSBob29rIGludGVyY2VwdHMgdmlydHVhbFxuICAgIC8vIG1vZHVsZSBJRHMgYmVmb3JlIEBkZW5vL3ZpdGUtcGx1Z2luLCBsZXR0aW5nIHRoZSBvcGVuRWxlbWVudCBwbHVnaW4gaGFuZGxlIHRoZW0uXG4gICAgeyBuYW1lOiAndmlydHVhbC1wYXNzdGhyb3VnaCcsIHJlc29sdmVJZChpZCkgeyBpZiAoaWQuc3RhcnRzV2l0aCgndmlydHVhbDonKSkgcmV0dXJuICdcXDAnICsgaWQ7IH0sIGVuZm9yY2U6ICdwcmUnIH0sXG4gICAgZGVubygpLFxuICAgIG9wZW5FbGVtZW50KHtcbiAgICBodG1sOiB7IHRpdGxlOiAnTXkgb3BlbkVsZW1lbnQgQXBwJyB9LFxuICAgIGFwcFNoZWxsOiB7XG4gICAgICB0YWdOYW1lOiAnYXBwLXNoZWxsJyxcbiAgICAgIGltcG9ydDogJy4vYXBwL2NvbXBvbmVudHMvYXBwLXNoZWxsLnRzeCcsXG4gICAgICBwcm9wczoge1xuICAgICAgICBzaXRlTmFtZTogJ015IG9wZW5FbGVtZW50IEFwcCcsXG4gICAgICB9LFxuICAgIH0sXG4gICAgLy8gVXNlIHByZS1idWlsdCBVSSBjb21wb25lbnRzIGZyb20gQG9wZW5lbGVtZW50L3VpXG4gICAgLy8gKG5wbSBkaXN0cmlidXRlcyBjb21waWxlZCBKUyAtIG5vIGRlY29yYXRvciBlcnJvcnMpXG4gICAgcGFja2FnZUlzbGFuZHM6IFsnQG9wZW5lbGVtZW50L3VpJ10sXG4gICAgLy8gU1NSIG11c3QgYnVuZGxlIEBvcGVuZWxlbWVudC91aSAoZGVjb3JhdG9ycyBuZWVkIGNvbXBpbGF0aW9uKVxuICAgIHNzcjoge1xuICAgICAgbm9FeHRlcm5hbDogWydAb3BlbmVsZW1lbnQvdWknXSxcbiAgICB9LFxuICAgIGluamVjdDoge1xuICAgICAgaGVhZEZyYWdtZW50czogW1xuICAgICAgICAvLyBEZXNpZ24gdG9rZW5zIC0gRFJZOiB2YWx1ZXMgZnJvbSBAb3BlbmVsZW1lbnQvdWkvb3Blbi1wcm9wcy10b2tlbnMudHNcbiAgICAgICAgY29sb3JUb2tlbnNTdHlsZSxcbiAgICAgIF0sXG4gICAgfSxcbiAgICAvLyBCbG9nICsgTmF2aWdhdGlvbiArIFNpdGVtYXAgKGZyb20gQG9wZW5lbGVtZW50L2NvbnRlbnQpXG4gICAgY29udGVudDoge1xuICAgICAgYmxvZzoge1xuICAgICAgICBjb250ZW50RGlyOiAnY29udGVudC9ibG9nJyxcbiAgICAgICAgYmFzZVBhdGg6ICcvYmxvZycsXG4gICAgICB9LFxuICAgICAgbmF2OiB7XG4gICAgICAgIHJvdXRlc0RpcjogJ2FwcC9yb3V0ZXMnLFxuICAgICAgICBoZWFkZXJOYXY6IFtcbiAgICAgICAgICB7IGhyZWY6ICcvJywgbGFiZWw6ICdIb21lJyB9LFxuICAgICAgICAgIHsgaHJlZjogJy9ibG9nJywgbGFiZWw6ICdCbG9nJyB9LFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICB9LFxuICB9KV0sXG59KTtcbmAsXG4gICAgJ2FwcC9jb21wb25lbnRzL2FwcC1zaGVsbC50c3gnOiBgLyoqIEBqc3hJbXBvcnRTb3VyY2UgQG9wZW5lbGVtZW50L2NvcmUgKi9cbmltcG9ydCB7IGRlZmluZUxheW91dCB9IGZyb20gJ0BvcGVuZWxlbWVudC9hcHAnO1xuaW1wb3J0IHsgU3R5bGVTaGVldCB9IGZyb20gJ0BvcGVuZWxlbWVudC9lbGVtZW50JztcblxuZXhwb3J0IGNvbnN0IHRhZ05hbWUgPSAnYXBwLXNoZWxsJztcblxuY29uc3Qgc3R5bGVzID0gbmV3IFN0eWxlU2hlZXQoKTtcbnN0eWxlcy5yZXBsYWNlU3luYyhcXGBcbiAgOmhvc3QgeyBkaXNwbGF5OiBibG9jazsgbWluLWhlaWdodDogMTAwdmg7IGJhY2tncm91bmQ6IHZhcigtLWdyYXktMSk7IH1cbiAgaGVhZGVyLCBtYWluLCBmb290ZXIgeyBtYXgtd2lkdGg6IDg2MHB4OyBtYXJnaW46IDAgYXV0bzsgcGFkZGluZzogMXJlbTsgfVxuICBoZWFkZXIgeyBkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGJvcmRlci1ib3R0b206IDFweCBzb2xpZCB2YXIoLS1ncmF5LTMpOyB9XG4gIGZvb3RlciB7IGNvbG9yOiB2YXIoLS1ncmF5LTcpOyBmb250LXNpemU6IDAuODc1cmVtOyBib3JkZXItdG9wOiAxcHggc29saWQgdmFyKC0tZ3JheS0zKTsgfVxuICBhIHsgY29sb3I6IHZhcigtLWJyYW5kKTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXdlaWdodDogNjAwOyB9XG5cXGApO1xuXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVMYXlvdXQodGFnTmFtZSwge1xuICBzdHlsZXMsXG4gIHJlbmRlcihwcm9wczogeyBzaXRlTmFtZT86IHN0cmluZyB9KSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDw+XG4gICAgICAgIDxoZWFkZXIgZGF0YS1vcGVuLWxheW91dD1cImFwcC1zaGVsbFwiPlxuICAgICAgICAgIDxhIGhyZWY9XCIvXCI+e3Byb3BzLnNpdGVOYW1lID8/ICdvcGVuRWxlbWVudCd9PC9hPlxuICAgICAgICAgIDxuYXY+XG4gICAgICAgICAgICA8YSBocmVmPVwiL2ZyZXNobmVzc1wiPkZyZXNobmVzczwvYT5cbiAgICAgICAgICAgIDxhIGhyZWY9XCIvYXBpL2hlYWx0aFwiPkFQSSBoZWFsdGg8L2E+XG4gICAgICAgICAgPC9uYXY+XG4gICAgICAgIDwvaGVhZGVyPlxuICAgICAgICA8bWFpbj5cbiAgICAgICAgICA8c2xvdD48L3Nsb3Q+XG4gICAgICAgIDwvbWFpbj5cbiAgICAgICAgPGZvb3Rlcj5HZW5lcmF0ZWQgYnkgQG9wZW5lbGVtZW50L2NyZWF0ZS48L2Zvb3Rlcj5cbiAgICAgIDwvPlxuICAgICk7XG4gIH0sXG59KTtcbmAsXG4gICAgJ2FwcC9yb3V0ZXMvaW5kZXgudHN4JzogYC8qKiBAanN4SW1wb3J0U291cmNlIEBvcGVuZWxlbWVudC9jb3JlICovXG5pbXBvcnQgeyBkZWZpbmVFbGVtZW50LCBkZWZpbmVQYWdlIH0gZnJvbSAnQG9wZW5lbGVtZW50L2FwcCc7XG5pbXBvcnQgeyBTdHlsZVNoZWV0IH0gZnJvbSAnQG9wZW5lbGVtZW50L2VsZW1lbnQnO1xuXG5leHBvcnQgY29uc3QgdGFnTmFtZSA9ICdob21lLXBhZ2UnO1xuXG5jb25zdCBzdHlsZXMgPSBuZXcgU3R5bGVTaGVldCgpO1xuc3R5bGVzLnJlcGxhY2VTeW5jKFxcYFxuICA6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyBtYXgtd2lkdGg6IDgwMHB4OyBtYXJnaW46IDJyZW0gYXV0bzsgcGFkZGluZzogMCAxcmVtOyB9XG4gIGgxIHsgZm9udC1zaXplOiAycmVtOyBtYXJnaW4tYm90dG9tOiAwLjVyZW07IH1cbiAgcCB7IGNvbG9yOiB2YXIoLS10ZXh0LXNlY29uZGFyeSwgIzY2Nik7IH1cbiAgaW1nIHsgd2lkdGg6IDY0cHg7IGhlaWdodDogNjRweDsgfVxuXFxgKTtcblxuZGVmaW5lRWxlbWVudCh0YWdOYW1lLCB7XG4gIHN0eWxlcyxcbiAgcmVuZGVyKCkge1xuICAgIHJldHVybiAoXG4gICAgICA8PlxuICAgICAgICA8aDE+SGVsbG8gZnJvbSBvcGVuRWxlbWVudCE8L2gxPlxuICAgICAgICA8cD5cbiAgICAgICAgICBZb3VyIG9wZW5FbGVtZW50IGFwcCBpcyBydW5uaW5nLiBFZGl0IDxjb2RlPmFwcC9yb3V0ZXMvaW5kZXgudHN4PC9jb2RlPiB0b1xuICAgICAgICAgIGdldCBzdGFydGVkLlxuICAgICAgICA8L3A+XG4gICAgICAgIDxpbWcgc3JjPVwiL29wZW5lbGVtZW50LW1hcmsuc3ZnXCIgYWx0PVwib3BlbkVsZW1lbnQgbWFya1wiIC8+XG4gICAgICAgIDxteS1jb3VudGVyPjwvbXktY291bnRlcj5cbiAgICAgIDwvPlxuICAgICk7XG4gIH0sXG59KTtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lUGFnZSh7XG4gIHJvdXRlOiB7IHBhdGg6ICcvJyB9LFxuICBoZWFkOiB7XG4gICAgdGl0bGU6ICdNeSBvcGVuRWxlbWVudCBBcHAnLFxuICAgIGRlc2NyaXB0aW9uOiAnR2VuZXJhdGVkIG9wZW5FbGVtZW50IHN0YXJ0ZXIgYXBwJyxcbiAgfSxcbiAgcmVuZGVySW50ZW50OiB7XG4gICAgbW9kZTogJ3N0YXRpYycsXG4gICAgc3RyZWFtaW5nOiAnYXV0bycsXG4gICAgcmV2YWxpZGF0ZTogZmFsc2UsXG4gIH0sXG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gPGhvbWUtcGFnZSAvPjtcbiAgfSxcbn0pO1xuYCxcbiAgICAnYXBwL3JvdXRlcy9mcmVzaG5lc3MudHN4JzogYC8qKiBAanN4SW1wb3J0U291cmNlIEBvcGVuZWxlbWVudC9jb3JlICovXG5pbXBvcnQgeyBkZWZpbmVFbGVtZW50LCBkZWZpbmVQYWdlIH0gZnJvbSAnQG9wZW5lbGVtZW50L2FwcCc7XG5pbXBvcnQgeyBTdHlsZVNoZWV0IH0gZnJvbSAnQG9wZW5lbGVtZW50L2VsZW1lbnQnO1xuXG5leHBvcnQgY29uc3QgdGFnTmFtZSA9ICdmcmVzaG5lc3MtcGFnZSc7XG5cbmNvbnN0IHN0eWxlcyA9IG5ldyBTdHlsZVNoZWV0KCk7XG5zdHlsZXMucmVwbGFjZVN5bmMoXFxgXG4gIDpob3N0IHsgZGlzcGxheTogYmxvY2s7IG1heC13aWR0aDogODAwcHg7IG1hcmdpbjogMnJlbSBhdXRvOyBwYWRkaW5nOiAwIDFyZW07IH1cbiAgcCB7IGNvbG9yOiB2YXIoLS10ZXh0LXNlY29uZGFyeSwgIzY2Nik7IH1cblxcYCk7XG5cbmRlZmluZUVsZW1lbnQodGFnTmFtZSwge1xuICBzdHlsZXMsXG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gKFxuICAgICAgPD5cbiAgICAgICAgPGgxPkZyZXNobmVzcyBwcm9vZjwvaDE+XG4gICAgICAgIDxwPlRoaXMgcGFnZSByZWNvcmRzIElTUi9jYWNoZSBpbnRlbnQgd2l0aCBhIDMwMCBzZWNvbmQgcmV2YWxpZGF0ZSB3aW5kb3cuPC9wPlxuICAgICAgPC8+XG4gICAgKTtcbiAgfSxcbn0pO1xuXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVQYWdlKHtcbiAgcm91dGU6IHsgcGF0aDogJy9mcmVzaG5lc3MnIH0sXG4gIGhlYWQ6IHtcbiAgICB0aXRsZTogJ0ZyZXNobmVzcyBwcm9vZicsXG4gICAgZGVzY3JpcHRpb246ICdHZW5lcmF0ZWQgb3BlbkVsZW1lbnQgSVNSIGludGVudCByb3V0ZScsXG4gIH0sXG4gIHJlbmRlckludGVudDoge1xuICAgIG1vZGU6ICdzdGF0aWMnLFxuICAgIHN0cmVhbWluZzogJ2F1dG8nLFxuICAgIHJldmFsaWRhdGU6IDMwMCxcbiAgfSxcbiAgcmVuZGVyKCkge1xuICAgIHJldHVybiA8ZnJlc2huZXNzLXBhZ2UgLz47XG4gIH0sXG59KTtcbmAsXG4gICAgJ2FwcC9yb3V0ZXMvYXBpL2hlYWx0aC50cyc6IGBleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGgoKSB7XG4gIHJldHVybiBSZXNwb25zZS5qc29uKHtcbiAgICBvazogdHJ1ZSxcbiAgICBmcmFtZXdvcms6ICdvcGVuRWxlbWVudCcsXG4gICAgcm91dGU6ICcvYXBpL2hlYWx0aCcsXG4gIH0pO1xufVxuYCxcbiAgICAnYXBwL2lzbGFuZHMvbXktY291bnRlci50c3gnOiBgLyoqIEBqc3hJbXBvcnRTb3VyY2UgQG9wZW5lbGVtZW50L2NvcmUgKi9cbmltcG9ydCB7IGRlZmluZUlzbGFuZCwgZGVmaW5lSXNsYW5kQ29uZmlnIH0gZnJvbSAnQG9wZW5lbGVtZW50L2FwcCc7XG5pbXBvcnQgeyBzaWduYWwsIFN0eWxlU2hlZXQgfSBmcm9tICdAb3BlbmVsZW1lbnQvZWxlbWVudCc7XG5cbmV4cG9ydCBjb25zdCB0YWdOYW1lID0gJ215LWNvdW50ZXInO1xuZXhwb3J0IGNvbnN0IG9wZW5FbGVtZW50ID0gZGVmaW5lSXNsYW5kQ29uZmlnKHsgaHlkcmF0ZTogJ2lkbGUnLCBzc3I6IHRydWUsIGRzZDogdHJ1ZSB9KTtcblxuY29uc3Qgc3R5bGVzID0gbmV3IFN0eWxlU2hlZXQoKTtcbnN0eWxlcy5yZXBsYWNlU3luYyhcXGBcbiAgOmhvc3QgeyBkaXNwbGF5OiBpbmxpbmUtZmxleDsgZ2FwOiAwLjVyZW07IGFsaWduLWl0ZW1zOiBjZW50ZXI7IG1hcmdpbi10b3A6IDFyZW07IH1cbiAgYnV0dG9uIHsgcGFkZGluZzogMC4yNXJlbSAwLjc1cmVtOyBjdXJzb3I6IHBvaW50ZXI7IH1cblxcYCk7XG5cbmNvbnN0IGNvdW50ID0gc2lnbmFsKDApO1xuXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVJc2xhbmQodGFnTmFtZSwge1xuICBzdHlsZXMsXG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gKFxuICAgICAgPD5cbiAgICAgICAgPGJ1dHRvbiBvbkNsaWNrPXsoKSA9PiBjb3VudC52YWx1ZS0tfT4tPC9idXR0b24+XG4gICAgICAgIDxzcGFuPntjb3VudC52YWx1ZX08L3NwYW4+XG4gICAgICAgIDxidXR0b24gb25DbGljaz17KCkgPT4gY291bnQudmFsdWUrK30+KzwvYnV0dG9uPlxuICAgICAgPC8+XG4gICAgKTtcbiAgfSxcbn0sIHsgaHlkcmF0ZTogb3BlbkVsZW1lbnQuaHlkcmF0ZSwgZHNkOiBvcGVuRWxlbWVudC5kc2QsIHNzcjogb3BlbkVsZW1lbnQuc3NyIH0pO1xuYCxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgY29uc3QgbmFtZSA9IERlbm8uYXJnc1swXTtcbiAgaWYgKCFuYW1lIHx8IG5hbWUgPT09ICctLWhlbHAnIHx8IG5hbWUgPT09ICctaCcpIHtcbiAgICBjb25zb2xlLmxvZygnVXNhZ2U6IGRlbm8gcnVuIC1BIG5wbTpAb3BlbmVsZW1lbnQvY3JlYXRlIDxwcm9qZWN0LW5hbWU+Jyk7XG4gICAgRGVuby5leGl0KG5hbWUgPyAwIDogMSk7XG4gIH1cblxuICAvLyBILTE0IGZpeDogVmFsaWRhdGUgcHJvamVjdCBuYW1lIGZvcm1hdCB0byBwcmV2ZW50IHBhdGggdHJhdmVyc2FsXG4gIGlmICghL15bYS16QS1aMC05Xy1dKyQvLnRlc3QobmFtZSkpIHtcbiAgICBsb2cuZXJyb3IoXG4gICAgICBgSW52YWxpZCBwcm9qZWN0IG5hbWU6IFwiJHtuYW1lfVwiLiBQcm9qZWN0IG5hbWUgbXVzdCBvbmx5IGNvbnRhaW4gbGV0dGVycywgbnVtYmVycywgdW5kZXJzY29yZXMsIGFuZCBoeXBoZW5zLmAsXG4gICAgKTtcbiAgICBEZW5vLmV4aXQoMSk7XG4gIH1cblxuICBjb25zdCBjd2QgPSBEZW5vLmN3ZCgpO1xuICBjb25zdCB0YXJnZXREaXIgPSByZXNvbHZlKGN3ZCwgbmFtZSk7XG4gIGNvbnN0IHJlbGF0aXZlVGFyZ2V0ID0gcmVsYXRpdmUoY3dkLCB0YXJnZXREaXIpO1xuXG4gIGlmIChcbiAgICAhcmVsYXRpdmVUYXJnZXQgfHxcbiAgICByZWxhdGl2ZVRhcmdldCA9PT0gJy4uJyB8fFxuICAgIHJlbGF0aXZlVGFyZ2V0LnN0YXJ0c1dpdGgoYC4uJHtzZXB9YCkgfHxcbiAgICBpc0Fic29sdXRlKHJlbGF0aXZlVGFyZ2V0KVxuICApIHtcbiAgICBsb2cuZXJyb3IoXG4gICAgICBgUmVmdXNpbmcgdG8gY3JlYXRlIHByb2plY3Qgb3V0c2lkZSB0aGUgY3VycmVudCBkaXJlY3Rvcnk6ICR7bmFtZX1gLFxuICAgICk7XG4gICAgRGVuby5leGl0KDEpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBEZW5vLnN0YXQodGFyZ2V0RGlyKTtcbiAgICBsb2cuZXJyb3IoYERpcmVjdG9yeSBcIiR7bmFtZX1cIiBhbHJlYWR5IGV4aXN0cy5gKTtcbiAgICBEZW5vLmV4aXQoMSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoIShlIGluc3RhbmNlb2YgRGVuby5lcnJvcnMuTm90Rm91bmQpKSB7XG4gICAgICBsb2cuZXJyb3IoYEZhaWxlZCB0byBpbnNwZWN0IHRhcmdldCBkaXJlY3RvcnkgXCIke25hbWV9XCI6ICR7ZX1gKTtcbiAgICAgIERlbm8uZXhpdCgxKTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXNvbHZlIHBhY2thZ2UgdmVyc2lvbnMgYmVmb3JlIGdlbmVyYXRpbmcgdGVtcGxhdGVzXG4gIGNvbnN0IHYgPSBhd2FpdCByZXNvbHZlVmVyc2lvbnMoKTtcblxuICB0cnkge1xuICAgIGF3YWl0IERlbm8ubWtkaXIodGFyZ2V0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBkaXJlY3RvcnkgXCIke25hbWV9XCI6ICR7ZX1gKTtcbiAgICBEZW5vLmV4aXQoMSk7XG4gIH1cblxuICBjb25zdCBUUEwgPSBidWlsZFRlbXBsYXRlcyh2KTtcbiAgZm9yIChjb25zdCBbcGF0aCwgY29udGVudF0gb2YgT2JqZWN0LmVudHJpZXMoVFBMKSkge1xuICAgIGNvbnN0IGZ1bGxQYXRoID0gam9pbih0YXJnZXREaXIsIHBhdGgpO1xuICAgIGF3YWl0IERlbm8ubWtkaXIoZGlybmFtZShmdWxsUGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGF3YWl0IERlbm8ud3JpdGVUZXh0RmlsZShmdWxsUGF0aCwgY29udGVudCk7XG4gICAgY29uc29sZS5pbmZvKGAgIGNyZWF0ZWQgJHtwYXRofWApO1xuICB9XG5cbiAgY29uc29sZS5pbmZvKGBcXG5vcGVuRWxlbWVudCBwcm9qZWN0IGNyZWF0ZWQgYXQgLi8ke3JlbGF0aXZlVGFyZ2V0fS9gKTtcbiAgY29uc29sZS5pbmZvKGBcXG4gIGNkICR7cmVsYXRpdmVUYXJnZXR9YCk7XG4gIGNvbnNvbGUuaW5mbygnICBkZW5vIHRhc2sgZGV2Jyk7XG59XG5cbm1haW4oKTtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLElBQUksUUFBUSxrQkFBa0I7QUFDdkM7Ozs7Ozs7Q0FPQyxHQUVELFNBQVMsT0FBTyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxHQUFHLFFBQVEsWUFBWTtBQUM5RSxTQUFTLGFBQWEsUUFBUSxXQUFXO0FBQ3pDLFNBQVMsWUFBWSxRQUFRLDJCQUEyQjtBQUV4RCxrRUFBa0U7QUFDbEUsdUZBQXVGO0FBQ3ZGLEVBQUU7QUFDRiwyRUFBMkU7QUFDM0Usd0VBQXdFO0FBRXhFLE1BQU0sWUFBWTtBQUNsQixNQUFNLE1BQU0sYUFBYTtBQUN6QixNQUFNLGNBQXNDO0VBQzFDLE1BQU07RUFDTixhQUFhO0VBQ2IsS0FBSztFQUNMLFNBQVM7RUFDVCxJQUFJO0VBQ0osUUFBUTtFQUNSLFNBQVM7QUFDWDtBQUVBLFNBQVMscUJBQXFCLEdBQVc7RUFDdkMsTUFBTSxVQUFVLFlBQVksR0FBRztFQUMvQixNQUFNLFdBQVcsY0FBYyxJQUFJLElBQUksS0FBSztFQUM1QyxNQUFNLE1BQU0sV0FBVyxDQUFDLElBQUksSUFBSTtFQUNoQyxNQUFNLFNBQVMsUUFBUSxVQUFV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
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@openelement/create",
3
+ "version": "0.41.0-alpha.1",
4
+ "type": "module",
5
+ "main": "./cli.js",
6
+ "types": "./cli.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./cli.d.ts",
10
+ "import": "./cli.js",
11
+ "default": "./cli.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@deno/shim-deno": "~0.19.0"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/open-element/openelement.git"
20
+ },
21
+ "keywords": [
22
+ "openelement",
23
+ "web-components",
24
+ "ssg",
25
+ "framework",
26
+ "deno"
27
+ ],
28
+ "bin": {
29
+ "openelement-create": "./cli.js",
30
+ "create-openelement": "./cli.js"
31
+ }
32
+ }