@stencil/core 2.15.1 → 2.16.1-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/cli/index.cjs +115 -27
- package/cli/index.js +115 -27
- package/cli/package.json +1 -1
- package/compiler/package.json +1 -1
- package/compiler/stencil.js +821 -291
- package/compiler/stencil.min.js +2 -2
- package/dependencies.json +1 -1
- package/dev-server/client/index.js +1 -1
- package/dev-server/client/package.json +1 -1
- package/dev-server/client/test/hmr-util.spec.d.ts +1 -0
- package/dev-server/client/test/status.spec.d.ts +1 -0
- package/dev-server/connector.html +3 -3
- package/dev-server/index.js +1 -1
- package/dev-server/package.json +1 -1
- package/dev-server/server-process.js +5 -3
- package/internal/app-data/package.json +1 -1
- package/internal/client/css-shim.js +1 -1
- package/internal/client/dom.js +1 -1
- package/internal/client/index.js +11 -9
- package/internal/client/package.json +1 -1
- package/internal/client/patch-browser.js +1 -1
- package/internal/client/patch-esm.js +1 -1
- package/internal/client/shadow-css.js +2 -3
- package/internal/hydrate/index.js +37 -32
- package/internal/hydrate/package.json +1 -1
- package/internal/hydrate/shadow-css.js +9 -9
- package/internal/package.json +1 -1
- package/internal/stencil-private.d.ts +39 -3
- package/internal/stencil-public-compiler.d.ts +70 -3
- package/internal/stencil-public-docs.d.ts +3 -0
- package/internal/testing/index.js +35 -30
- package/internal/testing/package.json +1 -1
- package/internal/testing/shadow-css.js +9 -9
- package/mock-doc/index.cjs +8 -2
- package/mock-doc/index.d.ts +9 -2
- package/mock-doc/index.js +8 -2
- package/mock-doc/package.json +1 -1
- package/package.json +22 -16
- package/screenshot/index.js +2 -0
- package/screenshot/package.json +1 -1
- package/sys/node/autoprefixer.js +1 -1
- package/sys/node/index.js +2038 -1330
- package/sys/node/package.json +1 -1
- package/sys/node/worker.js +1 -1
- package/testing/index.js +335 -331
- package/testing/jest/test/jest-config.spec.d.ts +1 -0
- package/testing/jest/test/jest-preprocessor.spec.d.ts +1 -0
- package/testing/jest/test/jest-runner.spec.d.ts +1 -0
- package/testing/jest/test/jest-serializer.spec.d.ts +1 -0
- package/testing/package.json +1 -1
package/cli/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
Stencil CLI (CommonJS) v2.
|
|
2
|
+
Stencil CLI (CommonJS) v2.16.1-0 | MIT Licensed | https://stenciljs.com
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
@@ -118,6 +118,8 @@ const TASK_CANCELED_MSG = `task canceled`;
|
|
|
118
118
|
* Forward-slash paths can be used in Windows as long as they're not
|
|
119
119
|
* extended-length paths and don't contain any non-ascii characters.
|
|
120
120
|
* This was created since the path methods in Node.js outputs \\ paths on Windows.
|
|
121
|
+
* @param path the Windows-based path to convert
|
|
122
|
+
* @returns the converted path
|
|
121
123
|
*/
|
|
122
124
|
const normalizePath = (path) => {
|
|
123
125
|
if (typeof path !== 'string') {
|
|
@@ -530,7 +532,7 @@ const getNpmConfigEnvArgs = (sys) => {
|
|
|
530
532
|
const dependencies = [
|
|
531
533
|
{
|
|
532
534
|
name: "@stencil/core",
|
|
533
|
-
version: "2.
|
|
535
|
+
version: "2.16.1-0",
|
|
534
536
|
main: "compiler/stencil.js",
|
|
535
537
|
resources: [
|
|
536
538
|
"package.json",
|
|
@@ -967,10 +969,10 @@ async function updateConfig(sys, newOptions) {
|
|
|
967
969
|
|
|
968
970
|
const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
|
|
969
971
|
const DOCS_CUSTOM = 'docs-custom';
|
|
970
|
-
const DOCS_JSON =
|
|
971
|
-
const DOCS_README =
|
|
972
|
-
const DOCS_VSCODE =
|
|
973
|
-
const WWW =
|
|
972
|
+
const DOCS_JSON = 'docs-json';
|
|
973
|
+
const DOCS_README = 'docs-readme';
|
|
974
|
+
const DOCS_VSCODE = 'docs-vscode';
|
|
975
|
+
const WWW = 'www';
|
|
974
976
|
|
|
975
977
|
/**
|
|
976
978
|
* Used to within taskBuild to provide the component_count property.
|
|
@@ -1072,10 +1074,12 @@ const prepareData = async (coreCompiler, config, sys, duration_ms, component_cou
|
|
|
1072
1074
|
};
|
|
1073
1075
|
};
|
|
1074
1076
|
/**
|
|
1075
|
-
* Reads package-lock.json, yarn.lock, and package.json files in order to cross
|
|
1077
|
+
* Reads package-lock.json, yarn.lock, and package.json files in order to cross-reference
|
|
1076
1078
|
* the dependencies and devDependencies properties. Pulls up the current installed version
|
|
1077
1079
|
* of each package under the @stencil, @ionic, and @capacitor scopes.
|
|
1078
|
-
* @
|
|
1080
|
+
* @param sys the system instance where telemetry is invoked
|
|
1081
|
+
* @param config the Stencil configuration associated with the current task that triggered telemetry
|
|
1082
|
+
* @returns an object listing all dev and production dependencies under the aforementioned scopes
|
|
1079
1083
|
*/
|
|
1080
1084
|
async function getInstalledPackages(sys, config) {
|
|
1081
1085
|
let packages = [];
|
|
@@ -1154,7 +1158,12 @@ function sanitizeDeclaredVersion(version) {
|
|
|
1154
1158
|
return version.replace(/[*^~]/g, '');
|
|
1155
1159
|
}
|
|
1156
1160
|
/**
|
|
1157
|
-
* If telemetry is enabled, send a metric
|
|
1161
|
+
* If telemetry is enabled, send a metric to an external data store
|
|
1162
|
+
* @param sys the system instance where telemetry is invoked
|
|
1163
|
+
* @param config the Stencil configuration associated with the current task that triggered telemetry
|
|
1164
|
+
* @param name the name of a trackable metric. Note this name is not necessarily a scalar value to track, like
|
|
1165
|
+
* "Stencil Version". For example, "stencil_cli_command" is a name that is used to track all CLI command information.
|
|
1166
|
+
* @param value the data to send to the external data store under the provided name argument
|
|
1158
1167
|
*/
|
|
1159
1168
|
async function sendMetric(sys, config, name, value) {
|
|
1160
1169
|
const session_id = await getTelemetryToken(sys);
|
|
@@ -1307,7 +1316,14 @@ const IS_NODE_ENV = typeof global !== 'undefined' &&
|
|
|
1307
1316
|
(!global.origin || typeof global.origin !== 'string');
|
|
1308
1317
|
|
|
1309
1318
|
/**
|
|
1310
|
-
* Task to generate component boilerplate.
|
|
1319
|
+
* Task to generate component boilerplate and write it to disk. This task can
|
|
1320
|
+
* cause the program to exit with an error under various circumstances, such as
|
|
1321
|
+
* being called in an inappropriate place, being asked to overwrite files that
|
|
1322
|
+
* already exist, etc.
|
|
1323
|
+
*
|
|
1324
|
+
* @param coreCompiler the CoreCompiler we're using currently, here we're
|
|
1325
|
+
* mainly accessing the `path` module
|
|
1326
|
+
* @param config the user-supplied config, which we need here to access `.sys`.
|
|
1311
1327
|
*/
|
|
1312
1328
|
const taskGenerate = async (coreCompiler, config) => {
|
|
1313
1329
|
if (!IS_NODE_ENV) {
|
|
@@ -1337,10 +1353,16 @@ const taskGenerate = async (coreCompiler, config) => {
|
|
|
1337
1353
|
const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
|
|
1338
1354
|
const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
|
|
1339
1355
|
await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });
|
|
1340
|
-
const
|
|
1356
|
+
const filesToGenerate = extensionsToGenerate.map((extension) => ({
|
|
1357
|
+
extension,
|
|
1358
|
+
path: getFilepathForFile(coreCompiler, outDir, componentName, extension),
|
|
1359
|
+
}));
|
|
1360
|
+
await checkForOverwrite(filesToGenerate, config);
|
|
1361
|
+
const writtenFiles = await Promise.all(filesToGenerate.map((file) => getBoilerplateAndWriteFile(config, componentName, extensionsToGenerate.includes('css'), file))).catch((error) => config.logger.error(error));
|
|
1341
1362
|
if (!writtenFiles) {
|
|
1342
1363
|
return config.sys.exit(1);
|
|
1343
1364
|
}
|
|
1365
|
+
// TODO(STENCIL-424): Investigate moving these console.log calls to config.logger.info
|
|
1344
1366
|
console.log();
|
|
1345
1367
|
console.log(`${config.logger.gray('$')} stencil generate ${input}`);
|
|
1346
1368
|
console.log();
|
|
@@ -1350,6 +1372,9 @@ const taskGenerate = async (coreCompiler, config) => {
|
|
|
1350
1372
|
};
|
|
1351
1373
|
/**
|
|
1352
1374
|
* Show a checkbox prompt to select the files to be generated.
|
|
1375
|
+
*
|
|
1376
|
+
* @returns a read-only array of `GenerableExtension`, the extensions that the user has decided
|
|
1377
|
+
* to generate
|
|
1353
1378
|
*/
|
|
1354
1379
|
const chooseFilesToGenerate = async () => {
|
|
1355
1380
|
const { prompt } = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('../sys/node/prompts.js')); });
|
|
@@ -1365,22 +1390,76 @@ const chooseFilesToGenerate = async () => {
|
|
|
1365
1390
|
})).filesToGenerate;
|
|
1366
1391
|
};
|
|
1367
1392
|
/**
|
|
1368
|
-
* Get a
|
|
1393
|
+
* Get a filepath for a file we want to generate!
|
|
1394
|
+
*
|
|
1395
|
+
* The filepath for a given file depends on the path, the user-supplied
|
|
1396
|
+
* component name, the extension, and whether we're inside of a test directory.
|
|
1397
|
+
*
|
|
1398
|
+
* @param coreCompiler the compiler we're using, here to acces the `.path` module
|
|
1399
|
+
* @param path path to where we're going to generate the component
|
|
1400
|
+
* @param componentName the user-supplied name for the generated component
|
|
1401
|
+
* @param extension the file extension
|
|
1402
|
+
* @returns the full filepath to the component (with a possible `test` directory
|
|
1403
|
+
* added)
|
|
1404
|
+
*/
|
|
1405
|
+
const getFilepathForFile = (coreCompiler, path, componentName, extension) => isTest(extension)
|
|
1406
|
+
? coreCompiler.path.join(path, 'test', `${componentName}.${extension}`)
|
|
1407
|
+
: coreCompiler.path.join(path, `${componentName}.${extension}`);
|
|
1408
|
+
/**
|
|
1409
|
+
* Get the boilerplate for a file and write it to disk
|
|
1410
|
+
*
|
|
1411
|
+
* @param config the current config, needed for file operations
|
|
1412
|
+
* @param componentName the component name (user-supplied)
|
|
1413
|
+
* @param withCss are we generating CSS?
|
|
1414
|
+
* @param file the file we want to write
|
|
1415
|
+
* @returns a `Promise<string>` which holds the full filepath we've written to,
|
|
1416
|
+
* used to print out a little summary of our activity to the user.
|
|
1369
1417
|
*/
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
const outFile = coreCompiler.path.join(path, `${name}.${extension}`);
|
|
1375
|
-
const boilerplate = getBoilerplateByExtension(name, extension, withCss);
|
|
1376
|
-
await config.sys.writeFile(outFile, boilerplate);
|
|
1377
|
-
return outFile;
|
|
1418
|
+
const getBoilerplateAndWriteFile = async (config, componentName, withCss, file) => {
|
|
1419
|
+
const boilerplate = getBoilerplateByExtension(componentName, file.extension, withCss);
|
|
1420
|
+
await config.sys.writeFile(file.path, boilerplate);
|
|
1421
|
+
return file.path;
|
|
1378
1422
|
};
|
|
1423
|
+
/**
|
|
1424
|
+
* Check to see if any of the files we plan to write already exist and would
|
|
1425
|
+
* therefore be overwritten if we proceed, because we'd like to not overwrite
|
|
1426
|
+
* people's code!
|
|
1427
|
+
*
|
|
1428
|
+
* This function will check all the filepaths and if it finds any files log an
|
|
1429
|
+
* error and exit with an error code. If it doesn't find anything it will just
|
|
1430
|
+
* peacefully return `Promise<void>`.
|
|
1431
|
+
*
|
|
1432
|
+
* @param files the files we want to check
|
|
1433
|
+
* @param config the Config object, used here to get access to `sys.readFile`
|
|
1434
|
+
*/
|
|
1435
|
+
const checkForOverwrite = async (files, config) => {
|
|
1436
|
+
const alreadyPresent = [];
|
|
1437
|
+
await Promise.all(files.map(async ({ path }) => {
|
|
1438
|
+
if ((await config.sys.readFile(path)) !== undefined) {
|
|
1439
|
+
alreadyPresent.push(path);
|
|
1440
|
+
}
|
|
1441
|
+
}));
|
|
1442
|
+
if (alreadyPresent.length > 0) {
|
|
1443
|
+
config.logger.error('Generating code would overwrite the following files:', ...alreadyPresent.map((path) => '\t' + path));
|
|
1444
|
+
await config.sys.exit(1);
|
|
1445
|
+
}
|
|
1446
|
+
};
|
|
1447
|
+
/**
|
|
1448
|
+
* Check if an extension is for a test
|
|
1449
|
+
*
|
|
1450
|
+
* @param extension the extension we want to check
|
|
1451
|
+
* @returns a boolean indicating whether or not its a test
|
|
1452
|
+
*/
|
|
1379
1453
|
const isTest = (extension) => {
|
|
1380
1454
|
return extension === 'e2e.ts' || extension === 'spec.tsx';
|
|
1381
1455
|
};
|
|
1382
1456
|
/**
|
|
1383
1457
|
* Get the boilerplate for a file by its extension.
|
|
1458
|
+
*
|
|
1459
|
+
* @param tagName the name of the component we're generating
|
|
1460
|
+
* @param extension the file extension we want boilerplate for (.css, tsx, etc)
|
|
1461
|
+
* @param withCss a boolean indicating whether we're generating a CSS file
|
|
1462
|
+
* @returns a string container the file boilerplate for the supplied extension
|
|
1384
1463
|
*/
|
|
1385
1464
|
const getBoilerplateByExtension = (tagName, extension, withCss) => {
|
|
1386
1465
|
switch (extension) {
|
|
@@ -1397,7 +1476,10 @@ const getBoilerplateByExtension = (tagName, extension, withCss) => {
|
|
|
1397
1476
|
}
|
|
1398
1477
|
};
|
|
1399
1478
|
/**
|
|
1400
|
-
* Get the boilerplate for a component
|
|
1479
|
+
* Get the boilerplate for a file containing the definition of a component
|
|
1480
|
+
* @param tagName the name of the tag to give the component
|
|
1481
|
+
* @param hasStyle designates if the component has an external stylesheet or not
|
|
1482
|
+
* @returns the contents of a file that defines a component
|
|
1401
1483
|
*/
|
|
1402
1484
|
const getComponentBoilerplate = (tagName, hasStyle) => {
|
|
1403
1485
|
const decorator = [`{`];
|
|
@@ -1431,7 +1513,9 @@ const getStyleUrlBoilerplate = () => `:host {
|
|
|
1431
1513
|
}
|
|
1432
1514
|
`;
|
|
1433
1515
|
/**
|
|
1434
|
-
* Get the boilerplate for a spec test
|
|
1516
|
+
* Get the boilerplate for a file containing a spec (unit) test for a component
|
|
1517
|
+
* @param tagName the name of the tag associated with the component under test
|
|
1518
|
+
* @returns the contents of a file that unit tests a component
|
|
1435
1519
|
*/
|
|
1436
1520
|
const getSpecTestBoilerplate = (tagName) => `import { newSpecPage } from '@stencil/core/testing';
|
|
1437
1521
|
import { ${toPascalCase(tagName)} } from '../${tagName}';
|
|
@@ -1453,22 +1537,26 @@ describe('${tagName}', () => {
|
|
|
1453
1537
|
});
|
|
1454
1538
|
`;
|
|
1455
1539
|
/**
|
|
1456
|
-
* Get the boilerplate for an E2E test
|
|
1540
|
+
* Get the boilerplate for a file containing an end-to-end (E2E) test for a component
|
|
1541
|
+
* @param tagName the name of the tag associated with the component under test
|
|
1542
|
+
* @returns the contents of a file that E2E tests a component
|
|
1457
1543
|
*/
|
|
1458
|
-
const getE2eTestBoilerplate = (
|
|
1544
|
+
const getE2eTestBoilerplate = (tagName) => `import { newE2EPage } from '@stencil/core/testing';
|
|
1459
1545
|
|
|
1460
|
-
describe('${
|
|
1546
|
+
describe('${tagName}', () => {
|
|
1461
1547
|
it('renders', async () => {
|
|
1462
1548
|
const page = await newE2EPage();
|
|
1463
|
-
await page.setContent('<${
|
|
1549
|
+
await page.setContent('<${tagName}></${tagName}>');
|
|
1464
1550
|
|
|
1465
|
-
const element = await page.find('${
|
|
1551
|
+
const element = await page.find('${tagName}');
|
|
1466
1552
|
expect(element).toHaveClass('hydrated');
|
|
1467
1553
|
});
|
|
1468
1554
|
});
|
|
1469
1555
|
`;
|
|
1470
1556
|
/**
|
|
1471
1557
|
* Convert a dash case string to pascal case.
|
|
1558
|
+
* @param str the string to convert
|
|
1559
|
+
* @returns the converted input as pascal case
|
|
1472
1560
|
*/
|
|
1473
1561
|
const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
|
|
1474
1562
|
|
package/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
Stencil CLI v2.
|
|
2
|
+
Stencil CLI v2.16.1-0 | MIT Licensed | https://stenciljs.com
|
|
3
3
|
*/
|
|
4
4
|
const toLowerCase = (str) => str.toLowerCase();
|
|
5
5
|
const dashToPascalCase = (str) => toLowerCase(str)
|
|
@@ -94,6 +94,8 @@ const TASK_CANCELED_MSG = `task canceled`;
|
|
|
94
94
|
* Forward-slash paths can be used in Windows as long as they're not
|
|
95
95
|
* extended-length paths and don't contain any non-ascii characters.
|
|
96
96
|
* This was created since the path methods in Node.js outputs \\ paths on Windows.
|
|
97
|
+
* @param path the Windows-based path to convert
|
|
98
|
+
* @returns the converted path
|
|
97
99
|
*/
|
|
98
100
|
const normalizePath = (path) => {
|
|
99
101
|
if (typeof path !== 'string') {
|
|
@@ -506,7 +508,7 @@ const getNpmConfigEnvArgs = (sys) => {
|
|
|
506
508
|
const dependencies = [
|
|
507
509
|
{
|
|
508
510
|
name: "@stencil/core",
|
|
509
|
-
version: "2.
|
|
511
|
+
version: "2.16.1-0",
|
|
510
512
|
main: "compiler/stencil.js",
|
|
511
513
|
resources: [
|
|
512
514
|
"package.json",
|
|
@@ -943,10 +945,10 @@ async function updateConfig(sys, newOptions) {
|
|
|
943
945
|
|
|
944
946
|
const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
|
|
945
947
|
const DOCS_CUSTOM = 'docs-custom';
|
|
946
|
-
const DOCS_JSON =
|
|
947
|
-
const DOCS_README =
|
|
948
|
-
const DOCS_VSCODE =
|
|
949
|
-
const WWW =
|
|
948
|
+
const DOCS_JSON = 'docs-json';
|
|
949
|
+
const DOCS_README = 'docs-readme';
|
|
950
|
+
const DOCS_VSCODE = 'docs-vscode';
|
|
951
|
+
const WWW = 'www';
|
|
950
952
|
|
|
951
953
|
/**
|
|
952
954
|
* Used to within taskBuild to provide the component_count property.
|
|
@@ -1048,10 +1050,12 @@ const prepareData = async (coreCompiler, config, sys, duration_ms, component_cou
|
|
|
1048
1050
|
};
|
|
1049
1051
|
};
|
|
1050
1052
|
/**
|
|
1051
|
-
* Reads package-lock.json, yarn.lock, and package.json files in order to cross
|
|
1053
|
+
* Reads package-lock.json, yarn.lock, and package.json files in order to cross-reference
|
|
1052
1054
|
* the dependencies and devDependencies properties. Pulls up the current installed version
|
|
1053
1055
|
* of each package under the @stencil, @ionic, and @capacitor scopes.
|
|
1054
|
-
* @
|
|
1056
|
+
* @param sys the system instance where telemetry is invoked
|
|
1057
|
+
* @param config the Stencil configuration associated with the current task that triggered telemetry
|
|
1058
|
+
* @returns an object listing all dev and production dependencies under the aforementioned scopes
|
|
1055
1059
|
*/
|
|
1056
1060
|
async function getInstalledPackages(sys, config) {
|
|
1057
1061
|
let packages = [];
|
|
@@ -1130,7 +1134,12 @@ function sanitizeDeclaredVersion(version) {
|
|
|
1130
1134
|
return version.replace(/[*^~]/g, '');
|
|
1131
1135
|
}
|
|
1132
1136
|
/**
|
|
1133
|
-
* If telemetry is enabled, send a metric
|
|
1137
|
+
* If telemetry is enabled, send a metric to an external data store
|
|
1138
|
+
* @param sys the system instance where telemetry is invoked
|
|
1139
|
+
* @param config the Stencil configuration associated with the current task that triggered telemetry
|
|
1140
|
+
* @param name the name of a trackable metric. Note this name is not necessarily a scalar value to track, like
|
|
1141
|
+
* "Stencil Version". For example, "stencil_cli_command" is a name that is used to track all CLI command information.
|
|
1142
|
+
* @param value the data to send to the external data store under the provided name argument
|
|
1134
1143
|
*/
|
|
1135
1144
|
async function sendMetric(sys, config, name, value) {
|
|
1136
1145
|
const session_id = await getTelemetryToken(sys);
|
|
@@ -1283,7 +1292,14 @@ const IS_NODE_ENV = typeof global !== 'undefined' &&
|
|
|
1283
1292
|
(!global.origin || typeof global.origin !== 'string');
|
|
1284
1293
|
|
|
1285
1294
|
/**
|
|
1286
|
-
* Task to generate component boilerplate.
|
|
1295
|
+
* Task to generate component boilerplate and write it to disk. This task can
|
|
1296
|
+
* cause the program to exit with an error under various circumstances, such as
|
|
1297
|
+
* being called in an inappropriate place, being asked to overwrite files that
|
|
1298
|
+
* already exist, etc.
|
|
1299
|
+
*
|
|
1300
|
+
* @param coreCompiler the CoreCompiler we're using currently, here we're
|
|
1301
|
+
* mainly accessing the `path` module
|
|
1302
|
+
* @param config the user-supplied config, which we need here to access `.sys`.
|
|
1287
1303
|
*/
|
|
1288
1304
|
const taskGenerate = async (coreCompiler, config) => {
|
|
1289
1305
|
if (!IS_NODE_ENV) {
|
|
@@ -1313,10 +1329,16 @@ const taskGenerate = async (coreCompiler, config) => {
|
|
|
1313
1329
|
const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
|
|
1314
1330
|
const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
|
|
1315
1331
|
await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });
|
|
1316
|
-
const
|
|
1332
|
+
const filesToGenerate = extensionsToGenerate.map((extension) => ({
|
|
1333
|
+
extension,
|
|
1334
|
+
path: getFilepathForFile(coreCompiler, outDir, componentName, extension),
|
|
1335
|
+
}));
|
|
1336
|
+
await checkForOverwrite(filesToGenerate, config);
|
|
1337
|
+
const writtenFiles = await Promise.all(filesToGenerate.map((file) => getBoilerplateAndWriteFile(config, componentName, extensionsToGenerate.includes('css'), file))).catch((error) => config.logger.error(error));
|
|
1317
1338
|
if (!writtenFiles) {
|
|
1318
1339
|
return config.sys.exit(1);
|
|
1319
1340
|
}
|
|
1341
|
+
// TODO(STENCIL-424): Investigate moving these console.log calls to config.logger.info
|
|
1320
1342
|
console.log();
|
|
1321
1343
|
console.log(`${config.logger.gray('$')} stencil generate ${input}`);
|
|
1322
1344
|
console.log();
|
|
@@ -1326,6 +1348,9 @@ const taskGenerate = async (coreCompiler, config) => {
|
|
|
1326
1348
|
};
|
|
1327
1349
|
/**
|
|
1328
1350
|
* Show a checkbox prompt to select the files to be generated.
|
|
1351
|
+
*
|
|
1352
|
+
* @returns a read-only array of `GenerableExtension`, the extensions that the user has decided
|
|
1353
|
+
* to generate
|
|
1329
1354
|
*/
|
|
1330
1355
|
const chooseFilesToGenerate = async () => {
|
|
1331
1356
|
const { prompt } = await import('../sys/node/prompts.js');
|
|
@@ -1341,22 +1366,76 @@ const chooseFilesToGenerate = async () => {
|
|
|
1341
1366
|
})).filesToGenerate;
|
|
1342
1367
|
};
|
|
1343
1368
|
/**
|
|
1344
|
-
* Get a
|
|
1369
|
+
* Get a filepath for a file we want to generate!
|
|
1370
|
+
*
|
|
1371
|
+
* The filepath for a given file depends on the path, the user-supplied
|
|
1372
|
+
* component name, the extension, and whether we're inside of a test directory.
|
|
1373
|
+
*
|
|
1374
|
+
* @param coreCompiler the compiler we're using, here to acces the `.path` module
|
|
1375
|
+
* @param path path to where we're going to generate the component
|
|
1376
|
+
* @param componentName the user-supplied name for the generated component
|
|
1377
|
+
* @param extension the file extension
|
|
1378
|
+
* @returns the full filepath to the component (with a possible `test` directory
|
|
1379
|
+
* added)
|
|
1380
|
+
*/
|
|
1381
|
+
const getFilepathForFile = (coreCompiler, path, componentName, extension) => isTest(extension)
|
|
1382
|
+
? coreCompiler.path.join(path, 'test', `${componentName}.${extension}`)
|
|
1383
|
+
: coreCompiler.path.join(path, `${componentName}.${extension}`);
|
|
1384
|
+
/**
|
|
1385
|
+
* Get the boilerplate for a file and write it to disk
|
|
1386
|
+
*
|
|
1387
|
+
* @param config the current config, needed for file operations
|
|
1388
|
+
* @param componentName the component name (user-supplied)
|
|
1389
|
+
* @param withCss are we generating CSS?
|
|
1390
|
+
* @param file the file we want to write
|
|
1391
|
+
* @returns a `Promise<string>` which holds the full filepath we've written to,
|
|
1392
|
+
* used to print out a little summary of our activity to the user.
|
|
1345
1393
|
*/
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
const outFile = coreCompiler.path.join(path, `${name}.${extension}`);
|
|
1351
|
-
const boilerplate = getBoilerplateByExtension(name, extension, withCss);
|
|
1352
|
-
await config.sys.writeFile(outFile, boilerplate);
|
|
1353
|
-
return outFile;
|
|
1394
|
+
const getBoilerplateAndWriteFile = async (config, componentName, withCss, file) => {
|
|
1395
|
+
const boilerplate = getBoilerplateByExtension(componentName, file.extension, withCss);
|
|
1396
|
+
await config.sys.writeFile(file.path, boilerplate);
|
|
1397
|
+
return file.path;
|
|
1354
1398
|
};
|
|
1399
|
+
/**
|
|
1400
|
+
* Check to see if any of the files we plan to write already exist and would
|
|
1401
|
+
* therefore be overwritten if we proceed, because we'd like to not overwrite
|
|
1402
|
+
* people's code!
|
|
1403
|
+
*
|
|
1404
|
+
* This function will check all the filepaths and if it finds any files log an
|
|
1405
|
+
* error and exit with an error code. If it doesn't find anything it will just
|
|
1406
|
+
* peacefully return `Promise<void>`.
|
|
1407
|
+
*
|
|
1408
|
+
* @param files the files we want to check
|
|
1409
|
+
* @param config the Config object, used here to get access to `sys.readFile`
|
|
1410
|
+
*/
|
|
1411
|
+
const checkForOverwrite = async (files, config) => {
|
|
1412
|
+
const alreadyPresent = [];
|
|
1413
|
+
await Promise.all(files.map(async ({ path }) => {
|
|
1414
|
+
if ((await config.sys.readFile(path)) !== undefined) {
|
|
1415
|
+
alreadyPresent.push(path);
|
|
1416
|
+
}
|
|
1417
|
+
}));
|
|
1418
|
+
if (alreadyPresent.length > 0) {
|
|
1419
|
+
config.logger.error('Generating code would overwrite the following files:', ...alreadyPresent.map((path) => '\t' + path));
|
|
1420
|
+
await config.sys.exit(1);
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
/**
|
|
1424
|
+
* Check if an extension is for a test
|
|
1425
|
+
*
|
|
1426
|
+
* @param extension the extension we want to check
|
|
1427
|
+
* @returns a boolean indicating whether or not its a test
|
|
1428
|
+
*/
|
|
1355
1429
|
const isTest = (extension) => {
|
|
1356
1430
|
return extension === 'e2e.ts' || extension === 'spec.tsx';
|
|
1357
1431
|
};
|
|
1358
1432
|
/**
|
|
1359
1433
|
* Get the boilerplate for a file by its extension.
|
|
1434
|
+
*
|
|
1435
|
+
* @param tagName the name of the component we're generating
|
|
1436
|
+
* @param extension the file extension we want boilerplate for (.css, tsx, etc)
|
|
1437
|
+
* @param withCss a boolean indicating whether we're generating a CSS file
|
|
1438
|
+
* @returns a string container the file boilerplate for the supplied extension
|
|
1360
1439
|
*/
|
|
1361
1440
|
const getBoilerplateByExtension = (tagName, extension, withCss) => {
|
|
1362
1441
|
switch (extension) {
|
|
@@ -1373,7 +1452,10 @@ const getBoilerplateByExtension = (tagName, extension, withCss) => {
|
|
|
1373
1452
|
}
|
|
1374
1453
|
};
|
|
1375
1454
|
/**
|
|
1376
|
-
* Get the boilerplate for a component
|
|
1455
|
+
* Get the boilerplate for a file containing the definition of a component
|
|
1456
|
+
* @param tagName the name of the tag to give the component
|
|
1457
|
+
* @param hasStyle designates if the component has an external stylesheet or not
|
|
1458
|
+
* @returns the contents of a file that defines a component
|
|
1377
1459
|
*/
|
|
1378
1460
|
const getComponentBoilerplate = (tagName, hasStyle) => {
|
|
1379
1461
|
const decorator = [`{`];
|
|
@@ -1407,7 +1489,9 @@ const getStyleUrlBoilerplate = () => `:host {
|
|
|
1407
1489
|
}
|
|
1408
1490
|
`;
|
|
1409
1491
|
/**
|
|
1410
|
-
* Get the boilerplate for a spec test
|
|
1492
|
+
* Get the boilerplate for a file containing a spec (unit) test for a component
|
|
1493
|
+
* @param tagName the name of the tag associated with the component under test
|
|
1494
|
+
* @returns the contents of a file that unit tests a component
|
|
1411
1495
|
*/
|
|
1412
1496
|
const getSpecTestBoilerplate = (tagName) => `import { newSpecPage } from '@stencil/core/testing';
|
|
1413
1497
|
import { ${toPascalCase(tagName)} } from '../${tagName}';
|
|
@@ -1429,22 +1513,26 @@ describe('${tagName}', () => {
|
|
|
1429
1513
|
});
|
|
1430
1514
|
`;
|
|
1431
1515
|
/**
|
|
1432
|
-
* Get the boilerplate for an E2E test
|
|
1516
|
+
* Get the boilerplate for a file containing an end-to-end (E2E) test for a component
|
|
1517
|
+
* @param tagName the name of the tag associated with the component under test
|
|
1518
|
+
* @returns the contents of a file that E2E tests a component
|
|
1433
1519
|
*/
|
|
1434
|
-
const getE2eTestBoilerplate = (
|
|
1520
|
+
const getE2eTestBoilerplate = (tagName) => `import { newE2EPage } from '@stencil/core/testing';
|
|
1435
1521
|
|
|
1436
|
-
describe('${
|
|
1522
|
+
describe('${tagName}', () => {
|
|
1437
1523
|
it('renders', async () => {
|
|
1438
1524
|
const page = await newE2EPage();
|
|
1439
|
-
await page.setContent('<${
|
|
1525
|
+
await page.setContent('<${tagName}></${tagName}>');
|
|
1440
1526
|
|
|
1441
|
-
const element = await page.find('${
|
|
1527
|
+
const element = await page.find('${tagName}');
|
|
1442
1528
|
expect(element).toHaveClass('hydrated');
|
|
1443
1529
|
});
|
|
1444
1530
|
});
|
|
1445
1531
|
`;
|
|
1446
1532
|
/**
|
|
1447
1533
|
* Convert a dash case string to pascal case.
|
|
1534
|
+
* @param str the string to convert
|
|
1535
|
+
* @returns the converted input as pascal case
|
|
1448
1536
|
*/
|
|
1449
1537
|
const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
|
|
1450
1538
|
|
package/cli/package.json
CHANGED