123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var fs_1 = require("fs");
  4. var path_1 = require("path");
  5. var Constants = require("./util/constants");
  6. var interfaces_1 = require("./util/interfaces");
  7. var helpers_1 = require("./util/helpers");
  8. var logger_1 = require("./logger/logger");
  9. function templateUpdate(changedFiles, context) {
  10. try {
  11. var changedTemplates = changedFiles.filter(function (changedFile) { return changedFile.ext === '.html'; });
  12. var start = Date.now();
  13. var bundleFiles = context.fileCache.getAll().filter(function (file) { return file.path.indexOf(context.buildDir) >= 0 && path_1.extname(file.path) === '.js'; });
  14. // update the corresponding transpiled javascript file with the template changed (inline it)
  15. // as well as the bundle
  16. for (var _i = 0, changedTemplates_1 = changedTemplates; _i < changedTemplates_1.length; _i++) {
  17. var changedTemplateFile = changedTemplates_1[_i];
  18. var file = context.fileCache.get(changedTemplateFile.filePath);
  19. if (!updateCorrespondingJsFile(context, file.content, changedTemplateFile.filePath)) {
  20. throw new Error("Failed to inline template " + changedTemplateFile.filePath);
  21. }
  22. // find the corresponding bundle
  23. for (var _a = 0, bundleFiles_1 = bundleFiles; _a < bundleFiles_1.length; _a++) {
  24. var bundleFile = bundleFiles_1[_a];
  25. var newContent = replaceExistingJsTemplate(bundleFile.content, file.content, changedTemplateFile.filePath);
  26. if (newContent && newContent !== bundleFile.content) {
  27. context.fileCache.set(bundleFile.path, { path: bundleFile.path, content: newContent });
  28. fs_1.writeFileSync(bundleFile.path, newContent);
  29. break;
  30. }
  31. }
  32. }
  33. // awesome, all good and template updated in the bundle file
  34. var logger = new logger_1.Logger("template update");
  35. logger.setStartTime(start);
  36. // congrats, all good
  37. changedTemplates.forEach(function (changedTemplate) {
  38. logger_1.Logger.debug("templateUpdate, updated: " + changedTemplate.filePath);
  39. });
  40. context.templateState = interfaces_1.BuildState.SuccessfulBuild;
  41. logger.finish();
  42. return Promise.resolve();
  43. }
  44. catch (ex) {
  45. logger_1.Logger.debug("templateUpdate error: " + ex.message);
  46. context.transpileState = interfaces_1.BuildState.RequiresBuild;
  47. context.deepLinkState = interfaces_1.BuildState.RequiresBuild;
  48. context.bundleState = interfaces_1.BuildState.RequiresUpdate;
  49. return Promise.resolve();
  50. }
  51. }
  52. exports.templateUpdate = templateUpdate;
  53. function updateCorrespondingJsFile(context, newTemplateContent, existingHtmlTemplatePath) {
  54. var moduleFileExtension = helpers_1.changeExtension(helpers_1.getStringPropertyValue(Constants.ENV_NG_MODULE_FILE_NAME_SUFFIX), '.js');
  55. var javascriptFiles = context.fileCache.getAll().filter(function (file) { return path_1.dirname(file.path) === path_1.dirname(existingHtmlTemplatePath) && path_1.extname(file.path) === '.js' && !file.path.endsWith(moduleFileExtension); });
  56. for (var _i = 0, javascriptFiles_1 = javascriptFiles; _i < javascriptFiles_1.length; _i++) {
  57. var javascriptFile = javascriptFiles_1[_i];
  58. var newContent = replaceExistingJsTemplate(javascriptFile.content, newTemplateContent, existingHtmlTemplatePath);
  59. if (newContent && newContent !== javascriptFile.content) {
  60. javascriptFile.content = newContent;
  61. // set the file again to generate a new timestamp
  62. // do the same for the typescript file just to invalidate any caches, etc.
  63. context.fileCache.set(javascriptFile.path, javascriptFile);
  64. var typescriptFilePath = helpers_1.changeExtension(javascriptFile.path, '.ts');
  65. context.fileCache.set(typescriptFilePath, context.fileCache.get(typescriptFilePath));
  66. return true;
  67. }
  68. }
  69. return false;
  70. }
  71. function inlineTemplate(sourceText, sourcePath) {
  72. var componentDir = path_1.parse(sourcePath).dir;
  73. var match;
  74. var replacement;
  75. var lastMatch = null;
  76. while (match = getTemplateMatch(sourceText)) {
  77. if (match.component === lastMatch) {
  78. // panic! we don't want to melt any machines if there's a bug
  79. logger_1.Logger.debug("Error matching component: " + match.component);
  80. return sourceText;
  81. }
  82. lastMatch = match.component;
  83. if (match.templateUrl === '') {
  84. logger_1.Logger.error("Error @Component templateUrl missing in: \"" + sourcePath + "\"");
  85. return sourceText;
  86. }
  87. replacement = updateTemplate(componentDir, match);
  88. if (replacement) {
  89. sourceText = sourceText.replace(match.component, replacement);
  90. }
  91. }
  92. return sourceText;
  93. }
  94. exports.inlineTemplate = inlineTemplate;
  95. function updateTemplate(componentDir, match) {
  96. var htmlFilePath = path_1.join(componentDir, match.templateUrl);
  97. try {
  98. var templateContent = fs_1.readFileSync(htmlFilePath, 'utf8');
  99. return replaceTemplateUrl(match, htmlFilePath, templateContent);
  100. }
  101. catch (e) {
  102. logger_1.Logger.error("template error, \"" + htmlFilePath + "\": " + e);
  103. }
  104. return null;
  105. }
  106. exports.updateTemplate = updateTemplate;
  107. function replaceTemplateUrl(match, htmlFilePath, templateContent) {
  108. var orgTemplateProperty = match.templateProperty;
  109. var newTemplateProperty = getTemplateFormat(htmlFilePath, templateContent);
  110. return match.component.replace(orgTemplateProperty, newTemplateProperty);
  111. }
  112. exports.replaceTemplateUrl = replaceTemplateUrl;
  113. function replaceExistingJsTemplate(existingSourceText, newTemplateContent, htmlFilePath) {
  114. var prefix = getTemplatePrefix(htmlFilePath);
  115. var startIndex = existingSourceText.indexOf(prefix);
  116. var isStringified = false;
  117. if (startIndex === -1) {
  118. prefix = stringify(prefix);
  119. isStringified = true;
  120. }
  121. startIndex = existingSourceText.indexOf(prefix);
  122. if (startIndex === -1) {
  123. return null;
  124. }
  125. var suffix = getTemplateSuffix(htmlFilePath);
  126. if (isStringified) {
  127. suffix = stringify(suffix);
  128. }
  129. var endIndex = existingSourceText.indexOf(suffix, startIndex + 1);
  130. if (endIndex === -1) {
  131. return null;
  132. }
  133. var oldTemplate = existingSourceText.substring(startIndex, endIndex + suffix.length);
  134. var newTemplate = getTemplateFormat(htmlFilePath, newTemplateContent);
  135. if (isStringified) {
  136. newTemplate = stringify(newTemplate);
  137. }
  138. var lastChange = null;
  139. while (existingSourceText.indexOf(oldTemplate) > -1 && existingSourceText !== lastChange) {
  140. lastChange = existingSourceText = existingSourceText.replace(oldTemplate, newTemplate);
  141. }
  142. return existingSourceText;
  143. }
  144. exports.replaceExistingJsTemplate = replaceExistingJsTemplate;
  145. function stringify(str) {
  146. str = JSON.stringify(str);
  147. return str.substr(1, str.length - 2);
  148. }
  149. function getTemplateFormat(htmlFilePath, content) {
  150. // turn the template into one line and espcape single quotes
  151. content = content.replace(/\r|\n/g, '\\n');
  152. content = content.replace(/\'/g, '\\\'');
  153. return getTemplatePrefix(htmlFilePath) + "'" + content + "'" + getTemplateSuffix(htmlFilePath);
  154. }
  155. exports.getTemplateFormat = getTemplateFormat;
  156. function getTemplatePrefix(htmlFilePath) {
  157. return "template:/*ion-inline-start:\"" + path_1.resolve(htmlFilePath) + "\"*/";
  158. }
  159. function getTemplateSuffix(htmlFilePath) {
  160. return "/*ion-inline-end:\"" + path_1.resolve(htmlFilePath) + "\"*/";
  161. }
  162. function getTemplateMatch(str) {
  163. var match = COMPONENT_REGEX.exec(str);
  164. if (match) {
  165. return {
  166. start: match.index,
  167. end: match.index + match[0].length,
  168. component: match[0],
  169. templateProperty: match[3],
  170. templateUrl: match[5].trim()
  171. };
  172. }
  173. return null;
  174. }
  175. exports.getTemplateMatch = getTemplateMatch;
  176. var COMPONENT_REGEX = /Component\s*?\(\s*?(\{([\s\S]*?)(\s*templateUrl\s*:\s*(['"`])(.*?)(['"`])\s*?)([\s\S]*?)}\s*?)\)/m;