index.cjs 65 KB

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