版博士V2.0程序
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1 год назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. "use strict";
  2. /**
  3. * Code generator for i18n js resource
  4. */
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.generate = void 0;
  7. const shared_1 = require("@intlify/shared");
  8. const acorn_1 = require("acorn");
  9. const escodegen_1 = require("escodegen");
  10. const estree_walker_1 = require("estree-walker");
  11. const codegen_1 = require("./codegen");
  12. /**
  13. * @internal
  14. */
  15. function generate(targetSource, { type = 'plain', bridge = false, exportESM = false, filename = 'vue-i18n-loader.js', inSourceMap = undefined, locale = '', isGlobal = false, sourceMap = false, env = 'development', forceStringify = false, onError = undefined, strictMessage = true, escapeHtml = false, useClassComponent = false, allowDynamic = false }, injector) {
  16. const target = Buffer.isBuffer(targetSource)
  17. ? targetSource.toString()
  18. : targetSource;
  19. const value = target;
  20. const options = {
  21. type,
  22. bridge,
  23. exportESM,
  24. source: value,
  25. sourceMap,
  26. locale,
  27. isGlobal,
  28. inSourceMap,
  29. env,
  30. filename,
  31. forceStringify,
  32. onError,
  33. strictMessage,
  34. escapeHtml,
  35. useClassComponent
  36. };
  37. const generator = (0, codegen_1.createCodeGenerator)(options);
  38. const ast = (0, acorn_1.parse)(value, {
  39. ecmaVersion: 'latest',
  40. sourceType: 'module',
  41. sourceFile: filename,
  42. allowImportExportEverywhere: true
  43. });
  44. const exportResult = scanAst(ast);
  45. if (!allowDynamic) {
  46. // if (!astExportDefaultWithObject.length) {
  47. if (!exportResult || exportResult !== 'object') {
  48. throw new Error(`You need to define an object as the locale message with 'export default'.`);
  49. }
  50. }
  51. else {
  52. if (!exportResult) {
  53. throw new Error(`You need to define 'export default' that will return the locale messages.`);
  54. }
  55. if (exportResult !== 'object') {
  56. /**
  57. * NOTE:
  58. * If `allowDynamic` is `true`, do not transform the code by this function, return it as is.
  59. * This means that the user **must transform locale messages ownself**.
  60. * Especially at the production, you need to do locale messages pre-compiling.
  61. */
  62. return {
  63. ast,
  64. code: value,
  65. map: inSourceMap
  66. };
  67. }
  68. }
  69. const codeMaps = generateNode(generator, ast, options, injector);
  70. const { code, map } = generator.context();
  71. // if (map) {
  72. // const s = new SourceMapConsumer((map as any).toJSON())
  73. // s.eachMapping(m => {
  74. // console.log('sourcemap json', m)
  75. // })
  76. // }
  77. // prettier-ignore
  78. const newMap = map
  79. ? (0, codegen_1.mapLinesColumns)(map.toJSON(), codeMaps, inSourceMap) || null // eslint-disable-line @typescript-eslint/no-explicit-any
  80. : null;
  81. return {
  82. ast,
  83. code,
  84. map: newMap != null ? newMap : undefined
  85. };
  86. }
  87. exports.generate = generate;
  88. function scanAst(ast) {
  89. if (ast.type !== 'Program') {
  90. throw new Error('Invalid AST: does not have Program node');
  91. }
  92. let ret = false;
  93. for (const node of ast.body) {
  94. if (node.type === 'ExportDefaultDeclaration') {
  95. if (node.declaration.type === 'ObjectExpression') {
  96. ret = 'object';
  97. break;
  98. }
  99. else if (node.declaration.type === 'FunctionDeclaration') {
  100. ret = 'function';
  101. break;
  102. }
  103. else if (node.declaration.type === 'ArrowFunctionExpression') {
  104. ret = 'arrow-function';
  105. break;
  106. }
  107. }
  108. }
  109. return ret;
  110. }
  111. function generateNode(generator, node, options, injector) {
  112. const propsCountStack = [];
  113. const pathStack = [];
  114. const itemsCountStack = [];
  115. const skipStack = [];
  116. const { forceStringify } = generator.context();
  117. const codeMaps = new Map();
  118. const { type, bridge, exportESM, sourceMap, isGlobal, locale, useClassComponent } = options;
  119. const componentNamespace = '_Component';
  120. (0, estree_walker_1.walk)(node, {
  121. /**
  122. * NOTE:
  123. * force cast to Node of `estree-walker@3.x`,
  124. * because `estree-walker@3.x` is not dual packages,
  125. * so it's support only esm only ...
  126. */
  127. // @ts-ignore
  128. enter(node, parent) {
  129. switch (node.type) {
  130. case 'Program':
  131. if (type === 'plain') {
  132. generator.push(`const resource = `);
  133. }
  134. else if (type === 'sfc') {
  135. // for 'sfc'
  136. const variableName = type === 'sfc' ? (!isGlobal ? '__i18n' : '__i18nGlobal') : '';
  137. const localeName = type === 'sfc' ? (locale != null ? locale : `""`) : '';
  138. const exportSyntax = bridge
  139. ? exportESM
  140. ? `export default`
  141. : `module.exports =`
  142. : `export default`;
  143. generator.push(`${exportSyntax} function (Component) {`);
  144. generator.indent();
  145. // prettier-ignore
  146. const componentVariable = bridge
  147. ? `Component.options || Component`
  148. : useClassComponent
  149. ? `Component.__o || Component`
  150. : `Component`;
  151. // prettier-ignore
  152. generator.pushline(`const ${componentNamespace} = ${componentVariable}`);
  153. generator.pushline(`${componentNamespace}.${variableName} = ${componentNamespace}.${variableName} || []`);
  154. generator.push(`${componentNamespace}.${variableName}.push({`);
  155. generator.indent();
  156. generator.pushline(`"locale": ${JSON.stringify(localeName)},`);
  157. generator.push(`"resource": `);
  158. }
  159. break;
  160. case 'ObjectExpression':
  161. generator.push(`{`);
  162. generator.indent();
  163. propsCountStack.push(node.properties.length);
  164. if (parent != null && parent.type === 'ArrayExpression') {
  165. const lastIndex = itemsCountStack.length - 1;
  166. const currentCount = parent.elements.length - itemsCountStack[lastIndex];
  167. pathStack.push(currentCount.toString());
  168. itemsCountStack[lastIndex] = --itemsCountStack[lastIndex];
  169. }
  170. break;
  171. case 'Property':
  172. if (parent != null && parent.type === 'ObjectExpression') {
  173. if (node != null) {
  174. if (isJSONablePrimitiveLiteral(node.value) &&
  175. (node.key.type === 'Literal' || node.key.type === 'Identifier')) {
  176. // prettier-ignore
  177. const name = node.key.type === 'Literal'
  178. ? String(node.key.value)
  179. : node.key.name;
  180. if ((node.value.type === 'Literal' &&
  181. (0, shared_1.isString)(node.value.value)) ||
  182. node.value.type === 'TemplateLiteral') {
  183. const value = getValue(node.value);
  184. generator.push(`${JSON.stringify(name)}: `);
  185. pathStack.push(name);
  186. const { code, map } = (0, codegen_1.generateMessageFunction)(value, options, pathStack);
  187. sourceMap && map != null && codeMaps.set(value, map);
  188. generator.push(`${code}`, node.value, value);
  189. skipStack.push(false);
  190. }
  191. else {
  192. const value = getValue(node.value);
  193. if (forceStringify) {
  194. const strValue = JSON.stringify(value);
  195. generator.push(`${JSON.stringify(name)}: `);
  196. pathStack.push(name);
  197. const { code, map } = (0, codegen_1.generateMessageFunction)(strValue, options, pathStack);
  198. sourceMap && map != null && codeMaps.set(strValue, map);
  199. generator.push(`${code}`, node.value, strValue);
  200. }
  201. else {
  202. generator.push(`${JSON.stringify(name)}: ${JSON.stringify(value)}`);
  203. pathStack.push(name);
  204. }
  205. skipStack.push(false);
  206. }
  207. }
  208. else if ((node.value.type === 'FunctionExpression' ||
  209. node.value.type === 'ArrowFunctionExpression') &&
  210. (node.key.type === 'Literal' || node.key.type === 'Identifier')) {
  211. // prettier-ignore
  212. const name = node.key.type === 'Literal'
  213. ? String(node.key.value)
  214. : node.key.name;
  215. generator.push(`${JSON.stringify(name)}: `);
  216. pathStack.push(name);
  217. const code = (0, escodegen_1.generate)(node.value);
  218. generator.push(`${code}`, node.value, code);
  219. skipStack.push(false);
  220. }
  221. else if ((node.value.type === 'ObjectExpression' ||
  222. node.value.type === 'ArrayExpression') &&
  223. (node.key.type === 'Literal' || node.key.type === 'Identifier')) {
  224. // prettier-ignore
  225. const name = node.key.type === 'Literal'
  226. ? String(node.key.value)
  227. : node.key.name;
  228. generator.push(`${JSON.stringify(name)}: `);
  229. pathStack.push(name);
  230. }
  231. else {
  232. // for Regex, function, etc.
  233. skipStack.push(true);
  234. }
  235. }
  236. const lastIndex = propsCountStack.length - 1;
  237. propsCountStack[lastIndex] = --propsCountStack[lastIndex];
  238. }
  239. break;
  240. case 'ArrayExpression':
  241. generator.push(`[`);
  242. generator.indent();
  243. if (parent != null && parent.type === 'ArrayExpression') {
  244. const lastIndex = itemsCountStack.length - 1;
  245. const currentCount = parent.elements.length - itemsCountStack[lastIndex];
  246. pathStack.push(currentCount.toString());
  247. itemsCountStack[lastIndex] = --itemsCountStack[lastIndex];
  248. }
  249. itemsCountStack.push(node.elements.length);
  250. break;
  251. default:
  252. if (node != null && parent != null) {
  253. if (parent.type === 'ArrayExpression') {
  254. const lastIndex = itemsCountStack.length - 1;
  255. const currentCount = parent.elements.length - itemsCountStack[lastIndex];
  256. pathStack.push(currentCount.toString());
  257. if (isJSONablePrimitiveLiteral(node)) {
  258. if ((node.type === 'Literal' && (0, shared_1.isString)(node.value)) ||
  259. node.type === 'TemplateLiteral') {
  260. const value = getValue(node);
  261. const { code, map } = (0, codegen_1.generateMessageFunction)(value, options, pathStack);
  262. sourceMap && map != null && codeMaps.set(value, map);
  263. generator.push(`${code}`, node, value);
  264. }
  265. else {
  266. const value = getValue(node);
  267. if (forceStringify) {
  268. const strValue = JSON.stringify(value);
  269. const { code, map } = (0, codegen_1.generateMessageFunction)(strValue, options, pathStack);
  270. sourceMap && map != null && codeMaps.set(strValue, map);
  271. generator.push(`${code}`, node, strValue);
  272. }
  273. else {
  274. generator.push(`${JSON.stringify(value)}`);
  275. }
  276. }
  277. skipStack.push(false);
  278. }
  279. else {
  280. // for Regex, function, etc.
  281. skipStack.push(true);
  282. }
  283. itemsCountStack[lastIndex] = --itemsCountStack[lastIndex];
  284. }
  285. }
  286. else {
  287. // ...
  288. }
  289. break;
  290. }
  291. },
  292. /**
  293. * NOTE:
  294. * force cast to Node of `estree-walker@3.x`,
  295. * because `estree-walker@3.x` is not dual packages,
  296. * so it's support only esm only ...
  297. */
  298. // @ts-ignore
  299. leave(node, parent) {
  300. switch (node.type) {
  301. case 'Program':
  302. if (type === 'sfc') {
  303. generator.deindent();
  304. generator.push(`})`);
  305. if (bridge && injector) {
  306. generator.newline();
  307. generator.pushline(`${componentNamespace}.__i18nBridge = ${componentNamespace}.__i18nBridge || []`);
  308. generator.pushline(`${componentNamespace}.__i18nBridge.push('${injector()}')`);
  309. generator.pushline(`delete ${componentNamespace}._Ctor`);
  310. }
  311. generator.deindent();
  312. generator.pushline(`}`);
  313. }
  314. else if (type === 'plain') {
  315. generator.push(`\n`);
  316. generator.push('export default resource');
  317. }
  318. break;
  319. case 'ObjectExpression':
  320. if (propsCountStack[propsCountStack.length - 1] === 0) {
  321. pathStack.pop();
  322. propsCountStack.pop();
  323. }
  324. generator.deindent();
  325. generator.push(`}`);
  326. if (parent != null && parent.type === 'ArrayExpression') {
  327. if (itemsCountStack[itemsCountStack.length - 1] !== 0) {
  328. pathStack.pop();
  329. generator.pushline(`,`);
  330. }
  331. }
  332. break;
  333. case 'Property':
  334. if (parent != null && parent.type === 'ObjectExpression') {
  335. if (propsCountStack[propsCountStack.length - 1] !== 0) {
  336. pathStack.pop();
  337. if (!skipStack.pop()) {
  338. generator.pushline(`,`);
  339. }
  340. }
  341. }
  342. break;
  343. case 'ArrayExpression':
  344. if (itemsCountStack[itemsCountStack.length - 1] === 0) {
  345. pathStack.pop();
  346. itemsCountStack.pop();
  347. }
  348. generator.deindent();
  349. generator.push(`]`);
  350. if (parent != null && parent.type === 'ArrayExpression') {
  351. if (itemsCountStack[itemsCountStack.length - 1] !== 0) {
  352. pathStack.pop();
  353. if (!skipStack.pop()) {
  354. generator.pushline(`,`);
  355. }
  356. }
  357. }
  358. break;
  359. case 'Literal':
  360. if (parent != null && parent.type === 'ArrayExpression') {
  361. if (itemsCountStack[itemsCountStack.length - 1] !== 0) {
  362. pathStack.pop();
  363. if (!skipStack.pop()) {
  364. generator.pushline(`,`);
  365. }
  366. }
  367. else {
  368. if (!skipStack.pop()) {
  369. generator.pushline(`,`);
  370. }
  371. }
  372. }
  373. break;
  374. default:
  375. break;
  376. }
  377. }
  378. });
  379. return codeMaps;
  380. }
  381. function isJSONablePrimitiveLiteral(node) {
  382. return ((node.type === 'Literal' &&
  383. ((0, shared_1.isString)(node.value) ||
  384. (0, shared_1.isNumber)(node.value) ||
  385. (0, shared_1.isBoolean)(node.value) ||
  386. node.value === null)) ||
  387. node.type === 'TemplateLiteral');
  388. // NOTE: the following code is same the above code
  389. /*
  390. if (node.type === 'Literal') {
  391. if (
  392. isString(node.value) ||
  393. isNumber(node.value) ||
  394. isBoolean(node.value) ||
  395. node.value === null
  396. ) {
  397. return true
  398. } else if (isRegExp(node.value)) {
  399. return false
  400. } else {
  401. return false
  402. }
  403. } else if (node.type === 'TemplateLiteral') {
  404. return true
  405. } else {
  406. return false
  407. }
  408. */
  409. }
  410. function getValue(node) {
  411. // prettier-ignore
  412. return node.type === 'Literal'
  413. ? node.value
  414. : node.type === 'TemplateLiteral'
  415. ? node.quasis.map(quasi => quasi.value.cooked).join('')
  416. : undefined;
  417. }