ts.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.resolveVueCompilerOptions = exports.createParsedCommandLine = exports.createParsedCommandLineByJson = void 0;
  4. const path = require("path-browserify");
  5. function createParsedCommandLineByJson(ts, parseConfigHost, rootDir, json, configFileName = rootDir + '/jsconfig.json') {
  6. const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
  7. ts.parseJsonConfigFileContent(json, proxyHost.host, rootDir, {}, configFileName);
  8. let vueOptions = {};
  9. for (const extendPath of proxyHost.extendConfigPaths.reverse()) {
  10. try {
  11. vueOptions = {
  12. ...vueOptions,
  13. ...getPartialVueCompilerOptions(ts, ts.readJsonConfigFile(extendPath, proxyHost.host.readFile)),
  14. };
  15. }
  16. catch (err) { }
  17. }
  18. const parsed = ts.parseJsonConfigFileContent(json, proxyHost.host, rootDir, {}, configFileName, undefined, (vueOptions.extensions ?? ['.vue']).map(extension => ({
  19. extension: extension.slice(1),
  20. isMixedContent: true,
  21. scriptKind: ts.ScriptKind.Deferred,
  22. })));
  23. // fix https://github.com/vuejs/language-tools/issues/1786
  24. // https://github.com/microsoft/TypeScript/issues/30457
  25. // patching ts server broke with outDir + rootDir + composite/incremental
  26. parsed.options.outDir = undefined;
  27. return {
  28. ...parsed,
  29. vueOptions,
  30. };
  31. }
  32. exports.createParsedCommandLineByJson = createParsedCommandLineByJson;
  33. function createParsedCommandLine(ts, parseConfigHost, tsConfigPath) {
  34. try {
  35. const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
  36. const config = ts.readJsonConfigFile(tsConfigPath, proxyHost.host.readFile);
  37. ts.parseJsonSourceFileConfigFileContent(config, proxyHost.host, path.dirname(tsConfigPath), {}, tsConfigPath);
  38. let vueOptions = {};
  39. for (const extendPath of proxyHost.extendConfigPaths.reverse()) {
  40. try {
  41. vueOptions = {
  42. ...vueOptions,
  43. ...getPartialVueCompilerOptions(ts, ts.readJsonConfigFile(extendPath, proxyHost.host.readFile)),
  44. };
  45. }
  46. catch (err) { }
  47. }
  48. const parsed = ts.parseJsonSourceFileConfigFileContent(config, proxyHost.host, path.dirname(tsConfigPath), {}, tsConfigPath, undefined, (vueOptions.extensions ?? ['.vue']).map(extension => ({
  49. extension: extension.slice(1),
  50. isMixedContent: true,
  51. scriptKind: ts.ScriptKind.Deferred,
  52. })));
  53. // fix https://github.com/vuejs/language-tools/issues/1786
  54. // https://github.com/microsoft/TypeScript/issues/30457
  55. // patching ts server broke with outDir + rootDir + composite/incremental
  56. parsed.options.outDir = undefined;
  57. return {
  58. ...parsed,
  59. vueOptions,
  60. };
  61. }
  62. catch (err) {
  63. // console.warn('Failed to resolve tsconfig path:', tsConfigPath, err);
  64. return {
  65. fileNames: [],
  66. options: {},
  67. vueOptions: resolveVueCompilerOptions({}),
  68. errors: [],
  69. };
  70. }
  71. }
  72. exports.createParsedCommandLine = createParsedCommandLine;
  73. function proxyParseConfigHostForExtendConfigPaths(parseConfigHost) {
  74. const extendConfigPaths = [];
  75. const host = new Proxy(parseConfigHost, {
  76. get(target, key) {
  77. if (key === 'readFile') {
  78. return (fileName) => {
  79. if (!fileName.endsWith('/package.json') && !extendConfigPaths.includes(fileName)) {
  80. extendConfigPaths.push(fileName);
  81. }
  82. return target.readFile(fileName);
  83. };
  84. }
  85. return target[key];
  86. }
  87. });
  88. return {
  89. host,
  90. extendConfigPaths,
  91. };
  92. }
  93. function getPartialVueCompilerOptions(ts, tsConfigSourceFile) {
  94. const folder = path.dirname(tsConfigSourceFile.fileName);
  95. const obj = ts.convertToObject(tsConfigSourceFile, []);
  96. const rawOptions = obj?.vueCompilerOptions ?? {};
  97. const result = {
  98. ...rawOptions,
  99. };
  100. const target = rawOptions.target ?? 'auto';
  101. if (target === 'auto') {
  102. const resolvedPath = resolvePath('vue/package.json');
  103. if (resolvedPath) {
  104. const vuePackageJson = require(resolvedPath);
  105. const versionNumbers = vuePackageJson.version.split('.');
  106. result.target = Number(versionNumbers[0] + '.' + versionNumbers[1]);
  107. }
  108. else {
  109. // console.warn('Load vue/package.json failed from', folder);
  110. }
  111. }
  112. else {
  113. result.target = target;
  114. }
  115. if (rawOptions.plugins) {
  116. const plugins = rawOptions.plugins
  117. .map((pluginPath) => {
  118. try {
  119. const resolvedPath = resolvePath(pluginPath);
  120. if (resolvedPath) {
  121. return require(resolvedPath);
  122. }
  123. else {
  124. console.warn('Load plugin failed:', pluginPath);
  125. }
  126. }
  127. catch (error) {
  128. console.warn('Load plugin failed:', pluginPath, error);
  129. }
  130. return [];
  131. })
  132. .flat(Infinity);
  133. result.plugins = plugins;
  134. }
  135. if (rawOptions.hooks) {
  136. result.hooks = rawOptions.hooks
  137. .map(resolvePath)
  138. .filter((hook) => !!hook);
  139. }
  140. if (rawOptions.experimentalAdditionalLanguageModules) {
  141. result.experimentalAdditionalLanguageModules = rawOptions.experimentalAdditionalLanguageModules
  142. .map(resolvePath)
  143. .filter((module) => !!module);
  144. }
  145. return result;
  146. function resolvePath(scriptPath) {
  147. try {
  148. if (require?.resolve) {
  149. return require.resolve(scriptPath, { paths: [folder] });
  150. }
  151. else {
  152. // console.warn('failed to resolve path:', scriptPath, 'require.resolve is not supported in web');
  153. }
  154. }
  155. catch (error) {
  156. // console.warn(error);
  157. }
  158. }
  159. }
  160. // https://developer.mozilla.org/en-US/docs/Web/HTML/Element
  161. const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' +
  162. 'header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,' +
  163. 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' +
  164. 'data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,' +
  165. 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' +
  166. 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' +
  167. 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' +
  168. 'option,output,progress,select,textarea,details,dialog,menu,' +
  169. 'summary,template,blockquote,iframe,tfoot';
  170. // https://developer.mozilla.org/en-US/docs/Web/SVG/Element
  171. const SVG_TAGS = 'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' +
  172. 'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' +
  173. 'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' +
  174. 'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' +
  175. 'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' +
  176. 'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' +
  177. 'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' +
  178. 'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' +
  179. 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' +
  180. 'text,textPath,title,tspan,unknown,use,view';
  181. function resolveVueCompilerOptions(vueOptions) {
  182. const target = vueOptions.target ?? 3.3;
  183. const lib = vueOptions.lib || (target < 2.7 ? '@vue/runtime-dom' : 'vue');
  184. return {
  185. ...vueOptions,
  186. target,
  187. extensions: vueOptions.extensions ?? ['.vue'],
  188. lib,
  189. jsxSlots: vueOptions.jsxSlots ?? false,
  190. strictTemplates: vueOptions.strictTemplates ?? false,
  191. skipTemplateCodegen: vueOptions.skipTemplateCodegen ?? false,
  192. nativeTags: vueOptions.nativeTags ?? [...new Set([
  193. ...HTML_TAGS.split(','),
  194. ...SVG_TAGS.split(','),
  195. // fix https://github.com/johnsoncodehk/volar/issues/1340
  196. 'hgroup',
  197. 'slot',
  198. 'component',
  199. ])],
  200. dataAttributes: vueOptions.dataAttributes ?? [],
  201. htmlAttributes: vueOptions.htmlAttributes ?? ['aria-*'],
  202. optionsWrapper: vueOptions.optionsWrapper ?? (target >= 2.7
  203. ? [`(await import('${lib}')).defineComponent(`, `)`]
  204. : [`(await import('vue')).default.extend(`, `)`]),
  205. macros: {
  206. defineProps: ['defineProps'],
  207. defineSlots: ['defineSlots'],
  208. defineEmits: ['defineEmits'],
  209. defineExpose: ['defineExpose'],
  210. defineModel: ['defineModel'],
  211. defineOptions: ['defineOptions'],
  212. withDefaults: ['withDefaults'],
  213. ...vueOptions.macros,
  214. },
  215. plugins: vueOptions.plugins ?? [],
  216. hooks: vueOptions.hooks ?? [],
  217. // experimental
  218. experimentalDefinePropProposal: vueOptions.experimentalDefinePropProposal ?? false,
  219. experimentalAdditionalLanguageModules: vueOptions.experimentalAdditionalLanguageModules ?? [],
  220. experimentalResolveStyleCssClasses: vueOptions.experimentalResolveStyleCssClasses ?? 'scoped',
  221. // https://github.com/vuejs/vue-next/blob/master/packages/compiler-dom/src/transforms/vModel.ts#L49-L51
  222. // https://vuejs.org/guide/essentials/forms.html#form-input-bindings
  223. experimentalModelPropName: vueOptions.experimentalModelPropName ?? {
  224. '': {
  225. input: true
  226. },
  227. value: {
  228. input: { type: 'text' },
  229. textarea: true,
  230. select: true
  231. }
  232. },
  233. experimentalUseElementAccessInTemplate: vueOptions.experimentalUseElementAccessInTemplate ?? false,
  234. };
  235. }
  236. exports.resolveVueCompilerOptions = resolveVueCompilerOptions;
  237. //# sourceMappingURL=ts.js.map