@rindo/core 2.16.0-beta.0
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/LICENSE.md +27 -0
- package/bin/rindo +57 -0
- package/cli/index.cjs +1784 -0
- package/cli/index.d.ts +15 -0
- package/cli/index.js +1758 -0
- package/cli/package.json +14 -0
- package/compiler/lib.d.ts +24 -0
- package/compiler/lib.dom.d.ts +17791 -0
- package/compiler/lib.dom.iterable.d.ts +323 -0
- package/compiler/lib.es2015.collection.d.ts +89 -0
- package/compiler/lib.es2015.core.d.ts +559 -0
- package/compiler/lib.es2015.d.ts +30 -0
- package/compiler/lib.es2015.generator.d.ts +79 -0
- package/compiler/lib.es2015.iterable.d.ts +497 -0
- package/compiler/lib.es2015.promise.d.ts +78 -0
- package/compiler/lib.es2015.proxy.d.ts +41 -0
- package/compiler/lib.es2015.reflect.d.ts +123 -0
- package/compiler/lib.es2015.symbol.d.ts +48 -0
- package/compiler/lib.es2015.symbol.wellknown.d.ts +324 -0
- package/compiler/lib.es2016.array.include.d.ts +118 -0
- package/compiler/lib.es2016.d.ts +22 -0
- package/compiler/lib.es2016.full.d.ts +25 -0
- package/compiler/lib.es2017.d.ts +26 -0
- package/compiler/lib.es2017.full.d.ts +25 -0
- package/compiler/lib.es2017.intl.d.ts +32 -0
- package/compiler/lib.es2017.object.d.ts +51 -0
- package/compiler/lib.es2017.sharedmemory.d.ts +137 -0
- package/compiler/lib.es2017.string.d.ts +47 -0
- package/compiler/lib.es2017.typedarrays.d.ts +55 -0
- package/compiler/lib.es2018.asyncgenerator.d.ts +79 -0
- package/compiler/lib.es2018.asynciterable.d.ts +45 -0
- package/compiler/lib.es2018.d.ts +26 -0
- package/compiler/lib.es2018.full.d.ts +25 -0
- package/compiler/lib.es2018.intl.d.ts +73 -0
- package/compiler/lib.es2018.promise.d.ts +32 -0
- package/compiler/lib.es2018.regexp.d.ts +39 -0
- package/compiler/lib.es2019.array.d.ts +85 -0
- package/compiler/lib.es2019.d.ts +25 -0
- package/compiler/lib.es2019.full.d.ts +25 -0
- package/compiler/lib.es2019.object.d.ts +35 -0
- package/compiler/lib.es2019.string.d.ts +39 -0
- package/compiler/lib.es2019.symbol.d.ts +26 -0
- package/compiler/lib.es2020.bigint.d.ts +728 -0
- package/compiler/lib.es2020.d.ts +27 -0
- package/compiler/lib.es2020.full.d.ts +25 -0
- package/compiler/lib.es2020.intl.d.ts +368 -0
- package/compiler/lib.es2020.promise.d.ts +49 -0
- package/compiler/lib.es2020.sharedmemory.d.ts +99 -0
- package/compiler/lib.es2020.string.d.ts +30 -0
- package/compiler/lib.es2020.symbol.wellknown.d.ts +39 -0
- package/compiler/lib.es2021.d.ts +25 -0
- package/compiler/lib.es2021.full.d.ts +25 -0
- package/compiler/lib.es2021.intl.d.ts +44 -0
- package/compiler/lib.es2021.promise.d.ts +50 -0
- package/compiler/lib.es2021.string.d.ts +35 -0
- package/compiler/lib.es2021.weakref.d.ts +75 -0
- package/compiler/lib.es5.d.ts +4495 -0
- package/compiler/lib.es6.d.ts +25 -0
- package/compiler/lib.esnext.d.ts +22 -0
- package/compiler/lib.esnext.full.d.ts +25 -0
- package/compiler/lib.esnext.intl.d.ts +23 -0
- package/compiler/lib.esnext.promise.d.ts +43 -0
- package/compiler/lib.esnext.string.d.ts +35 -0
- package/compiler/lib.esnext.weakref.d.ts +75 -0
- package/compiler/lib.scripthost.d.ts +327 -0
- package/compiler/lib.webworker.d.ts +5733 -0
- package/compiler/lib.webworker.importscripts.d.ts +26 -0
- package/compiler/lib.webworker.iterable.d.ts +160 -0
- package/compiler/package.json +8 -0
- package/compiler/rindo.d.ts +95 -0
- package/compiler/rindo.js +67222 -0
- package/compiler/rindo.min.js +4 -0
- package/dependencies.json +109 -0
- package/dev-server/client/app-error.d.ts +18 -0
- package/dev-server/client/events.d.ts +6 -0
- package/dev-server/client/hmr-components.d.ts +1 -0
- package/dev-server/client/hmr-external-styles.d.ts +1 -0
- package/dev-server/client/hmr-images.d.ts +1 -0
- package/dev-server/client/hmr-inline-styles.d.ts +1 -0
- package/dev-server/client/hmr-util.d.ts +9 -0
- package/dev-server/client/hmr-window.d.ts +10 -0
- package/dev-server/client/index.d.ts +6 -0
- package/dev-server/client/index.js +808 -0
- package/dev-server/client/logger.d.ts +5 -0
- package/dev-server/client/package.json +8 -0
- package/dev-server/client/progress.d.ts +3 -0
- package/dev-server/client/status.d.ts +4 -0
- package/dev-server/connector.html +6 -0
- package/dev-server/index.d.ts +3 -0
- package/dev-server/index.js +264 -0
- package/dev-server/open-in-editor-api.js +1 -0
- package/dev-server/package.json +8 -0
- package/dev-server/server-process.js +1763 -0
- package/dev-server/server-worker-thread.js +39 -0
- package/dev-server/static/favicon.ico +0 -0
- package/dev-server/templates/directory-index.html +132 -0
- package/dev-server/templates/initial-load.html +160 -0
- package/dev-server/visualstudio.vbs +82 -0
- package/dev-server/ws.js +1 -0
- package/dev-server/xdg-open +1066 -0
- package/internal/app-data/index.cjs +92 -0
- package/internal/app-data/index.d.ts +4 -0
- package/internal/app-data/index.js +88 -0
- package/internal/app-data/package.json +15 -0
- package/internal/client/css-shim.js +4 -0
- package/internal/client/dom.js +73 -0
- package/internal/client/index.js +3059 -0
- package/internal/client/package.json +8 -0
- package/internal/client/patch-browser.js +124 -0
- package/internal/client/patch-esm.js +23 -0
- package/internal/client/polyfills/core-js.js +11 -0
- package/internal/client/polyfills/css-shim.js +1 -0
- package/internal/client/polyfills/dom.js +79 -0
- package/internal/client/polyfills/es5-html-element.js +1 -0
- package/internal/client/polyfills/index.js +34 -0
- package/internal/client/polyfills/system.js +6 -0
- package/internal/client/shadow-css.js +387 -0
- package/internal/hydrate/index.js +1132 -0
- package/internal/hydrate/package.json +7 -0
- package/internal/hydrate/runner.d.ts +217 -0
- package/internal/hydrate/runner.js +777 -0
- package/internal/hydrate/shadow-css.js +143 -0
- package/internal/index.d.ts +4 -0
- package/internal/index.js +2 -0
- package/internal/package.json +9 -0
- package/internal/rindo-core/index.cjs +1 -0
- package/internal/rindo-core/index.d.ts +52 -0
- package/internal/rindo-core/index.js +16 -0
- package/internal/rindo-ext-modules.d.ts +41 -0
- package/internal/rindo-private.d.ts +2289 -0
- package/internal/rindo-public-compiler.d.ts +2273 -0
- package/internal/rindo-public-docs.d.ts +116 -0
- package/internal/rindo-public-runtime.d.ts +1565 -0
- package/internal/testing/index.js +1093 -0
- package/internal/testing/package.json +7 -0
- package/internal/testing/shadow-css.js +143 -0
- package/mock-doc/index.cjs +4658 -0
- package/mock-doc/index.d.ts +928 -0
- package/mock-doc/index.js +4622 -0
- package/mock-doc/package.json +15 -0
- package/package.json +151 -0
- package/readme.md +74 -0
- package/screenshot/compare/assets/favicon.ico +0 -0
- package/screenshot/compare/assets/logo.png +0 -0
- package/screenshot/compare/build/app.css +1 -0
- package/screenshot/compare/build/app.esm.js +1 -0
- package/screenshot/compare/build/app.js +33 -0
- package/screenshot/compare/build/index.esm.js +0 -0
- package/screenshot/compare/build/p-081b0641.js +1 -0
- package/screenshot/compare/build/p-227a1e18.entry.js +1 -0
- package/screenshot/compare/build/p-2c298727.entry.js +1 -0
- package/screenshot/compare/build/p-5479268c.entry.js +1 -0
- package/screenshot/compare/build/p-573ec8a4.entry.js +1 -0
- package/screenshot/compare/build/p-6ba08604.entry.js +1 -0
- package/screenshot/compare/build/p-6bc63295.entry.js +1 -0
- package/screenshot/compare/build/p-7a3759fd.entry.js +1 -0
- package/screenshot/compare/build/p-7b4e3ba7.js +1 -0
- package/screenshot/compare/build/p-988eb362.css +1 -0
- package/screenshot/compare/build/p-9b6a9315.js +1 -0
- package/screenshot/compare/build/p-b4cc611c.entry.js +1 -0
- package/screenshot/compare/build/p-d1bf53f5.entry.js +1 -0
- package/screenshot/compare/build/p-e2efe0df.js +1 -0
- package/screenshot/compare/build/p-e8ca6d97.entry.js +1 -0
- package/screenshot/compare/build/p-ec2f13e0.entry.js +1 -0
- package/screenshot/compare/build/p-f0b99977.entry.js +1 -0
- package/screenshot/compare/build/p-f4745c2f.entry.js +1 -0
- package/screenshot/compare/build/p-fbbae598.js +1 -0
- package/screenshot/compare/host.config.json +15 -0
- package/screenshot/compare/index.html +1 -0
- package/screenshot/compare/manifest.json +13 -0
- package/screenshot/connector-base.d.ts +42 -0
- package/screenshot/connector-local.d.ts +7 -0
- package/screenshot/connector.js +2 -0
- package/screenshot/index.d.ts +3 -0
- package/screenshot/index.js +659 -0
- package/screenshot/local-connector.js +2 -0
- package/screenshot/package.json +15 -0
- package/screenshot/pixel-match.d.ts +1 -0
- package/screenshot/pixel-match.js +2673 -0
- package/screenshot/screenshot-compare.d.ts +3 -0
- package/screenshot/screenshot-fs.d.ts +15 -0
- package/sys/node/autoprefixer.js +8 -0
- package/sys/node/glob.js +1 -0
- package/sys/node/graceful-fs.js +1 -0
- package/sys/node/index.d.ts +18 -0
- package/sys/node/index.js +6124 -0
- package/sys/node/node-fetch.js +1 -0
- package/sys/node/package.json +8 -0
- package/sys/node/prompts.js +1 -0
- package/sys/node/worker.js +52 -0
- package/testing/index.d.ts +12 -0
- package/testing/index.js +4232 -0
- package/testing/jest/jest-config.d.ts +16 -0
- package/testing/jest/jest-environment.d.ts +15 -0
- package/testing/jest/jest-preprocessor.d.ts +59 -0
- package/testing/jest/jest-runner.d.ts +9 -0
- package/testing/jest/jest-screenshot.d.ts +2 -0
- package/testing/jest/jest-serializer.d.ts +5 -0
- package/testing/jest/jest-setup-test-framework.d.ts +1 -0
- package/testing/jest-environment.js +3 -0
- package/testing/jest-preprocessor.js +3 -0
- package/testing/jest-preset.js +37 -0
- package/testing/jest-runner.js +3 -0
- package/testing/jest-setuptestframework.js +3 -0
- package/testing/matchers/attributes.d.ts +14 -0
- package/testing/matchers/class-list.d.ts +12 -0
- package/testing/matchers/events.d.ts +21 -0
- package/testing/matchers/html.d.ts +12 -0
- package/testing/matchers/index.d.ts +23 -0
- package/testing/matchers/screenshot.d.ts +5 -0
- package/testing/matchers/text.d.ts +4 -0
- package/testing/mock-fetch.d.ts +11 -0
- package/testing/mocks.d.ts +10 -0
- package/testing/package.json +8 -0
- package/testing/puppeteer/index.d.ts +2 -0
- package/testing/puppeteer/puppeteer-browser.d.ts +6 -0
- package/testing/puppeteer/puppeteer-declarations.d.ts +429 -0
- package/testing/puppeteer/puppeteer-element.d.ts +67 -0
- package/testing/puppeteer/puppeteer-emulate.d.ts +2 -0
- package/testing/puppeteer/puppeteer-events.d.ts +21 -0
- package/testing/puppeteer/puppeteer-page.d.ts +2 -0
- package/testing/puppeteer/puppeteer-screenshot.d.ts +4 -0
- package/testing/reset-build-conditionals.d.ts +2 -0
- package/testing/spec-page.d.ts +2 -0
- package/testing/test-transpile.d.ts +2 -0
- package/testing/testing-logger.d.ts +25 -0
- package/testing/testing-sys.d.ts +6 -0
- package/testing/testing-utils.d.ts +6 -0
- package/testing/testing.d.ts +2 -0
package/cli/index.js
ADDED
|
@@ -0,0 +1,1758 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
Rindo CLI v0.0.0-dev.20220810110141 | MIT Licensed | https://rindojs.web.app
|
|
3
|
+
*/
|
|
4
|
+
const toLowerCase = (str) => str.toLowerCase();
|
|
5
|
+
const dashToPascalCase = (str) => toLowerCase(str)
|
|
6
|
+
.split('-')
|
|
7
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
8
|
+
.join('');
|
|
9
|
+
const isFunction = (v) => typeof v === 'function';
|
|
10
|
+
const isString = (v) => typeof v === 'string';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Builds a template `Diagnostic` entity for a build error. The created `Diagnostic` is returned, and have little
|
|
14
|
+
* detail attached to it regarding the specifics of the error - it is the responsibility of the caller of this method
|
|
15
|
+
* to attach the specifics of the error message.
|
|
16
|
+
*
|
|
17
|
+
* The created `Diagnostic` is pushed to the `diagnostics` argument as a side effect of calling this method.
|
|
18
|
+
*
|
|
19
|
+
* @param diagnostics the existing diagnostics that the created template `Diagnostic` should be added to
|
|
20
|
+
* @returns the created `Diagnostic`
|
|
21
|
+
*/
|
|
22
|
+
const buildError = (diagnostics) => {
|
|
23
|
+
const diagnostic = {
|
|
24
|
+
level: 'error',
|
|
25
|
+
type: 'build',
|
|
26
|
+
header: 'Build Error',
|
|
27
|
+
messageText: 'build error',
|
|
28
|
+
relFilePath: null,
|
|
29
|
+
absFilePath: null,
|
|
30
|
+
lines: [],
|
|
31
|
+
};
|
|
32
|
+
if (diagnostics) {
|
|
33
|
+
diagnostics.push(diagnostic);
|
|
34
|
+
}
|
|
35
|
+
return diagnostic;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Builds a diagnostic from an `Error`, appends it to the `diagnostics` parameter, and returns the created diagnostic
|
|
39
|
+
* @param diagnostics the series of diagnostics the newly created diagnostics should be added to
|
|
40
|
+
* @param err the error to derive information from in generating the diagnostic
|
|
41
|
+
* @param msg an optional message to use in place of `err` to generate the diagnostic
|
|
42
|
+
* @returns the generated diagnostic
|
|
43
|
+
*/
|
|
44
|
+
const catchError = (diagnostics, err, msg) => {
|
|
45
|
+
const diagnostic = {
|
|
46
|
+
level: 'error',
|
|
47
|
+
type: 'build',
|
|
48
|
+
header: 'Build Error',
|
|
49
|
+
messageText: 'build error',
|
|
50
|
+
relFilePath: null,
|
|
51
|
+
absFilePath: null,
|
|
52
|
+
lines: [],
|
|
53
|
+
};
|
|
54
|
+
if (isString(msg)) {
|
|
55
|
+
diagnostic.messageText = msg.length ? msg : 'UNKNOWN ERROR';
|
|
56
|
+
}
|
|
57
|
+
else if (err != null) {
|
|
58
|
+
if (err.stack != null) {
|
|
59
|
+
diagnostic.messageText = err.stack.toString();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (err.message != null) {
|
|
63
|
+
diagnostic.messageText = err.message.length ? err.message : 'UNKNOWN ERROR';
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
diagnostic.messageText = err.toString();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
|
|
71
|
+
diagnostics.push(diagnostic);
|
|
72
|
+
}
|
|
73
|
+
return diagnostic;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Determine if the provided diagnostics have any build errors
|
|
77
|
+
* @param diagnostics the diagnostics to inspect
|
|
78
|
+
* @returns true if any of the diagnostics in the list provided are errors that did not occur at runtime. false
|
|
79
|
+
* otherwise.
|
|
80
|
+
*/
|
|
81
|
+
const hasError = (diagnostics) => {
|
|
82
|
+
if (diagnostics == null || diagnostics.length === 0) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return diagnostics.some((d) => d.level === 'error' && d.type !== 'runtime');
|
|
86
|
+
};
|
|
87
|
+
const shouldIgnoreError = (msg) => {
|
|
88
|
+
return msg === TASK_CANCELED_MSG;
|
|
89
|
+
};
|
|
90
|
+
const TASK_CANCELED_MSG = `task canceled`;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
|
|
94
|
+
* Forward-slash paths can be used in Windows as long as they're not
|
|
95
|
+
* extended-length paths and don't contain any non-ascii characters.
|
|
96
|
+
* This was created since the path methods in Node.js outputs \\ paths on Windows.
|
|
97
|
+
*/
|
|
98
|
+
const normalizePath = (path) => {
|
|
99
|
+
if (typeof path !== 'string') {
|
|
100
|
+
throw new Error(`invalid path to normalize`);
|
|
101
|
+
}
|
|
102
|
+
path = normalizeSlashes(path.trim());
|
|
103
|
+
const components = pathComponents(path, getRootLength(path));
|
|
104
|
+
const reducedComponents = reducePathComponents(components);
|
|
105
|
+
const rootPart = reducedComponents[0];
|
|
106
|
+
const secondPart = reducedComponents[1];
|
|
107
|
+
const normalized = rootPart + reducedComponents.slice(1).join('/');
|
|
108
|
+
if (normalized === '') {
|
|
109
|
+
return '.';
|
|
110
|
+
}
|
|
111
|
+
if (rootPart === '' &&
|
|
112
|
+
secondPart &&
|
|
113
|
+
path.includes('/') &&
|
|
114
|
+
!secondPart.startsWith('.') &&
|
|
115
|
+
!secondPart.startsWith('@')) {
|
|
116
|
+
return './' + normalized;
|
|
117
|
+
}
|
|
118
|
+
return normalized;
|
|
119
|
+
};
|
|
120
|
+
const normalizeSlashes = (path) => path.replace(backslashRegExp, '/');
|
|
121
|
+
const altDirectorySeparator = '\\';
|
|
122
|
+
const urlSchemeSeparator = '://';
|
|
123
|
+
const backslashRegExp = /\\/g;
|
|
124
|
+
const reducePathComponents = (components) => {
|
|
125
|
+
if (!Array.isArray(components) || components.length === 0) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
const reduced = [components[0]];
|
|
129
|
+
for (let i = 1; i < components.length; i++) {
|
|
130
|
+
const component = components[i];
|
|
131
|
+
if (!component)
|
|
132
|
+
continue;
|
|
133
|
+
if (component === '.')
|
|
134
|
+
continue;
|
|
135
|
+
if (component === '..') {
|
|
136
|
+
if (reduced.length > 1) {
|
|
137
|
+
if (reduced[reduced.length - 1] !== '..') {
|
|
138
|
+
reduced.pop();
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else if (reduced[0])
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
reduced.push(component);
|
|
146
|
+
}
|
|
147
|
+
return reduced;
|
|
148
|
+
};
|
|
149
|
+
const getRootLength = (path) => {
|
|
150
|
+
const rootLength = getEncodedRootLength(path);
|
|
151
|
+
return rootLength < 0 ? ~rootLength : rootLength;
|
|
152
|
+
};
|
|
153
|
+
const getEncodedRootLength = (path) => {
|
|
154
|
+
if (!path)
|
|
155
|
+
return 0;
|
|
156
|
+
const ch0 = path.charCodeAt(0);
|
|
157
|
+
// POSIX or UNC
|
|
158
|
+
if (ch0 === 47 /* slash */ || ch0 === 92 /* backslash */) {
|
|
159
|
+
if (path.charCodeAt(1) !== ch0)
|
|
160
|
+
return 1; // POSIX: "/" (or non-normalized "\")
|
|
161
|
+
const p1 = path.indexOf(ch0 === 47 /* slash */ ? '/' : altDirectorySeparator, 2);
|
|
162
|
+
if (p1 < 0)
|
|
163
|
+
return path.length; // UNC: "//server" or "\\server"
|
|
164
|
+
return p1 + 1; // UNC: "//server/" or "\\server\"
|
|
165
|
+
}
|
|
166
|
+
// DOS
|
|
167
|
+
if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* colon */) {
|
|
168
|
+
const ch2 = path.charCodeAt(2);
|
|
169
|
+
if (ch2 === 47 /* slash */ || ch2 === 92 /* backslash */)
|
|
170
|
+
return 3; // DOS: "c:/" or "c:\"
|
|
171
|
+
if (path.length === 2)
|
|
172
|
+
return 2; // DOS: "c:" (but not "c:d")
|
|
173
|
+
}
|
|
174
|
+
// URL
|
|
175
|
+
const schemeEnd = path.indexOf(urlSchemeSeparator);
|
|
176
|
+
if (schemeEnd !== -1) {
|
|
177
|
+
const authorityStart = schemeEnd + urlSchemeSeparator.length;
|
|
178
|
+
const authorityEnd = path.indexOf('/', authorityStart);
|
|
179
|
+
if (authorityEnd !== -1) {
|
|
180
|
+
// URL: "file:///", "file://server/", "file://server/path"
|
|
181
|
+
// For local "file" URLs, include the leading DOS volume (if present).
|
|
182
|
+
// Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a
|
|
183
|
+
// special case interpreted as "the machine from which the URL is being interpreted".
|
|
184
|
+
const scheme = path.slice(0, schemeEnd);
|
|
185
|
+
const authority = path.slice(authorityStart, authorityEnd);
|
|
186
|
+
if (scheme === 'file' &&
|
|
187
|
+
(authority === '' || authority === 'localhost') &&
|
|
188
|
+
isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
|
|
189
|
+
const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
|
|
190
|
+
if (volumeSeparatorEnd !== -1) {
|
|
191
|
+
if (path.charCodeAt(volumeSeparatorEnd) === 47 /* slash */) {
|
|
192
|
+
// URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
|
|
193
|
+
return ~(volumeSeparatorEnd + 1);
|
|
194
|
+
}
|
|
195
|
+
if (volumeSeparatorEnd === path.length) {
|
|
196
|
+
// URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a"
|
|
197
|
+
// but not "file:///c:d" or "file:///c%3ad"
|
|
198
|
+
return ~volumeSeparatorEnd;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return ~(authorityEnd + 1); // URL: "file://server/", "http://server/"
|
|
203
|
+
}
|
|
204
|
+
return ~path.length; // URL: "file://server", "http://server"
|
|
205
|
+
}
|
|
206
|
+
// relative
|
|
207
|
+
return 0;
|
|
208
|
+
};
|
|
209
|
+
const isVolumeCharacter = (charCode) => (charCode >= 97 /* a */ && charCode <= 122 /* z */) ||
|
|
210
|
+
(charCode >= 65 /* A */ && charCode <= 90 /* Z */);
|
|
211
|
+
const getFileUrlVolumeSeparatorEnd = (url, start) => {
|
|
212
|
+
const ch0 = url.charCodeAt(start);
|
|
213
|
+
if (ch0 === 58 /* colon */)
|
|
214
|
+
return start + 1;
|
|
215
|
+
if (ch0 === 37 /* percent */ && url.charCodeAt(start + 1) === 51 /* _3 */) {
|
|
216
|
+
const ch2 = url.charCodeAt(start + 2);
|
|
217
|
+
if (ch2 === 97 /* a */ || ch2 === 65 /* A */)
|
|
218
|
+
return start + 3;
|
|
219
|
+
}
|
|
220
|
+
return -1;
|
|
221
|
+
};
|
|
222
|
+
const pathComponents = (path, rootLength) => {
|
|
223
|
+
const root = path.substring(0, rootLength);
|
|
224
|
+
const rest = path.substring(rootLength).split('/');
|
|
225
|
+
const restLen = rest.length;
|
|
226
|
+
if (restLen > 0 && !rest[restLen - 1]) {
|
|
227
|
+
rest.pop();
|
|
228
|
+
}
|
|
229
|
+
return [root, ...rest];
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Validates that a component tag meets required naming conventions to be used for a web component
|
|
234
|
+
* @param tag the tag to validate
|
|
235
|
+
* @returns an error message if the tag has an invalid name, undefined if the tag name passes all checks
|
|
236
|
+
*/
|
|
237
|
+
const validateComponentTag = (tag) => {
|
|
238
|
+
// we want to check this first since we call some String.prototype methods below
|
|
239
|
+
if (typeof tag !== 'string') {
|
|
240
|
+
return `Tag "${tag}" must be a string type`;
|
|
241
|
+
}
|
|
242
|
+
if (tag !== tag.trim()) {
|
|
243
|
+
return `Tag can not contain white spaces`;
|
|
244
|
+
}
|
|
245
|
+
if (tag !== tag.toLowerCase()) {
|
|
246
|
+
return `Tag can not contain upper case characters`;
|
|
247
|
+
}
|
|
248
|
+
if (tag.length === 0) {
|
|
249
|
+
return `Received empty tag value`;
|
|
250
|
+
}
|
|
251
|
+
if (tag.indexOf(' ') > -1) {
|
|
252
|
+
return `"${tag}" tag cannot contain a space`;
|
|
253
|
+
}
|
|
254
|
+
if (tag.indexOf(',') > -1) {
|
|
255
|
+
return `"${tag}" tag cannot be used for multiple tags`;
|
|
256
|
+
}
|
|
257
|
+
const invalidChars = tag.replace(/\w|-/g, '');
|
|
258
|
+
if (invalidChars !== '') {
|
|
259
|
+
return `"${tag}" tag contains invalid characters: ${invalidChars}`;
|
|
260
|
+
}
|
|
261
|
+
if (tag.indexOf('-') === -1) {
|
|
262
|
+
return `"${tag}" tag must contain a dash (-) to work as a valid web component`;
|
|
263
|
+
}
|
|
264
|
+
if (tag.indexOf('--') > -1) {
|
|
265
|
+
return `"${tag}" tag cannot contain multiple dashes (--) next to each other`;
|
|
266
|
+
}
|
|
267
|
+
if (tag.indexOf('-') === 0) {
|
|
268
|
+
return `"${tag}" tag cannot start with a dash (-)`;
|
|
269
|
+
}
|
|
270
|
+
if (tag.lastIndexOf('-') === tag.length - 1) {
|
|
271
|
+
return `"${tag}" tag cannot end with a dash (-)`;
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const parseFlags = (args, sys) => {
|
|
277
|
+
const flags = {
|
|
278
|
+
task: null,
|
|
279
|
+
args: [],
|
|
280
|
+
knownArgs: [],
|
|
281
|
+
unknownArgs: null,
|
|
282
|
+
};
|
|
283
|
+
// cmd line has more priority over npm scripts cmd
|
|
284
|
+
flags.args = args.slice();
|
|
285
|
+
if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
|
|
286
|
+
flags.task = flags.args[0];
|
|
287
|
+
}
|
|
288
|
+
parseArgs(flags, flags.args, flags.knownArgs);
|
|
289
|
+
if (sys && sys.name === 'node') {
|
|
290
|
+
const envArgs = getNpmConfigEnvArgs(sys);
|
|
291
|
+
parseArgs(flags, envArgs, flags.knownArgs);
|
|
292
|
+
envArgs.forEach((envArg) => {
|
|
293
|
+
if (!flags.args.includes(envArg)) {
|
|
294
|
+
flags.args.push(envArg);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
if (flags.task != null) {
|
|
299
|
+
const i = flags.args.indexOf(flags.task);
|
|
300
|
+
if (i > -1) {
|
|
301
|
+
flags.args.splice(i, 1);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
flags.unknownArgs = flags.args.filter((arg) => {
|
|
305
|
+
return !flags.knownArgs.includes(arg);
|
|
306
|
+
});
|
|
307
|
+
return flags;
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Parse command line arguments that are whitelisted via the BOOLEAN_ARG_OPTS,
|
|
311
|
+
* STRING_ARG_OPTS, and NUMBER_ARG_OPTS arrays in this file. Handles leading
|
|
312
|
+
* dashes on arguments, aliases that are defined for a small number of argument
|
|
313
|
+
* types, and parsing values for non-boolean arguments (e.g. port number).
|
|
314
|
+
*
|
|
315
|
+
* @param flags a ConfigFlags object
|
|
316
|
+
* @param args an array of command-line arguments to parse
|
|
317
|
+
* @param knownArgs an array to which all recognized, legal arguments are added
|
|
318
|
+
*/
|
|
319
|
+
const parseArgs = (flags, args, knownArgs) => {
|
|
320
|
+
BOOLEAN_ARG_OPTS.forEach((booleanName) => {
|
|
321
|
+
const alias = ARG_OPTS_ALIASES[booleanName];
|
|
322
|
+
const flagKey = configCase(booleanName);
|
|
323
|
+
if (typeof flags[flagKey] !== 'boolean') {
|
|
324
|
+
flags[flagKey] = null;
|
|
325
|
+
}
|
|
326
|
+
args.forEach((cmdArg) => {
|
|
327
|
+
if (cmdArg === `--${booleanName}`) {
|
|
328
|
+
flags[flagKey] = true;
|
|
329
|
+
knownArgs.push(cmdArg);
|
|
330
|
+
}
|
|
331
|
+
else if (cmdArg === `--${flagKey}`) {
|
|
332
|
+
flags[flagKey] = true;
|
|
333
|
+
knownArgs.push(cmdArg);
|
|
334
|
+
}
|
|
335
|
+
else if (cmdArg === `--no-${booleanName}`) {
|
|
336
|
+
flags[flagKey] = false;
|
|
337
|
+
knownArgs.push(cmdArg);
|
|
338
|
+
}
|
|
339
|
+
else if (cmdArg === `--no${dashToPascalCase(booleanName)}`) {
|
|
340
|
+
flags[flagKey] = false;
|
|
341
|
+
knownArgs.push(cmdArg);
|
|
342
|
+
}
|
|
343
|
+
else if (alias && cmdArg === `-${alias}`) {
|
|
344
|
+
flags[flagKey] = true;
|
|
345
|
+
knownArgs.push(cmdArg);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
STRING_ARG_OPTS.forEach((stringName) => {
|
|
350
|
+
const alias = ARG_OPTS_ALIASES[stringName];
|
|
351
|
+
const flagKey = configCase(stringName);
|
|
352
|
+
if (typeof flags[flagKey] !== 'string') {
|
|
353
|
+
flags[flagKey] = null;
|
|
354
|
+
}
|
|
355
|
+
for (let i = 0; i < args.length; i++) {
|
|
356
|
+
const cmdArg = args[i];
|
|
357
|
+
if (cmdArg.startsWith(`--${stringName}=`)) {
|
|
358
|
+
const values = cmdArg.split('=');
|
|
359
|
+
values.shift();
|
|
360
|
+
flags[flagKey] = values.join('=');
|
|
361
|
+
knownArgs.push(cmdArg);
|
|
362
|
+
}
|
|
363
|
+
else if (cmdArg === `--${stringName}`) {
|
|
364
|
+
flags[flagKey] = args[i + 1];
|
|
365
|
+
knownArgs.push(cmdArg);
|
|
366
|
+
knownArgs.push(args[i + 1]);
|
|
367
|
+
}
|
|
368
|
+
else if (cmdArg === `--${flagKey}`) {
|
|
369
|
+
flags[flagKey] = args[i + 1];
|
|
370
|
+
knownArgs.push(cmdArg);
|
|
371
|
+
knownArgs.push(args[i + 1]);
|
|
372
|
+
}
|
|
373
|
+
else if (cmdArg.startsWith(`--${flagKey}=`)) {
|
|
374
|
+
const values = cmdArg.split('=');
|
|
375
|
+
values.shift();
|
|
376
|
+
flags[flagKey] = values.join('=');
|
|
377
|
+
knownArgs.push(cmdArg);
|
|
378
|
+
}
|
|
379
|
+
else if (alias) {
|
|
380
|
+
if (cmdArg.startsWith(`-${alias}=`)) {
|
|
381
|
+
const values = cmdArg.split('=');
|
|
382
|
+
values.shift();
|
|
383
|
+
flags[flagKey] = values.join('=');
|
|
384
|
+
knownArgs.push(cmdArg);
|
|
385
|
+
}
|
|
386
|
+
else if (cmdArg === `-${alias}`) {
|
|
387
|
+
flags[flagKey] = args[i + 1];
|
|
388
|
+
knownArgs.push(args[i + 1]);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
NUMBER_ARG_OPTS.forEach((numberName) => {
|
|
394
|
+
const alias = ARG_OPTS_ALIASES[numberName];
|
|
395
|
+
const flagKey = configCase(numberName);
|
|
396
|
+
if (typeof flags[flagKey] !== 'number') {
|
|
397
|
+
flags[flagKey] = null;
|
|
398
|
+
}
|
|
399
|
+
for (let i = 0; i < args.length; i++) {
|
|
400
|
+
const cmdArg = args[i];
|
|
401
|
+
if (cmdArg.startsWith(`--${numberName}=`)) {
|
|
402
|
+
const values = cmdArg.split('=');
|
|
403
|
+
values.shift();
|
|
404
|
+
flags[flagKey] = parseInt(values.join(''), 10);
|
|
405
|
+
knownArgs.push(cmdArg);
|
|
406
|
+
}
|
|
407
|
+
else if (cmdArg === `--${numberName}`) {
|
|
408
|
+
flags[flagKey] = parseInt(args[i + 1], 10);
|
|
409
|
+
knownArgs.push(args[i + 1]);
|
|
410
|
+
}
|
|
411
|
+
else if (cmdArg.startsWith(`--${flagKey}=`)) {
|
|
412
|
+
const values = cmdArg.split('=');
|
|
413
|
+
values.shift();
|
|
414
|
+
flags[flagKey] = parseInt(values.join(''), 10);
|
|
415
|
+
knownArgs.push(cmdArg);
|
|
416
|
+
}
|
|
417
|
+
else if (cmdArg === `--${flagKey}`) {
|
|
418
|
+
flags[flagKey] = parseInt(args[i + 1], 10);
|
|
419
|
+
knownArgs.push(args[i + 1]);
|
|
420
|
+
}
|
|
421
|
+
else if (alias) {
|
|
422
|
+
if (cmdArg.startsWith(`-${alias}=`)) {
|
|
423
|
+
const values = cmdArg.split('=');
|
|
424
|
+
values.shift();
|
|
425
|
+
flags[flagKey] = parseInt(values.join(''), 10);
|
|
426
|
+
knownArgs.push(cmdArg);
|
|
427
|
+
}
|
|
428
|
+
else if (cmdArg === `-${alias}`) {
|
|
429
|
+
flags[flagKey] = parseInt(args[i + 1], 10);
|
|
430
|
+
knownArgs.push(args[i + 1]);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
const configCase = (prop) => {
|
|
437
|
+
prop = dashToPascalCase(prop);
|
|
438
|
+
return prop.charAt(0).toLowerCase() + prop.slice(1);
|
|
439
|
+
};
|
|
440
|
+
const BOOLEAN_ARG_OPTS = [
|
|
441
|
+
'build',
|
|
442
|
+
'cache',
|
|
443
|
+
'check-version',
|
|
444
|
+
'ci',
|
|
445
|
+
'compare',
|
|
446
|
+
'debug',
|
|
447
|
+
'dev',
|
|
448
|
+
'devtools',
|
|
449
|
+
'docs',
|
|
450
|
+
'e2e',
|
|
451
|
+
'es5',
|
|
452
|
+
'esm',
|
|
453
|
+
'headless',
|
|
454
|
+
'help',
|
|
455
|
+
'log',
|
|
456
|
+
'open',
|
|
457
|
+
'prerender',
|
|
458
|
+
'prerender-external',
|
|
459
|
+
'prod',
|
|
460
|
+
'profile',
|
|
461
|
+
'service-worker',
|
|
462
|
+
'screenshot',
|
|
463
|
+
'serve',
|
|
464
|
+
'skip-node-check',
|
|
465
|
+
'spec',
|
|
466
|
+
'ssr',
|
|
467
|
+
'stats',
|
|
468
|
+
'update-screenshot',
|
|
469
|
+
'verbose',
|
|
470
|
+
'version',
|
|
471
|
+
'watch',
|
|
472
|
+
];
|
|
473
|
+
const NUMBER_ARG_OPTS = ['max-workers', 'port'];
|
|
474
|
+
const STRING_ARG_OPTS = [
|
|
475
|
+
'address',
|
|
476
|
+
'config',
|
|
477
|
+
'docs-json',
|
|
478
|
+
'emulate',
|
|
479
|
+
'log-level',
|
|
480
|
+
'root',
|
|
481
|
+
'screenshot-connector',
|
|
482
|
+
];
|
|
483
|
+
const ARG_OPTS_ALIASES = {
|
|
484
|
+
config: 'c',
|
|
485
|
+
help: 'h',
|
|
486
|
+
port: 'p',
|
|
487
|
+
version: 'v',
|
|
488
|
+
};
|
|
489
|
+
const getNpmConfigEnvArgs = (sys) => {
|
|
490
|
+
// process.env.npm_config_argv
|
|
491
|
+
// {"remain":["4444"],"cooked":["run","serve","--port","4444"],"original":["run","serve","--port","4444"]}
|
|
492
|
+
let args = [];
|
|
493
|
+
try {
|
|
494
|
+
const npmConfigArgs = sys.getEnvironmentVar('npm_config_argv');
|
|
495
|
+
if (npmConfigArgs) {
|
|
496
|
+
args = JSON.parse(npmConfigArgs).original;
|
|
497
|
+
if (args[0] === 'run') {
|
|
498
|
+
args = args.slice(2);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch (e) { }
|
|
503
|
+
return args;
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const dependencies = [
|
|
507
|
+
{
|
|
508
|
+
name: "@rindo/core",
|
|
509
|
+
version: "0.0.0-dev.20220810110141",
|
|
510
|
+
main: "compiler/rindo.js",
|
|
511
|
+
resources: [
|
|
512
|
+
"package.json",
|
|
513
|
+
"compiler/lib.d.ts",
|
|
514
|
+
"compiler/lib.dom.d.ts",
|
|
515
|
+
"compiler/lib.dom.iterable.d.ts",
|
|
516
|
+
"compiler/lib.es2015.collection.d.ts",
|
|
517
|
+
"compiler/lib.es2015.core.d.ts",
|
|
518
|
+
"compiler/lib.es2015.d.ts",
|
|
519
|
+
"compiler/lib.es2015.generator.d.ts",
|
|
520
|
+
"compiler/lib.es2015.iterable.d.ts",
|
|
521
|
+
"compiler/lib.es2015.promise.d.ts",
|
|
522
|
+
"compiler/lib.es2015.proxy.d.ts",
|
|
523
|
+
"compiler/lib.es2015.reflect.d.ts",
|
|
524
|
+
"compiler/lib.es2015.symbol.d.ts",
|
|
525
|
+
"compiler/lib.es2015.symbol.wellknown.d.ts",
|
|
526
|
+
"compiler/lib.es2016.array.include.d.ts",
|
|
527
|
+
"compiler/lib.es2016.d.ts",
|
|
528
|
+
"compiler/lib.es2016.full.d.ts",
|
|
529
|
+
"compiler/lib.es2017.d.ts",
|
|
530
|
+
"compiler/lib.es2017.full.d.ts",
|
|
531
|
+
"compiler/lib.es2017.intl.d.ts",
|
|
532
|
+
"compiler/lib.es2017.object.d.ts",
|
|
533
|
+
"compiler/lib.es2017.sharedmemory.d.ts",
|
|
534
|
+
"compiler/lib.es2017.string.d.ts",
|
|
535
|
+
"compiler/lib.es2017.typedarrays.d.ts",
|
|
536
|
+
"compiler/lib.es2018.asyncgenerator.d.ts",
|
|
537
|
+
"compiler/lib.es2018.asynciterable.d.ts",
|
|
538
|
+
"compiler/lib.es2018.d.ts",
|
|
539
|
+
"compiler/lib.es2018.full.d.ts",
|
|
540
|
+
"compiler/lib.es2018.intl.d.ts",
|
|
541
|
+
"compiler/lib.es2018.promise.d.ts",
|
|
542
|
+
"compiler/lib.es2018.regexp.d.ts",
|
|
543
|
+
"compiler/lib.es2019.array.d.ts",
|
|
544
|
+
"compiler/lib.es2019.d.ts",
|
|
545
|
+
"compiler/lib.es2019.full.d.ts",
|
|
546
|
+
"compiler/lib.es2019.object.d.ts",
|
|
547
|
+
"compiler/lib.es2019.string.d.ts",
|
|
548
|
+
"compiler/lib.es2019.symbol.d.ts",
|
|
549
|
+
"compiler/lib.es2020.bigint.d.ts",
|
|
550
|
+
"compiler/lib.es2020.d.ts",
|
|
551
|
+
"compiler/lib.es2020.full.d.ts",
|
|
552
|
+
"compiler/lib.es2020.intl.d.ts",
|
|
553
|
+
"compiler/lib.es2020.promise.d.ts",
|
|
554
|
+
"compiler/lib.es2020.sharedmemory.d.ts",
|
|
555
|
+
"compiler/lib.es2020.string.d.ts",
|
|
556
|
+
"compiler/lib.es2020.symbol.wellknown.d.ts",
|
|
557
|
+
"compiler/lib.es2021.d.ts",
|
|
558
|
+
"compiler/lib.es2021.full.d.ts",
|
|
559
|
+
"compiler/lib.es2021.intl.d.ts",
|
|
560
|
+
"compiler/lib.es2021.promise.d.ts",
|
|
561
|
+
"compiler/lib.es2021.string.d.ts",
|
|
562
|
+
"compiler/lib.es2021.weakref.d.ts",
|
|
563
|
+
"compiler/lib.es5.d.ts",
|
|
564
|
+
"compiler/lib.es6.d.ts",
|
|
565
|
+
"compiler/lib.esnext.d.ts",
|
|
566
|
+
"compiler/lib.esnext.full.d.ts",
|
|
567
|
+
"compiler/lib.esnext.intl.d.ts",
|
|
568
|
+
"compiler/lib.esnext.promise.d.ts",
|
|
569
|
+
"compiler/lib.esnext.string.d.ts",
|
|
570
|
+
"compiler/lib.esnext.weakref.d.ts",
|
|
571
|
+
"compiler/lib.scripthost.d.ts",
|
|
572
|
+
"compiler/lib.webworker.d.ts",
|
|
573
|
+
"compiler/lib.webworker.importscripts.d.ts",
|
|
574
|
+
"compiler/lib.webworker.iterable.d.ts",
|
|
575
|
+
"internal/index.d.ts",
|
|
576
|
+
"internal/index.js",
|
|
577
|
+
"internal/package.json",
|
|
578
|
+
"internal/rindo-ext-modules.d.ts",
|
|
579
|
+
"internal/rindo-private.d.ts",
|
|
580
|
+
"internal/rindo-public-compiler.d.ts",
|
|
581
|
+
"internal/rindo-public-docs.d.ts",
|
|
582
|
+
"internal/rindo-public-runtime.d.ts",
|
|
583
|
+
"mock-doc/index.js",
|
|
584
|
+
"mock-doc/package.json",
|
|
585
|
+
"internal/client/css-shim.js",
|
|
586
|
+
"internal/client/dom.js",
|
|
587
|
+
"internal/client/index.js",
|
|
588
|
+
"internal/client/package.json",
|
|
589
|
+
"internal/client/patch-browser.js",
|
|
590
|
+
"internal/client/patch-esm.js",
|
|
591
|
+
"internal/client/shadow-css.js",
|
|
592
|
+
"internal/hydrate/index.js",
|
|
593
|
+
"internal/hydrate/package.json",
|
|
594
|
+
"internal/hydrate/runner.js",
|
|
595
|
+
"internal/hydrate/shadow-css.js",
|
|
596
|
+
"internal/rindo-core/index.d.ts",
|
|
597
|
+
"internal/rindo-core/index.js"
|
|
598
|
+
]
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: "rollup",
|
|
602
|
+
version: "2.42.3",
|
|
603
|
+
main: "dist/es/rollup.browser.js"
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
name: "terser",
|
|
607
|
+
version: "5.6.1",
|
|
608
|
+
main: "dist/bundle.min.js"
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
name: "typescript",
|
|
612
|
+
version: "4.5.4",
|
|
613
|
+
main: "lib/typescript.js"
|
|
614
|
+
}
|
|
615
|
+
];
|
|
616
|
+
|
|
617
|
+
const findConfig = async (opts) => {
|
|
618
|
+
const sys = opts.sys;
|
|
619
|
+
const cwd = sys.getCurrentDirectory();
|
|
620
|
+
const results = {
|
|
621
|
+
configPath: null,
|
|
622
|
+
rootDir: normalizePath(cwd),
|
|
623
|
+
diagnostics: [],
|
|
624
|
+
};
|
|
625
|
+
let configPath = opts.configPath;
|
|
626
|
+
if (isString(configPath)) {
|
|
627
|
+
if (!sys.platformPath.isAbsolute(configPath)) {
|
|
628
|
+
// passed in a custom rindo config location
|
|
629
|
+
// but it's relative, so prefix the cwd
|
|
630
|
+
configPath = normalizePath(sys.platformPath.join(cwd, configPath));
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
// config path already an absolute path, we're good here
|
|
634
|
+
configPath = normalizePath(opts.configPath);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
// nothing was passed in, use the current working directory
|
|
639
|
+
configPath = results.rootDir;
|
|
640
|
+
}
|
|
641
|
+
const stat = await sys.stat(configPath);
|
|
642
|
+
if (stat.error) {
|
|
643
|
+
const diagnostic = buildError(results.diagnostics);
|
|
644
|
+
diagnostic.absFilePath = configPath;
|
|
645
|
+
diagnostic.header = `Invalid config path`;
|
|
646
|
+
diagnostic.messageText = `Config path "${configPath}" not found`;
|
|
647
|
+
return results;
|
|
648
|
+
}
|
|
649
|
+
if (stat.isFile) {
|
|
650
|
+
results.configPath = configPath;
|
|
651
|
+
results.rootDir = sys.platformPath.dirname(configPath);
|
|
652
|
+
}
|
|
653
|
+
else if (stat.isDirectory) {
|
|
654
|
+
// this is only a directory, so let's make some assumptions
|
|
655
|
+
for (const configName of ['rindo.config.ts', 'rindo.config.js']) {
|
|
656
|
+
const testConfigFilePath = sys.platformPath.join(configPath, configName);
|
|
657
|
+
const stat = await sys.stat(testConfigFilePath);
|
|
658
|
+
if (stat.isFile) {
|
|
659
|
+
results.configPath = testConfigFilePath;
|
|
660
|
+
results.rootDir = sys.platformPath.dirname(testConfigFilePath);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return results;
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
const loadCoreCompiler = async (sys) => {
|
|
669
|
+
await sys.dynamicImport(sys.getCompilerExecutingPath());
|
|
670
|
+
return globalThis.rindo;
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
const startupLog = (logger, task) => {
|
|
674
|
+
if (task === 'info' || task === 'serve' || task === 'version') {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
logger.info(logger.cyan(`@rindo/core`));
|
|
678
|
+
};
|
|
679
|
+
const startupLogVersion = (logger, task, coreCompiler) => {
|
|
680
|
+
if (task === 'info' || task === 'serve' || task === 'version') {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const isDevBuild = coreCompiler.version.includes('-dev.');
|
|
684
|
+
let startupMsg;
|
|
685
|
+
if (isDevBuild) {
|
|
686
|
+
startupMsg = logger.yellow('[LOCAL DEV]');
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
startupMsg = logger.cyan(`v${coreCompiler.version}`);
|
|
690
|
+
}
|
|
691
|
+
startupMsg += logger.emoji(' ' + coreCompiler.vermoji);
|
|
692
|
+
logger.info(startupMsg);
|
|
693
|
+
};
|
|
694
|
+
const loadedCompilerLog = (sys, logger, flags, coreCompiler) => {
|
|
695
|
+
const sysDetails = sys.details;
|
|
696
|
+
const runtimeInfo = `${sys.name} ${sys.version}`;
|
|
697
|
+
const platformInfo = `${sysDetails.platform}, ${sysDetails.cpuModel}`;
|
|
698
|
+
const statsInfo = `cpus: ${sys.hardwareConcurrency}, freemem: ${Math.round(sysDetails.freemem() / 1000000)}MB, totalmem: ${Math.round(sysDetails.totalmem / 1000000)}MB`;
|
|
699
|
+
if (logger.getLevel() === 'debug') {
|
|
700
|
+
logger.debug(runtimeInfo);
|
|
701
|
+
logger.debug(platformInfo);
|
|
702
|
+
logger.debug(statsInfo);
|
|
703
|
+
logger.debug(`compiler: ${sys.getCompilerExecutingPath()}`);
|
|
704
|
+
logger.debug(`build: ${coreCompiler.buildId}`);
|
|
705
|
+
}
|
|
706
|
+
else if (flags.ci) {
|
|
707
|
+
logger.info(runtimeInfo);
|
|
708
|
+
logger.info(platformInfo);
|
|
709
|
+
logger.info(statsInfo);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
const startupCompilerLog = (coreCompiler, config) => {
|
|
713
|
+
if (config.suppressLogs === true) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const { logger } = config;
|
|
717
|
+
const isDebug = logger.getLevel() === 'debug';
|
|
718
|
+
const isPrerelease = coreCompiler.version.includes('-');
|
|
719
|
+
const isDevBuild = coreCompiler.version.includes('-dev.');
|
|
720
|
+
if (isPrerelease && !isDevBuild) {
|
|
721
|
+
logger.warn(logger.yellow(`This is a prerelease build, undocumented changes might happen at any time. Technical support is not available for prereleases, but any assistance testing is appreciated.`));
|
|
722
|
+
}
|
|
723
|
+
if (config.devMode && !isDebug) {
|
|
724
|
+
if (config.buildEs5) {
|
|
725
|
+
logger.warn(`Generating ES5 during development is a very task expensive, initial and incremental builds will be much slower. Drop the '--es5' flag and use a modern browser for development.`);
|
|
726
|
+
}
|
|
727
|
+
if (!config.enableCache) {
|
|
728
|
+
logger.warn(`Disabling cache during development will slow down incremental builds.`);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
const taskPrerender = async (coreCompiler, config) => {
|
|
734
|
+
startupCompilerLog(coreCompiler, config);
|
|
735
|
+
const hydrateAppFilePath = config.flags.unknownArgs[0];
|
|
736
|
+
if (typeof hydrateAppFilePath !== 'string') {
|
|
737
|
+
config.logger.error(`Missing hydrate app script path`);
|
|
738
|
+
return config.sys.exit(1);
|
|
739
|
+
}
|
|
740
|
+
const srcIndexHtmlPath = config.srcIndexHtml;
|
|
741
|
+
const diagnostics = await runPrerenderTask(coreCompiler, config, hydrateAppFilePath, null, srcIndexHtmlPath);
|
|
742
|
+
config.logger.printDiagnostics(diagnostics);
|
|
743
|
+
if (diagnostics.some((d) => d.level === 'error')) {
|
|
744
|
+
return config.sys.exit(1);
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
const runPrerenderTask = async (coreCompiler, config, hydrateAppFilePath, componentGraph, srcIndexHtmlPath) => {
|
|
748
|
+
const diagnostics = [];
|
|
749
|
+
try {
|
|
750
|
+
const prerenderer = await coreCompiler.createPrerenderer(config);
|
|
751
|
+
const results = await prerenderer.start({
|
|
752
|
+
hydrateAppFilePath,
|
|
753
|
+
componentGraph,
|
|
754
|
+
srcIndexHtmlPath,
|
|
755
|
+
});
|
|
756
|
+
diagnostics.push(...results.diagnostics);
|
|
757
|
+
}
|
|
758
|
+
catch (e) {
|
|
759
|
+
catchError(diagnostics, e);
|
|
760
|
+
}
|
|
761
|
+
return diagnostics;
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
const startCheckVersion = async (config, currentVersion) => {
|
|
765
|
+
if (config.devMode && !config.flags.ci && !currentVersion.includes('-dev.') && isFunction(config.sys.checkVersion)) {
|
|
766
|
+
return config.sys.checkVersion(config.logger, currentVersion);
|
|
767
|
+
}
|
|
768
|
+
return null;
|
|
769
|
+
};
|
|
770
|
+
const printCheckVersionResults = async (versionChecker) => {
|
|
771
|
+
if (versionChecker) {
|
|
772
|
+
const checkVersionResults = await versionChecker;
|
|
773
|
+
if (isFunction(checkVersionResults)) {
|
|
774
|
+
checkVersionResults();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
const taskWatch = async (coreCompiler, config) => {
|
|
780
|
+
let devServer = null;
|
|
781
|
+
let exitCode = 0;
|
|
782
|
+
try {
|
|
783
|
+
startupCompilerLog(coreCompiler, config);
|
|
784
|
+
const versionChecker = startCheckVersion(config, coreCompiler.version);
|
|
785
|
+
const compiler = await coreCompiler.createCompiler(config);
|
|
786
|
+
const watcher = await compiler.createWatcher();
|
|
787
|
+
if (config.flags.serve) {
|
|
788
|
+
const devServerPath = config.sys.getDevServerExecutingPath();
|
|
789
|
+
const { start } = await config.sys.dynamicImport(devServerPath);
|
|
790
|
+
devServer = await start(config.devServer, config.logger, watcher);
|
|
791
|
+
}
|
|
792
|
+
config.sys.onProcessInterrupt(() => {
|
|
793
|
+
config.logger.debug(`close watch`);
|
|
794
|
+
compiler && compiler.destroy();
|
|
795
|
+
});
|
|
796
|
+
const rmVersionCheckerLog = watcher.on('buildFinish', async () => {
|
|
797
|
+
// log the version check one time
|
|
798
|
+
rmVersionCheckerLog();
|
|
799
|
+
printCheckVersionResults(versionChecker);
|
|
800
|
+
});
|
|
801
|
+
if (devServer) {
|
|
802
|
+
const rmDevServerLog = watcher.on('buildFinish', () => {
|
|
803
|
+
// log the dev server url one time
|
|
804
|
+
rmDevServerLog();
|
|
805
|
+
config.logger.info(`${config.logger.cyan(devServer.browserUrl)}\n`);
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
const closeResults = await watcher.start();
|
|
809
|
+
if (closeResults.exitCode > 0) {
|
|
810
|
+
exitCode = closeResults.exitCode;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
catch (e) {
|
|
814
|
+
exitCode = 1;
|
|
815
|
+
config.logger.error(e);
|
|
816
|
+
}
|
|
817
|
+
if (devServer) {
|
|
818
|
+
await devServer.close();
|
|
819
|
+
}
|
|
820
|
+
if (exitCode > 0) {
|
|
821
|
+
return config.sys.exit(exitCode);
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
const tryFn = async (fn, ...args) => {
|
|
826
|
+
try {
|
|
827
|
+
return await fn(...args);
|
|
828
|
+
}
|
|
829
|
+
catch (_a) {
|
|
830
|
+
// ignore
|
|
831
|
+
}
|
|
832
|
+
return null;
|
|
833
|
+
};
|
|
834
|
+
const isInteractive = (sys, config, object) => {
|
|
835
|
+
var _a;
|
|
836
|
+
const terminalInfo = object ||
|
|
837
|
+
Object.freeze({
|
|
838
|
+
tty: sys.isTTY() ? true : false,
|
|
839
|
+
ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!((_a = config.flags) === null || _a === void 0 ? void 0 : _a.ci),
|
|
840
|
+
});
|
|
841
|
+
return terminalInfo.tty && !terminalInfo.ci;
|
|
842
|
+
};
|
|
843
|
+
const UUID_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);
|
|
844
|
+
function uuidv4() {
|
|
845
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
846
|
+
const r = (Math.random() * 16) | 0;
|
|
847
|
+
const v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
848
|
+
return v.toString(16);
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Reads and parses a JSON file from the given `path`
|
|
853
|
+
* @param sys The system where the command is invoked
|
|
854
|
+
* @param path the path on the file system to read and parse
|
|
855
|
+
* @returns the parsed JSON
|
|
856
|
+
*/
|
|
857
|
+
async function readJson(sys, path) {
|
|
858
|
+
const file = await sys.readFile(path);
|
|
859
|
+
return !!file && JSON.parse(file);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Does the command have the debug flag?
|
|
863
|
+
* @param config The config passed into the Rindo command
|
|
864
|
+
* @returns true if --debug has been passed, otherwise false
|
|
865
|
+
*/
|
|
866
|
+
function hasDebug(config) {
|
|
867
|
+
return config.flags.debug;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Does the command have the verbose and debug flags?
|
|
871
|
+
* @param config The config passed into the Rindo command
|
|
872
|
+
* @returns true if both --debug and --verbose have been passed, otherwise false
|
|
873
|
+
*/
|
|
874
|
+
function hasVerbose(config) {
|
|
875
|
+
return config.flags.verbose && hasDebug(config);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Used to determine if tracking should occur.
|
|
880
|
+
* @param config The config passed into the Rindo command
|
|
881
|
+
* @param sys The system where the command is invoked
|
|
882
|
+
* @param ci whether or not the process is running in a Continuous Integration (CI) environment
|
|
883
|
+
* @returns true if telemetry should be sent, false otherwise
|
|
884
|
+
*/
|
|
885
|
+
async function shouldTrack(config, sys, ci) {
|
|
886
|
+
return !ci && isInteractive(sys, config) && (await checkTelemetry(sys));
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
const isTest$1 = () => process.env.JEST_WORKER_ID !== undefined;
|
|
890
|
+
const defaultConfig = (sys) => sys.resolvePath(`${sys.homeDir()}/.navify/${isTest$1() ? 'tmp-config.json' : 'config.json'}`);
|
|
891
|
+
const defaultConfigDirectory = (sys) => sys.resolvePath(`${sys.homeDir()}/.navify`);
|
|
892
|
+
/**
|
|
893
|
+
* Reads an Navify configuration file from disk, parses it, and performs any necessary corrections to it if certain
|
|
894
|
+
* values are deemed to be malformed
|
|
895
|
+
* @param sys The system where the command is invoked
|
|
896
|
+
* @returns the config read from disk that has been potentially been updated
|
|
897
|
+
*/
|
|
898
|
+
async function readConfig(sys) {
|
|
899
|
+
let config = await readJson(sys, defaultConfig(sys));
|
|
900
|
+
if (!config) {
|
|
901
|
+
config = {
|
|
902
|
+
'tokens.telemetry': uuidv4(),
|
|
903
|
+
'telemetry.rindo': true,
|
|
904
|
+
};
|
|
905
|
+
await writeConfig(sys, config);
|
|
906
|
+
}
|
|
907
|
+
else if (!UUID_REGEX.test(config['tokens.telemetry'])) {
|
|
908
|
+
const newUuid = uuidv4();
|
|
909
|
+
await writeConfig(sys, { ...config, 'tokens.telemetry': newUuid });
|
|
910
|
+
config['tokens.telemetry'] = newUuid;
|
|
911
|
+
}
|
|
912
|
+
return config;
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Writes an Navify configuration file to disk.
|
|
916
|
+
* @param sys The system where the command is invoked
|
|
917
|
+
* @param config The config passed into the Rindo command
|
|
918
|
+
* @returns boolean If the command was successful
|
|
919
|
+
*/
|
|
920
|
+
async function writeConfig(sys, config) {
|
|
921
|
+
let result = false;
|
|
922
|
+
try {
|
|
923
|
+
await sys.createDir(defaultConfigDirectory(sys), { recursive: true });
|
|
924
|
+
await sys.writeFile(defaultConfig(sys), JSON.stringify(config, null, 2));
|
|
925
|
+
result = true;
|
|
926
|
+
}
|
|
927
|
+
catch (error) {
|
|
928
|
+
console.error(`Rindo Telemetry: couldn't write configuration file to ${defaultConfig(sys)} - ${error}.`);
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Update a subset of the Navify config.
|
|
934
|
+
* @param sys The system where the command is invoked
|
|
935
|
+
* @param newOptions The new options to save
|
|
936
|
+
* @returns boolean If the command was successful
|
|
937
|
+
*/
|
|
938
|
+
async function updateConfig(sys, newOptions) {
|
|
939
|
+
const config = await readConfig(sys);
|
|
940
|
+
return await writeConfig(sys, Object.assign(config, newOptions));
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
|
|
944
|
+
const DOCS_CUSTOM = 'docs-custom';
|
|
945
|
+
const DOCS_JSON = 'docs-json';
|
|
946
|
+
const DOCS_README = 'docs-readme';
|
|
947
|
+
const DOCS_VSCODE = 'docs-vscode';
|
|
948
|
+
const WWW = 'www';
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Used to within taskBuild to provide the component_count property.
|
|
952
|
+
*
|
|
953
|
+
* @param sys The system where the command is invoked
|
|
954
|
+
* @param config The config passed into the Rindo command
|
|
955
|
+
* @param logger The tool used to do logging
|
|
956
|
+
* @param coreCompiler The compiler used to do builds
|
|
957
|
+
* @param result The results of a compiler build.
|
|
958
|
+
*/
|
|
959
|
+
async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, result) {
|
|
960
|
+
const tracking = await shouldTrack(config, sys, config.flags.ci);
|
|
961
|
+
if (!tracking) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
const component_count = Object.keys(result.componentGraph).length;
|
|
965
|
+
const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);
|
|
966
|
+
await sendMetric(sys, config, 'rindo_cli_command', data);
|
|
967
|
+
logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* A function to wrap a compiler task function around. Will send telemetry if, and only if, the machine allows.
|
|
971
|
+
* @param sys The system where the command is invoked
|
|
972
|
+
* @param config The config passed into the Rindo command
|
|
973
|
+
* @param logger The tool used to do logging
|
|
974
|
+
* @param coreCompiler The compiler used to do builds
|
|
975
|
+
* @param action A Promise-based function to call in order to get the duration of any given command.
|
|
976
|
+
* @returns void
|
|
977
|
+
*/
|
|
978
|
+
async function telemetryAction(sys, config, logger, coreCompiler, action) {
|
|
979
|
+
var _a;
|
|
980
|
+
const tracking = await shouldTrack(config, sys, !!((_a = config === null || config === void 0 ? void 0 : config.flags) === null || _a === void 0 ? void 0 : _a.ci));
|
|
981
|
+
let duration = undefined;
|
|
982
|
+
let error;
|
|
983
|
+
if (action) {
|
|
984
|
+
const start = new Date();
|
|
985
|
+
try {
|
|
986
|
+
await action();
|
|
987
|
+
}
|
|
988
|
+
catch (e) {
|
|
989
|
+
error = e;
|
|
990
|
+
}
|
|
991
|
+
const end = new Date();
|
|
992
|
+
duration = end.getTime() - start.getTime();
|
|
993
|
+
}
|
|
994
|
+
// We'll get componentCount details inside the taskBuild, so let's not send two messages.
|
|
995
|
+
if (!tracking || (config.flags.task == 'build' && !config.flags.args.includes('--watch'))) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const data = await prepareData(coreCompiler, config, sys, duration);
|
|
999
|
+
await sendMetric(sys, config, 'rindo_cli_command', data);
|
|
1000
|
+
logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
|
|
1001
|
+
if (error) {
|
|
1002
|
+
throw error;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function hasAppTarget(config) {
|
|
1006
|
+
return config.outputTargets.some((target) => target.type === WWW && (!!target.serviceWorker || (!!target.baseUrl && target.baseUrl !== '/')));
|
|
1007
|
+
}
|
|
1008
|
+
function isUsingYarn(sys) {
|
|
1009
|
+
var _a;
|
|
1010
|
+
return ((_a = sys.getEnvironmentVar('npm_execpath')) === null || _a === void 0 ? void 0 : _a.includes('yarn')) || false;
|
|
1011
|
+
}
|
|
1012
|
+
async function getActiveTargets(config) {
|
|
1013
|
+
const result = config.outputTargets.map((t) => t.type);
|
|
1014
|
+
return Array.from(new Set(result));
|
|
1015
|
+
}
|
|
1016
|
+
const prepareData = async (coreCompiler, config, sys, duration_ms, component_count = undefined) => {
|
|
1017
|
+
const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' };
|
|
1018
|
+
const { packages, packagesNoVersions } = await getInstalledPackages(sys, config);
|
|
1019
|
+
const targets = await getActiveTargets(config);
|
|
1020
|
+
const yarn = isUsingYarn(sys);
|
|
1021
|
+
const rindo = coreCompiler.version || 'unknown';
|
|
1022
|
+
const system = `${sys.name} ${sys.version}`;
|
|
1023
|
+
const os_name = sys.details.platform;
|
|
1024
|
+
const os_version = sys.details.release;
|
|
1025
|
+
const cpu_model = sys.details.cpuModel;
|
|
1026
|
+
const build = coreCompiler.buildId || 'unknown';
|
|
1027
|
+
const has_app_pwa_config = hasAppTarget(config);
|
|
1028
|
+
return {
|
|
1029
|
+
yarn,
|
|
1030
|
+
duration_ms,
|
|
1031
|
+
component_count,
|
|
1032
|
+
targets,
|
|
1033
|
+
packages,
|
|
1034
|
+
packages_no_versions: packagesNoVersions,
|
|
1035
|
+
arguments: config.flags.args,
|
|
1036
|
+
task: config.flags.task,
|
|
1037
|
+
rindo,
|
|
1038
|
+
system,
|
|
1039
|
+
system_major: getMajorVersion(system),
|
|
1040
|
+
os_name,
|
|
1041
|
+
os_version,
|
|
1042
|
+
cpu_model,
|
|
1043
|
+
build,
|
|
1044
|
+
typescript,
|
|
1045
|
+
rollup,
|
|
1046
|
+
has_app_pwa_config,
|
|
1047
|
+
};
|
|
1048
|
+
};
|
|
1049
|
+
/**
|
|
1050
|
+
* Reads package-lock.json, yarn.lock, and package.json files in order to cross reference
|
|
1051
|
+
* the dependencies and devDependencies properties. Pulls up the current installed version
|
|
1052
|
+
* of each package under the @rindo, @navify, and @jigra scopes.
|
|
1053
|
+
* @returns string[]
|
|
1054
|
+
*/
|
|
1055
|
+
async function getInstalledPackages(sys, config) {
|
|
1056
|
+
let packages = [];
|
|
1057
|
+
let packagesNoVersions = [];
|
|
1058
|
+
const yarn = isUsingYarn(sys);
|
|
1059
|
+
try {
|
|
1060
|
+
// Read package.json and package-lock.json
|
|
1061
|
+
const appRootDir = sys.getCurrentDirectory();
|
|
1062
|
+
const packageJson = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package.json'));
|
|
1063
|
+
// They don't have a package.json for some reason? Eject button.
|
|
1064
|
+
if (!packageJson) {
|
|
1065
|
+
return { packages, packagesNoVersions };
|
|
1066
|
+
}
|
|
1067
|
+
const rawPackages = Object.entries({
|
|
1068
|
+
...packageJson.devDependencies,
|
|
1069
|
+
...packageJson.dependencies,
|
|
1070
|
+
});
|
|
1071
|
+
// Collect packages only in the rindo, navify, or jigra org's:
|
|
1072
|
+
// https://www.npmjs.com/org/rindo
|
|
1073
|
+
const navifyPackages = rawPackages.filter(([k]) => k.startsWith('@rindo/') || k.startsWith('@navify/') || k.startsWith('@jigra/'));
|
|
1074
|
+
try {
|
|
1075
|
+
packages = yarn ? await yarnPackages(sys, navifyPackages) : await npmPackages(sys, navifyPackages);
|
|
1076
|
+
}
|
|
1077
|
+
catch (e) {
|
|
1078
|
+
packages = navifyPackages.map(([k, v]) => `${k}@${v.replace('^', '')}`);
|
|
1079
|
+
}
|
|
1080
|
+
packagesNoVersions = navifyPackages.map(([k]) => `${k}`);
|
|
1081
|
+
return { packages, packagesNoVersions };
|
|
1082
|
+
}
|
|
1083
|
+
catch (err) {
|
|
1084
|
+
hasDebug(config) && console.error(err);
|
|
1085
|
+
return { packages, packagesNoVersions };
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Visits the npm lock file to find the exact versions that are installed
|
|
1090
|
+
* @param sys The system where the command is invoked
|
|
1091
|
+
* @param navifyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@navify` from the package.json file.
|
|
1092
|
+
* @returns an array of strings of all the packages and their versions.
|
|
1093
|
+
*/
|
|
1094
|
+
async function npmPackages(sys, navifyPackages) {
|
|
1095
|
+
const appRootDir = sys.getCurrentDirectory();
|
|
1096
|
+
const packageLockJson = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package-lock.json'));
|
|
1097
|
+
return navifyPackages.map(([k, v]) => {
|
|
1098
|
+
var _a, _b, _c, _d;
|
|
1099
|
+
let version = (_d = (_b = (_a = packageLockJson === null || packageLockJson === void 0 ? void 0 : packageLockJson.dependencies[k]) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : (_c = packageLockJson === null || packageLockJson === void 0 ? void 0 : packageLockJson.devDependencies[k]) === null || _c === void 0 ? void 0 : _c.version) !== null && _d !== void 0 ? _d : v;
|
|
1100
|
+
version = version.includes('file:') ? sanitizeDeclaredVersion(v) : version;
|
|
1101
|
+
return `${k}@${version}`;
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Visits the yarn lock file to find the exact versions that are installed
|
|
1106
|
+
* @param sys The system where the command is invoked
|
|
1107
|
+
* @param navifyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@navify` from the package.json file.
|
|
1108
|
+
* @returns an array of strings of all the packages and their versions.
|
|
1109
|
+
*/
|
|
1110
|
+
async function yarnPackages(sys, navifyPackages) {
|
|
1111
|
+
const appRootDir = sys.getCurrentDirectory();
|
|
1112
|
+
const yarnLock = sys.readFileSync(sys.resolvePath(appRootDir + '/yarn.lock'));
|
|
1113
|
+
const yarnLockYml = sys.parseYarnLockFile(yarnLock);
|
|
1114
|
+
return navifyPackages.map(([k, v]) => {
|
|
1115
|
+
var _a;
|
|
1116
|
+
const identifiedVersion = `${k}@${v}`;
|
|
1117
|
+
let version = (_a = yarnLockYml.object[identifiedVersion]) === null || _a === void 0 ? void 0 : _a.version;
|
|
1118
|
+
version = version.includes('undefined') ? sanitizeDeclaredVersion(identifiedVersion) : version;
|
|
1119
|
+
return `${k}@${version}`;
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* This function is used for fallback purposes, where an npm or yarn lock file doesn't exist in the consumers directory.
|
|
1124
|
+
* This will strip away '*', '^' and '~' from the declared package versions in a package.json.
|
|
1125
|
+
* @param version the raw semver pattern identifier version string
|
|
1126
|
+
* @returns a cleaned up representation without any qualifiers
|
|
1127
|
+
*/
|
|
1128
|
+
function sanitizeDeclaredVersion(version) {
|
|
1129
|
+
return version.replace(/[*^~]/g, '');
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* If telemetry is enabled, send a metric via IPC to a forked process for uploading.
|
|
1133
|
+
*/
|
|
1134
|
+
async function sendMetric(sys, config, name, value) {
|
|
1135
|
+
const session_id = await getTelemetryToken(sys);
|
|
1136
|
+
const message = {
|
|
1137
|
+
name,
|
|
1138
|
+
timestamp: new Date().toISOString(),
|
|
1139
|
+
source: 'rindo_cli',
|
|
1140
|
+
value,
|
|
1141
|
+
session_id,
|
|
1142
|
+
};
|
|
1143
|
+
await sendTelemetry(sys, config, { type: 'telemetry', message });
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Used to read the config file's tokens.telemetry property.
|
|
1147
|
+
* @param sys The system where the command is invoked
|
|
1148
|
+
* @returns string
|
|
1149
|
+
*/
|
|
1150
|
+
async function getTelemetryToken(sys) {
|
|
1151
|
+
const config = await readConfig(sys);
|
|
1152
|
+
if (config['tokens.telemetry'] === undefined) {
|
|
1153
|
+
config['tokens.telemetry'] = uuidv4();
|
|
1154
|
+
await writeConfig(sys, config);
|
|
1155
|
+
}
|
|
1156
|
+
return config['tokens.telemetry'];
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Issues a request to the telemetry server.
|
|
1160
|
+
* @param sys The system where the command is invoked
|
|
1161
|
+
* @param config The config passed into the Rindo command
|
|
1162
|
+
* @param data Data to be tracked
|
|
1163
|
+
*/
|
|
1164
|
+
async function sendTelemetry(sys, config, data) {
|
|
1165
|
+
try {
|
|
1166
|
+
const now = new Date().toISOString();
|
|
1167
|
+
const body = {
|
|
1168
|
+
metrics: [data.message],
|
|
1169
|
+
sent_at: now,
|
|
1170
|
+
};
|
|
1171
|
+
// This request is only made if telemetry is on.
|
|
1172
|
+
const response = await sys.fetch('https://api-navifyjs.web.app/events/metrics', {
|
|
1173
|
+
method: 'POST',
|
|
1174
|
+
headers: {
|
|
1175
|
+
'Content-Type': 'application/json',
|
|
1176
|
+
},
|
|
1177
|
+
body: JSON.stringify(body),
|
|
1178
|
+
});
|
|
1179
|
+
hasVerbose(config) &&
|
|
1180
|
+
console.debug('\nSent %O metric to events service (status: %O)', data.message.name, response.status, '\n');
|
|
1181
|
+
if (response.status !== 204) {
|
|
1182
|
+
hasVerbose(config) &&
|
|
1183
|
+
console.debug('\nBad response from events service. Request body: %O', response.body.toString(), '\n');
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
catch (e) {
|
|
1187
|
+
hasVerbose(config) && console.debug('Telemetry request failed:', e);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Checks if telemetry is enabled on this machine
|
|
1192
|
+
* @param sys The system where the command is invoked
|
|
1193
|
+
* @returns true if telemetry is enabled, false otherwise
|
|
1194
|
+
*/
|
|
1195
|
+
async function checkTelemetry(sys) {
|
|
1196
|
+
const config = await readConfig(sys);
|
|
1197
|
+
if (config['telemetry.rindo'] === undefined) {
|
|
1198
|
+
config['telemetry.rindo'] = true;
|
|
1199
|
+
await writeConfig(sys, config);
|
|
1200
|
+
}
|
|
1201
|
+
return config['telemetry.rindo'];
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Writes to the config file, enabling telemetry for this machine.
|
|
1205
|
+
* @param sys The system where the command is invoked
|
|
1206
|
+
* @returns true if writing the file was successful, false otherwise
|
|
1207
|
+
*/
|
|
1208
|
+
async function enableTelemetry(sys) {
|
|
1209
|
+
return await updateConfig(sys, { 'telemetry.rindo': true });
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Writes to the config file, disabling telemetry for this machine.
|
|
1213
|
+
* @param sys The system where the command is invoked
|
|
1214
|
+
* @returns true if writing the file was successful, false otherwise
|
|
1215
|
+
*/
|
|
1216
|
+
async function disableTelemetry(sys) {
|
|
1217
|
+
return await updateConfig(sys, { 'telemetry.rindo': false });
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Takes in a semver string in order to return the major version.
|
|
1221
|
+
* @param version The fully qualified semver version
|
|
1222
|
+
* @returns a string of the major version
|
|
1223
|
+
*/
|
|
1224
|
+
function getMajorVersion(version) {
|
|
1225
|
+
const parts = version.split('.');
|
|
1226
|
+
return parts[0];
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
const taskBuild = async (coreCompiler, config, sys) => {
|
|
1230
|
+
if (config.flags.watch) {
|
|
1231
|
+
// watch build
|
|
1232
|
+
await taskWatch(coreCompiler, config);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
// one-time build
|
|
1236
|
+
let exitCode = 0;
|
|
1237
|
+
try {
|
|
1238
|
+
startupCompilerLog(coreCompiler, config);
|
|
1239
|
+
const versionChecker = startCheckVersion(config, coreCompiler.version);
|
|
1240
|
+
const compiler = await coreCompiler.createCompiler(config);
|
|
1241
|
+
const results = await compiler.build();
|
|
1242
|
+
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1243
|
+
if (sys) {
|
|
1244
|
+
await telemetryBuildFinishedAction(sys, config, config.logger, coreCompiler, results);
|
|
1245
|
+
}
|
|
1246
|
+
await compiler.destroy();
|
|
1247
|
+
if (results.hasError) {
|
|
1248
|
+
exitCode = 1;
|
|
1249
|
+
}
|
|
1250
|
+
else if (config.flags.prerender) {
|
|
1251
|
+
const prerenderDiagnostics = await runPrerenderTask(coreCompiler, config, results.hydrateAppFilePath, results.componentGraph, null);
|
|
1252
|
+
config.logger.printDiagnostics(prerenderDiagnostics);
|
|
1253
|
+
if (prerenderDiagnostics.some((d) => d.level === 'error')) {
|
|
1254
|
+
exitCode = 1;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
await printCheckVersionResults(versionChecker);
|
|
1258
|
+
}
|
|
1259
|
+
catch (e) {
|
|
1260
|
+
exitCode = 1;
|
|
1261
|
+
config.logger.error(e);
|
|
1262
|
+
}
|
|
1263
|
+
if (exitCode > 0) {
|
|
1264
|
+
return config.sys.exit(exitCode);
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
const taskDocs = async (coreCompiler, config) => {
|
|
1269
|
+
config.devServer = null;
|
|
1270
|
+
config.outputTargets = config.outputTargets.filter(isOutputTargetDocs);
|
|
1271
|
+
config.devMode = true;
|
|
1272
|
+
startupCompilerLog(coreCompiler, config);
|
|
1273
|
+
const compiler = await coreCompiler.createCompiler(config);
|
|
1274
|
+
await compiler.build();
|
|
1275
|
+
await compiler.destroy();
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
const IS_NODE_ENV = typeof global !== 'undefined' &&
|
|
1279
|
+
typeof require === 'function' &&
|
|
1280
|
+
!!global.process &&
|
|
1281
|
+
typeof __filename === 'string' &&
|
|
1282
|
+
(!global.origin || typeof global.origin !== 'string');
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* Task to generate component boilerplate and write it to disk. This task can
|
|
1286
|
+
* cause the program to exit with an error under various circumstances, such as
|
|
1287
|
+
* being called in an inappropriate place, being asked to overwrite files that
|
|
1288
|
+
* already exist, etc.
|
|
1289
|
+
*
|
|
1290
|
+
* @param coreCompiler the CoreCompiler we're using currently, here we're
|
|
1291
|
+
* mainly accessing the `path` module
|
|
1292
|
+
* @param config the user-supplied config, which we need here to access `.sys`.
|
|
1293
|
+
*/
|
|
1294
|
+
const taskGenerate = async (coreCompiler, config) => {
|
|
1295
|
+
if (!IS_NODE_ENV) {
|
|
1296
|
+
config.logger.error(`"generate" command is currently only implemented for a NodeJS environment`);
|
|
1297
|
+
return config.sys.exit(1);
|
|
1298
|
+
}
|
|
1299
|
+
const path = coreCompiler.path;
|
|
1300
|
+
if (!config.configPath) {
|
|
1301
|
+
config.logger.error('Please run this command in your root directory (i. e. the one containing rindo.config.ts).');
|
|
1302
|
+
return config.sys.exit(1);
|
|
1303
|
+
}
|
|
1304
|
+
const absoluteSrcDir = config.srcDir;
|
|
1305
|
+
if (!absoluteSrcDir) {
|
|
1306
|
+
config.logger.error(`Rindo's srcDir was not specified.`);
|
|
1307
|
+
return config.sys.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
const { prompt } = await import('../sys/node/prompts.js');
|
|
1310
|
+
const input = config.flags.unknownArgs.find((arg) => !arg.startsWith('-')) ||
|
|
1311
|
+
(await prompt({ name: 'tagName', type: 'text', message: 'Component tag name (dash-case):' })).tagName;
|
|
1312
|
+
const { dir, base: componentName } = path.parse(input);
|
|
1313
|
+
const tagError = validateComponentTag(componentName);
|
|
1314
|
+
if (tagError) {
|
|
1315
|
+
config.logger.error(tagError);
|
|
1316
|
+
return config.sys.exit(1);
|
|
1317
|
+
}
|
|
1318
|
+
const extensionsToGenerate = ['tsx', ...(await chooseFilesToGenerate())];
|
|
1319
|
+
const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
|
|
1320
|
+
const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
|
|
1321
|
+
await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });
|
|
1322
|
+
const filesToGenerate = extensionsToGenerate.map((extension) => ({
|
|
1323
|
+
extension,
|
|
1324
|
+
path: getFilepathForFile(coreCompiler, outDir, componentName, extension),
|
|
1325
|
+
}));
|
|
1326
|
+
await checkForOverwrite(filesToGenerate, config);
|
|
1327
|
+
const writtenFiles = await Promise.all(filesToGenerate.map((file) => getBoilerplateAndWriteFile(config, componentName, extensionsToGenerate.includes('css'), file))).catch((error) => config.logger.error(error));
|
|
1328
|
+
if (!writtenFiles) {
|
|
1329
|
+
return config.sys.exit(1);
|
|
1330
|
+
}
|
|
1331
|
+
// TODO: Investigate moving these console.log calls to config.logger.info
|
|
1332
|
+
console.log();
|
|
1333
|
+
console.log(`${config.logger.gray('$')} rindo generate ${input}`);
|
|
1334
|
+
console.log();
|
|
1335
|
+
console.log(config.logger.bold('The following files have been generated:'));
|
|
1336
|
+
const absoluteRootDir = config.rootDir;
|
|
1337
|
+
writtenFiles.map((file) => console.log(` - ${path.relative(absoluteRootDir, file)}`));
|
|
1338
|
+
};
|
|
1339
|
+
/**
|
|
1340
|
+
* Show a checkbox prompt to select the files to be generated.
|
|
1341
|
+
*
|
|
1342
|
+
* @returns a read-only array of `GenerableExtension`, the extensions that the user has decided
|
|
1343
|
+
* to generate
|
|
1344
|
+
*/
|
|
1345
|
+
const chooseFilesToGenerate = async () => {
|
|
1346
|
+
const { prompt } = await import('../sys/node/prompts.js');
|
|
1347
|
+
return (await prompt({
|
|
1348
|
+
name: 'filesToGenerate',
|
|
1349
|
+
type: 'multiselect',
|
|
1350
|
+
message: 'Which additional files do you want to generate?',
|
|
1351
|
+
choices: [
|
|
1352
|
+
{ value: 'css', title: 'Stylesheet (.css)', selected: true },
|
|
1353
|
+
{ value: 'spec.tsx', title: 'Spec Test (.spec.tsx)', selected: true },
|
|
1354
|
+
{ value: 'e2e.ts', title: 'E2E Test (.e2e.ts)', selected: true },
|
|
1355
|
+
],
|
|
1356
|
+
})).filesToGenerate;
|
|
1357
|
+
};
|
|
1358
|
+
/**
|
|
1359
|
+
* Get a filepath for a file we want to generate!
|
|
1360
|
+
*
|
|
1361
|
+
* The filepath for a given file depends on the path, the user-supplied
|
|
1362
|
+
* component name, the extension, and whether we're inside of a test directory.
|
|
1363
|
+
*
|
|
1364
|
+
* @param coreCompiler the compiler we're using, here to acces the `.path` module
|
|
1365
|
+
* @param path path to where we're going to generate the component
|
|
1366
|
+
* @param componentName the user-supplied name for the generated component
|
|
1367
|
+
* @param extension the file extension
|
|
1368
|
+
* @returns the full filepath to the component (with a possible `test` directory
|
|
1369
|
+
* added)
|
|
1370
|
+
*/
|
|
1371
|
+
const getFilepathForFile = (coreCompiler, path, componentName, extension) => isTest(extension)
|
|
1372
|
+
? coreCompiler.path.join(path, 'test', `${componentName}.${extension}`)
|
|
1373
|
+
: coreCompiler.path.join(path, `${componentName}.${extension}`);
|
|
1374
|
+
/**
|
|
1375
|
+
* Get the boilerplate for a file and write it to disk
|
|
1376
|
+
*
|
|
1377
|
+
* @param config the current config, needed for file operations
|
|
1378
|
+
* @param componentName the component name (user-supplied)
|
|
1379
|
+
* @param withCss are we generating CSS?
|
|
1380
|
+
* @param file the file we want to write
|
|
1381
|
+
* @returns a `Promise<string>` which holds the full filepath we've written to,
|
|
1382
|
+
* used to print out a little summary of our activity to the user.
|
|
1383
|
+
*/
|
|
1384
|
+
const getBoilerplateAndWriteFile = async (config, componentName, withCss, file) => {
|
|
1385
|
+
const boilerplate = getBoilerplateByExtension(componentName, file.extension, withCss);
|
|
1386
|
+
await config.sys.writeFile(file.path, boilerplate);
|
|
1387
|
+
return file.path;
|
|
1388
|
+
};
|
|
1389
|
+
/**
|
|
1390
|
+
* Check to see if any of the files we plan to write already exist and would
|
|
1391
|
+
* therefore be overwritten if we proceed, because we'd like to not overwrite
|
|
1392
|
+
* people's code!
|
|
1393
|
+
*
|
|
1394
|
+
* This function will check all the filepaths and if it finds any files log an
|
|
1395
|
+
* error and exit with an error code. If it doesn't find anything it will just
|
|
1396
|
+
* peacefully return `Promise<void>`.
|
|
1397
|
+
*
|
|
1398
|
+
* @param files the files we want to check
|
|
1399
|
+
* @param config the Config object, used here to get access to `sys.readFile`
|
|
1400
|
+
*/
|
|
1401
|
+
const checkForOverwrite = async (files, config) => {
|
|
1402
|
+
const alreadyPresent = [];
|
|
1403
|
+
await Promise.all(files.map(async ({ path }) => {
|
|
1404
|
+
if ((await config.sys.readFile(path)) !== undefined) {
|
|
1405
|
+
alreadyPresent.push(path);
|
|
1406
|
+
}
|
|
1407
|
+
}));
|
|
1408
|
+
if (alreadyPresent.length > 0) {
|
|
1409
|
+
config.logger.error('Generating code would overwrite the following files:', ...alreadyPresent.map((path) => '\t' + path));
|
|
1410
|
+
await config.sys.exit(1);
|
|
1411
|
+
}
|
|
1412
|
+
};
|
|
1413
|
+
/**
|
|
1414
|
+
* Check if an extension is for a test
|
|
1415
|
+
*
|
|
1416
|
+
* @param extension the extension we want to check
|
|
1417
|
+
* @returns a boolean indicating whether or not its a test
|
|
1418
|
+
*/
|
|
1419
|
+
const isTest = (extension) => {
|
|
1420
|
+
return extension === 'e2e.ts' || extension === 'spec.tsx';
|
|
1421
|
+
};
|
|
1422
|
+
/**
|
|
1423
|
+
* Get the boilerplate for a file by its extension.
|
|
1424
|
+
*
|
|
1425
|
+
* @param tagName the name of the component we're generating
|
|
1426
|
+
* @param extension the file extension we want boilerplate for (.css, tsx, etc)
|
|
1427
|
+
* @param withCss a boolean indicating whether we're generating a CSS file
|
|
1428
|
+
* @returns a string container the file boilerplate for the supplied extension
|
|
1429
|
+
*/
|
|
1430
|
+
const getBoilerplateByExtension = (tagName, extension, withCss) => {
|
|
1431
|
+
switch (extension) {
|
|
1432
|
+
case 'tsx':
|
|
1433
|
+
return getComponentBoilerplate(tagName, withCss);
|
|
1434
|
+
case 'css':
|
|
1435
|
+
return getStyleUrlBoilerplate();
|
|
1436
|
+
case 'spec.tsx':
|
|
1437
|
+
return getSpecTestBoilerplate(tagName);
|
|
1438
|
+
case 'e2e.ts':
|
|
1439
|
+
return getE2eTestBoilerplate(tagName);
|
|
1440
|
+
default:
|
|
1441
|
+
throw new Error(`Unkown extension "${extension}".`);
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
/**
|
|
1445
|
+
* Get the boilerplate for a component.
|
|
1446
|
+
*/
|
|
1447
|
+
const getComponentBoilerplate = (tagName, hasStyle) => {
|
|
1448
|
+
const decorator = [`{`];
|
|
1449
|
+
decorator.push(` tag: '${tagName}',`);
|
|
1450
|
+
if (hasStyle) {
|
|
1451
|
+
decorator.push(` styleUrl: '${tagName}.css',`);
|
|
1452
|
+
}
|
|
1453
|
+
decorator.push(` shadow: true,`);
|
|
1454
|
+
decorator.push(`}`);
|
|
1455
|
+
return `import { Component, Host, h } from '@rindo/core';
|
|
1456
|
+
|
|
1457
|
+
@Component(${decorator.join('\n')})
|
|
1458
|
+
export class ${toPascalCase(tagName)} {
|
|
1459
|
+
|
|
1460
|
+
render() {
|
|
1461
|
+
return (
|
|
1462
|
+
<Host>
|
|
1463
|
+
<slot></slot>
|
|
1464
|
+
</Host>
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
}
|
|
1469
|
+
`;
|
|
1470
|
+
};
|
|
1471
|
+
/**
|
|
1472
|
+
* Get the boilerplate for style.
|
|
1473
|
+
*/
|
|
1474
|
+
const getStyleUrlBoilerplate = () => `:host {
|
|
1475
|
+
display: block;
|
|
1476
|
+
}
|
|
1477
|
+
`;
|
|
1478
|
+
/**
|
|
1479
|
+
* Get the boilerplate for a spec test.
|
|
1480
|
+
*/
|
|
1481
|
+
const getSpecTestBoilerplate = (tagName) => `import { newSpecPage } from '@rindo/core/testing';
|
|
1482
|
+
import { ${toPascalCase(tagName)} } from '../${tagName}';
|
|
1483
|
+
|
|
1484
|
+
describe('${tagName}', () => {
|
|
1485
|
+
it('renders', async () => {
|
|
1486
|
+
const page = await newSpecPage({
|
|
1487
|
+
components: [${toPascalCase(tagName)}],
|
|
1488
|
+
html: \`<${tagName}></${tagName}>\`,
|
|
1489
|
+
});
|
|
1490
|
+
expect(page.root).toEqualHtml(\`
|
|
1491
|
+
<${tagName}>
|
|
1492
|
+
<mock:shadow-root>
|
|
1493
|
+
<slot></slot>
|
|
1494
|
+
</mock:shadow-root>
|
|
1495
|
+
</${tagName}>
|
|
1496
|
+
\`);
|
|
1497
|
+
});
|
|
1498
|
+
});
|
|
1499
|
+
`;
|
|
1500
|
+
/**
|
|
1501
|
+
* Get the boilerplate for an E2E test.
|
|
1502
|
+
*/
|
|
1503
|
+
const getE2eTestBoilerplate = (name) => `import { newE2EPage } from '@rindo/core/testing';
|
|
1504
|
+
|
|
1505
|
+
describe('${name}', () => {
|
|
1506
|
+
it('renders', async () => {
|
|
1507
|
+
const page = await newE2EPage();
|
|
1508
|
+
await page.setContent('<${name}></${name}>');
|
|
1509
|
+
|
|
1510
|
+
const element = await page.find('${name}');
|
|
1511
|
+
expect(element).toHaveClass('hydrated');
|
|
1512
|
+
});
|
|
1513
|
+
});
|
|
1514
|
+
`;
|
|
1515
|
+
/**
|
|
1516
|
+
* Convert a dash case string to pascal case.
|
|
1517
|
+
*/
|
|
1518
|
+
const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
|
|
1519
|
+
|
|
1520
|
+
const taskTelemetry = async (config, sys, logger) => {
|
|
1521
|
+
const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
|
|
1522
|
+
const isEnabling = config.flags.args.includes('on');
|
|
1523
|
+
const isDisabling = config.flags.args.includes('off');
|
|
1524
|
+
const INFORMATION = `Opt in or our of telemetry. Information about the data we collect is available on our website: ${logger.bold('https://rindojs.web.app/telemetry')}`;
|
|
1525
|
+
const THANK_YOU = `Thank you for helping to make Rindo better! 💖`;
|
|
1526
|
+
const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\n\n`;
|
|
1527
|
+
const DISABLED_MESSAGE = `${logger.red('Disabled')}\n\n`;
|
|
1528
|
+
const hasTelemetry = await checkTelemetry(sys);
|
|
1529
|
+
if (isEnabling) {
|
|
1530
|
+
const result = await enableTelemetry(sys);
|
|
1531
|
+
result
|
|
1532
|
+
? console.log(`\n ${logger.bold('Telemetry is now ') + ENABLED_MESSAGE}`)
|
|
1533
|
+
: console.log(`Something went wrong when enabling Telemetry.`);
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
if (isDisabling) {
|
|
1537
|
+
const result = await disableTelemetry(sys);
|
|
1538
|
+
result
|
|
1539
|
+
? console.log(`\n ${logger.bold('Telemetry is now ') + DISABLED_MESSAGE}`)
|
|
1540
|
+
: console.log(`Something went wrong when disabling Telemetry.`);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
console.log(` ${logger.bold('Telemetry:')} ${logger.dim(INFORMATION)}`);
|
|
1544
|
+
console.log(`\n ${logger.bold('Status')}: ${hasTelemetry ? ENABLED_MESSAGE : DISABLED_MESSAGE}`);
|
|
1545
|
+
console.log(` ${prompt} ${logger.green('rindo telemetry [off|on]')}
|
|
1546
|
+
|
|
1547
|
+
${logger.cyan('off')} ${logger.dim('.............')} Disable sharing anonymous usage data
|
|
1548
|
+
${logger.cyan('on')} ${logger.dim('..............')} Enable sharing anonymous usage data
|
|
1549
|
+
`);
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
const taskHelp = async (config, logger, sys) => {
|
|
1553
|
+
const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
|
|
1554
|
+
console.log(`
|
|
1555
|
+
${logger.bold('Build:')} ${logger.dim('Build components for development or production.')}
|
|
1556
|
+
|
|
1557
|
+
${prompt} ${logger.green('rindo build [--dev] [--watch] [--prerender] [--debug]')}
|
|
1558
|
+
|
|
1559
|
+
${logger.cyan('--dev')} ${logger.dim('.............')} Development build
|
|
1560
|
+
${logger.cyan('--watch')} ${logger.dim('...........')} Rebuild when files update
|
|
1561
|
+
${logger.cyan('--serve')} ${logger.dim('...........')} Start the dev-server
|
|
1562
|
+
${logger.cyan('--prerender')} ${logger.dim('.......')} Prerender the application
|
|
1563
|
+
${logger.cyan('--docs')} ${logger.dim('............')} Generate component readme.md docs
|
|
1564
|
+
${logger.cyan('--config')} ${logger.dim('..........')} Set rindo config file
|
|
1565
|
+
${logger.cyan('--stats')} ${logger.dim('...........')} Write rindo-stats.json file
|
|
1566
|
+
${logger.cyan('--log')} ${logger.dim('.............')} Write rindo-build.log file
|
|
1567
|
+
${logger.cyan('--debug')} ${logger.dim('...........')} Set the log level to debug
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
${logger.bold('Test:')} ${logger.dim('Run unit and end-to-end tests.')}
|
|
1571
|
+
|
|
1572
|
+
${prompt} ${logger.green('rindo test [--spec] [--e2e]')}
|
|
1573
|
+
|
|
1574
|
+
${logger.cyan('--spec')} ${logger.dim('............')} Run unit tests with Jest
|
|
1575
|
+
${logger.cyan('--e2e')} ${logger.dim('.............')} Run e2e tests with Puppeteer
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
${logger.bold('Generate:')} ${logger.dim('Bootstrap components.')}
|
|
1579
|
+
|
|
1580
|
+
${prompt} ${logger.green('rindo generate')} or ${logger.green('rindo g')}
|
|
1581
|
+
|
|
1582
|
+
`);
|
|
1583
|
+
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1584
|
+
if (sys) {
|
|
1585
|
+
await taskTelemetry(config, sys, logger);
|
|
1586
|
+
}
|
|
1587
|
+
console.log(`
|
|
1588
|
+
${logger.bold('Examples:')}
|
|
1589
|
+
|
|
1590
|
+
${prompt} ${logger.green('rindo build --dev --watch --serve')}
|
|
1591
|
+
${prompt} ${logger.green('rindo build --prerender')}
|
|
1592
|
+
${prompt} ${logger.green('rindo test --spec --e2e')}
|
|
1593
|
+
${prompt} ${logger.green('rindo telemetry on')}
|
|
1594
|
+
${prompt} ${logger.green('rindo generate')}
|
|
1595
|
+
${prompt} ${logger.green('rindo g my-component')}
|
|
1596
|
+
`);
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
const taskInfo = (coreCompiler, sys, logger) => {
|
|
1600
|
+
const details = sys.details;
|
|
1601
|
+
const versions = coreCompiler.versions;
|
|
1602
|
+
console.log(``);
|
|
1603
|
+
console.log(`${logger.cyan(' System:')} ${sys.name} ${sys.version}`);
|
|
1604
|
+
console.log(`${logger.cyan(' Plaform:')} ${details.platform} (${details.release})`);
|
|
1605
|
+
console.log(`${logger.cyan(' CPU Model:')} ${details.cpuModel} (${sys.hardwareConcurrency} cpu${sys.hardwareConcurrency !== 1 ? 's' : ''})`);
|
|
1606
|
+
console.log(`${logger.cyan(' Compiler:')} ${sys.getCompilerExecutingPath()}`);
|
|
1607
|
+
console.log(`${logger.cyan(' Build:')} ${coreCompiler.buildId}`);
|
|
1608
|
+
console.log(`${logger.cyan(' Rindo:')} ${coreCompiler.version}${logger.emoji(' ' + coreCompiler.vermoji)}`);
|
|
1609
|
+
console.log(`${logger.cyan(' TypeScript:')} ${versions.typescript}`);
|
|
1610
|
+
console.log(`${logger.cyan(' Rollup:')} ${versions.rollup}`);
|
|
1611
|
+
console.log(`${logger.cyan(' Parse5:')} ${versions.parse5}`);
|
|
1612
|
+
console.log(`${logger.cyan(' Sizzle:')} ${versions.sizzle}`);
|
|
1613
|
+
console.log(`${logger.cyan(' Terser:')} ${versions.terser}`);
|
|
1614
|
+
console.log(``);
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
const taskServe = async (config) => {
|
|
1618
|
+
config.suppressLogs = true;
|
|
1619
|
+
config.flags.serve = true;
|
|
1620
|
+
config.devServer.openBrowser = config.flags.open;
|
|
1621
|
+
config.devServer.reloadStrategy = null;
|
|
1622
|
+
config.devServer.initialLoadUrl = '/';
|
|
1623
|
+
config.devServer.websocket = false;
|
|
1624
|
+
config.maxConcurrentWorkers = 1;
|
|
1625
|
+
config.devServer.root = isString(config.flags.root) ? config.flags.root : config.sys.getCurrentDirectory();
|
|
1626
|
+
const devServerPath = config.sys.getDevServerExecutingPath();
|
|
1627
|
+
const { start } = await config.sys.dynamicImport(devServerPath);
|
|
1628
|
+
const devServer = await start(config.devServer, config.logger);
|
|
1629
|
+
console.log(`${config.logger.cyan(' Root:')} ${devServer.root}`);
|
|
1630
|
+
console.log(`${config.logger.cyan(' Address:')} ${devServer.address}`);
|
|
1631
|
+
console.log(`${config.logger.cyan(' Port:')} ${devServer.port}`);
|
|
1632
|
+
console.log(`${config.logger.cyan(' Server:')} ${devServer.browserUrl}`);
|
|
1633
|
+
console.log(``);
|
|
1634
|
+
config.sys.onProcessInterrupt(() => {
|
|
1635
|
+
if (devServer) {
|
|
1636
|
+
config.logger.debug(`dev server close: ${devServer.browserUrl}`);
|
|
1637
|
+
devServer.close();
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
};
|
|
1641
|
+
|
|
1642
|
+
const run = async (init) => {
|
|
1643
|
+
const { args, logger, sys } = init;
|
|
1644
|
+
try {
|
|
1645
|
+
const flags = parseFlags(args, sys);
|
|
1646
|
+
const task = flags.task;
|
|
1647
|
+
if (flags.debug || flags.verbose) {
|
|
1648
|
+
logger.setLevel('debug');
|
|
1649
|
+
}
|
|
1650
|
+
if (flags.ci) {
|
|
1651
|
+
logger.enableColors(false);
|
|
1652
|
+
}
|
|
1653
|
+
if (isFunction(sys.applyGlobalPatch)) {
|
|
1654
|
+
sys.applyGlobalPatch(sys.getCurrentDirectory());
|
|
1655
|
+
}
|
|
1656
|
+
if (task === 'help' || flags.help) {
|
|
1657
|
+
await taskHelp({ flags: { task: 'help', args }, outputTargets: [] }, logger, sys);
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
startupLog(logger, task);
|
|
1661
|
+
const findConfigResults = await findConfig({ sys, configPath: flags.config });
|
|
1662
|
+
if (hasError(findConfigResults.diagnostics)) {
|
|
1663
|
+
logger.printDiagnostics(findConfigResults.diagnostics);
|
|
1664
|
+
return sys.exit(1);
|
|
1665
|
+
}
|
|
1666
|
+
const ensureDepsResults = await sys.ensureDependencies({
|
|
1667
|
+
rootDir: findConfigResults.rootDir,
|
|
1668
|
+
logger,
|
|
1669
|
+
dependencies: dependencies,
|
|
1670
|
+
});
|
|
1671
|
+
if (hasError(ensureDepsResults.diagnostics)) {
|
|
1672
|
+
logger.printDiagnostics(ensureDepsResults.diagnostics);
|
|
1673
|
+
return sys.exit(1);
|
|
1674
|
+
}
|
|
1675
|
+
const coreCompiler = await loadCoreCompiler(sys);
|
|
1676
|
+
if (task === 'version' || flags.version) {
|
|
1677
|
+
console.log(coreCompiler.version);
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
startupLogVersion(logger, task, coreCompiler);
|
|
1681
|
+
loadedCompilerLog(sys, logger, flags, coreCompiler);
|
|
1682
|
+
if (task === 'info') {
|
|
1683
|
+
await telemetryAction(sys, { flags: { task: 'info' }, outputTargets: [] }, logger, coreCompiler, async () => {
|
|
1684
|
+
await taskInfo(coreCompiler, sys, logger);
|
|
1685
|
+
});
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
const validated = await coreCompiler.loadConfig({
|
|
1689
|
+
config: {
|
|
1690
|
+
flags,
|
|
1691
|
+
},
|
|
1692
|
+
configPath: findConfigResults.configPath,
|
|
1693
|
+
logger,
|
|
1694
|
+
sys,
|
|
1695
|
+
});
|
|
1696
|
+
if (validated.diagnostics.length > 0) {
|
|
1697
|
+
logger.printDiagnostics(validated.diagnostics);
|
|
1698
|
+
if (hasError(validated.diagnostics)) {
|
|
1699
|
+
return sys.exit(1);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (isFunction(sys.applyGlobalPatch)) {
|
|
1703
|
+
sys.applyGlobalPatch(validated.config.rootDir);
|
|
1704
|
+
}
|
|
1705
|
+
await sys.ensureResources({ rootDir: validated.config.rootDir, logger, dependencies: dependencies });
|
|
1706
|
+
await telemetryAction(sys, validated.config, logger, coreCompiler, async () => {
|
|
1707
|
+
await runTask(coreCompiler, validated.config, task, sys);
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
catch (e) {
|
|
1711
|
+
if (!shouldIgnoreError(e)) {
|
|
1712
|
+
const details = `${logger.getLevel() === 'debug' && e instanceof Error ? e.stack : ''}`;
|
|
1713
|
+
logger.error(`uncaught cli error: ${e}${details}`);
|
|
1714
|
+
return sys.exit(1);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
const runTask = async (coreCompiler, config, task, sys) => {
|
|
1719
|
+
config.flags = config.flags || { task };
|
|
1720
|
+
config.outputTargets = config.outputTargets || [];
|
|
1721
|
+
switch (task) {
|
|
1722
|
+
case 'build':
|
|
1723
|
+
await taskBuild(coreCompiler, config, sys);
|
|
1724
|
+
break;
|
|
1725
|
+
case 'docs':
|
|
1726
|
+
await taskDocs(coreCompiler, config);
|
|
1727
|
+
break;
|
|
1728
|
+
case 'generate':
|
|
1729
|
+
case 'g':
|
|
1730
|
+
await taskGenerate(coreCompiler, config);
|
|
1731
|
+
break;
|
|
1732
|
+
case 'help':
|
|
1733
|
+
await taskHelp(config, config.logger, sys);
|
|
1734
|
+
break;
|
|
1735
|
+
case 'prerender':
|
|
1736
|
+
await taskPrerender(coreCompiler, config);
|
|
1737
|
+
break;
|
|
1738
|
+
case 'serve':
|
|
1739
|
+
await taskServe(config);
|
|
1740
|
+
break;
|
|
1741
|
+
case 'telemetry':
|
|
1742
|
+
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1743
|
+
if (sys) {
|
|
1744
|
+
await taskTelemetry(config, sys, config.logger);
|
|
1745
|
+
}
|
|
1746
|
+
break;
|
|
1747
|
+
case 'version':
|
|
1748
|
+
console.log(coreCompiler.version);
|
|
1749
|
+
break;
|
|
1750
|
+
default:
|
|
1751
|
+
config.logger.error(`${config.logger.emoji('❌ ')}Invalid rindo command, please see the options below:`);
|
|
1752
|
+
await taskHelp(config, config.logger, sys);
|
|
1753
|
+
return config.sys.exit(1);
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1757
|
+
export { parseFlags, run, runTask };
|
|
1758
|
+
//# sourceMappingURL=index.js.map
|