index.js 64 KB

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