i18n-utils.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. module.exports.mixin = function(result, ...args) {
  2. for (const arg of args) {
  3. mixinObject(result, arg);
  4. }
  5. return result;
  6. };
  7. module.exports.link = function(root) {
  8. const visited = new Set();
  9. link(root);
  10. return root;
  11. function link(o) {
  12. if (visited.has(o)) {
  13. return;
  14. }
  15. visited.add(o);
  16. const __extends__ = o.__extends__;
  17. const extended = {};
  18. if (typeof __extends__ === 'string') {
  19. const base = find(__extends__);
  20. if (!base) {
  21. console.error(`Can not find the __extends__ ${__extends__}`);
  22. } else {
  23. link(base);
  24. mixinObject(extended, base);
  25. }
  26. }
  27. for (const [k, v] of Object.entries(o)) {
  28. if (typeof v === 'object' && v) {
  29. link(v);
  30. }
  31. }
  32. mixinObject(o, extended);
  33. }
  34. function find(path) {
  35. const items = path.split('.');
  36. if (items.length === 0) {
  37. return undefined;
  38. }
  39. let result = root;
  40. for (const item of items) {
  41. if (!item) {
  42. return undefined;
  43. }
  44. if (!(item in result)) {
  45. return undefined;
  46. }
  47. const r = result[item];
  48. if (typeof r !== 'object' || !r) {
  49. return undefined;
  50. }
  51. result = r;
  52. }
  53. return result;
  54. }
  55. };
  56. function mixinObject(o1, o2, o1FullPath, o2FullPath) {
  57. for (const [k, v2] of Object.entries(o2)) {
  58. if (typeof v2 !== 'object' || !v2) {
  59. if (k in o1) {
  60. reportMixinFailure(k);
  61. } else {
  62. o1[k] = v2;
  63. }
  64. continue;
  65. }
  66. if (Array.isArray(v2)) {
  67. let v1;
  68. if (!(k in o1)) {
  69. v1 = o1[k] = [];
  70. } else if (Array.isArray(o1[k])) {
  71. v1 = o1[k];
  72. } else {
  73. reportMixinFailure(k);
  74. continue;
  75. }
  76. v1.push(...v2);
  77. continue;
  78. }
  79. // v2 is object
  80. {
  81. let v1;
  82. if (!(k in o1)) {
  83. v1 = o1[k] = {};
  84. } else {
  85. v1 = o1[k];
  86. if (typeof v1 !== 'object' || !v1) {
  87. reportMixinFailure(k);
  88. continue;
  89. }
  90. }
  91. mixinObject(v1, v2, getFullPath(o1FullPath, k), getFullPath(o2FullPath, k));
  92. continue;
  93. }
  94. }
  95. function reportMixinFailure(k) {
  96. console.error(
  97. `Can not mix `
  98. + `${getFullPath(o2FullPath, k)}(type: ${getLogType(o2[k])}) `
  99. + `into `
  100. + `${getFullPath(o1FullPath, k)}(type: ${getLogType(o1[k])})`
  101. );
  102. }
  103. function getFullPath(prefix, k) {
  104. return `${prefix}['${k}']`;
  105. }
  106. function getLogType(v) {
  107. if (typeof v !== 'object') {
  108. return typeof v;
  109. } else if (!v) {
  110. return 'null';
  111. } else if (Array.isArray(v)) {
  112. return 'array';
  113. } else {
  114. return 'object';
  115. }
  116. }
  117. }